geneticOptimizationSliderCrank.py

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

  1#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  2# This is an EXUDYN example
  3#
  4# Details:  Slider crank model with verification in MATLAB for machine dynamics course
  5#           optionally, the slider crank is mounted on a floating frame, leading to vibrations
  6#           if the system is unbalanced
  7#           Use this example in combination with cmd: 'python resultsMonitor.py solution/geneticSliderCrank.txt'
  8#
  9# Author:   Johannes Gerstmayr
 10# Date:     2019-12-07 (created)
 11#           2021-01-10 (adapted for genetic optimization)
 12#
 13# 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.
 14#
 15#+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 16
 17import exudyn as exu
 18from exudyn.itemInterface import *
 19from exudyn.utilities import * #includes itemInterface and rigidBodyUtilities
 20import exudyn.graphics as graphics #only import if it does not conflict
 21from exudyn.processing import GeneticOptimization, ParameterVariation, PlotOptimizationResults2D
 22
 23import numpy as np #for postprocessing
 24import os
 25from time import sleep
 26
 27useGraphics = False
 28L1=0.1
 29L2=0.3
 30m1=0.4
 31m2=0.2
 32m3=0.1
 33s1opt = -L1*(m2+m3)/m1 #-0.075
 34s2opt = -m3/m2*L2      #-0.15
 35
 36#this is the function which is repeatedly called from ParameterVariation
 37#parameterSet contains dictinary with varied parameters
 38def ParameterFunction(parameterSet):
 39    SC = exu.SystemContainer()
 40    mbs = SC.AddSystem()
 41
 42    #++++++++++++++++++++++++++++++++++++++++++++++
 43    #++++++++++++++++++++++++++++++++++++++++++++++
 44    #store default parameters in structure (all these parameters can be varied!)
 45    class P: pass #create emtpy structure for parameters; simplifies way to update parameters
 46    P.s1=L1*0.5
 47    P.s2=L2*0.5
 48    P.h=0.002
 49    P.computationIndex = ''
 50
 51    # #now update parameters with parameterSet (will work with any parameters in structure P)
 52    for key,value in parameterSet.items():
 53        setattr(P,key,value)
 54
 55    #++++++++++++++++++++++++++++++++++++++++++++++
 56    #++++++++++++++++++++++++++++++++++++++++++++++
 57    #START HERE: create parameterized model
 58
 59    testCases = 1 #floating body
 60    nGround = mbs.AddNode(NodePointGround(referenceCoordinates=[0,0,0])) #ground node for coordinate constraint
 61    mGround = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber = nGround, coordinate=0)) #Ground node ==> no action
 62
 63
 64    #++++++++++++++++++++++++++++++++
 65    #floating body to mount slider-crank mechanism
 66    constrainGroundBody = (testCases == 0) #use this flag to fix ground body
 67
 68    #graphics for floating frame:
 69    gFloating = graphics.BrickXYZ(-0.25, -0.25, -0.1, 0.8, 0.25, -0.05, color=[0.3,0.3,0.3,1.])
 70
 71    if constrainGroundBody:
 72        floatingRB = mbs.AddObject(ObjectGround(referencePosition=[0,0,0], visualization=VObjectGround(graphicsData=[gFloating])))
 73        mFloatingN = mbs.AddMarker(MarkerBodyPosition(bodyNumber = floatingRB, localPosition=[0,0,0]))
 74    else:
 75        nFloating = mbs.AddNode(Rigid2D(referenceCoordinates=[0,0,0], initialVelocities=[0,0,0]));
 76        mFloatingN = mbs.AddMarker(MarkerNodePosition(nodeNumber=nFloating))
 77        floatingRB = mbs.AddObject(RigidBody2D(physicsMass=2, physicsInertia=1, nodeNumber=nFloating, visualization=VObjectRigidBody2D(graphicsData=[gFloating])))
 78        mRB0 = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber = nFloating, coordinate=0))
 79        mRB1 = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber = nFloating, coordinate=1))
 80        mRB2 = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber = nFloating, coordinate=2))
 81
 82        #add spring dampers for reference frame:
 83        k=5000 #stiffness of floating body
 84        d=k*0.01
 85        mbs.AddObject(CoordinateSpringDamper(markerNumbers=[mGround,mRB0], stiffness=k, damping=d))
 86        mbs.AddObject(CoordinateSpringDamper(markerNumbers=[mGround,mRB1], stiffness=k, damping=d))
 87        mbs.AddObject(CoordinateSpringDamper(markerNumbers=[mGround,mRB2], stiffness=k, damping=d))
 88        mbs.AddObject(CoordinateConstraint(markerNumbers=[mGround,mRB2]))
 89
 90
 91
 92    #++++++++++++++++++++++++++++++++
 93    #nodes and bodies
 94    omega=2*pi/60*300 #3000 rpm
 95    M=0.1 #torque (default: 0.1)
 96
 97    s1L=-P.s1
 98    s1R=L1-P.s1
 99    s2L=-P.s2
100    s2R=L2-P.s2
101
102    #lambda=L1/L2
103    J1=(m1/12.)*L1**2 #inertia w.r.t. center of mass
104    J2=(m2/12.)*L2**2 #inertia w.r.t. center of mass
105
106    ty = 0.05    #thickness
107    tz = 0.05    #thickness
108
109    graphics1 = graphics.RigidLink(p0=[s1L,0,-0.5*tz],p1=[s1R,0,-0.5*tz],
110                                      axis0=[0,0,1], axis1=[0,0,1],radius=[0.5*ty,0.5*ty],
111                                      thickness=0.8*ty, width=[tz,tz], color=graphics.color.steelblue,nTiles=16)
112
113    graphics2 = graphics.RigidLink(p0=[s2L,0,0.5*tz],p1=[s2R,0,0.5*tz],
114                                      axis0=[0,0,1], axis1=[0,0,1],radius=[0.5*ty,0.5*ty],
115                                      thickness=0.8*ty, width=[tz,tz], color=graphics.color.lightred,nTiles=16)
116
117    #crank:
118    nRigid1 = mbs.AddNode(Rigid2D(referenceCoordinates=[P.s1,0,0],
119                                  initialVelocities=[0,0,0]));
120    oRigid1 = mbs.AddObject(RigidBody2D(physicsMass=m1,
121                                        physicsInertia=J1,
122                                        nodeNumber=nRigid1,
123                                        visualization=VObjectRigidBody2D(graphicsData= [graphics1])))
124
125    #connecting rod:
126    nRigid2 = mbs.AddNode(Rigid2D(referenceCoordinates=[L1+P.s2,0,0],
127                                  initialVelocities=[0,0,0]));
128    oRigid2 = mbs.AddObject(RigidBody2D(physicsMass=m2,
129                                        physicsInertia=J2,
130                                        nodeNumber=nRigid2,
131                                        visualization=VObjectRigidBody2D(graphicsData= [graphics2])))
132
133
134    #++++++++++++++++++++++++++++++++
135    #slider:
136    c=0.025 #dimension of mass
137    graphics3 = graphics.BrickXYZ(-c,-c,-c*2,c,c,0,graphics.color.grey)
138
139    #nMass = mbs.AddNode(Point2D(referenceCoordinates=[L1+L2,0]))
140    #oMass = mbs.AddObject(MassPoint2D(physicsMass=m3, nodeNumber=nMass,visualization=VObjectMassPoint2D(graphicsData= [graphics3])))
141    nMass = mbs.AddNode(Rigid2D(referenceCoordinates=[L1+L2,0,0]))
142    oMass = mbs.AddObject(RigidBody2D(physicsMass=m3, physicsInertia=0.001*m3, nodeNumber=nMass,visualization=VObjectRigidBody2D(graphicsData= [graphics3])))
143
144    #++++++++++++++++++++++++++++++++
145    #markers for joints:
146    mR1Left = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oRigid1, localPosition=    [s1L,0.,0.])) #support point # MUST be a rigidBodyMarker, because a torque is applied
147    mR1Right = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oRigid1, localPosition=[s1R,0.,0.])) #end point; connection to connecting rod
148
149    mR2Left = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oRigid2, localPosition= [s2L,0.,0.])) #connection to crank
150    mR2Right = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oRigid2, localPosition=[s2R,0.,0.])) #end point; connection to slider
151
152    mMass = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oMass, localPosition=[ 0.,0.,0.]))
153    mG0 = mFloatingN
154
155    #++++++++++++++++++++++++++++++++
156    #joints:
157    mbs.AddObject(RevoluteJoint2D(markerNumbers=[mG0,mR1Left]))
158    mbs.AddObject(RevoluteJoint2D(markerNumbers=[mR1Right,mR2Left]))
159    mbs.AddObject(RevoluteJoint2D(markerNumbers=[mR2Right,mMass]))
160
161
162    #prismatic joint:
163    mRigidGround = mbs.AddMarker(MarkerBodyRigid(bodyNumber = floatingRB, localPosition = [L1+L2,0,0]))
164    mRigidSlider = mbs.AddMarker(MarkerBodyRigid(bodyNumber = oMass, localPosition = [0,0,0]))
165
166    mbs.AddObject(PrismaticJoint2D(markerNumbers=[mRigidGround,mRigidSlider], constrainRotation=True))
167
168
169    #user function for load; switch off load after 1 second
170    userLoadOn = True
171    def userLoad(mbs, t, load):
172        setLoad = 0
173        if userLoadOn:
174            setLoad = load
175            omega = mbs.GetNodeOutput(nRigid1,variableType = exu.OutputVariableType.AngularVelocity)[2]
176            if omega > 2*pi*2:
177                #print("t=",t)
178                userLoadOn = False
179        return setLoad
180
181    #loads and driving forces:
182    mRigid1CoordinateTheta = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber = nRigid1, coordinate=2)) #angle coordinate is constrained
183    #mbs.AddLoad(LoadCoordinate(markerNumber=mRigid1CoordinateTheta, load = M, loadUserFunction=userLoad)) #torque at crank
184    mbs.AddLoad(LoadCoordinate(markerNumber=mRigid1CoordinateTheta, load = M)) #torque at crank
185
186    #write motion of support frame:
187    sFloating = mbs.AddSensor(SensorNode(nodeNumber=nFloating,
188                                         storeInternal=True,
189                                         outputVariableType=exu.OutputVariableType.Position))
190
191    #++++++++++++++++++++++++++++++++
192    #assemble, adjust settings and start time integration
193    mbs.Assemble()
194
195    simulationSettings = exu.SimulationSettings() #takes currently set values or default values
196    tEnd = 3
197
198    simulationSettings.timeIntegration.numberOfSteps = int(tEnd/P.h)
199    simulationSettings.timeIntegration.endTime = tEnd
200
201
202    simulationSettings.solutionSettings.solutionWritePeriod = 2e-3
203    simulationSettings.solutionSettings.writeSolutionToFile = useGraphics
204
205    simulationSettings.timeIntegration.newton.useModifiedNewton = True
206    simulationSettings.timeIntegration.newton.relativeTolerance = 1e-8
207    simulationSettings.timeIntegration.newton.absoluteTolerance = 1e-8
208
209    #++++++++++++++++++++++++++++++++++++++++++
210    #solve index 2 / trapezoidal rule:
211    simulationSettings.timeIntegration.generalizedAlpha.useNewmark = True
212    simulationSettings.timeIntegration.generalizedAlpha.useIndex2Constraints = True
213
214    dSize = 0.02
215    SC.visualizationSettings.nodes.defaultSize = dSize
216    SC.visualizationSettings.markers.defaultSize = dSize
217    SC.visualizationSettings.bodies.defaultSize = [dSize, dSize, dSize]
218    SC.visualizationSettings.connectors.defaultSize = dSize
219
220    #data obtained from SC.GetRenderState(); use np.round(d['modelRotation'],4)
221    SC.visualizationSettings.openGL.initialModelRotation = [[ 0.87758,  0.04786, -0.47703],
222                                                            [ 0.     ,  0.995  ,  0.09983],
223                                                            [ 0.47943, -0.08761,  0.8732]]
224    SC.visualizationSettings.openGL.initialZoom = 0.47
225    SC.visualizationSettings.openGL.initialCenterPoint = [0.192, -0.0039,-0.075]
226    SC.visualizationSettings.openGL.initialMaxSceneSize = 0.4
227    SC.visualizationSettings.general.autoFitScene = False
228    #mbs.WaitForUserToContinue()
229
230    if useGraphics:
231        exu.StartRenderer()
232
233    mbs.SolveDynamic(simulationSettings)
234
235    if useGraphics:
236        SC.WaitForRenderEngineStopFlag()
237        exu.StopRenderer() #safely close rendering window!
238
239    #++++++++++++++++++++++++++++++++++++++++++
240    #evaluate error:
241    #data = np.loadtxt(sensorFileName, comments='#', delimiter=',')
242    data = mbs.GetSensorStoredData(sFloating)
243
244    errorNorm = max(abs(data[:,1])) + max(abs(data[:,2])) #max displacement in x and y direction
245
246    if useGraphics:
247        print("max. oszillation=", errorNorm)
248
249        mbs.PlotSensor(sensorNumbers=[sFloating,sFloating], components=[0,1])
250
251    del mbs
252    del SC
253
254    return errorNorm
255    #++++++++++++++++++++++++++++++++++++++++++
256
257import matplotlib.pyplot as plt
258import matplotlib.ticker as ticker
259
260doOptimize = True
261#now perform parameter variation
262if __name__ == '__main__': #include this to enable parallel processing
263    if doOptimize:
264        import time
265
266        #%%++++++++++++++++++++++++++++++++++++++++++++++++++++
267        #GeneticOptimization
268        start_time = time.time()
269        [pOpt, vOpt, pList, values] = GeneticOptimization(objectiveFunction = ParameterFunction,
270                                             parameters = {'s1':(-L1,L1), 's2':(-L2,L2)}, #parameters provide search range
271                                             numberOfGenerations = 30,
272                                             populationSize = 50,
273                                             elitistRatio = 0.1,
274                                             crossoverProbability = 0.1,
275                                             rangeReductionFactor = 0.5,
276                                             addComputationIndex=True,
277                                             randomizerInitialization=0, #for reproducible results
278                                             #distanceFactor = 0.1, #for this example only one significant minimum
279                                             debugMode=False,
280                                             useMultiProcessing=True, #may be problematic for test
281                                             showProgress=True,
282                                             resultsFile = 'solution/geneticSliderCrank.txt',
283                                             )
284        #exu.Print("--- %s seconds ---" % (time.time() - start_time))
285
286        exu.Print("[pOpt, vOpt]=", [pOpt, vOpt])
287        u = vOpt
288        exu.Print("optimum=",u)
289        # using files:
290        # [pOpt, vOpt]= [{'s1': -0.07497827333782427, 's2': -0.14943029494085874}, 3.4312580948e-05]
291        # optimum= 3.4312580948e-05
292
293        # using internal storage:
294        # [pOpt, vOpt]= [{'s1': -0.07497827333782427, 's2': -0.14943029494085874}, 3.431258094752888e-05]
295        # optimum= 3.431258094752888e-05
296
297        if False:
298            # from mpl_toolkits.mplot3d import Axes3D  # noqa: F401 unused import
299            import matplotlib.pyplot as plt
300
301            plt.close('all')
302            [figList, axList] = PlotOptimizationResults2D(pList, values, yLogScale=True)
303    else:
304        useGraphics = True
305        parameterSet = {'s1':L1*0.5, 's2':L2*0.5, 'h':1e-5}
306        #parameterSet = {'s1':-0.075, 's2':-0.15, 'h':1e-5}
307        ParameterFunction(parameterSet)