sliderCrank3Dtest.py

You can view and download this file on Github: sliderCrank3Dtest.py

  1#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2# This is an EXUDYN example
  3#
  4# Details:  Slidercrank 3D  (iftomm benchmark problem)
  5#           Ref.: https://www.iftomm-multibody.org/benchmark/problem/... spatial rigid slider-crank mechanism
  6#
  7# Author:   Johannes Gerstmayr
  8# Date:     2020-02-16
  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#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 13
 14import exudyn as exu
 15from exudyn.utilities import * #includes itemInterface and rigidBodyUtilities
 16import exudyn.graphics as graphics
 17from exudyn.lieGroupIntegration import *
 18
 19import numpy as np
 20from numpy import linalg as LA
 21
 22testIsActive = exu.sys.get('testIsActive', False)
 23
 24SC = exu.SystemContainer()
 25mbs = SC.AddSystem()
 26
 27
 28###############################################################################
 29# given parameters:
 30
 31g = [0,0,-9.81]
 32lAB = 0.08 #crank length
 33lBC = 0.3  #conrod
 34theta0 = 0 #initial crank angle
 35omega0 = [6,0,0] #initial crank angular velocity
 36
 37#initial values for bodies 1 and 2 computed from initial value problem with constant angular velocity
 38v1Init = [1.2e-01, -2.400e-01, 0]
 39#omega1Init = [7.29730172e-01, -1.39497250e+00, 4.79376439e-01]
 40omega1Init = [1.6941176470530785, -0.8470588235366621, 0.705882352947701] #appr. 10 digits accuracy
 41#initial values: 0.12,-0.24,0,-0.9343942376,-2.73093948,-0.6316790456
 42v2Init = [0.24,0,0]
 43omega2Init = [0,0,0]
 44
 45zA = 0.12       #z-position of crank CoR
 46yA = 0.1        #y-position of crank CoR
 47
 48#initial x-position of slider:
 49xD  = np.sqrt(lBC**2 - yA**2 - (zA + lAB)**2);
 50exu.Print('slider initial position =', xD)
 51
 52#initial positions of points A-C
 53pA = [0, yA, zA]
 54pB = np.array([0, yA, zA]) + [0,0,lAB]
 55pC = [xD, 0, 0]
 56
 57vCB = np.array(pC) - np.array(pB)
 58exu.Print('vCB len=', LA.norm(vCB))
 59#xAxis1 = (1/lBC)*vCB #local x-axis of conrod
 60[xAxis1,zAxis1, vDummy] = GramSchmidt(vCB, pA) # compute projected pA to xAxis1 ==> gives z axis
 61yAxis1 = -np.cross(xAxis1, zAxis1)
 62
 63rotMatBC=np.array([xAxis1, yAxis1, zAxis1]).transpose()
 64
 65#mass and inertia
 66mAB = 0.12
 67mBC = 0.5
 68mSlider = 2
 69
 70iAB = np.diag([0.0001,0.00001,0.0001]) #crank inertia
 71#iBC = np.diag([0.004,0.0004,0.004])    #conrod inertia; iftomm: x=axis of conrod; McPhee: y=axis of conrod
 72iSlider = np.diag([0.0001,0.0001,0.0001]) #slider inertia; McPhee: no inertia of slider / does not rotate
 73
 74#Maple  / McPhee ?
 75#<Text-field prompt="&gt; " style="Maple Input" layout="Normal">m1:= 0.12; m2:= 0.5; m3:= 2; L1:= 0.08; L2:= 0.3; Ay:= 0.1; Az:= 0.12;</Text-field>
 76#<Text-field prompt="&gt; " style="Maple Input" layout="Normal">Ixx1:= 0.0001; Ixx2:= 0.0004; Iyy2:= 0.004; Izz2:= 0.004; G:= 9.81;</Text-field>
 77
 78#we choose x-axis as conrod axis!
 79iBC = np.diag([0.0004,0.004,0.004])    #conrod inertia; iftomm: x=axis of conrod; McPhee: y=axis of conrod
 80
 81
 82inertiaAB = RigidBodyInertia(mass=mAB, inertiaTensor=iAB)
 83inertiaBC = RigidBodyInertia(mass=mBC, inertiaTensor=iBC)
 84inertiaSlider = RigidBodyInertia(mass=mSlider, inertiaTensor=iSlider)
 85
 86fixedVelocity = False #constrain angular velocity of crank
 87
 88nodeType=exu.NodeType.RotationEulerParameters
 89#nodeType=exu.NodeType.RotationRxyz
 90
 91
 92################ Body0: CRANK
 93#graphicsAB = graphics.BrickXYZ(-d/2,-d/2,0, d/2,d/2, lAB, [0.1,0.1,0.8,1])
 94graphicsAB = graphics.RigidLink(p0=[0,0,0],p1=[0,0,lAB], axis0=[1,0,0], 
 95                                   radius=[0.01,0.01], thickness = 0.01, 
 96                                   width = [0.02,0.02], color=graphics.color.steelblue)
 97
 98dict0 = mbs.CreateRigidBody(referencePosition=pA,  
 99                            initialAngularVelocity=omega0,  
100                            inertia=inertiaAB,  
101                            gravity=g,  
102                            nodeType=nodeType,  
103                            graphicsDataList=[graphicsAB],  
104                            returnDict=True)  
105[n0, b0] = [dict0['nodeNumber'], dict0['bodyNumber']]
106
107
108################ Body1: CONROD
109graphicsBC = graphics.RigidLink(p0=[-0.5*lBC,0,0],p1=[0.5*lBC,0,0], axis1=[0,0,0], 
110                                   radius=[0.01,0.01], thickness = 0.01, 
111                                   width = [0.02,0.02], color=graphics.color.lightred)
112pBC = 0.5*(np.array(pB) + pC)
113dict1 = mbs.CreateRigidBody(referencePosition=pBC,  
114                            referenceRotationMatrix=rotMatBC,  
115                            initialVelocity=v1Init,  
116                            initialAngularVelocity=omega1Init,  
117                            inertia=inertiaBC,  
118                            gravity=g,  
119                            nodeType=nodeType,  
120                            graphicsDataList=[graphicsBC],  
121                            returnDict=True)  
122[n1, b1] = [dict1['nodeNumber'], dict1['bodyNumber']]
123
124################ Body2: SLIDER
125d = 0.03
126graphicsSlider = graphics.Brick(centerPoint=[0, 0, 0], size=[d, d, d], color=[0.5,0.5,0.5,0.5])
127dict2 = mbs.CreateRigidBody(referencePosition=pC,  
128                            initialVelocity=v2Init,  
129                            inertia=inertiaSlider,  
130                            nodeType=nodeType,  
131                            graphicsDataList=[graphicsSlider],  
132                            returnDict=True)  
133[n2,b2] = [dict2['nodeNumber'], dict2['bodyNumber']]
134
135
136oGround = mbs.CreateGround()
137markerGroundA = mbs.AddMarker(MarkerBodyRigid(name='markerGroundA', bodyNumber=oGround, localPosition=pA))
138markerGroundD = mbs.AddMarker(MarkerBodyRigid(name='markerGroundD', bodyNumber=oGround, localPosition=[0,0,0]))
139
140markerCrankA = mbs.AddMarker(MarkerBodyRigid(bodyNumber=b0))
141markerCrankB = mbs.AddMarker(MarkerBodyRigid(bodyNumber=b0, localPosition=[0,0,lAB]))
142
143markerConrodB = mbs.AddMarker(MarkerBodyRigid(bodyNumber=b1, localPosition=[-0.5*lBC,0,0]))
144markerConrodC = mbs.AddMarker(MarkerBodyRigid(bodyNumber=b1, localPosition=[ 0.5*lBC,0,0]))
145
146markerSlider = mbs.AddMarker(MarkerBodyRigid(bodyNumber=b2))
147
148mbs.AddObject(GenericJoint(markerNumbers=[markerGroundA, markerCrankA], constrainedAxes=[1,1,1,0,1,1], 
149                           visualization=VObjectJointGeneric(axesRadius=0.005, axesLength=0.02)))
150
151mbs.AddObject(GenericJoint(markerNumbers=[markerGroundD, markerSlider], constrainedAxes=[0,1,1,1,1,1],
152                            visualization=VObjectJointGeneric(axesRadius=0.005, axesLength=0.02)))
153
154mbs.AddObject(GenericJoint(markerNumbers=[markerCrankB, markerConrodB], constrainedAxes=[1,1,1,0,0,0],
155                            visualization=VObjectJointGeneric(axesRadius=0.005, axesLength=0.02)))
156
157#classical cardan, x=locked
158#mbs.AddObject(GenericJoint(markerNumbers=[markerConrodC, markerSlider], constrainedAxes=[1,1,1,1,0,0],
159#                            visualization=VObjectJointGeneric(axesRadius=0.005, axesLength=0.02)))
160
161mbs.AddObject(GenericJoint(markerNumbers=[markerSlider, markerConrodC], constrainedAxes=[1,1,1,0,0,1], # xAxisMarker0=free, yAxisMarker1=free
162                            visualization=VObjectJointGeneric(axesRadius=0.005, axesLength=0.02)))
163
164if not testIsActive:
165    sCrankAngle=mbs.AddSensor(SensorNode(nodeNumber = n0, storeInternal=True,#fileName='solution/crankAngle.txt',
166                             outputVariableType=exu.OutputVariableType.Rotation))
167    sCrankAngVel=mbs.AddSensor(SensorNode(nodeNumber = n0, storeInternal=True,#fileName='solution/crankAngularVelocity.txt',
168                             outputVariableType=exu.OutputVariableType.AngularVelocity))
169    sSliderPos=mbs.AddSensor(SensorNode(nodeNumber = n2, storeInternal=True,#fileName='solution/sliderPosition.txt',
170                             outputVariableType=exu.OutputVariableType.Position))
171    sSliderVel=mbs.AddSensor(SensorNode(nodeNumber = n2, storeInternal=True,#fileName='solution/sliderVelocity.txt',
172                             outputVariableType=exu.OutputVariableType.Velocity))
173
174if fixedVelocity:
175    groundNode = mbs.AddNode(NodePointGround(referenceCoordinates=[0,0,0])) #add a coordinate fixed to ground
176    markerGroundCoordinate = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber=groundNode, coordinate=0))
177    markerRotX = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber=n0, coordinate=3)) #Euler angle x
178    
179    mbs.AddObject(CoordinateConstraint(markerNumbers=[markerGroundCoordinate, markerRotX], 
180                                       offset = 6, velocityLevel=True))
181
182#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
183mbs.Assemble()
184#mbs.systemData.Info()
185
186simulationSettings = exu.SimulationSettings() #takes currently set values or default values
187simulationSettings.timeIntegration.newton.useModifiedNewton = False #Just for the test; modified Newton is usually faster
188
189fact = 1000 #1000 for testing
190outputFact = 1000
191simulationSettings.timeIntegration.numberOfSteps = 1000
192simulationSettings.timeIntegration.endTime = 0.2 #0.2 for testing
193simulationSettings.solution.file.writePeriod = simulationSettings.timeIntegration.endTime/outputFact
194simulationSettings.solution.sensors.writePeriod = simulationSettings.timeIntegration.endTime/outputFact
195simulationSettings.solution.file.write = (not testIsActive)
196simulationSettings.timeIntegration.verboseMode = 1
197
198simulationSettings.timeIntegration.generalizedAlpha.useIndex2Constraints = True
199simulationSettings.timeIntegration.generalizedAlpha.useNewmark = True
200simulationSettings.timeIntegration.generalizedAlpha.spectralRadius = 0.5 #0.6 works well 
201
202simulationSettings.timeIntegration.generalizedAlpha.computeInitialAccelerations=True
203
204SC.visualizationSettings.connectors.showJointAxes = True
205SC.visualizationSettings.connectors.jointAxesLength = 0.02
206SC.visualizationSettings.connectors.jointAxesRadius = 0.002
207
208if not testIsActive:
209    simulationSettings.timeIntegration.numberOfSteps = 20000
210    simulationSettings.timeIntegration.endTime = 5 #0.2 for testing
211    
212    SC.renderer.Start()
213    SC.renderer.DoIdleTasks()
214
215mbs.SolveDynamic(simulationSettings)
216
217
218#compute initial velocities:
219#if fixedVelocity:
220#    v0 = mbs.GetNodeOutput(n0,exu.OutputVariableType.Coordinates_t)
221#    exu.Print('v0=',v0)
222#    
223#    v1 = mbs.GetNodeOutput(n1,exu.OutputVariableType.Coordinates_t)
224#    exu.Print('v1=',v1[0:3])
225#    omega1 = mbs.GetNodeOutput(n1,exu.OutputVariableType.AngularVelocity)
226#    exu.Print('omega1=',omega1[0],omega1[1],omega1[2])
227#    
228#    v2 = mbs.GetNodeOutput(n2,exu.OutputVariableType.Coordinates_t)
229#    exu.Print('v2=',v2[0:3])
230
231
232#+++++++++++++++++++++++++++++++++++++++++++++
233#compute TestModel error for EulerParameters and index2 solver
234sol = mbs.systemData.GetODE2Coordinates(); 
235solref = mbs.systemData.GetODE2Coordinates(configuration=exu.ConfigurationType.Reference); 
236#exu.Print('sol=',sol)
237u = 0
238for i in range(14): #take coordinates of first two bodies
239    u += abs(sol[i]+solref[i])
240
241exu.Print('solution of 3D slidercrank iftomm benchmark=',u)
242
243exu.sys['testResult'] = u
244
245
246if not testIsActive:
247    #SC.renderer.DoIdleTasks()
248    SC.renderer.Stop() #safely close rendering window!
249
250if not testIsActive:
251    import matplotlib.pyplot as plt
252    import matplotlib.ticker as ticker
253    plt.close("all")
254    
255    [fig1, ax1] = plt.subplots()
256    [fig2, ax2] = plt.subplots()
257    # data1 = np.loadtxt('solution/crankAngularVelocity.txt', comments='#', delimiter=',')
258    data1 = mbs.GetSensorStoredData(sCrankAngVel)
259    ax1.plot(data1[:,0], data1[:,1], 'r-', label='crank angular velocity')  
260    # data1 = np.loadtxt('solution/crankAngle.txt', comments='#', delimiter=',')
261    data1 = mbs.GetSensorStoredData(sCrankAngle)
262    ax1.plot(data1[:,0], data1[:,1], 'b-', label='crank angle')  
263    if False: #only if available ...
264        data1 = np.loadtxt('../../docs/verification/Slidercrank3DiftommBenchmark/Spatial_rigid_slider-crank_mechanism_Masarati.txt', comments='#', delimiter=',')
265        ax1.plot(data1[:,0], data1[:,2], 'r:', label='Ref Masarati: crank angle')  
266        data1 = np.loadtxt('../../docs/verification/Slidercrank3DiftommBenchmark/Spatial_rigid_slider-crank_mechanism_Masoudi.txt', comments='#', delimiter='\t')
267        ax1.plot(data1[:,0], data1[:,2], 'k:', label='Ref Masoudi: crank angle')  
268        data1 = np.loadtxt('../../docs/verification/Slidercrank3DiftommBenchmark/Spatial_rigid_slider-crank_mechanism_Chaojie.txt', comments='#', delimiter=',')
269        ax1.plot(data1[:,0], data1[:,2], 'g:', label='Ref Chaojie: crank angle')  
270    
271
272    # data2 = np.loadtxt('solution/sliderPosition.txt', comments='#', delimiter=',')
273    data2 = mbs.GetSensorStoredData(sSliderPos)
274    ax2.plot(data2[:,0], data2[:,1], 'b-', label='slider position')  
275    #data2 = np.loadtxt('solution/sliderPosition_1e-4.txt', comments='#', delimiter=',')
276    #ax2.plot(data2[:,0], data2[:,1], 'r-', label='slider position, dt=1e-4')  
277#    data2 = np.loadtxt('solution/sliderVelocity.txt', comments='#', delimiter=',')
278#    ax2.plot(data2[:,0], data2[:,1], 'r-', label='slider velocity')  
279    
280    if False: #only if available ...
281        data2 = np.loadtxt('../../docs/verification/Slidercrank3DiftommBenchmark/Spatial_rigid_slider-crank_mechanism_Masarati.txt', comments='#', delimiter=',')
282        ax2.plot(data2[:,0], data2[:,1], 'r:', label='Ref Masarati: slider position')  
283        data2 = np.loadtxt('../../docs/verification/Slidercrank3DiftommBenchmark/Spatial_rigid_slider-crank_mechanism_Masoudi.txt', comments='#', delimiter='\t')
284        ax2.plot(data2[:,0], data2[:,1], 'k:', label='Ref Masoudi: slider position')  
285        data2 = np.loadtxt('../../docs/verification/Slidercrank3DiftommBenchmark/Spatial_rigid_slider-crank_mechanism_Chaojie.txt', comments='#', delimiter=',')
286        ax2.plot(data2[:,0], data2[:,1], 'g:', label='Ref Chaojie: slider position')  
287    
288    
289    axList=[ax1,ax2]
290    figList=[fig1, fig2]
291    
292    for ax in axList:
293        ax.grid(True, 'major', 'both')
294        ax.xaxis.set_major_locator(ticker.MaxNLocator(10)) 
295        ax.yaxis.set_major_locator(ticker.MaxNLocator(10)) 
296        ax.set_xlabel("time (s)")
297        ax.legend()
298        
299    ax1.set_ylabel("crank angle / angular velocity")
300    ax2.set_ylabel("slider position (m)")
301    
302    for f in figList:
303        f.tight_layout()
304        f.show() #bring to front