SimpleScenePython
From Yade
This scene can be generated by running
yade-version scripts/simple-scene.py
The scene will be save in /tmp/a.xml.bz2
.
<source lang="python">
- !/usr/local/bin/yade-trunk -x
- -*- encoding=utf-8 -*-
</source> Omega is the super-class that orchestrates the whole program. It holds the entire simulation (MetaBody), takes care of loading/saving, starting/stopping the simulation, loads plugins and more. <source lang="python"> o=Omega() # for advaned folks: this creates default MetaBody as well </source> Initializers are run before the simulation. <source lang="python"> o.initializers=[ </source> Create and reset to zero container of all PhysicalActions that will be used <source lang="python"> StandAloneEngine('PhysicalActionContainerInitializer'), </source> Create bounding boxes. They are needed to zoom the 3d view properly before we start the simulation. <source lang="python"> MetaEngine('BoundingVolumeMetaEngine',[EngineUnit('InteractingSphere2AABB'),EngineUnit('InteractingBox2AABB'),EngineUnit('MetaInteractingGeometry2AABB')]) ] </source> Engines are called consecutively at each iteration. Their order matters.
Some of them work by themselves (StandAloneEngine, DeusExMachina - the difference of these two is unimportant).
MetaEngines act as dispatchers and based on the type of objects they operate on, different EngineUnits are called. <source lang="python"> o.engines=[ </source> Resets forces and momenta the act on bodies <source lang="python"> StandAloneEngine('PhysicalActionContainerReseter'), </source> associates bounding volume - in this case, AxisAlignedBoundingBox (AABB) - to each body. MetaEngine calls corresponding EngineUnit, depending on whether the body is Sphere, Box, or MetaBody (rootBody). AABBs will be used to detect collisions later, by PersistentSAPCollider <source lang="python"> MetaEngine('BoundingVolumeMetaEngine',[ EngineUnit('InteractingSphere2AABB'), EngineUnit('InteractingBox2AABB'), EngineUnit('MetaInteractingGeometry2AABB') ]), </source> Using bounding boxes created by the previous engine, find possible body collisions. These possible collisions are inserted in Omega.interactions container (MetaBody::transientInteractions in c++). <source lang="python"> StandAloneEngine('PersistentSAPCollider'), </source> Decide whether the potential collisions are real; if so, create geometry information about each potential collision. Here, the decision about which EngineUnit to use depends on types of _both_ bodies. Note that there is no EngineUnit for box-box collision. They are not implemented. <source lang="python"> MetaEngine('InteractionGeometryMetaEngine',[ EngineUnit('InteractingSphere2InteractingSphere4SpheresContactGeometry'), EngineUnit('InteractingBox2InteractingSphere4SpheresContactGeometry') ]), </source> Create physical information about the interaction. This may consist in deriving contact rigidity from elastic moduli of each body, for example. The purpose is that the contact may be "solved" without reference to related bodies, only with the information contained in contact geometry and physics. <source lang="python"> MetaEngine('InteractionPhysicsMetaEngine',[EngineUnit('SimpleElasticRelationships')]), </source> "Solver" of the contact, also called (consitutive) law. Based on the information in interaction physics and geometry, it applies corresponding forces on bodies in interaction. <source lang="python"> StandAloneEngine('ElasticContactLaw'), </source> Apply gravity: all bodies will have gravity applied on them. Note the engine parameter 'gravity', a vector that gives the acceleration. <source lang="python"> DeusExMachina('GravityEngine',{'gravity':[0,0,-9.81]}), </source> Forces acting on bodies are damped to artificially increase energy dissipation in simulation. (In this model, the restitution coefficient of interaction is 1, which is not realistic.) This MetaEngine acts on all PhysicalActions and selects the right EngineUnit base on type of the PhysicalAction. <source lang="python"> MetaEngine('PhysicalActionDamper',[ EngineUnit('CundallNonViscousForceDamping',{'damping':0.2}), EngineUnit('CundallNonViscousMomentumDamping',{'damping':0.2}) ]), </source> Now we have forces and momenta acting on bodies. Newton's law calculates acceleration that corresponds to them. <source lang="python"> MetaEngine('PhysicalActionApplier',[ EngineUnit('NewtonsForceLaw'), EngineUnit('NewtonsMomentumLaw'), ]), </source> Acceleration results in velocity change. Integrating the velocity over dt, position of the body will change. <source lang="python"> MetaEngine('PhysicalParametersMetaEngine',[EngineUnit('LeapFrogPositionIntegrator')]), </source> Angular acceleration changes angular velocity, resulting in position and/or orientation change of the body. <source lang="python"> MetaEngine('PhysicalParametersMetaEngine',[EngineUnit('LeapFrogOrientationIntegrator')]), ] </source> The yade.utils module contains some handy functions, like yade.utils.box and yade.utils.sphere. After this import, they will be accessible as utils.box and utils.sphere. <source lang="python"> from yade import utils </source> create bodies in the simulation: one box in the origin and one floating above it.
The box:
- extents: half-size of the box. [.5,.5,.5] is unit cube
- center: position of the center of the box
- dynamic: it is not dynamic, i.e. will not move during simulation, even if forces are applied to it
- color: for the 3d display; specified within unit cube in the RGB space; [1,0,0] is, therefore, red
- young: Young's modulus
- poisson: Poissons's ratio
<source lang="python"> o.bodies.append(utils.box(center=[0,0,0],extents=[.5,.5,.5],dynamic=False,color=[1,0,0],young=30e9,poisson=.3,density=2400)) </source> The above command could be actully written without the util.box function like this: (will not be executed, since the condition is never True) <source lang="python"> if False: # Create empty body object b=Body() # set the isDynamic body attribute b['isDynamic']=False # Assign geometrical model (shape) to the body: a box of given size b.shape=GeometricalModel('Box',{'extents':[.5,.5,.5],'diffuseColor':[1,0,0]}) # Assign computational model (mold; may be simplified form of shape) to the body b.mold=InteractingGeometry('InteractingBox',{'extents':[.5,.5,.5],'diffuseColor':[1,0,0]}) # physical parameters: # store mass to a temporary mass=8*.5*.5*.5*2400 # * se3 (position & orientation) as 3 position coordinates, then 3 direction axis coordinates and rotation angle b.phys=PhysicalParameters('BodyMacroParameters',{'se3':[0,0,0,1,0,0,0],'mass':mass,'inertia':[mass*4*(.5**2+.5**2),mass*4*(.5**2+.5**2),mass*4*(.5**2+.5**2)],'young':30e9,'poisson':.3}) # other information about AABB will be updated during simulation by relevant BoundingVolumeMetaEngine b.bound=BoundingVolume('AABB',{'diffuseColor':[0,1,0]}) # add the body to the simulation o.bodies.append(b) </source> The sphere
- First two arguments are radius and center, respectively. They are used as "positional arguments" here:
python will deduce based on where they are what they mean.
It could also be written without using utils.sphere - see gui/py/utils.py for the code of the utils.sphere function <source lang="python"> o.bodies.append(utils.sphere([0,0,2],1,color=[0,1,0],young=30e9,poisson=.3,density=2400)) </source> Estimate timestep from p-wave speed and multiply it by safety factor of .2 <source lang="python"> o.dt=.2*utils.PWaveTimeStep() </source> Save the scene to file, so that it can be loaded later. Supported extension are: .xml, .xml.gz, .xml.bz2. <source lang="python"> o.save('/tmp/a.xml.bz2');
- utils.runInQtGui() # will run in background
- quit()
</source>