Exemplo n.º 1
0
solveDynamic = True
if solveDynamic:
    # time related settings:
    steps = 400
    tend = 0.8
    h = tend / steps
    SC.visualizationSettings.openGL.lineWidth = 2
    simulationSettings.timeIntegration.numberOfSteps = steps
    simulationSettings.timeIntegration.endTime = tend
    simulationSettings.timeIntegration.generalizedAlpha.useIndex2Constraints = True
    simulationSettings.timeIntegration.generalizedAlpha.useNewmark = simulationSettings.timeIntegration.generalizedAlpha.useIndex2Constraints
    simulationSettings.timeIntegration.generalizedAlpha.spectralRadius = 0.3
    simulationSettings.timeIntegration.verboseMode = 1
    simulationSettings.displayStatistics = True

    exu.SolveDynamic(mbs, simulationSettings)

if exudynTestGlobals.useGraphics:
    #SC.WaitForRenderEngineStopFlag()
    exu.StopRenderer()  #safely close rendering window!

sol = mbs.systemData.GetODE2Coordinates()
uDynamic = sol[nc]
#y-displacement of first node of four bar mechanism
exu.Print('dynamic solution of cable1 =', uDynamic)

exudynTestGlobals.testError += uDynamic - (
    -2.2290811574753953
)  #2020-03-05(corrected Cable2DshapeMarker): -2.2290811574753953 #2019-12-26: -2.2290811558815617; 2019-12-18: -2.229126333291627
exudynTestGlobals.testResult += uDynamic
Exemplo n.º 2
0
def SolutionViewer(mainSystem,
                   solution=[],
                   rowIncrement=1,
                   timeout=0.04,
                   runOnStart=True,
                   runMode=2):
    from exudyn.utilities import SetSolutionState, LoadSolutionFile

    mbs = mainSystem
    SC = mbs.GetSystemContainer()

    if solution == []:
        if not 'simulationSettings' in mbs.sys:
            raise ValueError(
                'SolutionViewer: no solution file found (already simulated?)!')
        sims = mbs.sys['simulationSettings']
        if not sims.solutionSettings.writeSolutionToFile:
            raise ValueError(
                'SolutionViewer: previous simulation has writeSolutionToFile==False; no solution file available!'
            )
        solution = LoadSolutionFile(
            sims.solutionSettings.coordinatesSolutionFileName
        )  #load solution file of previous simulation

    nRows = solution['nRows']
    if nRows == 0:
        print('ERROR in SolutionViewer: solution file is empty')
        return
    if (runMode != 0 and runMode != 1 and runMode != 2):
        print('ERROR in SolutionViewer: illegal run mode:', runMode)
        return
    if (rowIncrement < 1) or (rowIncrement > nRows):
        print(
            'ERROR in SolutionViewer: rowIncrement must be at least 1 and must not be larger than the number of rows in the solution file'
        )
    oldUpdateInterval = SC.visualizationSettings.general.graphicsUpdateInterval
    SC.visualizationSettings.general.graphicsUpdateInterval = 0.5 * min(
        timeout, 2e-3)  #avoid too small values to run multithreading properly
    mbs.SetRenderEngineStopFlag(False)  #not to stop right at the beginning

    # runLoop = False
    # while runLoop and not mainSystem.GetRenderEngineStopFlag():
    #     for i in range(0,nRows,rowIncrement):
    #         if not(mainSystem.GetRenderEngineStopFlag()):
    #             SetSolutionState(mainSystem, solution, i, exudyn.ConfigurationType.Visualization)
    #             exudyn.DoRendererIdleTasks(timeout)

    SetSolutionState(mainSystem, solution, 0,
                     exudyn.ConfigurationType.Visualization)
    exudyn.DoRendererIdleTasks(timeout)

    nSteps = int(nRows)  #only make these steps available in slider!
    maxNSteps = max(500, min(
        nSteps,
        1200))  #do not allow more steps, because dialog may be too large ...
    resolution = min(1., maxNSteps / nSteps)  #do not use values smaller than 1

    dialogItems = [
        {
            'type': 'label',
            'text': 'Solution steps:',
            'grid': (1, 0)
        },
        {
            'type': 'slider',
            'range': (0, nSteps - 1),
            'value': 0,
            'steps': maxNSteps,
            'variable': 'solutionViewerStep',
            'resolution': resolution,
            'grid': (1, 1)
        },
        {
            'type': 'label',
            'text': 'Increment:',
            'grid': (2, 0)
        },
        {
            'type': 'slider',
            'range': (1, 200),
            'value': rowIncrement,
            'steps': 200,
            'variable': 'solutionViewerRowIncrement',
            'grid': (2, 1)
        },
        {
            'type': 'label',
            'text': 'update period:',
            'grid': (3, 0)
        },
        {
            'type': 'slider',
            'range': (0.005, 1),
            'value': timeout,
            'steps': 200,
            'variable': 'solutionViewerPeriod',
            'grid': (3, 1)
        },
        {
            'type':
            'radio',
            'textValueList': [('Continuous run', 0), ('One cycle', 1),
                              ('Static', 2)],
            'value':
            runMode,
            'variable':
            'solutionViewerRunModus',
            'grid': [(4, 0), (4, 1), (4, 2)]
        },
        #{'type':'radio', 'textValueList':[('Mesh+Faces',3), ('Faces only',1), ('Mesh only',2)],'value':3, 'variable':'modeShapeMesh', 'grid': [(8,0),(8,1),(8,2)]},
        {
            'type': 'radio',
            'textValueList': [('Record animation', 0), ('No recording', 1)],
            'value': 1,
            'variable': 'solutionViewerSaveImages',
            'grid': [(5, 0), (5, 1)]
        },
    ]

    mbs.variables['solutionViewerRowIncrement'] = float(rowIncrement)
    mbs.variables['solutionViewerNSteps'] = nSteps
    mbs.variables['solutionViewerSolution'] = solution

    # mbs.variables['solutionViewerStep'] = 0
    # mbs.variables['solutionViewerPeriod'] = timeout

    def UFviewer(mbs, dialog):
        i = int(mbs.variables['solutionViewerStep'])

        # mbs.systemData.SetTime(t, exudyn.ConfigurationType.Visualization)
        SetSolutionState(mainSystem, mbs.variables['solutionViewerSolution'],
                         i, exudyn.ConfigurationType.Visualization)
        #exudyn.DoRendererIdleTasks(timeout)
        # SC.visualizationSettings.contour.reduceRange = False

        mbs.SendRedrawSignal()
        exudyn.DoRendererIdleTasks(
        )  #as there is no simulation, we must do this for graphicsDataUserFunctions
        # if mbs.variables['modeShapeSaveImages'] == 0:
        #     SC.RedrawAndSaveImage() #create images for animation
        # else:
        #     SC.visualizationSettings.exportImages.saveImageFileCounter = 0 #for next mode ...

        dialog.period = mbs.variables['solutionViewerPeriod']

        if mbs.variables['solutionViewerRunModus'] < 2:
            mbs.variables['solutionViewerStep'] += mbs.variables[
                'solutionViewerRowIncrement']
            # print("step=", mbs.variables['solutionViewerStep'])

            #first variable is scale, which contains step
            dialog.variableList[0][0].set(mbs.variables['solutionViewerStep'])
            # for var in dialog.variableList:
            #     #self.mbs.variables[var[1]] = var[0].get()
            #     print(var[1],'=', var[0].get())

        if mbs.variables['solutionViewerSaveImages'] == 0:
            SC.RedrawAndSaveImage()  #create images for animation
        # else: #do not reset image counter to allow creating of multi-view images, slow motion, etc.
        #     SC.visualizationSettings.exportImages.saveImageFileCounter = 0 #

        if mbs.variables['solutionViewerStep'] > mbs.variables[
                'solutionViewerNSteps'] - 1.:
            #or (mbs.variables['solutionViewerRunModus'] and mbs.variables['solutionViewerStep']==mbs.variables['solutionViewerNSteps']-1.):
            mbs.variables['solutionViewerStep'] = 0
            dialog.variableList[0][0].set(0)

            SetSolutionState(mainSystem,
                             mbs.variables['solutionViewerSolution'], 0,
                             exudyn.ConfigurationType.Visualization)
            # mbs.SendRedrawSignal()
            # exudyn.DoRendererIdleTasks() #as there is no simulation, we must do this for graphicsDataUserFunctions
            if mbs.variables[
                    'solutionViewerRunModus'] == 1:  #one cylce ==> stop
                dialog.StartSimulation()  #start/stop simulation

    exudyn.StartRenderer()
    if 'renderState' in exudyn.sys:
        SC.SetRenderState(exudyn.sys['renderState'])  #load last model view

    simulationSettings = exudyn.SimulationSettings(
    )  #not used, but needed in dialog
    #   self.mbs.sys['solver'].InitializeSolver(self.mbs, self.simulationSettings)
    simulationSettings.solutionSettings.solutionInformation = ''

    if not SC.visualizationSettings.general.useMultiThreadedRendering:
        exudyn.DoRendererIdleTasks()  #do an update once

    dialog = InteractiveDialog(mbs,
                               simulationSettings=simulationSettings,
                               simulationFunction=UFviewer,
                               dialogItems=dialogItems,
                               title='Solution Viewer',
                               doTimeIntegration=False,
                               period=timeout,
                               showTime=True,
                               runOnStart=runOnStart)

    #SC.WaitForRenderEngineStopFlag() #not needed, Render window closes when dialog is quit
    exudyn.StopRenderer()  #safely close rendering window!

    SC.visualizationSettings.general.graphicsUpdateInterval = oldUpdateInterval  #set values back to original
Exemplo n.º 3
0
#modify system online

#add nodes
mbs.AddNode(NodePoint())
mbs.AddNode(NodePoint(referenceCoordinates=[1, 0, 0]))

#add objects
mbs.AddObject(ObjectMassPoint(nodeNumber=0, physicsMass=1))
mbs.AddObject(ObjectMassPoint(nodeNumber=1, physicsMass=1))

#make nodes bigger
SC.visualizationSettings.nodes.defaultSize = 0.05

#add marker
m0 = mbs.AddMarker(MarkerNodePosition(nodeNumber=0))

#add load
mbs.AddLoad(LoadForceVector(markerNumber=m0, loadVector=[0, -1, 0]))

#prepare system for simulation
mbs.Assemble()

#simulate with default parameters
exu.SolveDynamic(mbs, exu.SimulationSettings())

#stop rendering window
exu.StopRenderer()

#mbs can be still modified and work can be continued!
Exemplo n.º 4
0
def AnimateModes(systemContainer,
                 mainSystem,
                 nodeNumber,
                 period=0.04,
                 stepsPerPeriod=30,
                 showTime=True,
                 renderWindowText='',
                 runOnStart=False,
                 runMode=0):

    SC = systemContainer
    mbs = mainSystem
    SC.visualizationSettings.general.graphicsUpdateInterval = 0.25 * min(
        period, 2e-3)  #set according update interval!
    SC.visualizationSettings.general.showSolverTime = showTime
    #SC.visualizationSettings.general.showComputationInfo = False
    SC.visualizationSettings.general.showSolverInformation = False
    SC.visualizationSettings.general.renderWindowString = renderWindowText + 'mode 0'

    coordIndex = mbs.GetNodeODE2Index(nodeNumber)
    nodeCoords = mbs.GetNodeOutput(nodeNumber,
                                   exudyn.OutputVariableType.Coordinates,
                                   exudyn.ConfigurationType.Reference)
    numberOfModes = len(nodeCoords)
    #numberOfModes = mbs.GetNode(nODE2)['numberOfODE2Coordinates']

    if (runMode != 0 and runMode != 1 and runMode != 2):
        print('ERROR in AnimateModes: illegal run mode:', runMode)
        return

    #use interactive dialog:
    dialogItems = [
        {
            'type': 'label',
            'text': 'Mode shape:',
            'grid': (1, 0)
        },
        {
            'type': 'slider',
            'range': (0, numberOfModes - 1),
            'value': 0,
            'steps': numberOfModes,
            'variable': 'modeShapeModeNumber',
            'grid': (1, 1)
        },
        {
            'type': 'label',
            'text': 'Contour plot:',
            'grid': (2, 0)
        },
        {
            'type':
            'radio',
            'textValueList':
            [('None', int(exudyn.OutputVariableType._None)),
             ('DisplacementLocal',
              int(exudyn.OutputVariableType.DisplacementLocal)),
             ('Displacement', int(exudyn.OutputVariableType.Displacement)),
             ('StressLocal', int(exudyn.OutputVariableType.StressLocal)),
             ('StrainLocal', int(exudyn.OutputVariableType.StrainLocal))],
            'value':
            int(exudyn.OutputVariableType.DisplacementLocal),
            'variable':
            'modeShapeOutputVariable',
            'grid': [(3, 0), (3, 1), (3, 2), (3, 3), (3, 4)]
        },
        {
            'type': 'label',
            'text': 'Contour Component (use -1 for norm):',
            'grid': (4, 0)
        },
        {
            'type': 'slider',
            'range': (-1, 5),
            'value': 0,
            'steps': 7,
            'variable': 'modeShapeComponent',
            'grid': (4, 1)
        },
        {
            'type': 'label',
            'text': 'Amplitude:',
            'grid': (5, 0)
        },
        {
            'type': 'slider',
            'range': (0, 0.5),
            'value': 0.05,
            'steps': 501,
            'variable': 'modeShapeAmplitude',
            'grid': (5, 1)
        },
        {
            'type': 'label',
            'text': 'update period:',
            'grid': (6, 0)
        },
        {
            'type': 'slider',
            'range': (0.01, 2),
            'value': 0.04,
            'steps': 200,
            'variable': 'modeShapePeriod',
            'grid': (6, 1)
        },
        {
            'type':
            'radio',
            'textValueList': [('Continuous run', 0), ('One cycle', 1),
                              ('Static', 2)],
            'value':
            runMode,
            'variable':
            'modeShapeRunModus',
            'grid': [(7, 0), (7, 1), (7, 2)]
        },
        {
            'type':
            'radio',
            'textValueList': [('Mesh+Faces', 3), ('Faces only', 1),
                              ('Mesh only', 2)],
            'value':
            3,
            'variable':
            'modeShapeMesh',
            'grid': [(8, 0), (8, 1), (8, 2)]
        },
        {
            'type': 'radio',
            'textValueList': [('Record animation', 0), ('No recording', 1)],
            'value': 1,
            'variable': 'modeShapeSaveImages',
            'grid': [(9, 0), (9, 1)]
        },
    ]

    mbs.variables['modeShapePeriod'] = period
    mbs.variables['modeShapeStepsPerPeriod'] = stepsPerPeriod
    mbs.variables['modeShapeTimeIndex'] = 0
    mbs.variables['modeShapeLastSetting'] = [-1, 0, 0, 0]
    mbs.variables['modeShapeNodeCoordIndex'] = coordIndex

    def UFshowModes(mbs, dialog):
        i = mbs.variables['modeShapeTimeIndex']
        mbs.variables['modeShapeTimeIndex'] += 1
        stepsPerPeriod = mbs.variables['modeShapeStepsPerPeriod']
        amplitude = mbs.variables['modeShapeAmplitude']
        if amplitude == 0:
            SC.visualizationSettings.bodies.deformationScaleFactor = 0
            amplitude = 1
        else:
            SC.visualizationSettings.bodies.deformationScaleFactor = 1

        if mbs.variables['modeShapeRunModus'] == 2:  #no sin(t) in static case
            stepsPerPeriod = 1
            t = 0
        else:
            t = i / stepsPerPeriod * 2 * pi
            amplitude *= sin(t)
        mbs.systemData.SetTime(t, exudyn.ConfigurationType.Visualization)

        ode2Coords = mbs.systemData.GetODE2Coordinates()
        selectedMode = int(mbs.variables['modeShapeModeNumber'])
        outputVariable = exudyn.OutputVariableType(
            int(mbs.variables['modeShapeOutputVariable']))

        ode2Coords[mbs.variables['modeShapeNodeCoordIndex'] +
                   selectedMode] = amplitude

        mbs.systemData.SetODE2Coordinates(
            ode2Coords, exudyn.ConfigurationType.Visualization)

        SC.visualizationSettings.contour.reduceRange = False
        #check, if automatic range of contour colors shall be recomputed:
        if (mbs.variables['modeShapeLastSetting'][0] != int(
                mbs.variables['modeShapeModeNumber'])
                or mbs.variables['modeShapeLastSetting'][1] != int(
                    mbs.variables['modeShapeOutputVariable'])
                or mbs.variables['modeShapeLastSetting'][2] !=
                mbs.variables['modeShapeAmplitude']
                or mbs.variables['modeShapeLastSetting'][3] != int(
                    mbs.variables['modeShapeComponent'])):
            #print("set=",mbs.variables['modeShapeLastSetting'])
            SC.visualizationSettings.contour.reduceRange = True
            SC.visualizationSettings.general.renderWindowString = renderWindowText + 'mode ' + str(
                int(mbs.variables['modeShapeModeNumber']))

        mbs.variables['modeShapeLastSetting'] = [
            int(mbs.variables['modeShapeModeNumber']),
            int(mbs.variables['modeShapeOutputVariable']),
            mbs.variables['modeShapeAmplitude'],
            int(mbs.variables['modeShapeComponent'])
        ]

        SC.visualizationSettings.contour.outputVariable = outputVariable
        SC.visualizationSettings.contour.outputVariableComponent = int(
            mbs.variables['modeShapeComponent'])  #component
        SC.visualizationSettings.openGL.showFaces = (
            mbs.variables['modeShapeMesh'] & 1) == 1
        SC.visualizationSettings.openGL.showFaceEdges = (
            mbs.variables['modeShapeMesh'] & 2) == 2

        mbs.SendRedrawSignal()
        if not SC.visualizationSettings.general.useMultiThreadedRendering:
            exudyn.DoRendererIdleTasks()
        if mbs.variables['modeShapeSaveImages'] == 0:
            SC.RedrawAndSaveImage()  #create images for animation
        else:
            SC.visualizationSettings.exportImages.saveImageFileCounter = 0  #for next mode ...

        dialog.period = mbs.variables['modeShapePeriod']

        if mbs.variables['modeShapeTimeIndex'] >= stepsPerPeriod:
            mbs.variables['modeShapeTimeIndex'] = 0
            if mbs.variables['modeShapeRunModus'] > 0:  #one cylce or static
                dialog.StartSimulation()

    exudyn.StartRenderer()
    if 'renderState' in exudyn.sys:
        SC.SetRenderState(exudyn.sys['renderState'])  #load last model view

    simulationSettings = exudyn.SimulationSettings(
    )  #not used, but needed in dialog
    #   self.mbs.sys['solver'].InitializeSolver(self.mbs, self.simulationSettings)
    simulationSettings.solutionSettings.solutionInformation = 'Mode X'

    if not SC.visualizationSettings.general.useMultiThreadedRendering:
        exudyn.DoRendererIdleTasks()  #do an update once

    dialog = InteractiveDialog(
        mbs,
        simulationSettings=simulationSettings,
        simulationFunction=UFshowModes,
        dialogItems=dialogItems,
        title='Animate mode shapes',
        doTimeIntegration=False,
        period=period,
        showTime=False,  #done in UFshowModes
        runOnStart=runOnStart)

    #SC.WaitForRenderEngineStopFlag() #not needed, Render window closes when dialog is quit
    exudyn.StopRenderer()  #safely close rendering window!
Exemplo n.º 5
0
def ParameterFunction(parameterSet):

    s1=L1*0.5
    s2=L2*0.5
    if False:
        s1 = s1opt
        s2 = s2opt

    if 's1' in parameterSet:
        s1 = parameterSet['s1']
    h=0.002
    if 'h' in parameterSet:
        h = parameterSet['h']
    if 's2' in parameterSet:
        s2 = parameterSet['s2']

    iCalc = 'Ref' #needed for parallel computation ==> output files are different for every computation
    if 'computationIndex' in parameterSet:
        iCalc = str(parameterSet['computationIndex'])
        #print("computation index=",iCalc, flush=True)

    SC = exu.SystemContainer()
    mbs = SC.AddSystem()
    
    testCases = 1 #floating body
    nGround = mbs.AddNode(NodePointGround(referenceCoordinates=[0,0,0])) #ground node for coordinate constraint
    mGround = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber = nGround, coordinate=0)) #Ground node ==> no action
    
    
    #++++++++++++++++++++++++++++++++
    #floating body to mount slider-crank mechanism
    constrainGroundBody = (testCases == 0) #use this flag to fix ground body
    
    #graphics for floating frame:
    gFloating = GraphicsDataOrthoCube(-0.25, -0.25, -0.1, 0.8, 0.25, -0.05, color=[0.3,0.3,0.3,1.]) 
    
    if constrainGroundBody:
        floatingRB = mbs.AddObject(ObjectGround(referencePosition=[0,0,0], visualization=VObjectGround(graphicsData=[gFloating])))    
        mFloatingN = mbs.AddMarker(MarkerBodyPosition(bodyNumber = floatingRB, localPosition=[0,0,0]))
    else:
        nFloating = mbs.AddNode(Rigid2D(referenceCoordinates=[0,0,0], initialVelocities=[0,0,0]));
        mFloatingN = mbs.AddMarker(MarkerNodePosition(nodeNumber=nFloating))
        floatingRB = mbs.AddObject(RigidBody2D(physicsMass=2, physicsInertia=1, nodeNumber=nFloating, visualization=VObjectRigidBody2D(graphicsData=[gFloating])))
        mRB0 = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber = nFloating, coordinate=0))
        mRB1 = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber = nFloating, coordinate=1))
        mRB2 = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber = nFloating, coordinate=2))

        #add spring dampers for reference frame:        
        k=5000 #stiffness of floating body
        d=k*0.01
        mbs.AddObject(CoordinateSpringDamper(markerNumbers=[mGround,mRB0], stiffness=k, damping=d))
        mbs.AddObject(CoordinateSpringDamper(markerNumbers=[mGround,mRB1], stiffness=k, damping=d))
        mbs.AddObject(CoordinateSpringDamper(markerNumbers=[mGround,mRB2], stiffness=k, damping=d))
        mbs.AddObject(CoordinateConstraint(markerNumbers=[mGround,mRB2]))
    
    
    
    #++++++++++++++++++++++++++++++++
    #nodes and bodies
    omega=2*pi/60*300 #3000 rpm
    M=0.1 #torque (default: 0.1)

    s1L=-s1
    s1R=L1-s1
    s2L=-s2
    s2R=L2-s2
    
    #lambda=L1/L2
    J1=(m1/12.)*L1**2 #inertia w.r.t. center of mass
    J2=(m2/12.)*L2**2 #inertia w.r.t. center of mass
    
    ty = 0.05    #thickness
    tz = 0.05    #thickness

    graphics1 = GraphicsDataRigidLink(p0=[s1L,0,-0.5*tz],p1=[s1R,0,-0.5*tz], 
                                      axis0=[0,0,1], axis1=[0,0,1],radius=[0.5*ty,0.5*ty],
                                      thickness=0.8*ty, width=[tz,tz], color=color4steelblue,nTiles=16)
    
    graphics2 = GraphicsDataRigidLink(p0=[s2L,0,0.5*tz],p1=[s2R,0,0.5*tz], 
                                      axis0=[0,0,1], axis1=[0,0,1],radius=[0.5*ty,0.5*ty],
                                      thickness=0.8*ty, width=[tz,tz], color=color4lightred,nTiles=16)
    
    #crank:
    nRigid1 = mbs.AddNode(Rigid2D(referenceCoordinates=[s1,0,0], 
                                  initialVelocities=[0,0,0]));
    oRigid1 = mbs.AddObject(RigidBody2D(physicsMass=m1, 
                                        physicsInertia=J1,
                                        nodeNumber=nRigid1,
                                        visualization=VObjectRigidBody2D(graphicsData= [graphics1])))
    
    #connecting rod:
    nRigid2 = mbs.AddNode(Rigid2D(referenceCoordinates=[L1+s2,0,0], 
                                  initialVelocities=[0,0,0]));
    oRigid2 = mbs.AddObject(RigidBody2D(physicsMass=m2, 
                                        physicsInertia=J2,
                                        nodeNumber=nRigid2,
                                        visualization=VObjectRigidBody2D(graphicsData= [graphics2])))
    
    
    #++++++++++++++++++++++++++++++++
    #slider:
    c=0.025 #dimension of mass
    graphics3 = GraphicsDataOrthoCube(-c,-c,-c*2,c,c,0,color4grey)
    
    #nMass = mbs.AddNode(Point2D(referenceCoordinates=[L1+L2,0]))
    #oMass = mbs.AddObject(MassPoint2D(physicsMass=m3, nodeNumber=nMass,visualization=VObjectMassPoint2D(graphicsData= [graphics3])))
    nMass = mbs.AddNode(Rigid2D(referenceCoordinates=[L1+L2,0,0]))
    oMass = mbs.AddObject(RigidBody2D(physicsMass=m3, physicsInertia=0.001*m3, nodeNumber=nMass,visualization=VObjectRigidBody2D(graphicsData= [graphics3])))
    
    #++++++++++++++++++++++++++++++++
    #markers for joints:
    mR1Left = mbs.AddMarker(MarkerBodyRigid(bodyNumber=oRigid1, localPosition=    [s1L,0.,0.])) #support point # MUST be a rigidBodyMarker, because a torque is applied
    mR1Right = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oRigid1, localPosition=[s1R,0.,0.])) #end point; connection to connecting rod
    
    mR2Left = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oRigid2, localPosition= [s2L,0.,0.])) #connection to crank
    mR2Right = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oRigid2, localPosition=[s2R,0.,0.])) #end point; connection to slider
    
    mMass = mbs.AddMarker(MarkerBodyPosition(bodyNumber=oMass, localPosition=[ 0.,0.,0.]))
    mG0 = mFloatingN
    
    #++++++++++++++++++++++++++++++++
    #joints:
    mbs.AddObject(RevoluteJoint2D(markerNumbers=[mG0,mR1Left]))
    mbs.AddObject(RevoluteJoint2D(markerNumbers=[mR1Right,mR2Left]))
    mbs.AddObject(RevoluteJoint2D(markerNumbers=[mR2Right,mMass]))
        
    
    #prismatic joint:
    mRigidGround = mbs.AddMarker(MarkerBodyRigid(bodyNumber = floatingRB, localPosition = [L1+L2,0,0]))
    mRigidSlider = mbs.AddMarker(MarkerBodyRigid(bodyNumber = oMass, localPosition = [0,0,0]))
    
    mbs.AddObject(PrismaticJoint2D(markerNumbers=[mRigidGround,mRigidSlider], constrainRotation=True))
    
    
    #user function for load; switch off load after 1 second
    userLoadOn = True
    def userLoad(mbs, t, load):
        setLoad = 0
        if userLoadOn:
            setLoad = load
            omega = mbs.GetNodeOutput(nRigid1,variableType = exu.OutputVariableType.AngularVelocity)[2]
            if omega > 2*pi*2:
                #print("t=",t)
                userLoadOn = False
        return setLoad
    
    #loads and driving forces:
    mRigid1CoordinateTheta = mbs.AddMarker(MarkerNodeCoordinate(nodeNumber = nRigid1, coordinate=2)) #angle coordinate is constrained
    #mbs.AddLoad(LoadCoordinate(markerNumber=mRigid1CoordinateTheta, load = M, loadUserFunction=userLoad)) #torque at crank
    mbs.AddLoad(LoadCoordinate(markerNumber=mRigid1CoordinateTheta, load = M)) #torque at crank

    #write motion of support frame:    
    sensorFileName = 'solution/floatingPos'+iCalc+'.txt'
    sFloating = mbs.AddSensor(SensorNode(nodeNumber=nFloating, fileName=sensorFileName, 
                             outputVariableType=exu.OutputVariableType.Position))
    
    #++++++++++++++++++++++++++++++++
    #assemble, adjust settings and start time integration
    mbs.Assemble()
    
    simulationSettings = exu.SimulationSettings() #takes currently set values or default values
    tEnd = 3
    
    simulationSettings.timeIntegration.numberOfSteps = int(tEnd/h) 
    simulationSettings.timeIntegration.endTime = tEnd              

    #simulationSettings.timeIntegration.newton.relativeTolerance = 1e-8 #10000
    #simulationSettings.timeIntegration.verboseMode = 1 #10000
    
    simulationSettings.solutionSettings.solutionWritePeriod = 2e-3
    simulationSettings.solutionSettings.writeSolutionToFile = useGraphics

    simulationSettings.timeIntegration.newton.useModifiedNewton = True
    simulationSettings.timeIntegration.newton.relativeTolerance = 1e-8
    simulationSettings.timeIntegration.newton.absoluteTolerance = 1e-8
    
    #++++++++++++++++++++++++++++++++++++++++++
    #solve index 2 / trapezoidal rule:
    simulationSettings.timeIntegration.generalizedAlpha.useNewmark = True
    simulationSettings.timeIntegration.generalizedAlpha.useIndex2Constraints = True
    
    dSize = 0.02
    SC.visualizationSettings.nodes.defaultSize = dSize
    SC.visualizationSettings.markers.defaultSize = dSize
    SC.visualizationSettings.bodies.defaultSize = [dSize, dSize, dSize]
    SC.visualizationSettings.connectors.defaultSize = dSize
    
    #data obtained from SC.GetRenderState(); use np.round(d['modelRotation'],4)
    SC.visualizationSettings.openGL.initialModelRotation = [[ 0.87758,  0.04786, -0.47703],
                                                            [ 0.     ,  0.995  ,  0.09983],
                                                            [ 0.47943, -0.08761,  0.8732]]
    SC.visualizationSettings.openGL.initialZoom = 0.47
    SC.visualizationSettings.openGL.initialCenterPoint = [0.192, -0.0039,-0.075]
    SC.visualizationSettings.openGL.initialMaxSceneSize = 0.4
    SC.visualizationSettings.general.autoFitScene = False
    #mbs.WaitForUserToContinue()
    
    if useGraphics: 
        exu.StartRenderer()
   
    exu.SolveDynamic(mbs, simulationSettings)
        
    if useGraphics: 
        #+++++++++++++++++++++++++++++++++++++
        #animate solution
#        mbs.WaitForUserToContinue
#        fileName = 'coordinatesSolution.txt'
#        solution = LoadSolutionFile('coordinatesSolution.txt')
#        AnimateSolution(mbs, solution, 10, 0.025, True)
        #+++++++++++++++++++++++++++++++++++++

        SC.WaitForRenderEngineStopFlag()
        exu.StopRenderer() #safely close rendering window!
    
    #++++++++++++++++++++++++++++++++++++++++++
    #evaluate error:
    data = np.loadtxt(sensorFileName, comments='#', delimiter=',')

    errorNorm = max(abs(data[:,1])) + max(abs(data[:,2])) #max displacement in x and y direction

    #++++++++++++++++++++++++++++++++++++++++++
    #clean up optimization
    if True: #delete files; does not work for parallel, consecutive operation
        if iCalc != 'Ref':
            os.remove(sensorFileName) #remove files in order to clean up
            while(os.path.exists(sensorFileName)): #wait until file is really deleted -> usually some delay
                sleep(0.001) #not nice, but there is no other way than that
        
    if useGraphics:
        print("max. oszillation=", errorNorm)
        from exudyn.plot import PlotSensor
        
        PlotSensor(mbs, sensorNumbers=[sFloating,sFloating], components=[0,1])

    del mbs
    del SC
    
    return errorNorm