rigidRotor3Drunup.py
You can view and download this file on Github: rigidRotor3Drunup.py
1#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2# This is an EXUDYN example
3#
4# Details: Example with 3D rotor, showing runup
5#
6# Author: Johannes Gerstmayr
7# Date: 2019-12-05
8#
9# 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.
10#
11#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
12import sys
13sys.path.append('../TestModels') #for modelUnitTest as this example may be used also as a unit test
14
15import exudyn as exu
16#a local run must not open a plot window when windows are suppressed (#2477)
17if exu.special.userInterface.suppressPlots: import matplotlib; matplotlib.use('Agg')
18from exudyn.itemInterface import *
19from exudyn.utilities import * #includes itemInterface and rigidBodyUtilities
20import exudyn.graphics as graphics
21
22import time
23import numpy as np
24
25SC = exu.SystemContainer()
26mbs = SC.AddSystem()
27print('EXUDYN version='+exu.config.Version())
28
29L=1 #rotor axis length
30isSymmetric = True
31if isSymmetric:
32 L0 = 0.5 #0.5 (symmetric rotor); position of rotor on x-axis
33else :
34 L0 = 0.9 #default: 0.9m; position of rotor on x-axis
35L1 = L-L0 #
36m = 2 #mass in kg
37r = 0.5*1.5 #radius for disc mass distribution
38lRotor = 0.2 #length of rotor disk
39k = 800 #stiffness of (all/both) springs in rotor in N/m
40Jxx = 0.5*m*r**2 #polar moment of inertia
41Jyyzz = 0.25*m*r**2 + 1/12.*m*lRotor**2 #moment of inertia for y and z axes
42
43omega0=np.sqrt(2*k/m) #linear system
44
45D0 = 0.002 #dimensionless damping
46d = 2*omega0*D0*m #damping constant in N/(m/s)
47
48f0 = 0*omega0/(2*np.pi) #frequency start (Hz)
49f1 = 2.*omega0/(2*np.pi) #frequency end (Hz)
50
51torque = 0.2 #driving torque; Nm ; 0.1Nm does not surpass critical speed; 0.2Nm works
52eps = 2e-3*0.74 # excentricity of mass in y-direction
53 #symmetric rotor: 2e-3 gives large oscillations;
54 #symmetric rotor: 0.74*2e-3 shows kink in runup curve
55
56omegaInitial = 0*4*omega0 #initial rotation speed in rad/s
57
58tEnd = 200 #end time of simulation
59steps = 40000 #number of steps
60
61fRes = omega0/(2*np.pi)
62print('symmetric rotor resonance frequency (Hz)= '+str(fRes))
63#print('runup over '+str(tEnd)+' seconds, fStart='+str(f0)+'Hz, fEnd='+str(f1)+'Hz')
64
65#linear frequency sweep evaluated at time t, for time interval [0, t1] and frequency interval [f0,f1];
66def Sweep(t, t1, f0, f1):
67 k = (f1-f0)/t1
68 return np.sin(2*np.pi*(f0+k*0.5*t)*t) #take care of factor 0.5 in k*0.5*t, in order to obtain correct frequencies!!!
69def SweepCos(t, t1, f0, f1):
70 k = (f1-f0)/t1
71 return np.cos(2*np.pi*(f0+k*0.5*t)*t) #take care of factor 0.5 in k*0.5*t, in order to obtain correct frequencies!!!
72
73# #user function for load
74# def userLoad(t, load):
75# #return load*np.sin(0.5*omega0*t) #gives resonance
76# if t>40: time.sleep(0.02) #make simulation slower
77# return load*Sweep(t, tEnd, f0, f1)
78# #return load*Sweep(t, tEnd, f1, f0) #backward sweep
79
80# #backward whirl excitation:
81# amp = 0.10 #in resonance: *0.01
82# def userLoadBWy(t, load):
83# return load*SweepCos(t, tEnd, f0, f1) #negative sign: BW, positive sign: FW
84# def userLoadBWz(t, load):
85# return load*Sweep(t, tEnd, f0, f1)
86#def userLoadBWx(t, load):
87# return load*np.sin(omegaInitial*t)
88#def userLoadBWy(t, load):
89# return -load*np.cos(omegaInitial*t) #negative sign: FW, positive sign: BW
90
91#background1 = graphics.BrickXYZ(0,0,0,.5,0.5,0.5,[0.3,0.3,0.9,1])
92
93#draw RGB-frame at origin
94p=[0,0,0]
95lFrame = 0.8
96tFrame = 0.01
97backgroundX = graphics.Cylinder(p,[lFrame,0,0],tFrame,[0.9,0.3,0.3,1],12)
98backgroundY = graphics.Cylinder(p,[0,lFrame,0],tFrame,[0.3,0.9,0.3,1],12)
99backgroundZ = graphics.Cylinder(p,[0,0,lFrame],tFrame,[0.3,0.3,0.9,1],12)
100#mbs.AddObject(ObjectGround(referencePosition= [0,0,0], visualization=VObjectGround(graphicsData= [backgroundX, backgroundY, backgroundZ])))
101
102#rotor is rotating around x-axis
103ep0 = eulerParameters0 #no rotation
104ep_t0 = AngularVelocity2EulerParameters_t([omegaInitial,0,0], ep0)
105print(ep_t0)
106
107p0 = [L0-0.5*L,eps,0] #reference position
108v0 = [0.,0.,0.] #initial translational velocity
109
110#node for Rigid2D body: px, py, phi:
111n1=mbs.AddNode(NodeRigidBodyEP(referenceCoordinates = p0+ep0, initialVelocities=v0+list(ep_t0)))
112
113#ground nodes
114nGround0=mbs.AddNode(NodePointGround(referenceCoordinates = [-L/2,0,0]))
115nGround1=mbs.AddNode(NodePointGround(referenceCoordinates = [ L/2,0,0]))
116
117#add mass point (this is a 3D object with 3 coordinates):
118gRotor = graphics.Cylinder([-lRotor*0.5,0,0],[lRotor,0,0],r,[0.3,0.3,0.9,1],128)
119gRotor2 = graphics.Cylinder([-L0,0,0],[L,0,0],r*0.05,[0.3,0.3,0.9,1],16)
120gRotor3 = [backgroundX, backgroundY, backgroundZ]
121rigid = mbs.AddObject(RigidBody(mass=m, inertia=[Jxx,Jyyzz,Jyyzz,0,0,0], nodeNumber = n1, visualization=VObjectRigidBody2D(graphicsData=[gRotor, gRotor2]+gRotor3)))
122
123mbs.AddSensor(SensorBody(bodyNumber=rigid,
124 fileName='solution/runupDisplacement.txt',
125 outputVariableType=exu.OutputVariableType.Displacement))
126mbs.AddSensor(SensorBody(bodyNumber=rigid,
127 fileName='solution/runupAngularVelocity.txt',
128 outputVariableType=exu.OutputVariableType.AngularVelocity))
129
130#marker for ground (=fixed):
131groundMarker0=mbs.AddMarker(MarkerNodePosition(nodeNumber= nGround0))
132groundMarker1=mbs.AddMarker(MarkerNodePosition(nodeNumber= nGround1))
133
134#marker for rotor axis and support:
135rotorAxisMarker0 =mbs.AddMarker(MarkerBodyPosition(bodyNumber=rigid, localPosition=[-L0,-eps,0]))
136rotorAxisMarker1 =mbs.AddMarker(MarkerBodyPosition(bodyNumber=rigid, localPosition=[ L1,-eps,0]))
137
138
139#++++++++++++++++++++++++++++++++++++
140mbs.AddObject(CartesianSpringDamper(markerNumbers=[groundMarker0, rotorAxisMarker0],
141 stiffness=[k,k,k], damping=[d, d, d]))
142mbs.AddObject(CartesianSpringDamper(markerNumbers=[groundMarker1, rotorAxisMarker1],
143 stiffness=[0,k,k], damping=[0, d, d])) #do not constrain x-axis twice
144
145#coordinate markers for loads:
146rotorMarkerUy=mbs.AddMarker(MarkerNodeCoordinate(nodeNumber= n1, coordinate=1))
147rotorMarkerUz=mbs.AddMarker(MarkerNodeCoordinate(nodeNumber= n1, coordinate=2))
148
149#add torque:
150rotorRigidMarker =mbs.AddMarker(MarkerBodyRigid(bodyNumber=rigid, localPosition=[0,0,0]))
151mbs.AddLoad(Torque(markerNumber=rotorRigidMarker, loadVector=[torque,0,0]))
152
153#print(mbs)
154mbs.Assemble()
155#mbs.systemData.Info()
156
157simulationSettings = exu.SimulationSettings()
158simulationSettings.solution.file.writePeriod = 1e-5 #output interval
159simulationSettings.solution.sensors.writePeriod = 1e-5 #output interval
160
161if isSymmetric:
162 simulationSettings.solution.file.information = "Runup of Laval rotor, resonance="+str(round(fRes,3))+"Hz at 80-90 seconds"
163else:
164 simulationSettings.solution.file.information = "Runup of unsymmetric rotor"
165
166simulationSettings.timeIntegration.numberOfSteps = steps
167simulationSettings.timeIntegration.endTime = tEnd
168simulationSettings.timeIntegration.generalizedAlpha.useIndex2Constraints = True
169simulationSettings.timeIntegration.generalizedAlpha.useNewmark = True
170
171simulationSettings.timeIntegration.generalizedAlpha.spectralRadius = 1
172
173#create animations (causes slow simulation):
174createAnimation=True
175if createAnimation:
176 simulationSettings.solution.recordImagesInterval = 0.2
177 SC.visualizationSettings.exportImages.saveImageFileName = "images/frame"
178 SC.visualizationSettings.view0.window.renderWindowSize = [1600,1080]
179
180
181SC.renderer.Start() #start graphics visualization
182SC.renderer.DoIdleTasks() #wait for pressing SPACE bar to continue
183
184#start solver:
185mbs.SolveDynamic(simulationSettings)
186
187#SC.renderer.DoIdleTasks()#wait for pressing 'Q' to quit
188SC.renderer.Stop() #safely close rendering window!
189
190#evaluate final (=current) output values
191u = mbs.GetNodeOutput(n1, exu.OutputVariableType.AngularVelocity)
192print('omega=',u)
193#print('displacement=',u[0])
194
195#+++++++++++++++++++++++++++++++++++++++++++++++++++++
196import matplotlib.pyplot as plt
197import matplotlib.ticker as ticker
198
199if False:
200 plt.close('all') #close all plots
201
202 dataDisp = np.loadtxt(OutputFilePath('solution/runupDisplacement.txt'), comments='#', delimiter=',')
203 dataOmega = np.loadtxt(OutputFilePath('solution/runupAngularVelocity.txt'), comments='#', delimiter=',')
204
205 plt.plot(dataDisp[:,0], dataDisp[:,3], 'b-') #numerical solution
206 plt.xlabel("time (s)")
207 plt.ylabel("z-displacement (m)")
208
209 plt.figure()
210 plt.plot((1/(2*np.pi))*dataOmega[:,1], dataDisp[:,3], 'b-') #numerical solution
211 plt.xlabel("angular velocity (1/s)")
212 plt.ylabel("z-displacement (m)")
213
214 plt.figure()
215 plt.plot(dataOmega[:,0], (1/(2*np.pi))*dataOmega[:,1], 'b-') #numerical solution
216 plt.xlabel("time (s)")
217 plt.ylabel("angular velocity (1/s)")
218
219 plt.figure()
220 plt.plot(dataDisp[:,2], dataDisp[:,3], 'r-') #numerical solution
221 plt.xlabel("y-displacement (m)")
222 plt.ylabel("z-displacement (m)")
223
224 #plt.plot(data[n-500:n-1,1], data[n-500:n-1,2], 'r-') #numerical solution
225
226 ax=plt.gca() # get current axes
227 ax.grid(True, 'major', 'both')
228 ax.xaxis.set_major_locator(ticker.MaxNLocator(10))
229 ax.yaxis.set_major_locator(ticker.MaxNLocator(10))
230 plt.tight_layout()
231 plt.show()