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