rigidRotor3DFWBW.py
You can view and download this file on Github: rigidRotor3DFWBW.py
1#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2# This is an EXUDYN example
3#
4# Details: Example with 3D rotor; rotates around X-axis
5# showing forward (FW) and backward (BW) whirls and FW/BW whirl resonances
6#
7# Author: Johannes Gerstmayr
8# Date: 2019-12-05
9#
10# Copyright:This file is part of Exudyn. Exudyn is free software. You can redistribute it and/or modify it under the terms of the Exudyn license. See 'LICENSE.txt' for more details.
11#
12#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
13import sys
14sys.path.append('../TestModels') #for modelUnitTest as this example may be used also as a unit test
15
16import exudyn as exu
17from exudyn.itemInterface import *
18from exudyn.utilities import * #includes itemInterface and rigidBodyUtilities
19import exudyn.graphics as graphics #only import if it does not conflict
20from math import cos, sin
21
22import time
23import numpy as np
24
25SC = exu.SystemContainer()
26mbs = SC.AddSystem()
27print('EXUDYN version='+exu.GetVersionString())
28
29L=1 #rotor axis length
30isSymmetric = True
31symStr = "General"
32if isSymmetric:
33 L0 = 0.5 #0.5 (symmetric rotor); position of rotor on x-axis
34 symStr = "Laval"
35 s = "symmetric"
36else :
37 L0 = 0.9 #default: 0.9m; position of rotor on x-axis
38 s = "unsymmetric"
39
40L1 = L-L0 #
41m = 2 #mass in kg
42r = 0.5*1.5 #radius for disc mass distribution
43lRotor = 0.2 #length of rotor disk
44k = 800 #stiffness of (all/both) springs in rotor in N/m
45Jxx = 0.5*m*r**2 #polar moment of inertia
46Jyyzz = 0.25*m*r**2 + 1/12.*m*lRotor**2 #moment of inertia for y and z axes
47
48omega0=np.sqrt(2*k/m) #linear system
49
50D0 = 0.002 #dimensionless damping
51d = 2*omega0*D0*m #damping constant in N/(m/s)
52
53f0 = 0*omega0/(2*np.pi) #frequency start (Hz)
54f1 = 2.*omega0/(2*np.pi) #frequency end (Hz)
55
56torque = 0.2*2 #driving torque; Nm ; 0.1Nm does not surpass critical speed; 0.2Nm works
57eps = 2e-3*0. #0.74; excentricity of mass in y-direction
58 #symmetric rotor: 2e-3 gives large oscillations;
59 #symmetric rotor: 0.74*2e-3 shows kink in runup curve
60
61omegaInitial = 0*4*omega0 #initial rotation speed in rad/s
62
63tEnd = 20 #end time of simulation
64steps = int(tEnd*1000) #number of steps
65
66modeStr = "BW" #"FW" or "BW"
67sign = 1
68if modeStr == "BW": sign = -1
69
70fRes = omega0/(2*np.pi)
71print('symmetric rotor resonance frequency (Hz)= '+str(fRes))
72#print('runup over '+str(tEnd)+' seconds, fStart='+str(f0)+'Hz, fEnd='+str(f1)+'Hz')
73
74#3D load vector
75loadFact = 1
76n1 = 0 #rotor node number, will be defined later
77def UFload(mbs, t, load):
78 #compute angle of rotation (only true if rotation about 1 axis)
79 phi = mbs.GetNodeOutput(nodeNumber=n1, variableType=exu.OutputVariableType.Rotation)[0]
80 return [0, sign*loadFact*cos(phi), loadFact*sin(phi)]
81
82#background1 = graphics.BrickXYZ(0,0,0,.5,0.5,0.5,[0.3,0.3,0.9,1])
83
84#draw RGB-frame at origin
85p=[0,0,0]
86lFrame = 0.9
87tFrame = 0.01
88backgroundX = graphics.Cylinder(p,[lFrame,0,0],tFrame,[0.9,0.3,0.3,1],12)
89backgroundY = graphics.Cylinder(p,[0,lFrame,0],tFrame,[0.3,0.9,0.3,1],12)
90backgroundZ = graphics.Cylinder(p,[0,0,lFrame],tFrame,[0.3,0.3,0.9,1],12)
91
92#visualize forces:
93lVec = r*0.8
94f1=0.08 #arrow size
95f2=0.04 #arrow size 2
96rigid = 0 #will be set later!
97#ground user function, but draws load on body
98def UFgraphics(mainSystem, bodyNr):
99 t=mainSystem.systemData.GetTime()
100 #get rotation for rigid body:
101 rot = mbs.GetObjectOutputBody(rigid, exu.OutputVariableType.Rotation,
102 [0,0,0], exu.ConfigurationType.Visualization)
103 omega = mbs.GetObjectOutputBody(rigid, exu.OutputVariableType.AngularVelocity,
104 [0,0,0], exu.ConfigurationType.Visualization)
105 phi = rot[0]
106 phi += 0.9*0.05*omega[0] #graphics is always delayed ...
107 #print("rot=", phi)
108
109 #g0=graphics.Sphere(point=p0,radius=0.01, color=graphics.color.green)
110 #g1=graphics.Sphere(point=p1,radius=0.01, color=graphics.color.red)
111 xVec = 0.5+lRotor
112 p0 = [xVec,0,0]
113 p1 = [xVec,sign*lVec*cos(phi), lVec*sin(phi)]
114 p2 = [xVec,sign*(1-f1)*lVec*cos(phi)-f2*lVec*sin(phi), (1-f1)*lVec*sin(phi)+f2*sign*lVec*cos(phi)]
115 p3 = [xVec,sign*(1-f1)*lVec*cos(phi)+f2*lVec*sin(phi), (1-f1)*lVec*sin(phi)-f2*sign*lVec*cos(phi)]
116 gLine = {'type':'Line', 'data': p0+p1+p2+p1+p3, 'color':graphics.color.red}
117 return [gLine]#,g0,g1] #return list of graphics data
118
119mbs.AddObject(ObjectGround(referencePosition= [0,0,0],
120 visualization=VObjectGround(graphicsDataUserFunction=UFgraphics)))
121
122#rotor is rotating around x-axis
123ep0 = eulerParameters0 #no rotation
124ep_t0 = AngularVelocity2EulerParameters_t([omegaInitial,0,0], ep0)
125print(ep_t0)
126
127p0 = [L0-0.5*L,eps,0] #reference position
128v0 = [0.,0.,0.] #initial translational velocity
129
130#node for Rigid2D body: px, py, phi:
131n1=mbs.AddNode(NodeRigidBodyEP(referenceCoordinates = p0+ep0, initialVelocities=v0+list(ep_t0)))
132
133#ground nodes
134nGround0=mbs.AddNode(NodePointGround(referenceCoordinates = [-L/2,0,0]))
135nGround1=mbs.AddNode(NodePointGround(referenceCoordinates = [ L/2,0,0]))
136
137#add mass point (this is a 3D object with 3 coordinates):
138gRotor = graphics.Cylinder([-lRotor*0.5,0,0],[lRotor,0,0],r,[0.3,0.3,0.9,1],128)
139gRotor2 = graphics.Cylinder([-L0,0,0],[L,0,0],r*0.05,[0.3,0.3,0.9,1],16)
140gRotor3 = [backgroundX, backgroundY, backgroundZ]
141rigid = mbs.AddObject(RigidBody(physicsMass=m, physicsInertia=[Jxx,Jyyzz,Jyyzz,0,0,0], nodeNumber = n1, visualization=VObjectRigidBody2D(graphicsData=[gRotor, gRotor2]+gRotor3)))
142
143mbs.AddSensor(SensorBody(bodyNumber=rigid,
144 fileName='solution/runupDisplacement'+modeStr+'.txt',
145 outputVariableType=exu.OutputVariableType.Displacement))
146mbs.AddSensor(SensorBody(bodyNumber=rigid,
147 fileName='solution/runupAngularVelocity'+modeStr+'.txt',
148 outputVariableType=exu.OutputVariableType.AngularVelocity))
149
150#marker for ground (=fixed):
151groundMarker0=mbs.AddMarker(MarkerNodePosition(nodeNumber= nGround0))
152groundMarker1=mbs.AddMarker(MarkerNodePosition(nodeNumber= nGround1))
153
154#marker for rotor axis and support:
155rotorAxisMarker0 =mbs.AddMarker(MarkerBodyPosition(bodyNumber=rigid, localPosition=[-L0,-eps,0]))
156rotorAxisMarker1 =mbs.AddMarker(MarkerBodyPosition(bodyNumber=rigid, localPosition=[ L1,-eps,0]))
157
158
159#++++++++++++++++++++++++++++++++++++
160mbs.AddObject(CartesianSpringDamper(markerNumbers=[groundMarker0, rotorAxisMarker0],
161 stiffness=[k,k,k], damping=[d, d, d]))
162mbs.AddObject(CartesianSpringDamper(markerNumbers=[groundMarker1, rotorAxisMarker1],
163 stiffness=[0,k,k], damping=[0, d, d])) #do not constrain x-axis twice
164
165#coordinate markers for loads:
166rotorMarkerUy=mbs.AddMarker(MarkerNodeCoordinate(nodeNumber= n1, coordinate=1))
167rotorMarkerUz=mbs.AddMarker(MarkerNodeCoordinate(nodeNumber= n1, coordinate=2))
168
169#add torque:
170rotorRigidMarker =mbs.AddMarker(MarkerBodyRigid(bodyNumber=rigid, localPosition=[0,0,0]))
171mbs.AddLoad(Torque(markerNumber=rotorRigidMarker,
172 loadVector=[torque,0,0],
173 visualization={'show':False}))
174
175#BW/FW load vector:
176mbs.AddLoad(Force(markerNumber=rotorRigidMarker,
177 loadVector=[0,0,0],
178 loadVectorUserFunction=UFload))
179
180#print(mbs)
181mbs.Assemble()
182#mbs.systemData.Info()
183
184simulationSettings = exu.SimulationSettings()
185simulationSettings.solutionSettings.solutionWritePeriod = 1e-5 #output interval
186simulationSettings.solutionSettings.sensorsWritePeriod = 1e-5 #output interval
187
188simulationSettings.solutionSettings.solutionInformation = "Runup of "+s+" rotor: "+modeStr + ", " + symStr
189
190simulationSettings.timeIntegration.numberOfSteps = steps
191simulationSettings.timeIntegration.endTime = tEnd
192simulationSettings.timeIntegration.generalizedAlpha.useIndex2Constraints = True
193simulationSettings.timeIntegration.generalizedAlpha.useNewmark = True
194
195simulationSettings.timeIntegration.generalizedAlpha.spectralRadius = 1
196
197#create animations (causes slow simulation):
198createAnimation=True
199if createAnimation:
200 simulationSettings.solutionSettings.recordImagesInterval = 0.05
201 SC.visualizationSettings.exportImages.saveImageFileName = "images/frame"
202 SC.visualizationSettings.window.renderWindowSize = [1600,1080]
203 SC.visualizationSettings.openGL.multiSampling = 4
204
205#visualize loads:
206# SC.visualizationSettings.loads.fixedLoadSize=False
207# SC.visualizationSettings.loads.loadSizeFactor=100
208# SC.visualizationSettings.loads.drawSimplified = False
209
210if True:
211 exu.StartRenderer() #start graphics visualization
212 mbs.WaitForUserToContinue() #wait for pressing SPACE bar to continue
213
214 #start solver:
215 mbs.SolveDynamic(simulationSettings)
216
217 #SC.WaitForRenderEngineStopFlag()#wait for pressing 'Q' to quit
218 exu.StopRenderer() #safely close rendering window!
219
220 #evaluate final (=current) output values
221 u = mbs.GetNodeOutput(n1, exu.OutputVariableType.AngularVelocity)
222 print('omega final (Hz)=',(1./(2.*np.pi))*u)
223 #print('displacement=',u[0])
224
225
226##+++++++++++++++++++++++++++++++++++++++++++++++++++++
227import matplotlib.pyplot as plt
228import matplotlib.ticker as ticker
229
230if False:
231 plt.close('all') #close all plots
232
233
234 dataDispFW = np.loadtxt('solution/runupDisplacementFW.txt', comments='#', delimiter=',')
235 dataOmegaFW = np.loadtxt('solution/runupAngularVelocityFW.txt', comments='#', delimiter=',')
236 dataDispBW = np.loadtxt('solution/runupDisplacementBW.txt', comments='#', delimiter=',')
237 dataOmegaBW = np.loadtxt('solution/runupAngularVelocityBW.txt', comments='#', delimiter=',')
238 plt.rcParams.update({'font.size': 12})
239
240 if False:
241 plt.plot(dataDispFW[:,0], dataDispFW[:,3], 'r-', label='FW') #numerical solution
242 plt.plot(dataDispBW[:,0], dataDispBW[:,3], 'b-', label='BW') #numerical solution
243 plt.xlabel("time (s)")
244 plt.ylabel("z-displacement (m)")
245 ax=plt.gca() # get current axes
246 ax.grid(True, 'major', 'both')
247 ax.xaxis.set_major_locator(ticker.MaxNLocator(10))
248 ax.yaxis.set_major_locator(ticker.MaxNLocator(10))
249 plt.legend()
250 plt.tight_layout()
251
252 plt.figure()
253 plt.plot((1/(2*np.pi))*dataOmegaFW[:,1], dataDispFW[:,3], 'r-', label='FW', linewidth=0.7) #numerical solution
254 plt.plot((1/(2*np.pi))*dataOmegaBW[:,1], dataDispBW[:,3], 'b-', label='BW', linewidth=0.7) #numerical solution
255 plt.xlabel("angular velocity (1/s)")
256 plt.ylabel("z-displacement (m)")
257 ax=plt.gca() # get current axes
258 ax.grid(True, 'major', 'both')
259 ax.xaxis.set_major_locator(ticker.MaxNLocator(10))
260 ax.yaxis.set_major_locator(ticker.MaxNLocator(10))
261 plt.legend()
262 plt.tight_layout()
263
264 #save figure:
265 #plt.savefig("rotorBWFWrunup"+symStr+".pdf")
266
267 # plt.figure()
268 # plt.plot(dataOmegaFW[:,0], (1/(2*np.pi))*dataOmegaFW[:,1], 'r-') #numerical solution
269 # plt.xlabel("time (s)")
270 # plt.ylabel("angular velocity (1/s)")
271 # ax=plt.gca() # get current axes
272 # ax.grid(True, 'major', 'both')
273 # ax.xaxis.set_major_locator(ticker.MaxNLocator(10))
274 # ax.yaxis.set_major_locator(ticker.MaxNLocator(10))
275 # plt.tight_layout()
276
277 # plt.figure()
278 # plt.plot(dataDispFW[:,2], dataDispFW[:,3], 'r-') #numerical solution
279 # plt.xlabel("y-displacement (m)")
280 # plt.ylabel("z-displacement (m)")
281 # ax=plt.gca() # get current axes
282 # ax.grid(True, 'major', 'both')
283 # ax.xaxis.set_major_locator(ticker.MaxNLocator(10))
284 # ax.yaxis.set_major_locator(ticker.MaxNLocator(10))
285 # plt.tight_layout()
286
287 #plt.plot(data[n-500:n-1,1], data[n-500:n-1,2], 'r-') #numerical solution
288
289 plt.show()