postNewtonStepContactTest.py
You can view and download this file on Github: postNewtonStepContactTest.py
1#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2# This is an EXUDYN example
3#
4# Details: Test with postNewtonUserFunction and recommendedStepSize modeling a simplistic 1-mass- penalty contact problem;
5# Uses step reduction to resolve contact switching point
6#
7# Author: Johannes Gerstmayr
8# Date: 2021-03-20
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 #only import if it does not conflict
17
18useGraphics = True #without test
19#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
20#you can erase the following lines and all exudynTestGlobals related operations if this is not intended to be used as TestModel:
21try: #only if called from test suite
22 from modelUnitTests import exudynTestGlobals #for globally storing test results
23 useGraphics = exudynTestGlobals.useGraphics
24except:
25 class ExudynTestGlobals:
26 pass
27 exudynTestGlobals = ExudynTestGlobals()
28#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
29
30SC = exu.SystemContainer()
31mbs = SC.AddSystem()
32exu.Print('EXUDYN version='+exu.GetVersionString())
33
34#define parameters of mass point
35L=0.5
36r = 0.05
37g=9.81
38mass = 0.25 #mass in kg
39spring = 20000 #stiffness of spring-damper in N/m
40damper = 0*0.01*spring #damping constant in N/(m/s)
41load0 = -mass*g #in negative y-direction
42
43doRefSol = False
44tEnd = 0.5 #end time of simulation
45h = 5e-3
46if doRefSol:
47 h=1e-5
48
49#data coordinate: 0=no contact, 1=contact
50nData=mbs.AddNode(NodeGenericData(initialCoordinates=[0], numberOfDataCoordinates=1))
51
52#node for 3D mass point:
53n1=mbs.AddNode(Point(referenceCoordinates = [0,L,0],
54 initialCoordinates = [0,r-L+0.01,0],
55 initialVelocities = [0,-1,0]))
56
57#user function for spring force
58def springForce(mbs, t, itemIndex, u, v, k, d, offset): #changed 2023-01-21:, mu, muPropZone):
59 p = L+u-r
60 #print(p)
61 data = mbs.systemData.GetDataCoordinates()
62 if data[0] == 1:
63 return k*p
64 else:
65 return 0
66
67def PostNewtonUserFunction(mbs, t):
68 p0 = mbs.GetNodeOutput(n1, exu.OutputVariableType.Position, configuration=exu.ConfigurationType.StartOfStep)[1] - r
69 p = mbs.GetNodeOutput(n1, exu.OutputVariableType.Position)[1] - r
70 #v0 = mbs.GetNodeOutput(n1, exu.OutputVariableType.Velocity, configuration=exu.ConfigurationType.StartOfStep)[1]
71 #a0 = mbs.GetNodeOutput(n1, exu.OutputVariableType.Acceleration, configuration=exu.ConfigurationType.StartOfStep)[1]
72 h = mbs.sys['dynamicSolver'].it.currentStepSize #grab current step size from dynamic solver
73 data = mbs.systemData.GetDataCoordinates()
74 data0 = mbs.systemData.GetDataCoordinates(configuration=exu.ConfigurationType.StartOfStep)
75
76 #data[0] = 0 #no contact; 0 corresponds to the only one data coordinate in the system, attributed to contact
77 recommendedStepSize = -1
78 error = 0
79 #check if previous assumption was wrong ==> set error, reduce step size and set new contact state
80 if p < 0:
81 if data0[0] == 0:
82 error = abs(p)
83 #recommendedStepSize = 1e-6 #simple alternative
84 #x = abs(v0)*h #this is the estimated distance (acc=0) per step
85 #x = 0.5*abs(a0)*h**2
86 #recommendedStepSize = min(h,abs(h*(x-error)/x)) #assuming almost constant velocity during step
87 if (p0 > 0):
88 recommendedStepSize = h*(abs(p0))/(abs(p0)+abs(p))
89 else:
90 recommendedStepSize = 0.25*h #simple alternative
91
92
93 data[0] = 1 #contact
94 #else:
95 # recommendedStepSize = 1e-4
96 # error = abs(h-1e-4)
97 else:
98 if data0[0] == 1:
99 error = abs(p)
100 #recommendedStepSize = 1e-6 #simple alternative
101 if (p0 > 0):
102 recommendedStepSize = h*(abs(p0))/(abs(p0)+abs(p))
103 else:
104 recommendedStepSize = 0.25*h #simple alternative
105 data[0] = 0 #contact off
106
107 #print("t=", round(t,6), ", p=", round(p,6), ", p0=", round(p0,6), #", a0=", round(a0,6),
108 # ", h=", round(h,6), ", hRec=",
109 # round(recommendedStepSize,6), ", tRec=", round(t-h+recommendedStepSize,6),
110 # ", c0=", data0[0], ", c=", data[0], ", e=", error)
111
112 mbs.systemData.SetDataCoordinates(data)
113 return [error,recommendedStepSize]
114
115mbs.SetPostNewtonUserFunction(PostNewtonUserFunction)
116
117#ground node
118d=0.01
119gGround = graphics.Brick([0,-d*0.5,0],[2*L,d,d],color=graphics.color.grey)
120oGround=mbs.AddObject(ObjectGround(visualization=VObjectGround(graphicsData=[gGround])))
121
122nGround=mbs.AddNode(NodePointGround(referenceCoordinates = [0,0,0]))
123
124#add mass point (this is a 3D object with 3 coordinates):
125gSphere = graphics.Sphere([0,0,0], r, color=graphics.color.red, nTiles=20)
126massPoint = mbs.AddObject(MassPoint(physicsMass = mass, nodeNumber = n1,
127 visualization=VMassPoint(graphicsData=[gSphere])))
128
129#marker for ground (=fixed):
130groundMarker=mbs.AddMarker(MarkerNodeCoordinate(nodeNumber= nGround, coordinate = 0))
131#marker for springDamper for first (x-)coordinate:
132nodeMarker =mbs.AddMarker(MarkerNodeCoordinate(nodeNumber= n1, coordinate = 1)) #y-coordinate
133
134#Spring-Damper between two marker coordinates
135mbs.AddObject(CoordinateSpringDamper(markerNumbers = [groundMarker, nodeMarker],
136 stiffness = spring, damping = damper,
137 springForceUserFunction = springForce,
138 visualization=VCoordinateSpringDamper(show=False)))
139
140#add load:
141loadC = mbs.AddLoad(LoadCoordinate(markerNumber = nodeMarker,
142 load = load0))
143
144
145if useGraphics:
146 sPos = mbs.AddSensor(SensorNode(nodeNumber=n1, storeInternal=True,#fileName="solution/sensorPos.txt"
147 outputVariableType=exu.OutputVariableType.Position))
148 sVel = mbs.AddSensor(SensorNode(nodeNumber=n1, storeInternal=True,#fileName="solution/sensorVel.txt"
149 outputVariableType=exu.OutputVariableType.Velocity))
150 sAcc = mbs.AddSensor(SensorNode(nodeNumber=n1, storeInternal=True,#fileName="solution/sensorAcc.txt"
151 outputVariableType=exu.OutputVariableType.Acceleration))
152 #dummy, for PlotSensor
153 #these files are created, if doRefSol=True:
154 sPosRef = mbs.AddSensor(SensorNode(nodeNumber=n1, outputVariableType=exu.OutputVariableType.Position,
155 storeInternal=not doRefSol,fileName="solution/sensorPosRef.txt",
156 writeToFile=doRefSol)) #set True to compute reference solution
157 sVelRef = mbs.AddSensor(SensorNode(nodeNumber=n1, outputVariableType=exu.OutputVariableType.Velocity,
158 storeInternal=not doRefSol,fileName="solution/sensorVelRef.txt",
159 writeToFile=doRefSol)) #set True to compute reference solution
160 sAccRef = mbs.AddSensor(SensorNode(nodeNumber=n1, outputVariableType=exu.OutputVariableType.Acceleration,
161 storeInternal=not doRefSol,fileName="solution/sensorAccRef.txt",
162 writeToFile=doRefSol)) #set True to compute reference solution
163
164#exu.Print(mbs)
165mbs.Assemble()
166
167simulationSettings = exu.SimulationSettings()
168simulationSettings.solutionSettings.writeSolutionToFile = False
169simulationSettings.solutionSettings.sensorsWritePeriod = 1e-5
170simulationSettings.timeIntegration.numberOfSteps = int(tEnd/h)
171simulationSettings.timeIntegration.endTime = tEnd
172simulationSettings.timeIntegration.minimumStepSize = 1e-10
173simulationSettings.timeIntegration.stepInformation = 3 #do not show step increase
174
175#important settings for contact:
176simulationSettings.timeIntegration.discontinuous.iterationTolerance = 1e-8 #this is the accepted penetration before reducing step size
177simulationSettings.timeIntegration.discontinuous.maxIterations = 1 #immediately perform step reduction
178simulationSettings.timeIntegration.discontinuous.ignoreMaxIterations = False #repeat step in case of failure
179simulationSettings.timeIntegration.adaptiveStepRecoverySteps = 0 #number of steps to wait until step size is increased again
180simulationSettings.timeIntegration.adaptiveStepIncrease = 10 #after successful step, increase again rapidly
181
182
183simulationSettings.timeIntegration.generalizedAlpha.spectralRadius = 1
184
185simulationSettings.displayStatistics = True
186simulationSettings.timeIntegration.verboseMode = 1
187#simulationSettings.timeIntegration.simulateInRealtime = True
188
189if useGraphics:
190 exu.StartRenderer() #start graphics visualization
191 #mbs.WaitForUserToContinue() #wait for pressing SPACE bar to continue
192
193#start solver:
194mbs.SolveDynamic(solverType=exu.DynamicSolverType.TrapezoidalIndex2, simulationSettings=simulationSettings)
195#mbs.SolveDynamic(solverType=exu.DynamicSolverType.RK67, simulationSettings=simulationSettings)
196
197if useGraphics:
198 #SC.WaitForRenderEngineStopFlag()#wait for pressing 'Q' to quit
199 exu.StopRenderer() #safely close rendering window!
200
201u = mbs.GetNodeOutput(n1, exu.OutputVariableType.Position)
202exu.Print('postNewtonStepContactTest=',u[1])
203
204exudynTestGlobals.testError = u[1] - (0.057286638346409235)
205exudynTestGlobals.testResult = u[1]
206
207
208if useGraphics:
209
210 import matplotlib.pyplot as plt
211 plt.close('all')
212
213 mbs.PlotSensor(sensorNumbers=[sPos, sPosRef], components=[1,1], figureName='Pos')
214 mbs.PlotSensor(sensorNumbers=[sVel, sVelRef], components=[1,1], figureName='Vel')
215 mbs.PlotSensor(sensorNumbers=[sAcc, sAccRef], components=[1,1], figureName='Acc')