woo.dem
¶
Inlets & Outlets¶
TODO
Inlet¶
Object
→ Engine
→ PeriodicEngine
→ Inlet

class
woo.dem.
Inlet
(*args, **kwargs)¶ Inlet generating new particles. This is an abstract base class which in itself does not generate anything, but provides some unified interface to derived classes.
Overloaded function.

maxMass
(= 1.0)¶ Mass at which the engine will not produce any particles (inactive if not positive)
[type: Real, unit: kg]

maxNum
(= 1)¶ Number of generated particles after which no more will be produced (inactive if not positive)
[type: long]

doneHook
(= '')¶ Python string to be evaluated when
maxMass
ormaxNum
have been reached (or withRandomInlet
,maxAttempts
were exhausted andRandomInlet.atMaxAttempts
equals'done'
). The engine is made dead automatically even if doneHook is not specified.[type: string]

mass
(= 0.0)¶ Generated mass total
[type: Real, unit: kg]

num
(= 0)¶ Number of generated particles
[type: long]

currRate
(= nan)¶ Current value of mass flow rate
[type: Real, unit: kg/s, readonly in python]

zeroRateAtStop
(= True)¶ When the generator stops (mass/number of particles reached, …), set
currRate
to zero immediately[type: bool]

currRateSmooth
(= 1.0)¶ Smoothing factor for currRate ∈〈0,1〉
[type: Real, range: 0−1]

glColor
(= 0.0)¶ Color for rendering (nan disables rendering)
[type: Real, not shown in the UI]

ConveyorInlet¶
Object
→ Engine
→ PeriodicEngine
→ Inlet
→ ConveyorInlet

class
woo.dem.
ConveyorInlet
(*args, **kwargs)¶ Inlet producing infinite band of particles from packing periodic in the xdirection. Clumps are fully supported.
Overloaded function.
__init__(self: woo.dem.ConveyorInlet) > None
__init__(self: woo.dem.ConveyorInlet, *args, **kwargs) > None
► Particles

spherePack
(= None)¶ woo.pack.SpherePack
object; when specified,centers
,radii
(andclumps
, if clumps are contained) are discarded and will be computed from thisSpherePack
. The attribute is reset afterwards.[type: shared_ptr<SpherePack>, not shown in the UI, not saved]

shapePack
(= None)¶ Purely geomerical description of particles to be generated (will replace
spherePack
,centers
,radii
,clumps
andcellLen
in the future).[type: shared_ptr<
ShapePack
>, not dumped]

zTrim
(= False)¶ Trim packing from above so that the ratio of
vel
/packVel
is as small as possible. Spheres/clumps will be discarded from above and this flag will be set to false once trimming is done (it will not be called again explicitly even ifmassRate
orvel
change.[type: bool, not shown in the UI]

zTrimHt
(= nan)¶ Height at which the packing was trimmed if
zTrim
was set.[type: Real, not shown in the UI]

cellLen
(= nan)¶ Length of the band cell, which is repeated periodically (if
spherePack
is given and is periodic, this value is deduced)[type: Real, unit: m]

radii
(= [])¶ Radii for the packing (if
spherePack
is given, radii are computed)[type: vector<Real>, not shown in the UI, not dumped]

centers
(= [])¶ Centers of spheres/clumps in the packing (if
spherePack
is given, centers are computed)[type: vector<Vector3r>, not shown in the UI, not dumped]

clumps
(= [])¶ Clump geometry, corresponding to each
radii
andcenters
. (ifspherePack
is given, clumps are computed)[type: vector<shared_ptr<SphereClumpGeom>>, not shown in the UI, not dumped]

massRate
(= nan)¶ Average mass flow rate; if given,
vel
is adjusted (if both are given,massRate
takes precedence).[type: Real, unit: kg/s]

vel
(= nan)¶ Velocity of particles; if specified,
massRate
is adjusted (of both are given, such as in constructor,massRate
has precedence and a warning is issued if the two don’t match)[type: Real, unit: m/s]

packVel
(= nan)¶ Velocity by which the packing is traversed and new particles emmited; always smaller than or equal to
vel
. Computed automatically.[type: Real, unit: m/s, readonly in python]

relLatVel
(= 0.0)¶ Relative velocity components lateral to
vel
(local xaxis); both components are assigned with uniform probability from range (relLatVel*vel,+relLatVel*vel), at the moment the particle leaves the barrier layer.[type: Real]
► Clipping

clipX
(= [])¶ If given, clip the given packing from above by the given function \(z_max(x)\) given as piecewiselinear function in samelength arrays
clipX
andclipZ
. IfclipX
is empty, no clipping is done.[type: vector<Real>, unit: m]

clipZ
(= [])¶ Zcoordinate (max sphere \(z\) coordinate), with points corresponding to
clipX
.[type: vector<Real>, unit: m]

clipLastX
(= 0.0)¶ Xcoordinate of lastgenerated particles, for use with clipping (clipping may have different periodicity than the packing, this value can be different from
lastX
and wraps aroundcellLen
.[type: Real, readonly in python]

clipPos
(= 0)¶ Internal variable for optimizing interpolation in
clipX
andclipZ
.[type: size_t, not shown in the UI, readonly in python]
► Tunables

startLen
(= nan)¶ Band to be created at the very start; if NaN, only the usual starting amount is created (depending on feed velocity)
[type: Real]

barrierColor
(= 0.2)¶ Color for barrier particles (NaN for random)
[type: Real]

color
(= nan)¶ Color for nonbarrier particles (NaN for random)
[type: Real]

barrierLayer
(= 3.0)¶ Some length of the last part of new particles has all DoFs blocked, so that when new particles are created, there are no sudden contacts in the band; in the next step, DoFs in this layer are unblocked. If barrierLayer is negative, it is relative to the maximum radius in the given packing, and is automatically set to the correct value at the first run
[type: Real]

movingBedZ
(= nan)¶ If given, particles with z coordinate lower than this value will move indefinitely with the conveyor (contact velocity, blocked DOFs), technically not added to the barrier at all.
[type: Real]

movingBedColor
(= 0.5)¶ Color for particles selected with
movingBedZ
(NaN for random).[type: Real]

save
(= True)¶ Save generated particles so that PSD can be generated afterwards
[type: bool]

matState
(= False)¶ Endow new particles with
InletMatState
(for tracking when a particular particle was created and similar.[type: bool]
► Bookkeeping

nextIx
(= 1)¶ Index of lastgenerated particles in the packing
[type: int, readonly in python]

lastX
(= 0.0)¶ Xcoordinate of lastgenerated particles in the packing
[type: Real, readonly in python]

barrier
(= [])¶ Nodes which make up the barrier and will be unblocked once they leave barrierLayer.
[type: list<shared_ptr<Node>>, not accessible from python]

node
(= <Node @ 0x22564f0, at (0, 0, 0)>)¶ Position and orientation of the factory; local xaxis is the feed direction.
[type: shared_ptr<
Node
>]

streamBeginNode
(= None)¶ Node at which the particle stream will start, which can be moving during the simulation without disrupting stream continuity. It is the position of this node, projected onto \(x\)axis of
node
, which is relevant.[type: shared_ptr<
Node
>]

barrierImpose
(= None)¶ Imposition which is used for barrier nodes, as long as they are in the barrier.
[type: shared_ptr<
Impose
>]

xDebt
(= 0.0)¶ Length of packing which was not covered in the last step due to
streamBeginNode
offset.[type: Real, not shown in the UI, readonly in python]

initSortLimit
(= 200)¶ Limit of number of particles generated in a single step above which
woo.dem.InsertionSortCollider.forceInitSort
will be set (only useful ifInsertionSortCollider
is actually used).[type: int]

avgRate
(= nan)¶ Average feed rate (computed from
Material density
, packing and andvel
[type: Real, unit: kg/s, readonly in python]

kinEnergyIx
(= 1)¶ Index for kinetic energy in scene.energy
[type: int, not saved, not accessible from python]

genDiamMassTime
(= [])¶ List of generated diameters, masses and times (for making granulometry)
[type: vector<Vector3r>, not shown in the UI, readonly in python]

clear
(self: woo.dem.ConveyorInlet) → None¶

diamMass
(self: woo.dem.ConveyorInlet, zipped: bool = False) → object¶ Return masses and diameters of generated particles. With zipped, return list of (diameter, mass); without zipped, return tuple of 2 arrays, diameters and masses.

massOfDiam
(self: woo.dem.ConveyorInlet, min: float = 0, max: float = inf) → float¶ Return mass of particles of which diameters are between min and max.
RandomInlet¶
Object
→ Engine
→ PeriodicEngine
→ Inlet
→ RandomInlet

class
woo.dem.
RandomInlet
(*args, **kwargs)¶ Inlet generating new particles. This class overrides
woo.core.Engine.critDt
, which in turn callswoo.dem.ParticleGenerator.critDt
with all possiblematerials
one by one.Overloaded function.
__init__(self: woo.dem.RandomInlet) > None
__init__(self: woo.dem.RandomInlet, *args, **kwargs) > None

massRate
(= nan)¶ Mass flow rate; if nonpositive, keep generating and placing new particles until
maxAttempts
is exhausted andatMaxAttempts
is used to decide what to do next.[type: Real, unit: kg/s]

materials
(= [])¶ Set of materials for new particles, randomly picked from
[type: vector<shared_ptr<Material>>]

matStates
(= [])¶ Set of material states; when material is picked from
materials
,MatState
at the same index is assigned to the particle; if it isNone
ormatStates
is shorter than requested index, no material state will be assigned.[type: vector<shared_ptr<MatState>>]

generator
(= None)¶ Particle generator instance
[type: shared_ptr<
ParticleGenerator
>]

shooter
(= None)¶ Particle shooter instance (assigns velocities to generated particles. If not given, particles have zero velocities initially.
[type: shared_ptr<
ParticleShooter
>]

spatialBias
(= None)¶ Make random position biased based on the radius of the current particle; if unset, distribute uniformly.
[type: shared_ptr<
SpatialBias
>]

maxAttempts
(= 5000)¶ Maximum attempts to position new particles randomly, without collision. If 0, no limit is imposed. When reached,
atMaxAttempts
determines, what will be done. Each particle is tried maxAttempts/maxMetaAttempts times, then a new particle is tried.[type: int]

attemptPar
(= 5)¶ Number of trying a different particle to position (each will be tried maxAttempts/attemptPar times)
[type: int]

atMaxAttempts
(= 0)¶ What to do when maxAttempts is reached.
[type: int, named enum, possible values are: ‘error’ (0), ‘dead’ (1), ‘warn’ (2), ‘silent’ (‘nothing’, ‘ignore’, ‘’; 3), ‘doneHook’ (‘done’; 4)]

padDist
(= 0.0)¶ Pad geometry by this distance inside; random points will be chosen inside the shrunk geometry, whereas boxes will be validated in the larger one. This attribute must be set by the generator.
[type: Real, readonly in python]

kinEnergyIx
(= 1)¶ Index for kinetic energy in scene.energy
[type: int, not saved, not accessible from python]

color
(= nan)¶ Color for new particles (NaN for random; negative for keeping color assigned by the generator).
[type: Real]

stepGoalMass
(= 0.0)¶ Mass to be attained in this step
[type: Real, readonly in python]

collideExisting
(= True)¶ Consider collisions with preexisting particle; this is generally a good idea, though if e.g. there are no preexisting particles, it is useful to set to
False
to avoid having to define collider for no other reason than makeRandomInlet
happy.[type: bool]

clear
(self: woo.dem.RandomInlet) → None¶

randomPosition
(self: woo.dem.RandomInlet, arg0: float, arg1: float) → _wooEigen11.Vector3¶

validateBox
(self: woo.dem.RandomInlet, arg0: _wooEigen11.AlignedBox3) → bool¶
CylinderInlet¶
Object
→ Engine
→ PeriodicEngine
→ Inlet
→ RandomInlet
→ CylinderInlet

class
woo.dem.
CylinderInlet
(*args, **kwargs)¶ Generate particle inside an arbitrarily oriented cylinder.
Overloaded function.
__init__(self: woo.dem.CylinderInlet) > None
__init__(self: woo.dem.CylinderInlet, *args, **kwargs) > None

node
(= None)¶ Node defining local coordinate system. If not given, global coordinates are used.
[type: shared_ptr<
Node
>]

height
(= nan)¶ Height along the local \(x\)axis.
[type: Real, unit: m]

radius
(= nan)¶ Radius of the cylinder (perpendicular to the local \(x\)axis).
[type: Real, unit: m]

glSlices
(= 16)¶ Number of subdivision slices for rendering.
[type: int]
BoxInlet¶
Object
→ Engine
→ PeriodicEngine
→ Inlet
→ RandomInlet
→ BoxInlet

class
woo.dem.
BoxInlet
(*args, **kwargs)¶ Generate particle inside axisaligned box volume.
Overloaded function.

box
(= AlignedBox3((nan, nan, nan), (nan, nan, nan)))¶ Box volume specification (lower and upper corners)
[type: AlignedBox3r]

BoxInlet2d¶
Object
→ Engine
→ PeriodicEngine
→ Inlet
→ RandomInlet
→ BoxInlet
→ BoxInlet2d

class
woo.dem.
BoxInlet2d
(*args, **kwargs)¶ Generate particles inside axisaligned plane (its normal axis is given via the
axis
attribute; particles are allowed to stick out of that plane.Overloaded function.
__init__(self: woo.dem.BoxInlet2d) > None

axis
(= 2)¶ Axis normal to the plane in which particles are generated.
[type: short]
ArcInlet¶
Object
→ Engine
→ PeriodicEngine
→ Inlet
→ RandomInlet
→ ArcInlet

class
woo.dem.
ArcInlet
(*args, **kwargs)¶ Inlet generating particles in prismatic arc (revolved rectangle) specified using cylindrical coordinates (with the
ISO 3111
convention, as mentioned at the Wikipedia page) in a local system.Overloaded function.

node
(= <Node @ 0x2135ef0, at (0, 0, 0)>)¶ Node defining local coordinate system. Must be given.
[type: shared_ptr<
Node
>]

cylBox
(= AlignedBox3((1.7976931348623157e308, 1.7976931348623157e308, 1.7976931348623157e308), (1.7976931348623157e308, 1.7976931348623157e308, 1.7976931348623157e308)))¶ Box in cylindrical coordinates, as: (ρ₀,φ₀,z₀),(ρ₁,φ₁,z₁). ρ must be nonnegative, (φ₁φ₀)≤2π.
[type: AlignedBox3r]

glSlices
(= 32)¶ Number of slices for rendering circle (the arc takes the proportionate value
[type: int]

ParticleGenerator¶

class
woo.dem.
ParticleGenerator
(*args, **kwargs)¶ Abstract class for generating particles
Overloaded function.
__init__(self: woo.dem.ParticleGenerator) > None
__init__(self: woo.dem.ParticleGenerator, *args, **kwargs) > None

genDiamMassTime
(= [])¶ List of generated particle’s (equivalent) radii and masses (for making granulometry)
[type: vector<Vector3r>, not shown in the UI, not dumped, readonly in python]

save
(= True)¶ Save generated particles so that PSD can be generated afterwards
[type: bool]

__call__
(self: woo.dem.ParticleGenerator, mat: woo.dem.Material, time: float = 0) → tuple¶ Call the generation routine, returning one particle (at origin) and its boundingbox when at origin. Useful for debugging.

clear
(self: woo.dem.ParticleGenerator) → None¶ Clear stored data about generated particles; only subsequently generated particles will be considered in the PSD.

critDt
(self: woo.dem.ParticleGenerator, density: float, young: float) → float¶ Return critical timestep for particles generated by us, given that their density and Young’s modulus are as given in arguments.

diamMass
(self: woo.dem.ParticleGenerator, zipped: bool = False) → object¶ With zipped, return list of (diameter, mass); without zipped, return tuple of 2 arrays, diameters and masses.

massOfDiam
(self: woo.dem.ParticleGenerator, min: float = 0, max: float = inf) → float¶ Return mass of particles of which diameters are between min and max.

minMaxDiam
(self: woo.dem.ParticleGenerator) → _wooEigen11.Vector2¶ Return the range of minimum and maximum diameters.

padDist
(self: woo.dem.ParticleGenerator) → float¶ Return padding distance by which the factory geometry should be shrunk before generating a random point.
PsdSphereGenerator¶
Object
→ ParticleGenerator
→ PsdSphereGenerator

class
woo.dem.
PsdSphereGenerator
(*args, **kwargs)¶ Generate spherical particles following a given Particle Size Distribution (PSD)
Overloaded function.
__init__(self: woo.dem.PsdSphereGenerator) > None
__init__(self: woo.dem.PsdSphereGenerator, *args, **kwargs) > None

discrete
(= False)¶ The points on the PSD curve will be interpreted as the only allowed diameter values; if false, linear interpolation between them is assumed instead. Do not change once the generator is running.
[type: bool]

psdPts
(= [])¶ Points of the PSD curve; the first component is particle diameter [m] (not radius!), the second component is passing percentage. Both diameter and passing values must be increasing (diameters must be strictly increasing). Passing values are normalized so that the last value is 1.0 (therefore, you can enter the values in percents if you like).
[type: vector<Vector2r>, units: [m,]]

mass
(= True)¶ PSD has mass percentages; if false, number of particles percentages are assumed. Do not change once the generator is running.
[type: bool]

weightPerBin
(= [])¶ Keep track of mass/number of particles for each point on the PSD so that we get as close to the curve as possible. Only used for discrete PSD.
[type: vector<Real>, not shown in the UI, not dumped, readonly in python]

weightTotal
(= 0.0)¶ Total mass (number, with discrete) of of particles generated.
[type: Real, not shown in the UI, not dumped, readonly in python]

inputPsd
(self: woo.dem.PsdSphereGenerator, normalize: bool = True, cumulative: bool = True, num: int = 80) → tuple¶ Return input PSD; it will be a staircase function if discrete is true, otherwise linearly interpolated. With normalize, the maximum is equal to 1.; otherwise, the curve is multiplied with the actually generated mass/numer of particles (depending on whether
mass
is true or false); the result should then be very similar to thewoo.dem.ParticleGenerator.psd
output with actually generated spheres. Discrete noncumulative PSDs are handled specially: discrete distributions return skypline plot with peaks represented as plateaus of the relative width 1/num; continuous distributions return ideal histogram computed for relative bin with 1/num; thus returned histogram will match noncummulative histogram returned byParticleGenerator.psd(cumulative=False)
, provided num is the same in both cases.Todo
with
cumulative=False
and when the PSD does not \(x\)start at 0, the plot is not correct as the hump coming from the jump in the PSD (from 0 to nonzero at the left) is not taken in account.
PsdCapsuleGenerator¶
Object
→ ParticleGenerator
→ PsdSphereGenerator
→ PsdCapsuleGenerator

class
woo.dem.
PsdCapsuleGenerator
(*args, **kwargs)¶ Generate capsules following a given Particle Size Distribution; elongation is chosen randomly using
shaftRadiusRatio
; orientation is random.Overloaded function.
PsdClumpGenerator¶
Object
→ ParticleGenerator
→ PsdSphereGenerator
→ PsdClumpGenerator

class
woo.dem.
PsdClumpGenerator
(*args, **kwargs)¶ Generate clump particles following a given Particle Size Distribution (
psd
) and selection ofclump shapes
, using thewoo.dem.SphereClumpGeom.scaleProb
function.For example, with
psd=[(.1, 0), (.2, .7), (.4, 1.)]
, the PSD function (which is a cumulative distribution function) looks likewhile the probability density function is
Now suppose three clumps are given with
scaleProb
as:[(.1, 1), (.3, 0)] # for d>.3, the leftmost value (0) is used [(.2, .1) ] # value extends to both left and right with just one point [(.2, 0), (.4, .6)] # for d<.2, the rightmost value (0) is used
which define the following piecewiselinear probability functions
For every diameter \(d\) chosen according to the PSD, values of
scaleProb
functions are found in \(d\) and used to choose which clump to create. The PDF for diameter combined with clumps probabilities then gives the following probability:Selected clump configuration is scaled to \(d\) (using its
equivRad
).Overloaded function.
__init__(self: woo.dem.PsdClumpGenerator) > None
__init__(self: woo.dem.PsdClumpGenerator, *args, **kwargs) > None

clumps
(= [])¶ Sequence of clump geometry definitions (
SphereClumpGeom
); for every selected radius from the PSD, clump will be chosen based on theSphereClumpGeom.scaleProb
function and scaled to that radius.[type: vector<shared_ptr<SphereClumpGeom>>]

scaleMethod
(= 0)¶ Method to compute clump scaling. The default uses the equivalent radius to determine scaling to fulfill prescribed PSD. Other methods are to scale according to the radius of the first sphere in the clump, or according to the average sphere radius in the clump.
[type: int, named enum, possible values are: ‘equiv’ (‘equivRad’; 0), ‘firstSphere’ (1), ‘avgSphere’ (2)]

genClumpNo
(= [])¶ If
save
is set, keeps clump numbers (indices inclumps
for each generated clump.[type: vector<int>, not shown in the UI, readonly in python]

oris
(= [])¶ Base orientations for clumps, in the same order as
clumps
. If the sequence is shorter than selected clump configuration, its orientation will be completely random.[type: vector<Quaternionr>]

oriFuzz
(= [])¶ Fuzz (in radians) for orientation, if set based on
oris
; iforiFuzz
is shorter than clump configuration in question, the base orientation (oriFuzz
) is used asis. Random orientation axis is picked first, then rotation angle is taken from〈oriFuzz[i],+oriFuzz[i]〉
with uniform probability. Note: this simple algorithm does not generate completely homogeneous probability density in the rotation space.[type: vector<Real>]
PsdEllipsoidGenerator¶
Object
→ ParticleGenerator
→ PsdSphereGenerator
→ PsdEllipsoidGenerator

class
woo.dem.
PsdEllipsoidGenerator
(*args, **kwargs)¶ Generate ellipsoids following a given Particle Size Distribution; ratio of
Ellipsoid.semiAxes
is chosen randomly from thesemiAxesRatio
range; orientation is random.Overloaded function.
__init__(self: woo.dem.PsdEllipsoidGenerator) > None
__init__(self: woo.dem.PsdEllipsoidGenerator, *args, **kwargs) > None

axisRatio2
(= Vector2(0.5, 0.5))¶ Range for second semiaxis ratio.
[type: Vector2r]

axisRatio3
(= Vector2(0.5, 0.5))¶ Range for third semiaxis ratio; if one of the coefficients is nonpositive, the thirs semiaxis will be the same as the second one.
[type: Vector2r]
MinMaxSphereGenerator¶
Object
→ ParticleGenerator
→ MinMaxSphereGenerator

class
woo.dem.
MinMaxSphereGenerator
(*args, **kwargs)¶ Generate particles with given minimum and maximum radius
Overloaded function.
__init__(self: woo.dem.MinMaxSphereGenerator) > None
__init__(self: woo.dem.MinMaxSphereGenerator, *args, **kwargs) > None

dRange
(= Vector2(nan, nan))¶ Minimum and maximum diameters of generated spheres.
[type: Vector2r]
PharmaCapsuleGenerator¶
Object
→ ParticleGenerator
→ PharmaCapsuleGenerator

class
woo.dem.
PharmaCapsuleGenerator
(*args, **kwargs)¶ Generate pharmaceutical capsules of fixed size; they consist of body and cap. two caps of differing diameter and are thus represented as two interpenetrated (clumped) capsules. The default value corresponds to Human Cap Size 1 from Torpac <http://www.torpac.com>.
Overloaded function.
__init__(self: woo.dem.PharmaCapsuleGenerator) > None
__init__(self: woo.dem.PharmaCapsuleGenerator, *args, **kwargs) > None

len
(= 0.0194)¶ Total (locked) length of the capsule.
[type: Real]

capLen
(= 0.00978)¶ Cut length of the cap.
[type: Real]

extDiam
(= Vector2(0.00691, 0.00663))¶ External diameter of the cap and the body.
[type: Vector2r]

colors
(= Vector2(0.5, 0.99))¶ Color of body and cap; white and red with the default (coolwarm) colormap.
[type: Vector2r]

cutCorr
(= 0.5)¶ Make the cap shorter by this amount relative to the area of outer cap over the inner cap; this is to compensate for the approximation that the cap is not cut sharply.
[type: Real]
SpatialBias¶

class
woo.dem.
SpatialBias
(*args, **kwargs)¶ Functor which biases random position (in unit cube) based on particle diameter, returning the biased position in unit cube. These objects are used with
RandomInlet.spatialBias
to make possible things like sptially graded distribution of random particles.Overloaded function.
__init__(self: woo.dem.SpatialBias) > None
__init__(self: woo.dem.SpatialBias, *args, **kwargs) > None

unitPos
(self: woo.dem.SpatialBias, diam: float) → _wooEigen11.Vector3¶ Return biased position inside a unit cube (caller transforms this to cartesian coordinates in the simulation space.
AxialBias¶
Object
→ SpatialBias
→ AxialBias

class
woo.dem.
AxialBias
(*args, **kwargs)¶ Bias position (within unit interval) along
axis
\(p\), so that radii are distributed alongaxis
, as in \(p=\frac{dd_0}{d_1d_0}+f\left(a\frac{1}{2}\right)\), where \(f\) is thefuzz
, \(a\) is unit random number, \(d\) is the current particle diameter and \(d_0\) and \(d_1\) are diameters at the lower and upper end (d01
). \(p\) is clamped to \(\rangle0,1\langle\) after the computation.Overloaded function.
__init__(self: woo.dem.AxialBias) > None

axis
(= 0)¶ Axis which is biased.
[type: int]

d01
(= Vector2(nan, nan))¶ Diameter at the lower and upper end (the order matters); it is possible that \(r_0>r_1\), in which case the bias is reversed (bigger radii have smaller coordinate).
[type: Vector2r]

fuzz
(= 0.0)¶ Allow for random variations around the position determined from diameter.
[type: Real]

phase
(= nan)¶ If NaN, coordinate after fuzz will be clamped to 0…1. If a number, it will be added to the coordinate after fuzz (zero is allowed) and the value will be modulated to 0…1 (rather than clamped), overflowing between beginning and end.
[type: float]
LayeredAxialBias¶
Object
→ SpatialBias
→ AxialBias
→ LayeredAxialBias

class
woo.dem.
LayeredAxialBias
(*args, **kwargs)¶ Bias position so that particles occupy different layers based on their diameter. This is similar to
PsdAxialBias
withdiscrete
, but allows for more flexibility, such as one fraction occupying multiple nonadjacent layers.Overloaded function.
__init__(self: woo.dem.LayeredAxialBias) > None
__init__(self: woo.dem.LayeredAxialBias, *args, **kwargs) > None

layerSpec
(= [])¶ Vector specifying layering; each item contains the following numbers:
dMin, dMax, xMin0, xMax0, xMin1, xMax1, ...
. A particle which falls withindMin, dMax
will be placed, with uniform probability, into intervals specified by other couples. Coordinates are given in normalized space, soxMin..xMax
must lie in in 〈0,1〉. Particles which do not fall into any fraction will not be biased (thus placed uniformly randomly), and a warning will be issued.[type: vector<VectorXr>]

xRangeSum
(= [])¶ Sum of
xMax_ixMin_i
for each fraction, for faster lookup. Internal/debugging use only.[type: vector<Real>, not shown in the UI, not dumped, not saved, readonly in python]
PsdAxialBias¶
Object
→ SpatialBias
→ AxialBias
→ PsdAxialBias

class
woo.dem.
PsdAxialBias
(*args, **kwargs)¶ Bias position based on PSD curve, so that fractions get the amount of space they require according to their percentage. The PSD must be specified with mass fractions, using With
discrete
(suitable for use withPsdParticleGenerator.discrete
), the whole interval between the current and previous radius will be used with uniform probability, allowing for layered particle arangement. Thed01
attribute is ignored with PSD.Overloaded function.
__init__(self: woo.dem.PsdAxialBias) > None
__init__(self: woo.dem.PsdAxialBias, *args, **kwargs) > None

psdPts
(= [])¶ Points of the mapping function, similar to
PsdParticleGenerator.psdPts
.[type: vector<Vector2r>]

invert
(= False)¶ Reverse the ordering along the axis, which makes the bigger particles be close to zero.
[type: bool]

discrete
(= False)¶ Interpret
psdPts
as piecewiseconstant (rather than piecewiselinear) function. Each diameter will be distributed uniformly in the whole interval between percentage of the current and previous points.[type: bool]

reorder
(= [])¶ Reorder the PSD fractions; this is mainly useful for discrete distributions, where the order can be nonincreasing, such as with
reorder=[1,0,2]
which will put the finest fraction in the middle of the other two[type: vector<int>]
NonuniformAxisPlacementBias¶
Object
→ SpatialBias
→ NonuniformAxisPlacementBias

class
woo.dem.
NonuniformAxisPlacementBias
(*args, **kwargs)¶ Distribute particle placement probability nonuniformly along given
axis
, following a piecewiselinear probability density function.Overloaded function.
__init__(self: woo.dem.NonuniformAxisPlacementBias) > None
__init__(self: woo.dem.NonuniformAxisPlacementBias, *args, **kwargs) > None

axis
(= 0)¶ Biased axis.
[type: int]

pdf
(= [])¶ Probability density function values, on uniform grid spanning the axis unit range. If given, integrated numerically (trapezoid integration) to obtain
cdf
(which is normalized).[type: vector<Real>]

cdf
(= [])¶ Cumulative distribution function, either given directly, or computed from
pdf
, on uniform grid on unit range. Automatically normalized so that it ends at unity.[type: vector<Real>]

dx
(= nan)¶ Precomputed value of step size.
[type: Real, not shown in the UI, not dumped, readonly in python]
ParticleShooter¶

class
woo.dem.
ParticleShooter
(*args, **kwargs)¶ Abstract class for assigning initial velocities to generated particles.
Overloaded function.
AlignedMinMaxShooter¶
Object
→ ParticleShooter
→ AlignedMinMaxShooter

class
woo.dem.
AlignedMinMaxShooter
(*args, **kwargs)¶ Shoot particles in one direction, with velocity magnitude constrained by vRange values
Overloaded function.
__init__(self: woo.dem.AlignedMinMaxShooter) > None
__init__(self: woo.dem.AlignedMinMaxShooter, *args, **kwargs) > None

dir
(= Vector3(1, 0, 0))¶ Direction (will be normalized).
[type: Vector3r]

vRange
(= Vector2(nan, nan))¶ Minimum and maximum velocities.
[type: Vector2r]
ArcShooter¶
Object
→ ParticleShooter
→ ArcShooter

class
woo.dem.
ArcShooter
(*args, **kwargs)¶ Shoot particles in direction defined by (normallydistributed) angles from tangent and base plane (cylindrical coordinates defined by
node
) in given point, with magnitude constraind byvRange
.Overloaded function.
__init__(self: woo.dem.ArcShooter) > None

node
(= <Node @ 0x21370f0, at (0, 0, 0)>)¶ Node defining local coordinate system. Must be given.
[type: shared_ptr<
Node
>]

elevRange
(= Vector2(0, 0))¶ Range for elevation from the plane perpendicular to the local \(z\)axis (as defined by
node
). The actual value is chosen with uniform probability from this range.[type: Vector2r, unit: rad]

azimRange
(= Vector2(0, 0))¶ Range for azimuth angle, where zero is radial connecting particle position and local origin (
node
) and positive sense defined as rotation around thenode
\(z\)axis.[type: Vector2r, unit: rad]

vRange
(= Vector2(nan, nan))¶ Range for velocity magnitude.
[type: Vector2r, unit: m/s]
Outlet¶
Object
→ Engine
→ PeriodicEngine
→ Outlet

class
woo.dem.
Outlet
(*args, **kwargs)¶ Delete/mark particles which fall outside (or inside, if inside is True) given box. Deleted/mark particles are optionally stored in the diamMassTime array for later processing, if needed.
Particle are deleted when
markMask
is 0, otherwise they are only marked withmarkMask
and not deleted.Overloaded function.

markMask
(= 0)¶ When nonzero, switch to marking mode – particles of which
Particle.mask
does not comtainmarkMask
(i.e.(mask&markMask)!=markMask
) havemarkMask
bitadded toParticle.mask
(this can happen only once for each particle); particles are not deleted, but their diameter/mass added todiamMassTime
ifsave
is True.[type: uint]

mask
(= 4)¶ If nonzero, only particles matching the mask will be candidates for removal
[type: uint]

inside
(= False)¶ Delete particles which fall inside the volume rather than outside
[type: bool]

save
(= False)¶ Save particle data which are deleted in the
diamMassTime
list[type: bool]

recoverRadius
(= False)¶ Recover radius of Spheres by computing it back from particle’s mass and its material density (used when radius is changed due to radius thinning (in Law2_L6Geom_PelletPhys_Pellet.thinningFactor). When radius is recovered, the \(r/r_0\) ratio is added to
rDivR0
for further processing.[type: bool]

rDivR0
(= [])¶ List of the \(r/r_0\) ratio of deleted particles, when
recoverRadius
is true.[type: vector<Real>, not shown in the UI, readonly in python]

diamMassTime
(= [])¶ Radii and masses of deleted particles; not accessible from python (shadowed by the
diamMassTime
method).[type: vector<Vector3r>, not accessible from python]

locs
(= [])¶ Integer location specified for particles; 1 by default, derived classes can use this for any purposes (usually more precise location within the outlet volume).
[type: vector<int>, not shown in the UI, readonly in python]

num
(= 0)¶ Number of deleted particles
[type: int, readonly in python]

par
(= _8ParticleList[])¶ Deleted
particles
(only saved withsavePar
.[type: vector<shared_ptr<Particle>>, not shown in the UI, not dumped, readonly in python]

mass
(= 0.0)¶ Total mass of deleted particles
[type: Real, readonly in python]

glColor
(= 0.0)¶ Color for rendering (NaN disables rendering)
[type: Real]

glHideZero
(= False)¶ Show numbers (mass and rate) even if they are zero.
[type: bool]

currRate
(= nan)¶ Current value of mass flow rate
[type: Real, readonly in python]

currRateSmooth
(= 1.0)¶ Smoothing factor for currRate ∈〈0,1〉
[type: Real, range: 0−1]

kinEnergyIx
(= 1)¶ Index for kinetic energy in scene.energy
[type: int, not saved, not accessible from python]

clear
(self: woo.dem.Outlet) → None¶ Clear information about saved particles (particle list, if saved, mass and number, rDivR0)

diamMass
(self: woo.dem.Outlet, zipped: bool = False) → object¶ With zipped, return list of (diameter, mass); without zipped, return tuple of 2 arrays, diameters and masses.

massOfDiam
(self: woo.dem.Outlet, min: float = 0, max: float = inf) → float¶ Return mass of particles of which diameters are between min and max.

psd
(self: woo.dem.Outlet, mass: bool = True, cumulative: bool = True, normalize: bool = True, num: int = 80, dRange: _wooEigen11.Vector2 = Vector2(nan, nan), tRange: _wooEigen11.Vector2 = Vector2(nan, nan), zip: bool = False, emptyOk: bool = False, locs: list = []) → object¶ Return particle size distribution of deleted particles (only useful with save), spaced between dRange (a 2tuple of minimum and maximum radius); )

ArcOutlet¶
Object
→ Engine
→ PeriodicEngine
→ Outlet
→ ArcOutlet

class
woo.dem.
ArcOutlet
(*args, **kwargs)¶ Outlet detnig/marking particles in prismatic arc (revolved rectangle) specified using cylindrical coordinates (with the
ISO 3111
convention, as mentioned at the Wikipedia page) in a local system. See also analogousArcInlet
.Overloaded function.
__init__(self: woo.dem.ArcOutlet) > None

node
(= <Node @ 0x216fcc0, at (0, 0, 0)>)¶ Node defining local coordinates system. Must be given.
[type: shared_ptr<
Node
>]

cylBox
(= AlignedBox3((1.7976931348623157e308, 1.7976931348623157e308, 1.7976931348623157e308), (1.7976931348623157e308, 1.7976931348623157e308, 1.7976931348623157e308)))¶ Box in cylindrical coordinates, as: (ρ₀,φ₀,z₀),(ρ₁,φ₁,z₁). ρ must be nonnegative, (φ₁φ₀)≤2π.
[type: AlignedBox3r]

glSlices
(= 32)¶ Number of slices for rendering circle (the arc takes the proportionate value
[type: int]
BoxOutlet¶
Object
→ Engine
→ PeriodicEngine
→ Outlet
→ BoxOutlet

class
woo.dem.
BoxOutlet
(*args, **kwargs)¶ Outlet with box geometry
Overloaded function.
__init__(self: woo.dem.BoxOutlet) > None

box
(= AlignedBox3((1.7976931348623157e308, 1.7976931348623157e308, 1.7976931348623157e308), (1.7976931348623157e308, 1.7976931348623157e308, 1.7976931348623157e308)))¶ Box volume specification (lower and upper corners). If
node
is specified, the box is in local coordinates; otherwise, global coorinates are used.[type: AlignedBox3r]
StackedBoxOutlet¶
Object
→ Engine
→ PeriodicEngine
→ Outlet
→ BoxOutlet
→ StackedBoxOutlet

class
woo.dem.
StackedBoxOutlet
(*args, **kwargs)¶ Box outlet with subdivision along one axis, so that more precise location can be obtained; this is functionally equivalent to multiple adjacent
BoxOutlet's
, but faster since it is a single engine.Overloaded function.
__init__(self: woo.dem.StackedBoxOutlet) > None
__init__(self: woo.dem.StackedBoxOutlet, *args, **kwargs) > None

divs
(= [])¶ Coordinates of division between boxes in the stack; must be an increasing sequence.
[type: vector<Real>]

divColors
(= [])¶ Colors for rendering the dividers; if not given, use darkened
color
, same for all dividers.[type: vector<Real>]

axis
(= 0)¶ Axis along which the
box
is subdivided.[type: short]

loc0
(= 0)¶ Index at which numbering of boxes starts. The first box is 0 by default, but it can be changed using this attribute, e.g. setting loc0=10 will make the first box 10, second 11 etc.
[type: int]
DetectSteadyState¶
Object
→ Engine
→ PeriodicEngine
→ DetectSteadyState

class
woo.dem.
DetectSteadyState
(*args, **kwargs)¶ Detect steady state from summary flows of relevant inlets (total influx) and outlets (total efflux), plus waiting times inbetween.The detection is done is several stages:
(init) wait for
waitInit
before doing anything else;(flow) execute
hookFlow
, check if \(\sum_i o_i \geq \alpha \sum_j i_j\) (\(\alpha\) isrelFlow
); if true, protosteady state was reached and we proceed;(trans) execute
hookTrans
, then wait forwaitTrans
, then proceed to the next stage;(steady) executed
hookSteady
, then wait forwaitSteady
, then proceed;(done) execute
hookDone
and do nothing more.
Overloaded function.
__init__(self: woo.dem.DetectSteadyState) > None
__init__(self: woo.dem.DetectSteadyState, *args, **kwargs) > None

waitInit
(= 0.0)¶ Time to wait in
init
stage, before moving toflow
.[type: Real, unit: s]

relFlow
(= 1.0)¶ Relative flow used for comparing influx and efflux in the
flow
stage.[type: Real, unit: s]

waitTrans
(= 0.0)¶ Time to wait in
trans
stage, before moving tosteady
.[type: Real, unit: s]

waitSteady
(= 0.0)¶ Time to wait in the steady stage, before moving to
done
.[type: Real, unit: s]

hookFlow
(= '')¶ Hook executed when the
flow
stage is entered.[type: string]

hookTrans
(= '')¶ Hook executed when the
trans
stage is entered.[type: string]

hookSteady
(= '')¶ Hook executed when the
steady
stage is entered.[type: string]

hookDone
(= 'e.dead=True')¶ Hook executed when the
done
stage is entered.[type: string]

rateSmooth
(= 1.0)¶ Smoothing factor for rates ∈〈0,1〉
[type: Real, range: 0−1]

stage
(= 0)¶ Stage in which we currently are.
[type: int, readonly in python, named enum, possible values are: ‘init’ (0), ‘flow’ (1), ‘trans’ (2), ‘steady’ (3), ‘done’ (4)]

stageEntered
(= 0.0)¶ Time when the current stage was entered.
[type: Real, unit: s, readonly in python]

inlets
(= [])¶ Inlets of which rates are used to compute summary influx.
[type: vector<shared_ptr<Inlet>>]

outlets
(= [])¶ Inlets of which rates are used to compute summary efflux.
[type: vector<shared_ptr<Outlet>>]

influx
(= nan)¶ Smoothed summary influx value.
[type: Real, readonly in python]

efflux
(= nan)¶ Smoothed summary efflux value.
[type: Real, readonly in python]
DEM field¶
TODO
DemField¶

class
woo.dem.
DemField
(*args, **kwargs)¶ Field describing a discrete element assembly. Each particle references (possibly many) nodes.
Special constructor
When passed the
par
parameter in constructor, this sequence of particles will be assigned toparticles
and nodes created as withS.dem.add
. An additional optional parameterparNodes
will be passed as nodes toS.dem.add(...,nodes=...)
to determine which nodes are to be added.Overloaded function.

particles
(= <ParticleContainer @ 0x217c450>)¶ Particles (each particle holds its contacts, and references associated nodes)
[type: shared_ptr<
ParticleContainer
>, readonly in python]

contacts
(= <ContactContainer @ 0x217c670>)¶ Linear view on particle contacts
[type: shared_ptr<
ContactContainer
>, readonly in python]

loneMask
(= 2)¶ Particle groups which have bits in loneMask in common (i.e. (A.mask & B.mask & loneMask)!=0) will not have contacts between themselves
[type: uint]

gravity
(= Vector3(0, 0, 0))¶ Constant gravity acceleration
[type: Vector3r]

distFactor
(= 1.0)¶ Relative enlargement of bounding boxes, and of radii in contacts; only supported by a few functors (
Bo1_Sphere_Aabb
,Cg2_Sphere_Sphere_L6Geom
), storing the value inDemField
ensures the values are synchronized between all functors interested. Deactivated if negative; any negative value (1
by default) is equivalent to1
(no enlargement at all).[type: Real]

saveDead
(= False)¶ Save unused nodes of deleted particles, which would be otherwise removed (useful for displaying traces of deleted particles).
[type: bool]

deadNodes
(= NodeList[])¶ List of nodes belonging to deleted particles; only used if
saveDead
isTrue
[type: vector<shared_ptr<Node>>, not shown in the UI, readonly in python]

deadParticles
(= _8ParticleList[])¶ Deleted particles; only used if
saveDead
isTrue
[type: vector<shared_ptr<Particle>>, not shown in the UI, readonly in python]

clearDead
(self: woo.dem.DemField) → None¶

collectNodes
(self: woo.dem.DemField, fromCxx: bool = False) → int¶ Collect nodes from all particles and clumps and insert them to nodes defined for this field. Nodes are not added multiple times, even if they are referenced from different particles.

property
con
¶ Linear view on particle contacts

static
minimalEngines
(damping=0.0, gravity=None, verletDist= 0.05, kinSplit=False, dontCollect=False, noSlip=False, noBreak=False, cp2=None, law=None, model=None, grid=False, dynDtPeriod=100, cpKw={}, lawKw={})¶ Return default set of engines, suitable for basic simulations during testing.

nodesAppend
(*args, **kwargs)¶ Overloaded function.
nodesAppend(self: woo.dem.DemField, arg0: woo.core.Node) > None
Append given node to
nodes
, and setDemData.linIx
to the correct value automatically.nodesAppend(self: woo.dem.DemField, arg0: woo.core.NodeList) > None
Append given list of nodes to
nodes
, and setDemData.linIx
to the correct value automatically.

nodesAppendFromPar
(self: woo.dem.DemField, arg0: std::vector<std::shared_ptr<Particle>, std::allocator<std::shared_ptr<Particle> > >) → None¶ Append nodes of all particles given; nodes may repeat between particles (a set is created first), but nodes already in
nodes
before calling this method will cause an error.

property
par
¶ Particles (each particle holds its contacts, and references associated nodes)

static
sceneGetField
(arg0: woo.core.Scene) → woo.dem.DemField¶

static
sceneHasField
(arg0: woo.core.Scene) → bool¶

setNodesRefPos
(self: woo.dem.DemField) → None¶ Set reference position and orientation of all nodes to the current one; does nothing (silently) on builds without OpenGL.

splitNode
(self: woo.dem.DemField, node: woo.core.Node, pars: std::vector<std::shared_ptr<Particle>, std::allocator<std::shared_ptr<Particle> > >, massMult: float = nan, inertiaMult: float = nan) → woo.core.NodeList¶ For particles pars, replace their node node by a clone (
deepcopy
) of this node. If massMult and inertiaMult are given, mass/inertia of both original and cloned node are multiplied by those factors. Returns the original and the new node. Both nodes will be coincident in space. This function is used to unshare node shared by multiple particles, such as when breaking mesh apart.

ContactContainer¶

class
woo.dem.
ContactContainer
(*args, **kwargs)¶ Linear view on all contacts in the DEM field
Overloaded function.
__init__(self: woo.dem.ContactContainer) > None
__init__(self: woo.dem.ContactContainer, *args, **kwargs) > None

linView
(= [])¶ Linear storage of references; managed by accessor methods, do not modify directly!
[type: ContainerT, not accessible from python]

dirty
(= False)¶ Flag for notifying the collider that persistent data should be invalidated
[type: bool, not accessible from python]

stepColliderLastRun
(= 1)¶ Step number when a collider was last run; set by the collider, if it wants contacts that were not encoutered in that step to be deleted by ContactLoop (such as SpatialQuickSortCollider). Other colliders (such as InsertionSortCollider) set it it 1, which is the default.
[type: int, readonly in python]

threadsPending
(= [[], [], [], [], [], [], [], []])¶ Contacts which might be deleted by the collider in the next step (separate for each thread, for safe lockfree writes)
[type: std::vector<std::vector<PendingContact>>, not accessible from python]

__getitem__
(*args, **kwargs)¶ Overloaded function.
__getitem__(self: woo.dem.ContactContainer, arg0: _wooEigen11.Vector2i) > woo.dem.Contact
__getitem__(self: woo.dem.ContactContainer, arg0: int) > woo.dem.Contact

__iter__
(self: woo.dem.ContactContainer) → ContactContainer::pyIterator¶

__len__
(self: woo.dem.ContactContainer) → int¶

clear
(self: woo.dem.ContactContainer) → None¶

countReal
(self: woo.dem.ContactContainer) → int¶

exists
(self: woo.dem.ContactContainer, arg0: int, arg1: int) → bool¶

existsReal
(self: woo.dem.ContactContainer, arg0: int, arg1: int) → bool¶

realRatio
(self: woo.dem.ContactContainer) → float¶

remove
(self: woo.dem.ContactContainer, contact: woo.dem.Contact, force: bool = False) → None¶

removeNonReal
(self: woo.dem.ContactContainer) → None¶
ParticleContainer¶

class
woo.dem.
ParticleContainer
(*args, **kwargs)¶ Storage for DEM particles
Overloaded function.
__init__(self: woo.dem.ParticleContainer) > None
__init__(self: woo.dem.ParticleContainer, *args, **kwargs) > None

parts
(= _8ParticleList[])¶ Actual particle storage
[type: ContainerT, not accessible from python]

freeIds
(= [])¶ Free particle id’s
[type: list<id_t>, not accessible from python]

__getitem__
(self: woo.dem.ParticleContainer, arg0: int) → woo.dem.Particle¶

__iter__
(self: woo.dem.ParticleContainer) → ParticleContainer::pyIterator¶

__len__
(self: woo.dem.ParticleContainer) → int¶

add
(*args, **kwargs)¶ Overloaded function.
add(self: woo.dem.ParticleContainer, par: woo.dem.Particle, nodes: int = 1) > int
Add single particle, and maybe also add its nodes to
DemField.nodes
. nodes can be 1/True (always), 0/False (never) or 1 (maybe – based on heuristics). The heuristics is defined inwoo.dem.DemData.guessMoving
.add(self: woo.dem.ParticleContainer, pars: std::vector<std::shared_ptr<Particle>, std::allocator<std::shared_ptr<Particle> > >, nodes: int = 1) > list
Add list of particles, and optionally also adding its nodes to
DemField.nodes
; seeadd
for explanation of nodes.

addClumped
(self: woo.dem.ParticleContainer, par: std::vector<std::shared_ptr<Particle>, std::allocator<std::shared_ptr<Particle> > >, centralNode: woo.core.Node = None, nodes: int = False) → woo.core.Node¶ Add particles as rigid aggregate. Add resulting clump node (which is not a particle) to Scene.dem.nodes, subject to integration. centralNode must be provided if particles have zero mass (in that case, clump position cannot be computed), all DOFs will be blocked automatically in that case; centralNode.dem will be set with a new instance of
ClumpData
and the old value, if any, discarded. Clump node is added automatically toDemField.nodes
.Note
Clumped nodes are not added to
DemField.nodes
by default; this can be changed bynodes=True
, but it is to be done only in cases, such as whenwoo.dem.NodalForcesToHdf5
should use those nodes. Nodes will still be skipped for motion integration, which is done on the clump node itself.

clear
(self: woo.dem.ParticleContainer) → None¶ Bruteforce removal of all particles; bypasses any consistency checks (like nodeparticle refcounting), do not use.

disappear
(self: woo.dem.ParticleContainer, ids: List[int], mask: int) → None¶ Remask particle (so that it does not have contacts with other particles), remove contacts, which would no longer exist and make it invisible. Shorthand for calling
remask(ids,mask,visible=False,removeContacts=True)

exists
(self: woo.dem.ParticleContainer, id: int) → bool¶ Tell whether particle with this
id
exists in the container.

reappear
(self: woo.dem.ParticleContainer, ids: List[int], mask: int, removeOverlapping: bool = False) → None¶ Remask particle, remove particles, which would overlap with newlyappeared particle (if
removeOverlapping
isTrue
), make it visible again. Shorthand forremask(ids,mask,visible=True,removeContacts=False)

remask
(self: woo.dem.ParticleContainer, ids: List[int], mask: int, visible: bool, removeContacts: bool, removeOverlapping: bool) → None¶ Change particle mask and visibility; optionally remove contacts, which would no longer exist due to mask change; or remove particles, which would newly overlap with the particle. See also
disappear
andreappear
.
TraceVisRep¶
Object
→ NodeVisRep
→ TraceVisRep

class
woo.dem.
TraceVisRep
(*args, **kwargs)¶ Data with node’s position history; created by
Tracer
.Overloaded function.
__init__(self: woo.dem.TraceVisRep) > None
__init__(self: woo.dem.TraceVisRep, *args, **kwargs) > None

pts
(= [])¶ History points
[type: vector<Vector3r>, not shown in the UI, readonly in python]

scalars
(= [])¶ History scalars
[type: vector<Real>, not shown in the UI, readonly in python]

times
(= [])¶ History times (only saved with
Tracer.saveTime
).[type: vector<Real>, not shown in the UI, readonly in python]

t0
(= nan)¶ Time the trace was created/reset, for plotting relative time; does not change with compression.
[type: Real]

tracer
(= None)¶ Tracer
which created (and is, presumably, managing) this object; it is necessary for getting rendering parameters, and is updated automatically.[type: shared_ptr<
Tracer
>, readonly in python]

writeIx
(= 0)¶ Index where next data will be written
[type: size_t]

flags
(= 0)¶ Flags for this instance
[type: short]

consolidate
(self: woo.dem.TraceVisRep) → None¶ Make
pts
sequential (normally, the data are stored as circular buffer, with next write position atwriteIx
, so that they are ordered temporally.

pt
(self: woo.dem.TraceVisRep, arg0: int) → _wooEigen11.Vector3¶ Get one history point (to avoid copying arrays), indexed as in python (negative counts backwards).

scalar
(self: woo.dem.TraceVisRep, arg0: int) → float¶ Get one history scalar (to avoid copying arrays), indexed as in python (negative counts backwards).

time
(self: woo.dem.TraceVisRep, arg0: int) → float¶ Get one history time (to avoid copying arrays), indexed as in python (negative counts backwards).
Packings¶
TODO
ShapePack¶

class
woo.dem.
ShapePack
(*args, **kwargs)¶ Representation of geometry of many particles, with the ability of text I/O. It is meant as a replacement for
woo.pack.SpherePack
, which only handles spherical particles.Overloaded function.
__init__(self: woo.dem.ShapePack) > None

cellSize
(= Vector3(0, 0, 0))¶ Positive components signify periodic boundary along the respective axis.
[type: Vector3r]

movable
(= False)¶ Whether the packing is movable, i.e. should be automatically recentered after filtered with a predicate.
[type: bool]

div
(= 5)¶ Default value for recomputing properties of clumps (relative to the smallest equivalent radius)
[type: int]

raws
(= [])¶ Raw shapes of particles/clumps.
[type: vector<shared_ptr<ShapeClump>>]

userData
(= '')¶ String of arbitrary user data to be loaded/saved with the ShapePack.
[type: string]

loadFrom
(= '')¶ If given when constructing the instance, the file is loaded immediately and the attribute is reset.
[type: string]

add
(self: woo.dem.ShapePack, shapes: List[woo.dem.Shape], clumped: bool = True) → None¶

canonicalize
(self: woo.dem.ShapePack) → None¶

cellRepeat
(self: woo.dem.ShapePack, arg0: _wooEigen11.Vector3i) → None¶

filter
(self: woo.dem.ShapePack, predicate: Predicate, recenter: int =  1) → None¶

filtered
(self: woo.dem.ShapePack, predicate: Predicate, recenter: int =  1) → woo.dem.ShapePack¶

fromDem
(self: woo.dem.ShapePack, scene: woo.core.Scene, dem: woo.dem.DemField, mask: int = 0, skipUnsupported: bool = True) → None¶

load
(self: woo.dem.ShapePack, arg0: str) → None¶

loadTxt
(self: woo.dem.ShapePack, arg0: str) → None¶

save
(self: woo.dem.ShapePack, arg0: str) → None¶

saveTxt
(self: woo.dem.ShapePack, arg0: str) → None¶

solidVolume
(self: woo.dem.ShapePack) → float¶

toDem
(self: woo.dem.ShapePack, scene: woo.core.Scene, dem: woo.dem.DemField, mat: woo.dem.Material, mask: int = 5, color: float = nan) → None¶

translate
(self: woo.dem.ShapePack, arg0: _wooEigen11.Vector3) → None¶
RawShape¶

class
woo.dem.
RawShape
(*args, **kwargs)¶ Object holding raw geometry data for one
Shape
in a uniform manner: center and radius of bounding sphere, plus an array of raw data. It is used as an intermediary shapeneutral storage format.Overloaded function.

className
(= '')¶ Name of the Shape subclass.
[type: string]

center
(= Vector3(0, 0, 0))¶ Center of the bounding sphere.
[type: Vector3r]

radius
(= 0.0)¶ Radius of the bounding sphere.
[type: Real]

raw
(= [])¶ Raw data for shape reconstruction; the size of the array is shapespecific.
[type: vector<Real>]

ShapeClump¶

class
woo.dem.
ShapeClump
(*args, **kwargs)¶ Defines pure geometry of clumps. This is a base class, not to be used asis.
Overloaded function.
__init__(self: woo.dem.ShapeClump) > None

scaleProb
(= [])¶ Used by particle generators: piecewiselinear function probability(equivRad) given as a sequence of x,y coordinates. If not given, constant function \(p(d)=1\) is assumed. See the documentation of
woo.dem.PsdClumpGenerator
for details.[type: vector<Vector2r>]

pos
(= Vector3(0, 0, 0))¶ Centroid position (computed automatically)
[type: Vector3r, not dumped, readonly in python]

ori
(= Quaternion((1, 0, 0), 0))¶ Principal axes orientation (computed automatically)
[type: Quaternionr, not dumped, readonly in python]

volume
(= nan)¶ Volume (computed automatically)
[type: Real, unit: m³, not dumped, readonly in python]

equivRad
(= nan)¶ Equivalent radius of the clump (computed automatically) – mean of radii of gyration, i.e. \(\frac{1}{3}\sum \sqrt{I_{ii}/V}\).
[type: Real, unit: m, not dumped, readonly in python]

inertia
(= Vector3(nan, nan, nan))¶ Geometrical inertia (computed with unit density)
[type: Vector3r, not dumped, readonly in python]

div
(= 5)¶ Sampling grid fineness, when computing volume and other properties, relative to the smallest sphere’s radius. When zero or negative, assume spheres don’t intersect and use a different algorithm (Steiner’s theorem).
[type: int, not dumped]

clumped
(= True)¶ Whether nodes of this shape are clumped together when the particle is created (so far, clumped shapes only are produced).
[type: bool, readonly in python]

makeParticles
(self: woo.dem.ShapeClump, mat: woo.dem.Material, pos: _wooEigen11.Vector3, ori: _wooEigen11.Quaternion = Quaternion((1, 0, 0), 0), scale: float = 1.0, mask: int = 5) → tuple¶ Create particle(s) as described by this geometry, positioned in pos and rotated with ori. Geometry will be scaled by scale. Returns tuple ([Node,…],[Particle,..]).

recompute
(self: woo.dem.ShapeClump, div: int = 5, failOk: bool = False, fastOnly: bool = False) → None¶ Recompute principal axes of the clump, using div for subdivision (see
div
for the semantics). failOk (silently return in case of invalid data) and fastOnly (return if there is lots of cells in subdivision) are only to be used internally.
RawShapeClump¶
Object
→ ShapeClump
→ RawShapeClump

class
woo.dem.
RawShapeClump
(*args, **kwargs)¶ Clump consisting of generic shapes (
RawShape
).Overloaded function.
__init__(self: woo.dem.RawShapeClump) > None
__init__(self: woo.dem.RawShapeClump, *args, **kwargs) > None

rawShapes
(= [])¶ Data for creating primitive shapes
[type: vector<shared_ptr<RawShape>>]
SphereClumpGeom¶
Object
→ ShapeClump
→ SphereClumpGeom

class
woo.dem.
SphereClumpGeom
(*args, **kwargs)¶ Defines geometry of spherical clumps. Each clump is described by spheres it is made of (position and radius).
Overloaded function.
__init__(self: woo.dem.SphereClumpGeom) > None
__init__(self: woo.dem.SphereClumpGeom, *args, **kwargs) > None

centers
(= [])¶ Centers of constituent spheres, in clumplocal coordinates.
[type: vector<Vector3r>]

radii
(= [])¶ Radii of constituent spheres
[type: vector<Real>]

static
fromSpherePack
(pack: SpherePack, div: int = 5) → List[woo.dem.SphereClumpGeom]¶ Return [
SphereClumpGeom
] which contain all clumps and spheres from givenSpherePack
.
BoxTraceTimeSetter¶
Object
→ Engine
→ PeriodicEngine
→ BoxTraceTimeSetter

class
woo.dem.
BoxTraceTimeSetter
(*args, **kwargs)¶ Set
TraceVisRep.t0
of nodes insidebox
to the current time <Scene.time>; this is used for tracking how long has a particle been away from that region.Overloaded function.
__init__(self: woo.dem.BoxTraceTimeSetter) > None
__init__(self: woo.dem.BoxTraceTimeSetter, *args, **kwargs) > None

box
(= AlignedBox3((1.7976931348623157e308, 1.7976931348623157e308, 1.7976931348623157e308), (1.7976931348623157e308, 1.7976931348623157e308, 1.7976931348623157e308)))¶ Box volume; in local coordinates if
node
is given, global otherwise.[type: AlignedBox3r]

glColor
(= 0.5)¶ Color for rendering (NaN disables), mapped using the default colormap.
[type: Real]
Collision detection¶
TODO
Collider¶

class
woo.dem.
Collider
(*args, **kwargs)¶ Abstract class for finding spatial collisions between bodies.
Overloaded function.

static
mayCollide
(dem: woo.dem.DemField, pA: woo.dem.Particle, pB: woo.dem.Particle) → bool¶ Predicate whether two particles in question may collide or not

probeAabb
(self: woo.dem.Collider, mn: _wooEigen11.Vector3, mx: _wooEigen11.Vector3) → List[int]¶ Return list of particles intersected by axisaligned box with given corners

static
InsertionSortCollider¶
Object
→ Engine
→ Collider
→ InsertionSortCollider

class
woo.dem.
InsertionSortCollider
(*args, **kwargs)¶ Collider with O(n log(n)) complexity, using
Aabb
for bounds.At the initial step, Bodies’ bounds (along sortAxis) are first std::sort’ed along one axis (sortAxis), then collided. The initial sort has \(O(n^2)\) complexity, see Colliders’ performance for some information (There are scripts in examples/colliderperf for measurements).
Insertion sort is used for sorting the bound list that is already presorted from last iteration, where each inversion calls checkOverlap which then handles either overlap (by creating interaction if necessary) or its absence (by deleting interaction if it is only potential).
Bodies without bounding volume (such as clumps) are handled gracefully and never collide. Deleted bodies are handled gracefully as well.
This collider handles periodic boundary conditions. There are some limitations, notably:
No body can have Aabb larger than cell’s half size in that respective dimension. You get exception it it does and gets in interaction.
No body can travel more than cell’s distance in one step; this would mean that the simulation is numerically exploding, and it is only detected in some cases.
Stride can be used to avoid running collider at every step by enlarging the particle’s bounds, tracking their velocities and only rerun if they might have gone out of that bounds (see Verlet list for brief description and background) . This requires cooperation from
Leapfrog
as well asBoundDispatcher
, which will be found among engines automatically (exception is thrown if they are not found).If you wish to use strides, set
verletDist
(length by which bounds will be enlarged in all directions) to some value, e.g. 0.05 × typical particle radius. This parameter expresses the tradeoff between many potential interactions (running collider rarely, but with longer exact interaction resolution phase) and few potential interactions (running collider more frequently, but with less exact resolutions of interactions); it depends mainly on packing density and particle radius distribution.Overloaded function.
__init__(self: woo.dem.InsertionSortCollider) > None
__init__(self: woo.dem.InsertionSortCollider, *args, **kwargs) > None

forceInitSort
(= False)¶ When set to true, full sort will be run regardless of other conditions. This flag is then reset automatically to false
[type: bool]

noBoundOk
(= False)¶ Allow particles without bounding box. This is currently only useful for testing
woo.fem.Tetra
which don’t undergo any collisions.[type: bool]

sortAxis
(= 0)¶ Axis for the initial contact detection.
[type: int]

sortThenCollide
(= False)¶ Separate sorting and colliding phase; it is MUCH slower, but all interactions are processed at every step; this effectively makes the collider nonpersistent, not remembering last state. (The default behavior relies on the fact that inversions during insertion sort are overlaps of bounding boxes that just started/ceased to exist, and only processes those; this makes the collider much more efficient.)
[type: bool]

verletDist
(= 0.05)¶ Length by which to enlarge particle bounds, to avoid running collider at every step. Stride disabled if zero, and bounding boxes are updated at every step. Negative value will trigger automatic computation, so that the real value will be
verletDist
× minimum spherical particle radius and minimumInlet
radius (for particles which don’t exist yet); if there is no minimum radius found, it will be set to 0.0 (with a warning) and disabled.[type: Real]

maxVel2
(= 0.0)¶ Maximum encountered velocity of a particle, to compute bounding box shift.
[type: Real, readonly in python]

nFullRuns
(= 0)¶ Number of full runs, when collision detection is needed; only informative.
[type: int]

numReinit
(= 0)¶ Cumulative number of bound array reinitialization.
[type: int, readonly in python]

stepInvs
(= Vector3i(0, 0, 0))¶ Number of inversions in insertion sort in the last step; always zero in the nondebug builds
[type: Vector3i]

numInvs
(= Vector3i(0, 0, 0))¶ Cumulative number of inversions in insertion sort; always zero in the nondebug builds
[type: Vector3i]

boundDispatcher
(= <BoundDispatcher @ 0x213b600>)¶ BoundDispatcher
object that is used for creatingbounds
on collider’s request as necessary.[type: shared_ptr<
BoundDispatcher
>, readonly in python]

ompTuneSort
(= Vector3i(1, 1000, 0))¶ Finetuning for the OpenMPparallellized partial insertion sort. The first number is the number of chunks per CPU (2 means each core will process 2 chunks sequentially, on average). The second number (if positive) is the lower bound on number of particles per chunk; the third number (if positive) is the limit of bounds per one chunk (15000 means that if there are e.g. 300k particles, bounds will be processed in 20 chunks, even if the number of chunks from the first number is smaller).
[type: Vector3i]

sortChunks
(= 1)¶ Number of threads that were actually used during the last parallelized insertion sort.
[type: int, readonly in python]

paraPeri
(= False)¶ (debugging only): enable/disable(default) parallel sort with periodic boundaries.
[type: bool]

periDbgNew
(= False)¶ Compute periodic overlaps and periods twice (with the original and the new algorithm) compare the results and report discrepancies.
[type: bool]

maxSortPass
(= 20)¶ If partial sort is not done after this many passes, give up. Usually more than a few passes (with nonparallelized insertion sort) already means a particle went crazy or the whole simulation is exploding. Negative value is relative to the number of cores as parallel insertion sort is done per chunks and more chunks mean more passes might be necessary.
[type: int]

periodic
(= False)¶ Whether the collider is in periodic mode (readonly; for debugging)
[type: bool, not saved, readonly in python]

strideActive
(= False)¶ Whether striding is active (readonly; for debugging)
[type: bool, not saved, readonly in python]

dbgInfo
(self: woo.dem.InsertionSortCollider) → object¶ Return python distionary with information on some internal structures (debugging only)

dumpBounds
(self: woo.dem.InsertionSortCollider) → tuple¶ Return representation of the internal sort data. The format is
([...],[...],[...])
for 3 axes, where each...
is a list of entries (bounds). The entry is a tuple with the fllowing items:coordinate (float)
body id (int), but negated for negative bounds
period numer (int), if the collider is in the periodic regime.

property
maxima
¶ Array of maximum bbox coords; every 3 contiguous values are x, y, z for one particle

property
minima
¶ Array of minimum bbox coords; every 3 contiguous values are x, y,z for one particle

spatialOverlap
(self: woo.dem.InsertionSortCollider, scene: woo.core.Scene, id1: int, id2: int) → object¶ Debug access to the spatial overlap function.
GridCollider¶
Object
→ Engine
→ Collider
→ GridCollider

class
woo.dem.
GridCollider
(*args, **kwargs)¶ Gridbased collider.
Overloaded function.
__init__(self: woo.dem.GridCollider) > None
__init__(self: woo.dem.GridCollider, *args, **kwargs) > None
► Grid geometry

domain
(= AlignedBox3((0, 0, 0), (1, 1, 1)))¶ Domain spanned by the grid.
[type: AlignedBox3r]

dim
(= Vector3i(1, 1, 1))¶ Number of cells along each axis
[type: Vector3i, readonly in python]

cellSize
(= Vector3(nan, nan, nan))¶ Actual cell size
[type: Vector3r, readonly in python]
► Data

gridOld
(= None)¶ Grid containing entries in
gridPrev
but not ingridCurr
.[type: shared_ptr<
GridStore
>, not saved]

gridNew
(= None)¶ Grid containing entries in
gridCurr
but not ingridPrev
.[type: shared_ptr<
GridStore
>, not saved]
► Rendering

color
(= Vector3(1, 1, 0))¶ Color for rendering the domain
[type: Vector3r]

renderCells
(= False)¶ Render cells.
[type: bool]

minOccup
(= 0)¶ Minimum occupancy for cell to be rendered (zero cells are never rendered).
[type: int]

occupancyRange
(= None)¶ Range for coloring grids based on occupancy (automatically created)
[type: shared_ptr<
ScalarRange
>]
► Tunables

exIniSize
(= 6)¶ GridStore.exIniSize
for new grids.[type: int]

exNumMaps
(= 100)¶ GridStore.exNumMaps
for new grids.[type: int]

verletDist
(= 0.0)¶ Length by which particle size is enalrged, to avoid running the collider at every timestep.
[type: Real, unit: m]

verletSteps
(= 0)¶ If positive, enlarge boxes of some particle nodes (currently only spheres are supported) so that they will still be inside the box after verletSteps with their current velocity;
verletDist
is still used when velocity is too small.[type: int]

nFullRuns
(= 0)¶ Cumulative number of full runs, when collision detection is needed.
[type: int]

complSetMinSize
(= 1)¶ The value of setMinSize when calling
GridStore.computeRelativeComplements
.[type: int]

useDiff
(= True)¶ Create new contacts based on set complement of
gridPrev
with respect togridCurr
if both contain meaningful data and are compatible; if false, always traverse gridCurr and try adding all possible contacts (this should be much slower)[type: bool]

around
(= False)¶ If frue, particle in every cell is checked with particles in all cells around; this makes the grid storage substantially less loaded, as all particles can be shrunk by one half of the cell size.
Warning
this feature is broken and will raise exception if enabled; the tradeoff is not good, since many more cells need to be checked around every cell, and many more potential contacts are created.
[type: bool]

shrink
(= 0.0)¶ The amount of shrinking for each particle (half of the minimum cell size if around is true, zero otherwise.
[type: Real, not shown in the UI, readonly in python]

boundDispatcher
(= <GridBoundDispatcher @ 0x20e6810>)¶ Dispatches
GridBound
creation toGridBoundFuctor
based onShape
type.[type: shared_ptr<
GridBoundDispatcher
>]
GridStore¶

class
woo.dem.
GridStore
(*args, **kwargs)¶ 3d grid storing scalar (particles ids) in partially dense array; the grid is actually 4d (gridSize×cellLen), and each cell may contain additional items in separate mapped storage, if the cellLen is not big enough to accomodate required number of items. Appending to cells is guarded via mutexes (with
denseLock
) optionally, appending to extra storage is mutexprotected always. Write acces from python should be used for testing exclusively.Overloaded function.
__init__(self: woo.dem.GridStore) > None

gridSize
(= Vector3i(1, 1, 1))¶ Dimension of the grid.
[type: Vector3i, readonly in python]

cellLen
(= 4)¶ Size of the dense storage in each cell
[type: int, readonly in python]

denseLock
(= True)¶ Whether this grid supports percell dense storage locking for appending (must use protected_append)
[type: bool, readonly in python]

exIniSize
(= 4)¶ Initial size of extension vectors, and step of their growth if needed.
[type: int, readonly in python]

exNumMaps
(= 10)¶ Number of maps for extra items not fitting the dense storage (it affects how finegrained is locking for those extra elements)
[type: int, readonly in python]

lo
(= Vector3(nan, nan, nan))¶ Lower corner of the domain.
[type: Vector3r]

cellSize
(= Vector3(nan, nan, nan))¶ Spatial size of the grid cell.
[type: Vector3r]

__delitem__
(self: woo.dem.GridStore, arg0: _wooEigen11.Vector3i) → None¶

__getitem__
(self: woo.dem.GridStore, arg0: _wooEigen11.Vector3i) → list¶

__setitem__
(self: woo.dem.GridStore, arg0: _wooEigen11.Vector3i, arg1: List[int]) → None¶

append
(self: woo.dem.GridStore, ijk: _wooEigen11.Vector3i, id: int) → None¶ Append new element; uses mutexes with
denseLock

complements
(self: woo.dem.GridStore, B: woo.dem.GridStore, setMinSize: int =  1) → tuple¶

countEx
(self: woo.dem.GridStore) → dict¶ Return dictionary mapping ijk to number of items in the extra storage.

counts
(self: woo.dem.GridStore) → List[int]¶ Return array with number of cells with given number of elements: [number of cells with 0 elements, number of cells with 1 elements, …]

ijk2box
(self: woo.dem.GridStore, ijk: _wooEigen11.Vector3i) → _wooEigen11.AlignedBox3¶ Box for given cell

ijk2lin
(self: woo.dem.GridStore, arg0: _wooEigen11.Vector3i) → int¶

lin2ijk
(self: woo.dem.GridStore, arg0: int) → _wooEigen11.Vector3i¶

size
(self: woo.dem.GridStore, arg0: _wooEigen11.Vector3i) → int¶

xyz2ijk
(self: woo.dem.GridStore, arg0: _wooEigen11.Vector3) → _wooEigen11.Vector3i¶ Convert spatial coordinates to cell coordinate (no bound checking is done)

xyzNearIjk
(self: woo.dem.GridStore, from: _wooEigen11.Vector3i, ijk: _wooEigen11.Vector3i) → _wooEigen11.Vector3¶ Return point nearest to from (given in cell coords) in cell ijk

xyzNearXyz
(self: woo.dem.GridStore, from: _wooEigen11.Vector3, ijk: _wooEigen11.Vector3i) → _wooEigen11.Vector3¶ Return point nearest to from*(given in spatial coords) in cell *ijk (corner, at a face, on an edge, inside)
Bound¶

class
woo.dem.
Bound
(*args, **kwargs)¶ Object bounding the associated body.
Overloaded function.

box
(= AlignedBox3((1.7976931348623157e308, 1.7976931348623157e308, 1.7976931348623157e308), (1.7976931348623157e308, 1.7976931348623157e308, 1.7976931348623157e308)))¶ Axisaligned bounding box.
[type: AlignedBox3r, unit: m, not saved, readonly in python]

dispHierarchy
(self: woo.dem.Bound, names: bool = True) → list¶ Return list of dispatch classes (from down upwards), starting with the class instance itself, toplevel indexable at last. If names is true (default), return class names rather than numerical indices.

property
dispIndex
¶ Return class index of this instance.

GridBound¶

class
woo.dem.
GridBound
(*args, **kwargs)¶ Bound defined via grid cell indices (used with
GridCollider
)Overloaded function.
__init__(self: woo.dem.GridBound) > None

nodePlay
(= [])¶ Space in which respective nodes of the shapes may be without triggering new contact detection
[type: vector<AlignedBox3r>, readonly in python]
Aabb¶

class
woo.dem.
Aabb
(*args, **kwargs)¶ Axisaligned bounding box, for use with InsertionSortCollider.
Overloaded function.

nodeLastPos
(= [])¶ Node positions when bbox was last updated.
[type: vector<Vector3r>, unit: m, readonly in python]

maxD2
(= 0.0)¶ Maximum allowed squared distance for nodal displacements (i.e. how much was the bbox enlarged last time)
[type: Real, unit: m², not shown in the UI, readonly in python]

maxRot
(= nan)¶ Maximum allowed rotation (in radians, without discriminating different angles) that does not yet invalidate the bbox. Functor sets to 1 (or other negative value) for particles where node rotation does not influence the box (such as spheres or facets); in that case, orientation difference is not computed at all. If it is left at NaN, it is an indication that the functor does not implemnt this behavior and an error will be raised in the collider.
[type: Real, readonly in python]

nodeLastOri
(= [])¶ Node orientations when bbox was last updated.
[type: vector<Quaternionr>, readonly in python]

BoundFunctor¶
Object
→ Functor
→ BoundFunctor

class
woo.dem.
BoundFunctor
(*args, **kwargs)¶ Functor for creating/updating
woo.dem.Bound
.Overloaded function.
Bo1_Rod_Aabb¶
Object
→ Functor
→ BoundFunctor
→ Bo1_Rod_Aabb

class
woo.dem.
Bo1_Rod_Aabb
(*args, **kwargs)¶ Compute
woo.dem.Aabb
of aRod
particleOverloaded function.
Bo1_Facet_Aabb¶
Bo1_Sphere_Aabb¶
Object
→ Functor
→ BoundFunctor
→ Bo1_Sphere_Aabb

class
woo.dem.
Bo1_Sphere_Aabb
(*args, **kwargs)¶ Functor creating
Aabb
fromSphere
. HonorsDemField.distFactor
.Overloaded function.
__init__(self: woo.dem.Bo1_Sphere_Aabb) > None
__init__(self: woo.dem.Bo1_Sphere_Aabb, *args, **kwargs) > None

distFactor
(= 1.0)¶ removed in API 10103, set
DemField.distFactor
instead.[type: Real, not shown in the UI, not dumped, DEPRECATED, raises
ValueError
when accessed]
Bo1_Ellipsoid_Aabb¶
Object
→ Functor
→ BoundFunctor
→ Bo1_Sphere_Aabb
→ Bo1_Ellipsoid_Aabb

class
woo.dem.
Bo1_Ellipsoid_Aabb
(*args, **kwargs)¶ Functor creating
Aabb
fromEllipsoid
.Todo
Handle rotation which is not detected by verlet distance!
Warning
woo.dem.DemField.distFactor
is ignored.Overloaded function.
Bo1_InfCylinder_Aabb¶
Object
→ Functor
→ BoundFunctor
→ Bo1_InfCylinder_Aabb

class
woo.dem.
Bo1_InfCylinder_Aabb
(*args, **kwargs)¶ Creates/updates an
Aabb
of aInfCylinder
Overloaded function.
Bo1_Capsule_Aabb¶
Bo1_Wall_Aabb¶
GridBoundFunctor¶
Object
→ Functor
→ GridBoundFunctor

class
woo.dem.
GridBoundFunctor
(*args, **kwargs)¶ Functor for creating/updating
woo.dem.GridBound
.Overloaded function.
Grid1_Facet¶
Object
→ Functor
→ GridBoundFunctor
→ Grid1_Facet

class
woo.dem.
Grid1_Facet
(*args, **kwargs)¶ Functor filling
GridStore
fromFacet
, used withGridCollider
.Overloaded function.
__init__(self: woo.dem.Grid1_Facet) > None
__init__(self: woo.dem.Grid1_Facet, *args, **kwargs) > None

movable
(= False)¶ Set to allow movable facets (with grid enlarged by
GridCollider.verletDist
. If false and a moving facet is encountered, an exception is raised.[type: bool]
Grid1_InfCylinder¶
Object
→ Functor
→ GridBoundFunctor
→ Grid1_InfCylinder

class
woo.dem.
Grid1_InfCylinder
(*args, **kwargs)¶ Functor filling
GridStore
fromInfCylinder
, used withGridCollider
.Overloaded function.
__init__(self: woo.dem.Grid1_InfCylinder) > None
__init__(self: woo.dem.Grid1_InfCylinder, *args, **kwargs) > None

movable
(= False)¶ Set to allow movable cylinders (with grid enlarged by
GridCollider.verletDist
. If false and a moving cylinder is encountered, an exception is raised.[type: bool]
Grid1_Wall¶
Object
→ Functor
→ GridBoundFunctor
→ Grid1_Wall

class
woo.dem.
Grid1_Wall
(*args, **kwargs)¶ Functor filling
GridStore
fromWall
, used withGridCollider
.Overloaded function.
__init__(self: woo.dem.Grid1_Wall) > None

movable
(= False)¶ Set to allow movable walls (with grid enlarged by
GridCollider.verletDist
. If false and a movable wall is encountered, an exception is raised.[type: bool]
Grid1_Sphere¶
Object
→ Functor
→ GridBoundFunctor
→ Grid1_Sphere

class
woo.dem.
Grid1_Sphere
(*args, **kwargs)¶ Functor filling
GridStore
fromSphere
, used withGridCollider
.Overloaded function.
__init__(self: woo.dem.Grid1_Sphere) > None
__init__(self: woo.dem.Grid1_Sphere, *args, **kwargs) > None

distFactor
(= 1.0)¶ removed in API 10103, set
DemField.distFactor
instead.[type: Real, not shown in the UI, not dumped, DEPRECATED, raises
ValueError
when accessed]
BoundDispatcher¶
Object
→ Engine
→ Dispatcher
→ BoundDispatcher

class
woo.dem.
BoundDispatcher
(*args, **kwargs)¶ Dispatcher calling
functors
based on received argument type(s).Overloaded function.
__init__(self: woo.dem.BoundDispatcher) > None
__init__(self: woo.dem.BoundDispatcher, *args, **kwargs) > None

functors
(= [])¶ Functors active in the dispatch mechanism [overridden below].
[type: vector<shared_ptr<BoundFunctor>>]

dispFunctor
(self: woo.dem.BoundDispatcher, arg0: woo.dem.Shape) → woo.dem.BoundFunctor¶ Return functor that would be dispatched for given argument(s); None if no dispatch; ambiguous dispatch throws.

dispMatrix
(self: woo.dem.BoundDispatcher, names: bool = True) → dict¶ Return dictionary with contents of the dispatch matrix.
GridBoundDispatcher¶
Object
→ Engine
→ Dispatcher
→ GridBoundDispatcher

class
woo.dem.
GridBoundDispatcher
(*args, **kwargs)¶ Dispatcher calling
functors
based on received argument type(s).Overloaded function.
__init__(self: woo.dem.GridBoundDispatcher) > None
__init__(self: woo.dem.GridBoundDispatcher, *args, **kwargs) > None

functors
(= [])¶ Functors active in the dispatch mechanism [overridden below].
[type: vector<shared_ptr<GridBoundFunctor>>]

dispFunctor
(self: woo.dem.GridBoundDispatcher, arg0: woo.dem.Shape) → woo.dem.GridBoundFunctor¶ Return functor that would be dispatched for given argument(s); None if no dispatch; ambiguous dispatch throws.

dispMatrix
(self: woo.dem.GridBoundDispatcher, names: bool = True) → dict¶ Return dictionary with contents of the dispatch matrix.
Contacts¶
TODO
Contact¶

class
woo.dem.
Contact
(*args, **kwargs)¶ Contact in DEM
Overloaded function.

data
(= None)¶ Optional data stored by the functor for its own use
[type: shared_ptr<
CData
>, readonly in python]

cellDist
(= Vector3i(0, 0, 0))¶ Distace in the number of periodic cells by which pB must be shifted to get to the right relative position.
[type: Vector3i, readonly in python]

color
(= 0.0)¶ (Normalized) color value for this contact
[type: Real]

stepCreated
(= 1)¶ Step in which this contact was created by the collider, or step in which it was made real (if geom and phys exist). This number is NOT reset by Contact::reset(). If negative, it means the collider does not want to keep this contact around anymore (this happens if the contact is real but there is no overlap anymore).
[type: int, readonly in python]

minDist00Sq
(= 1.0)¶ Minimum distance between nodes[0] of both shapes so that the contact can exist. Set in ContactLoop by geometry functor once, and is used to check for possible contact without having to call the functor. If negative, not used. Currently, only SphereSphere contacts use this information.
[type: Real, readonly in python]

stepLastSeen
(= 1)¶ [type: int, readonly in python]

linIx
(= 0)¶ Position in the linear view (ContactContainer)
[type: size_t, not shown in the UI, readonly in python]

dPos
(self: woo.dem.Contact) → _wooEigen11.Vector3¶ Return position difference vector pBpA, taking Contact.cellDist in account properly. Both particles must be uninodal, exception is raised otherwise.

dist
(self: woo.dem.Contact) → float¶ Shorthand for dPos.norm().

forceSign
(*args, **kwargs)¶ Overloaded function.
forceSign(self: woo.dem.Contact, p: woo.dem.Particle) > int
Return sign of
CPhys.force
as it appies on the particle passed, i.e. +1 ifp==C.pA
and 1 ifp==C.pB
. Raise an exception ifp
is neitherpA
orpB
.forceSign(self: woo.dem.Contact, id: int) > int
Return sign of
CPhys.force
as it appies on the particle with idid
, i.e.id==C.id1
and 1 ifid==id2
. Raise an exception ifid
is neitherid1
orid2
.

property
id1
¶ Particle.id
of the first contacting particle.

property
id2
¶ Particle.id
of the second contacting particle.

isFresh
(self: woo.dem.Contact, scene: woo.core.Scene) → bool¶ Say whether this contact has just been created. Equivalent to
C.stepCreated==scene.step
.

property
real
¶ Whether the contact is real (has
geom
andphys
); unreal contacts are created by broadband collisions detection and have no physical significance.

resetPhys
(self: woo.dem.Contact) → None¶ Set
phys
to None (to force its reevaluation)

ContactLoop¶
Object
→ Engine
→ ContactLoop

class
woo.dem.
ContactLoop
(*args, **kwargs)¶ Loop over all contacts, possible in a parallel manner.
Special constructor
Constructs from 3 lists of
Cg2
,Cp2
,Law
functors respectively; they will be passed to interal dispatchers.Overloaded function.
__init__(self: woo.dem.ContactLoop) > None
__init__(self: woo.dem.ContactLoop, *args, **kwargs) > None

geoDisp
(= <CGeomDispatcher @ 0x20d76a0>)¶ CGeomDispatcher
object that is used for dispatch.[type: shared_ptr<
CGeomDispatcher
>, readonly in python]

phyDisp
(= <CPhysDispatcher @ 0x20c9ae0>)¶ CPhysDispatcher
object used for dispatch.[type: shared_ptr<
CPhysDispatcher
>, readonly in python]

lawDisp
(= <LawDispatcher @ 0x20d75c0>)¶ LawDispatcher
object used for dispatch.[type: shared_ptr<
LawDispatcher
>, readonly in python]

hook
(= None)¶ ContactHook
objects, empty by default.[type: shared_ptr<
ContactHook
>]

alreadyWarnedNoCollider
(= False)¶ Keep track of whether the user was already warned about missing collider.
[type: bool, not shown in the UI]

evalStress
(= False)¶ Evaluate stress tensor, in periodic simluations; if energy tracking is enabled, increments gradV energy.
[type: bool]

applyForces
(= True)¶ Apply forces directly; this avoids IntraForce engine, but will silently skip multinodal particles.
[type: bool]

updatePhys
(= 0)¶ Call
CPhysFunctor
even for contacts which already haveContact.phys
(to reflect changes in particle’s material, for example). ‘once’ will update only once and then set this back to ‘never’.[type: int, named enum, possible values are: ‘never’ (0), ‘always’ (1), ‘once’ (2)]

dist00
(= True)¶ Whether to apply the Contact.minDist00Sq optimization (for mesuring the speedup only)
[type: bool]

stress
(= Matrix3(0, 0, 0, 0, 0, 0, 0, 0, 0))¶ Stress value, used to compute gradV energy if trackWork is True.
[type: Matrix3r, readonly in python]

reorderEvery
(= 1000)¶ Reorder contacts so that real ones are at the beginning in the linear sequence, making the OpenMP loop traversal (hopefully) less unbalanced.
[type: int]

prevVol
(= nan)¶ Previous value of cell volume
[type: Real, not accessible from python]

prevStress
(= Matrix3(0, 0, 0, 0, 0, 0, 0, 0, 0))¶ Previous value of stress, used to compute midstep stress
[type: Matrix3r]

gradVIx
(= 1)¶ Cache energy index for gradV work
[type: int, not saved, not accessible from python]
ContactHook¶

class
woo.dem.
ContactHook
(*args, **kwargs)¶ Functor called from
ContactLoop
for some specific events on contacts; currently, these events are contact creation and contact deletion. This base class does nothing.Overloaded function.
__init__(self: woo.dem.ContactHook) > None
__init__(self: woo.dem.ContactHook, *args, **kwargs) > None

mask
(= 0)¶ Mask which must be matched by both particles in the contact.
[type: int]
CountContactsHook¶
Object
→ ContactHook
→ CountContactsHook

class
woo.dem.
CountContactsHook
(*args, **kwargs)¶ Functor counting contacts created and deleted in
ContactLoop
(contacts being deleted e.g. as a result of particle deletion are not counted), restricted by mask.Overloaded function.
__init__(self: woo.dem.CountContactsHook) > None
__init__(self: woo.dem.CountContactsHook, *args, **kwargs) > None

nNew
¶ Total number of new (real) contacts.
[type: OpenMPAccumulator<int>]

nDel
¶ Total number of deleted contacts.
[type: OpenMPAccumulator<int>]
Geometry¶
TODO
CGeom¶

class
woo.dem.
CGeom
(*args, **kwargs)¶ Geometrical configuration of contact
Overloaded function.

dispHierarchy
(self: woo.dem.CGeom, names: bool = True) → list¶ Return list of dispatch classes (from down upwards), starting with the class instance itself, toplevel indexable at last. If names is true (default), return class names rather than numerical indices.

property
dispIndex
¶ Return class index of this instance.

G3Geom¶

class
woo.dem.
G3Geom
(*args, **kwargs)¶ Geometry of particles in contact, defining relative velocities.
Overloaded function.

uN
(= nan)¶ Normal displacement, distace of separation of particles (mathematically equal to integral of vel[0], but given here for numerically more stable results, as this component can be usually computed directly).
[type: Real]

dShear
(= Vector3(0, 0, 0))¶ Shear displacement delta during last step.
[type: Vector3r]

twistAxis
(= Vector3(nan, nan, nan))¶ Axis of twisting rotation
[type: Vector3r, readonly in python]

orthonormalAxis
(= Vector3(nan, nan, nan))¶ Axis normal to twisting axis
[type: Vector3r, readonly in python]

normal
(= Vector3(nan, nan, nan))¶ Contact normal in global coordinates; G3Geom doesn’t touch Contact.node.ori (which is identity), therefore orientation must be kep separately
[type: Vector3r, readonly in python]

L6Geom¶

class
woo.dem.
L6Geom
(*args, **kwargs)¶ Geometry of particles in contact, defining relative velocities.
Overloaded function.

vel
(= Vector3(0, 0, 0))¶ Relative displacement rate in local coordinates, defined by
CGeom.node
[type: Vector3r, unit: m/s]

angVel
(= Vector3(0, 0, 0))¶ Relative rotation rate in local coordinates
[type: Vector3r, unit: rad/s]

uN
(= nan)¶ Normal displacement, distace of separation of particles (mathematically equal to integral of vel[0], but given here for numerically more stable results, as this component can be usually computed directly).
[type: Real]

lens
(= Vector2(0, 0))¶ Hint for Cp2 functor on how to distribute material stiffnesses according to lengths on both sides of the contact; their sum should be equal to the initial contact length.
[type: Vector2r, unit: m]

contA
(= nan)¶ (Fictious) contact area, used by Cp2 functor to compute stiffness.
[type: Real, unit: m²]

trsf
(= Matrix3(1, 0, 0, 0, 1, 0, 0, 0, 1))¶ Transformation (rotation) from global to local coordinates; only used internally, and is synchronized with
woo.core.Node.ori
automatically. If the algorithm works with pure quaternions at some point (it is not stable now), can be removed safely.[type: Matrix3r]

CGeomFunctor¶
Object
→ Functor
→ CGeomFunctor

class
woo.dem.
CGeomFunctor
(*args, **kwargs)¶ Functor for creating/updating
Contact.geom
objects.Overloaded function.
Cg2_Any_Any_L6Geom__Base¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base

class
woo.dem.
Cg2_Any_Any_L6Geom__Base
(*args, **kwargs)¶ Common base for L6Geomcomputing functors such as
Cg2_Sphere_Sphere_L6Geom
, holding common approximation flags.Overloaded function.
__init__(self: woo.dem.Cg2_Any_Any_L6Geom__Base) > None
__init__(self: woo.dem.Cg2_Any_Any_L6Geom__Base, *args, **kwargs) > None

noRatch
(= False)¶ FIXME: document what it really does.
[type: bool]

trsfRenorm
(= 100)¶ How often to renormalize
trsf
; if nonpositive, never renormalized (simulation might be unstable)[type: int]

approxMask
(= 0)¶ Selectively enable geometrical approximations (bitmask); add the values for approximations to be enabled.
1
use previous normal instead of midstep normal for computing tangent velocity
2
do not renormalize average (midstep) normal, if used.
4
use previous rotation instead of midstep rotation to transform velocities
8
use current branches instead of midstep branches to evaluate incident velocity (used without noRatch)
By default, the mask is zero, wherefore none of these approximations is used.
[type: int, range: 0−15]
Cg2_Facet_Sphere_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Facet_Sphere_L6Geom
Cg2_Wall_Capsule_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Wall_Capsule_L6Geom
Cg2_Facet_Ellipsoid_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Facet_Ellipsoid_L6Geom

class
woo.dem.
Cg2_Facet_Ellipsoid_L6Geom
(*args, **kwargs)¶ Compute
L6Geom
for contact ofellipsoid
andfacet
.Warning
This class does not work (the result is correct only for face contact, otherwise bogus) and is by default not returned in
woo.dem.DemField.minimalEngines
. See this question for a brief discussion.Overloaded function.
Cg2_Wall_Sphere_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Wall_Sphere_L6Geom

class
woo.dem.
Cg2_Wall_Sphere_L6Geom
(*args, **kwargs)¶ Incrementally compute
L6Geom
for contact betweenWall
andSphere
. Uses attributes ofCg2_Sphere_Sphere_L6Geom
.Overloaded function.
Cg2_Sphere_Capsule_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Sphere_Capsule_L6Geom
Cg2_Sphere_Sphere_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Sphere_Sphere_L6Geom

class
woo.dem.
Cg2_Sphere_Sphere_L6Geom
(*args, **kwargs)¶ Functor for computing incrementally configuration of 2
Spheres
stored inL3Geom
; the configuration is positioned in global space by local origin \(\vec{c}\) (contact point) and rotation matrix \(\mat{T}\) (orthonormal transformation matrix), and its degrees of freedom are local displacement \(\vec{u}\) (in one normal and two shear directions); withIg2_Sphere_Sphere_L6Geom
andL6Geom
, there is additionally \(\vec{\phi}\). The first row of \(\mat{T}\), i.e. local \(x\)axis, is the contact normal noted \(\vec{n}\) for brevity. Additionally, quasiconstant values of \(\vec{u}_0\) (and \(\vec{\phi}_0\)) are stored as shifted origins of \(\vec{u}\) (and \(\vec{\phi}\)); therefore, current value of displacement is always \(\curr{\vec{u}}\vec{u}_0\).Suppose two spheres with radii \(r_i\), positions \(\vec{x}_i\), velocities \(\vec{v}_i\), angular velocities \(\vec{\omega}_i\).
When there is not yet contact, it will be created if \(u_N=\curr{\vec{x}}_2\curr{\vec{x}}_1f_d(r_1+r2)<0\), where \(f_d\) is
distFactor
(sometimes also called “interaction radius”). If \(f_d>0\), then \(\vec{u}_{0x}\) will be initalized to \(u_N\), otherwise to 0. In another words, contact will be created if spheres enlarged by \(f_d\) touch, and the “equilibrium distance” (where \(\vec{u}_x\vec{u}{0x}\) is zero) will be set to the current distance if \(f_d\) is positive, and to the geometricallytouching distance if negative.Local axes (rows of \(\mat{T}\)) are initially defined as follows:
local \(x\)axis is \(\vec{n}=\vec{x}_l=\normalized{\vec{x}_2\vec{x}_1}\);
local \(y\)axis positioned arbitrarily, but in a deterministic manner: aligned with the \(xz\) plane (if \(\vec{n}_y<\vec{n}_z\)) or \(xy\) plane (otherwise);
local \(z\)axis \(\vec{z}_l=\vec{x}_l\times\vec{y}_l\).
If there has already been contact between the two spheres, it is updated to keep track of rigid motion of the contact (one that does not change mutual configuration of spheres) and mutual configuration changes. Rigid motion transforms local coordinate system and can be decomposed in rigid translation (affecting \(\vec{c}\)), and rigid rotation (affecting \(\mat{T}\)), which can be split in rotation \(\vec{o}_r\) perpendicular to the normal and rotation \(\vec{o}_t\) (“twist”) parallel with the normal:
\[\pprev{\vec{o}_r}=\prev{\vec{n}}\times\curr{\vec{n}}.\]Since velocities are known at previous midstep (\(t\Dt/2\)), we consider midstep normal
\[\pprev{\vec{n}}=\frac{\prev{\vec{n}}+\curr{\vec{n}}}{2}.\]For the sake of numerical stability, \(\pprev{\vec{n}}\) is renormalized after being computed, unless prohibited by
approxMask
. IfapproxMask
has the appropriate bit set, the midnormal is not compute, and we simply use \(\pprev{\vec{n}}\approx\prev{\vec{n}}\).Rigid rotation parallel with the normal is
\[\pprev{\vec{o}_t}=\pprev{\vec{n}}\left(\pprev{\vec{n}}\cdot\frac{\pprev{\vec{\omega}}_1+\pprev{\vec{\omega}}_2}{2}\right)\Dt.\]Branch vectors \(\vec{b}_1\), \(\vec{b}_2\) (connecting \(\curr{\vec{x}}_1\), \(\curr{\vec{x}}_2\) with \(\curr{\vec{c}}\) are computed depending on
noRatch
(seehere
).\begin{align*} \vec{b}_1&=\begin{cases} r_1 \curr{\vec{n}} & \mbox{with noRatch} \\ \curr{\vec{c}}\curr{\vec{x}}_1 & \mbox{otherwise} \end{cases} \\ \vec{b}_2&=\begin{cases} r_2\curr{\vec{n}} & \mbox{with noRatch} \\ \curr{\vec{c}}\curr{\vec{x}}_2 & \mbox{otherwise} \end{cases} \\ \end{align*}Relative velocity at \(\curr{\vec{c}}\) can be computed as
\[\pprev{\vec{v}_r}=(\pprev{\vec{\tilde{v}}_2}+\vec{\omega}_2\times\vec{b}_2)(\vec{v}_1+\vec{\omega}_1\times\vec{b}_1)\]where \(\vec{\tilde{v}}_2\) is \(\vec{v}_2\) without meanfield velocity gradient in periodic boundary conditions (see
Cell.homoDeform
). In the numerial implementation, the normal part of incident velocity is removed (since it is computed directly) with \(\pprev{\vec{v}_{r2}}=\pprev{\vec{v}_r}(\pprev{\vec{n}}\cdot\pprev{\vec{v}_r})\pprev{\vec{n}}\).Any vector \(\vec{a}\) expressed in global coordinates transforms during one timestep as
\[\curr{\vec{a}}=\prev{\vec{a}}+\pprev{\vec{v}_r}\Dt\prev{\vec{a}}\times\pprev{\vec{o}_r}\prev{\vec{a}}\times{\pprev{\vec{t}_r}}\]where the increments have the meaning of relative shear, rigid rotation normal to \(\vec{n}\) and rigid rotation parallel with \(\vec{n}\). Local coordinate system orientation, rotation matrix \(\mat{T}\), is updated by rows, i.e.
\[\begin{split}\curr{\mat{T}}=\begin{pmatrix} \curr{\vec{n}_x}, \curr{\vec{n}_y}, \curr{\vec{n}_z} \\ \prev{\mat{T}_{1,\bullet}}\prev{\mat{T}_{1,\bullet}}\times\pprev{\vec{o}_r}\prev{\mat{T}_{1,\bullet}}\times\pprev{\vec{o}_t} \\ \prev{\mat{T}_{2,\bullet}}\prev{\mat{T}_{2,\bullet}}\times\pprev{\vec{o}_r}\prev{\mat{T}_{,\bullet}}\times\pprev{\vec{o}_t} \end{pmatrix}\end{split}\]This matrix is renormalized (unless prevented by
approxMask
) and midstep transformation is computed using quaternion spherical interpolation as\[\pprev{\mat{T}}=\mathrm{Slerp}\,\left(\prev{\mat{T}};\curr{\mat{T}};t=1/2\right).\]Depending on
approxMask
, this computation can be avoided by approximating \(\pprev{\mat{T}}=\prev{\mat{T}}\).Finally, current displacement is evaluated as
\[\curr{\vec{u}}=\prev{u}+\pprev{\mat{T}}\pprev{\vec{v}_r}\Dt.\]For the normal component, nonincremental evaluation is preferred, giving
\[\curr{\vec{u}_x}=\curr{\vec{x}_2}\curr{\vec{x}_1}(r_1+r_2)\]If this functor is called for
L6Geom
, local rotation is updated as\[\curr{\vec{\phi}}=\prev{\vec{\phi}}+\pprev{\mat{T}}\Dt(\vec{\omega}_2\vec{\omega}_1)\]Overloaded function.
__init__(self: woo.dem.Cg2_Sphere_Sphere_L6Geom) > None
__init__(self: woo.dem.Cg2_Sphere_Sphere_L6Geom, *args, **kwargs) > None

distFactor
(= 1.0)¶ removed in API 10103, set
DemField.distFactor
instead.[type: Real, not shown in the UI, not dumped, DEPRECATED, raises
ValueError
when accessed]
Cg2_Wall_Ellipsoid_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Wall_Ellipsoid_L6Geom
Cg2_Capsule_Capsule_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Capsule_Capsule_L6Geom
Cg2_InfCylinder_Sphere_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_InfCylinder_Sphere_L6Geom

class
woo.dem.
Cg2_InfCylinder_Sphere_L6Geom
(*args, **kwargs)¶ Incrementally compute
L6Geom
for contact betweenInfCylinder
andSphere
. Uses attributes ofCg2_Sphere_Sphere_L6Geom
.Overloaded function.
Cg2_Rod_Sphere_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Rod_Sphere_L6Geom

class
woo.dem.
Cg2_Rod_Sphere_L6Geom
(*args, **kwargs)¶ Incrementally compute
L6Geom
for contact betweenRod
andSphere
. Uses attributes ofCg2_Sphere_Sphere_L6Geom
.Overloaded function.
Cg2_InfCylinder_Capsule_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_InfCylinder_Capsule_L6Geom
Cg2_Facet_InfCylinder_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Facet_InfCylinder_L6Geom
Cg2_Facet_Capsule_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Facet_Capsule_L6Geom
Cg2_Facet_Facet_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Facet_Facet_L6Geom
Cg2_Ellipsoid_Ellipsoid_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Ellipsoid_Ellipsoid_L6Geom

class
woo.dem.
Cg2_Ellipsoid_Ellipsoid_L6Geom
(*args, **kwargs)¶ Incrementally compute
L6Geom
for contact of 2ellipsoids
. Uses the PerramWertheim potential function ([PW85], [PRPraestgaardL96], [DTS05]). See example scripts examples/ell0.py and examples/ell1.py.Overloaded function.
__init__(self: woo.dem.Cg2_Ellipsoid_Ellipsoid_L6Geom) > None
__init__(self: woo.dem.Cg2_Ellipsoid_Ellipsoid_L6Geom, *args, **kwargs) > None

brent
(= True)¶ Use Brent iteration for finding maximum of the PerramWertheim potential. If false, use NewtonRaphson (not yet implemented).
[type: bool]

brentBits
(= 32)¶ Precision for the Brent method, as number of bits.
[type: int]
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Ellipsoid_Ellipsoid_L6Geom
→ Cg2_Sphere_Ellipsoid_L6Geom

class
woo.dem.
Cg2_Sphere_Ellipsoid_L6Geom
(*args, **kwargs)¶ Compute the geometry of
Ellipsoid
+Sphere
collision. Uses the code fromCg2_Ellipsoid_Ellipsoid_L6Geom
, representing the sphere as an ellipsoid with all semiaxes equal to the radius.Overloaded function.
Cg2_Wall_Facet_L6Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Any_Any_L6Geom__Base
→ Cg2_Wall_Facet_L6Geom
Cg2_Wall_Sphere_G3Geom¶
Cg2_Sphere_Sphere_G3Geom¶
Object
→ Functor
→ CGeomFunctor
→ Cg2_Sphere_Sphere_G3Geom

class
woo.dem.
Cg2_Sphere_Sphere_G3Geom
(*args, **kwargs)¶ Incrementally compute
G3Geom
for contact of 2 spheres. Detailed documentation in py/_extraDocs.pyOverloaded function.
__init__(self: woo.dem.Cg2_Sphere_Sphere_G3Geom) > None
__init__(self: woo.dem.Cg2_Sphere_Sphere_G3Geom, *args, **kwargs) > None

noRatch
(= True)¶ FIXME: document what it really does.
[type: bool]

useAlpha
(= True)¶ Use alpha correction proposed by McNamara, see source code for details
[type: bool]
CGeomDispatcher¶
Object
→ Engine
→ Dispatcher
→ CGeomDispatcher

class
woo.dem.
CGeomDispatcher
(*args, **kwargs)¶ Dispatcher calling
functors
based on received argument type(s).Overloaded function.
__init__(self: woo.dem.CGeomDispatcher) > None
__init__(self: woo.dem.CGeomDispatcher, *args, **kwargs) > None

functors
(= [])¶ Functors active in the dispatch mechanism [overridden below].
[type: vector<shared_ptr<CGeomFunctor>>]

dispFunctor
(self: woo.dem.CGeomDispatcher, arg0: woo.dem.Shape, arg1: woo.dem.Shape) → woo.dem.CGeomFunctor¶ Return functor that would be dispatched for given argument(s); None if no dispatch; ambiguous dispatch throws.

dispMatrix
(self: woo.dem.CGeomDispatcher, names: bool = True) → dict¶ Return dictionary with contents of the dispatch matrix.
Physical properties¶
TODO
CPhys¶

class
woo.dem.
CPhys
(*args, **kwargs)¶ Physical properties of contact.
Overloaded function.

force
(= Vector3(0, 0, 0))¶ Force applied on the first particle in the contact
[type: Vector3r, unit: N]

torque
(= Vector3(0, 0, 0))¶ Torque applied on the first particle in the contact
[type: Vector3r, unit: N·m]

dispHierarchy
(self: woo.dem.CPhys, names: bool = True) → list¶ Return list of dispatch classes (from down upwards), starting with the class instance itself, toplevel indexable at last. If names is true (default), return class names rather than numerical indices.

property
dispIndex
¶ Return class index of this instance.

FrictPhys¶

class
woo.dem.
FrictPhys
(*args, **kwargs)¶ Physical parameters of contact with sliding
Overloaded function.
__init__(self: woo.dem.FrictPhys) > None

tanPhi
(= nan)¶ Tangent of friction angle
[type: Real]

kn
(= nan)¶ Normal stiffness
[type: Real]

kt
(= nan)¶ Tangent stiffness
[type: Real]
ConcretePhys¶
Object
→ CPhys
→ FrictPhys
→ ConcretePhys

class
woo.dem.
ConcretePhys
(*args, **kwargs)¶ Representation of a single interaction of the Concrete type: storage for relevant parameters.
Overloaded function.
__init__(self: woo.dem.ConcretePhys) > None
__init__(self: woo.dem.ConcretePhys, *args, **kwargs) > None

E
(= nan)¶ normal modulus (stiffness / crossSection) [Pa]
[type: Real]

G
(= nan)¶ shear modulus [Pa]
[type: Real]

coh0
(= nan)¶ virgin material cohesion [Pa]
[type: Real]

epsCrackOnset
(= nan)¶ strain at which the material starts to behave nonlinearly
[type: Real]

epsFracture
(= nan)¶ strain at which the bond is fully broken []
[type: Real]

dmgTau
(= 1.0)¶ characteristic time for damage (if nonpositive, the law without ratedependence is used)
[type: Real]

dmgRateExp
(= 0.0)¶ exponent in the ratedependent damage evolution
[type: Real]

dmgStrain
(= 0.0)¶ damage strain (at previous or current step)
[type: Real]

dmgOverstress
(= 0.0)¶ damage viscous overstress (at previous step or at current step)
[type: Real]

plTau
(= 1.0)¶ characteristic time for viscoplasticity (if nonpositive, no ratedependence for shear)
[type: Real]

plRateExp
(= 0.0)¶ exponent in the ratedependent viscoplasticity
[type: Real]

isoPrestress
(= 0.0)¶ “prestress” of this link (used to simulate isotropic stress)
[type: Real]

neverDamage
(= False)¶ the damage evolution function will always return virgin state
[type: bool]

damLaw
(= 1)¶ Law for softening part of uniaxial tension. 0 for linear, 1 for exponential (default)
[type: int]

isCohesive
(= False)¶ if not cohesive, interaction is deleted when distance is greater than zero.
[type: bool]

epsT
(= Vector2(0, 0))¶ Shear strain; updated incrementally from
L6Geom.vel
.[type: Vector2r, not saved, readonly in python]
► Autocomputed

omega
(= 0.0)¶ Damage parameter
[type: Real, not saved, readonly in python]

uN0
(= nan)¶ Initial normal displacement (equilibrium state)
[type: Real, readonly in python]

epsN
(= 0.0)¶ Normal strain
[type: Real, not saved, readonly in python]

sigmaN
(= 0.0)¶ Normal force
[type: Real, not saved, readonly in python]

sigmaT
(= Vector2(0, 0))¶ Tangential stress
[type: Vector2r, not saved, readonly in python]

epsNPl
(= 0.0)¶ Normal plastic strain
[type: Real, not saved, readonly in python]

kappaD
(= 0.0)¶ Value of the kappa function
[type: Real, not saved, readonly in python]

relResidualStrength
(= 1.0)¶ Relative residual strength
[type: Real, not saved, readonly in python]

static
funcG
(kappaD: float, epsCrackOnset: float, epsFracture: float, neverDamage: bool = False, damLaw: int = 1) → float¶ Damage evolution law, evaluating the $omega$ parameter. $kappa_D$ is historically maximum strain, epsCrackOnset ($varepsilon_0$) =
epsCrackOnset
, epsFracture =epsFracture
; if neverDamage isTrue
, the value returned will always be 0 (no damage).

static
funcGInv
(omega: float, epsCrackOnset: float, epsFracture: float, neverDamage: bool = False, damLaw: int = 1) → float¶ Inversion of damage evolution law, evaluating the $kappa_D$ parameter. $omega$ is damage, for other parameters see funcG function

setDamage
(self: woo.dem.ConcretePhys, arg0: float) → None¶ TODO

setRelResidualStrength
(self: woo.dem.ConcretePhys, arg0: float) → None¶ TODO
HertzPhys¶
Object
→ CPhys
→ FrictPhys
→ HertzPhys

class
woo.dem.
HertzPhys
(*args, **kwargs)¶ Physical properties of a contact of two
FrictMat
with viscous damping enabled (viscosity is currently not provided as material parameter).Overloaded function.
__init__(self: woo.dem.HertzPhys) > None

kt0
(= 0.0)¶ Constant for computing current normal stiffness.
[type: Real]

R
(= 0.0)¶ Effective radius (for the Schwarz model)
[type: Real]

K
(= 0.0)¶ Effective stiffness (for the Schwarz model)
[type: Real]

gamma
(= 0.0)¶ Surface energy (for the Schwarz model)
[type: Real]

alpha
(= 0.0)¶ COS alpha coefficient
[type: Real]

contRad
(= 0.0)¶ Contact radius, used for storing previous value as the initial guess in the next step.
[type: Real]
PelletPhys¶
Object
→ CPhys
→ FrictPhys
→ PelletPhys
LudingPhys¶
Object
→ CPhys
→ FrictPhys
→ LudingPhys

class
woo.dem.
LudingPhys
(*args, **kwargs)¶ Physical properties for
ludingcontactmodel
.Overloaded function.
__init__(self: woo.dem.LudingPhys) > None

kn1
(= nan)¶ Normal plastic (loading) stiffness.
[type: Real]

kna
(= nan)¶ Normal adhesive stiffness.
[type: Real]

k2hat
(= nan)¶ Maximum stiffness.
[type: Real]

deltaMax
(= 0.0)¶ Historically maximum overlap value.
[type: Real]

kr
(= nan)¶ Roll stiffness.
[type: Real]

kw
(= nan)¶ Twist stiffness.
[type: Real]

viscN
(= nan)¶ Normal viscosity.
[type: Real]

viscT
(= nan)¶ Tangent viscosity.
[type: Real]

viscR
(= nan)¶ Roll viscosity.
[type: Real]

viscW
(= nan)¶ Twist viscosity.
[type: Real]

dynDivStat
(= nan)¶ Dynamic to static friction.
[type: Real]

statR
(= nan)¶ Roll static friction.
[type: Real]

statW
(= nan)¶ Twist static friction.
[type: Real]

xiT
(= Vector2(0, 0))¶ Tangent elastic displacement.
[type: Vector2r]

xiR
(= Vector2(0, 0))¶ Tangent elastic rotation.
[type: Vector2r]

xiW
(= 0.0)¶ Twist elastic rotation.
[type: Real]

work
(= [])¶ Percontact dissipation (unallocated when energy tracking is not enabled).
[type: vector<Real>]
IcePhys¶
Object
→ CPhys
→ FrictPhys
→ IcePhys

class
woo.dem.
IcePhys
(*args, **kwargs)¶ Physical properties of a contact of two
IceMat
.Overloaded function.

kWR
(= Vector2(nan, nan))¶ Twisting and rolling stiffness.
[type: Vector2r]

brkNT
(= Vector2(nan, nan))¶ Limits of breakage in normal & tangential senses.
[type: Vector2r, unit: N]

brkWR
(= Vector2(nan, nan))¶ Limits of breakage in twisting & rolling senses.
[type: Vector2r, unit: N·m]

mu
(= nan)¶ Kinetic (rolling) friction coefficient.
[type: Real]

bonds
(= 0)¶ Bits specifying whether the contact is bonded (in 4 senses) and whether it is breakable (in 4 senses).
[type: int, bit accessors: bondN, bondT, bondW, bondR, brkN, brkT, brkW, brkR]

uN0
(= 0.0)¶ Initial value of normal overlap; set automatically by
Law_L6Geom_IcePhys
wheniniEqlb
is true (default).[type: Real]

isBondX
(self: woo.dem.IcePhys, arg0: int) → bool¶ Whether the contact is bonded in the x sense (0..3)

isBrkBondX
(self: woo.dem.IcePhys, arg0: int) → bool¶ Whether the contact is breakable and bonded in the x sense (0..3)

isBrkX
(self: woo.dem.IcePhys, arg0: int) → bool¶ Whether the contact is breakable in the x sense (0..3)

CPhysFunctor¶
Object
→ Functor
→ CPhysFunctor

class
woo.dem.
CPhysFunctor
(*args, **kwargs)¶ Functor for creating/updating
Contact.phys
objects.Overloaded function.
Cp2_FrictMat_FrictPhys_CrossAnisotropic¶
Object
→ Functor
→ CPhysFunctor
→ Cp2_FrictMat_FrictPhys_CrossAnisotropic

class
woo.dem.
Cp2_FrictMat_FrictPhys_CrossAnisotropic
(*args, **kwargs)¶ Call
Cp2_FrictMat_FrictPhys
to create a newFrictPhys
, but multiply resultingnormal
andshear
stiffnesses by smooth dimensionless anisotropy distribution given byalpha
andbeta
. The functionality is demonstrated in the following movie:Overloaded function.
__init__(self: woo.dem.Cp2_FrictMat_FrictPhys_CrossAnisotropic) > None
__init__(self: woo.dem.Cp2_FrictMat_FrictPhys_CrossAnisotropic, *args, **kwargs) > None

E1
(= 1000000.0)¶ Inplane normal modulus
[type: Real, unit: Pa]

E2
(= 100000.0)¶ Outofplane normal modulus
[type: Real, unit: Pa]

G1
(= 10000.0)¶ Inplane shear modulus
[type: Real, unit: Pa]

G2
(= 10000.0)¶ Outofplane shear modulus
[type: Real, unit: Pa]

nu1
(= 0.4)¶ Major Poisson’s ratio; dependent value computed as \(\frac{E_1}{2G_1}1\).
[type: Real, readonly in python]

alpha
(= 0.0)¶ Strike angle for the local axes
[type: Real, unit: rad, range: 0−6.28319]

beta
(= 0.0)¶ Dip angle for the local axes
[type: Real, unit: rad, range: 0−1.5708]
Cp2_ConcreteMat_ConcretePhys¶
Object
→ Functor
→ CPhysFunctor
→ Cp2_ConcreteMat_ConcretePhys

class
woo.dem.
Cp2_ConcreteMat_ConcretePhys
(*args, **kwargs)¶ Compute
ConcretePhys
from twoConcreteMat
instances. Uses simple (arithmetic) averages if material are different. Simple copy of parameters is performed if the instance ofConcreteMat
is shared.Overloaded function.
__init__(self: woo.dem.Cp2_ConcreteMat_ConcretePhys) > None
__init__(self: woo.dem.Cp2_ConcreteMat_ConcretePhys, *args, **kwargs) > None

cohesiveThresholdStep
(= 10)¶ Should new contacts be cohesive? They will before this iter#, they will not be afterwards. If 0, they will never be. If negative, they will always be created as cohesive (10 by default).
[type: long]
Cp2_FrictMat_FrictPhys¶
Object
→ Functor
→ CPhysFunctor
→ Cp2_FrictMat_FrictPhys

class
woo.dem.
Cp2_FrictMat_FrictPhys
(*args, **kwargs)¶ TODO
Overloaded function.
__init__(self: woo.dem.Cp2_FrictMat_FrictPhys) > None
__init__(self: woo.dem.Cp2_FrictMat_FrictPhys, *args, **kwargs) > None

tanPhi
(= None)¶ Instance of
MatchMaker
determining how to compute contact friction angle. IfNone
, minimum value is used.[type: shared_ptr<
MatchMaker
>]
Cp2_HertzMat_HertzPhys¶
Object
→ Functor
→ CPhysFunctor
→ Cp2_FrictMat_FrictPhys
→ Cp2_HertzMat_HertzPhys

class
woo.dem.
Cp2_HertzMat_HertzPhys
(*args, **kwargs)¶ Compute
HertzPhys
given two instances of :ref`HertzMat`. The value ofHertzPhys.alpha
is averaged (fromHertzMat.alpha
) whileHertzPhys.gamma
is minimum (ofHertzMat.gamma
).Overloaded function.
__init__(self: woo.dem.Cp2_HertzMat_HertzPhys) > None
__init__(self: woo.dem.Cp2_HertzMat_HertzPhys, *args, **kwargs) > None

poisson
(= 0.2)¶ Poisson ratio for computing contact properties (not provided by the material class currently)
[type: Real]

en
(= nan)¶ Normal coefficient of restitution (if outside the 01 range, there will be no damping, making
en
effectively equal to one).[type: Real]
Cp2_PelletMat_PelletPhys¶
Object
→ Functor
→ CPhysFunctor
→ Cp2_FrictMat_FrictPhys
→ Cp2_PelletMat_PelletPhys

class
woo.dem.
Cp2_PelletMat_PelletPhys
(*args, **kwargs)¶ Compute
PelletPhys
given two instances of :ref`PelletMat`.PelletMat.normPlastCoeff
is averaged intoPelletPhys.normPlastCoeff
, while minimum ofPelletMat.kaDivKn
is taken to computePelletPhys.ka
.Overloaded function.
Cp2_LudingMat_LudingPhys¶
Object
→ Functor
→ CPhysFunctor
→ Cp2_FrictMat_FrictPhys
→ Cp2_LudingMat_LudingPhys

class
woo.dem.
Cp2_LudingMat_LudingPhys
(*args, **kwargs)¶ Compute
LudingPhys
given two instances ofLudingMat
.Overloaded function.
Cp2_IceMat_IcePhys¶
Object
→ Functor
→ CPhysFunctor
→ Cp2_FrictMat_FrictPhys
→ Cp2_IceMat_IcePhys

class
woo.dem.
Cp2_IceMat_IcePhys
(*args, **kwargs)¶ Compute
IcePhys
given two instances of :ref`IceMat`.Overloaded function.
__init__(self: woo.dem.Cp2_IceMat_IcePhys) > None
__init__(self: woo.dem.Cp2_IceMat_IcePhys, *args, **kwargs) > None

bonds0
(= 0)¶ Bonding bits for new contacts, for the initial configuration.
[type: int, bit accessors: bondN, bondT, bondW, bondR, brkN, brkT, brkW, brkR]

bonds1
(= 0)¶ Bonding bits for new contacts, for contacts created after the initial configuration.
[type: int, bit accessors: bondN, bondT, bondW, bondR, brkN, brkT, brkW, brkR]
CPhysDispatcher¶
Object
→ Engine
→ Dispatcher
→ CPhysDispatcher

class
woo.dem.
CPhysDispatcher
(*args, **kwargs)¶ Dispatcher calling
functors
based on received argument type(s).Overloaded function.
__init__(self: woo.dem.CPhysDispatcher) > None
__init__(self: woo.dem.CPhysDispatcher, *args, **kwargs) > None

functors
(= [])¶ Functors active in the dispatch mechanism [overridden below].
[type: vector<shared_ptr<CPhysFunctor>>]

dispFunctor
(self: woo.dem.CPhysDispatcher, arg0: woo.dem.Material, arg1: woo.dem.Material) → woo.dem.CPhysFunctor¶ Return functor that would be dispatched for given argument(s); None if no dispatch; ambiguous dispatch throws.

dispMatrix
(self: woo.dem.CPhysDispatcher, names: bool = True) → dict¶ Return dictionary with contents of the dispatch matrix.
Contact law¶
TODO
CData¶
G3GeomCData¶
Object
→ CData
→ G3GeomCData
IdealElPlData¶
Object
→ CData
→ IdealElPlData

class
woo.dem.
IdealElPlData
(*args, **kwargs)¶ Hold (optional) state variables for ideally elastoplastic contacts.
Overloaded function.
__init__(self: woo.dem.IdealElPlData) > None
__init__(self: woo.dem.IdealElPlData, *args, **kwargs) > None

uN0
(= 0.0)¶ Reference (equilibrium) value for uN (normal displacement).
[type: Real]
PelletCData¶
Object
→ CData
→ PelletCData

class
woo.dem.
PelletCData
(*args, **kwargs)¶ Hold state variables for pellet contact.
Overloaded function.
__init__(self: woo.dem.PelletCData) > None
__init__(self: woo.dem.PelletCData, *args, **kwargs) > None

uNPl
(= 0.0)¶ Plastic displacement on the contact.
[type: Real]

uN0
(= 0.0)¶ Initial distance (defines equilibrium).
[type: Real]
LawFunctor¶
Object
→ Functor
→ LawFunctor

class
woo.dem.
LawFunctor
(*args, **kwargs)¶ Functor for applying constitutive laws on
contact
.Overloaded function.
Law2_L6Geom_ConcretePhys¶
Object
→ Functor
→ LawFunctor
→ Law2_L6Geom_ConcretePhys

class
woo.dem.
Law2_L6Geom_ConcretePhys
(*args, **kwargs)¶ Constitutive law for concrete.
Overloaded function.
__init__(self: woo.dem.Law2_L6Geom_ConcretePhys) > None
__init__(self: woo.dem.Law2_L6Geom_ConcretePhys, *args, **kwargs) > None

yieldSurfType
(= 3)¶ yield function: 0: mohrcoulomb (original); 1: parabolic; 2: logarithmic, 3: log+lin_tension, 4: elliptic, 5: elliptic+log
[type: int, named enum, possible values are: ‘linear’ (‘lin’, ‘MC’, ‘mc’, ‘MohrCoulomb’; 0), ‘para’ (‘parabolic’; 1), ‘log’ (‘logarithmic’; 2), ‘log+lin’ (‘logarithmic, linear tension’, ‘loglin’; 3), ‘elliptic’ (‘ell’; 4), ‘elliptic+logarithmic’ (‘ell+log’; 5)]

yieldLogSpeed
(= 0.1)¶ scaling in the logarithmic yield surface (should be <1 for realistic results; >=0 for meaningful results)
[type: Real]

yieldEllipseShift
(= nan)¶ horizontal scaling of the ellipse (shifts on the +x axis as interactions with +y are given)
[type: Real]

omegaThreshold
(= 1.0)¶ damage after which the contact disappears (<1), since omega reaches 1 only for strain →+∞
[type: Real]

epsSoft
(= 0.003)¶ Strain at which softening in compression starts (nonnegative to deactivate)
[type: Real]

relKnSoft
(= 0.3)¶ Relative rigidity of the softening branch in compression (0=perfect elasticplastic, <0 softening, >0 hardening)
[type: Real]

elastPotIx
(= 1)¶ Index for elastic potential energy
[type: int, not saved, not accessible from python]

yieldSigmaTNorm
(self: woo.dem.Law2_L6Geom_ConcretePhys, sigmaN: float, omega: float, coh0: float, tanPhi: float) → float¶ Return radius of yield surface for given material and state parameters; uses attributes of the current instance (
yieldSurfType
etc), change them before calling if you need that.
Law2_L6Geom_PelletPhys_Pellet¶
Object
→ Functor
→ LawFunctor
→ Law2_L6Geom_PelletPhys_Pellet

class
woo.dem.
Law2_L6Geom_PelletPhys_Pellet
(*args, **kwargs)¶ Contact law with friction and plasticity in compression, designed for pellet behavior. See
pelletcontactmodel
for details.Overloaded function.
__init__(self: woo.dem.Law2_L6Geom_PelletPhys_Pellet) > None
__init__(self: woo.dem.Law2_L6Geom_PelletPhys_Pellet, *args, **kwargs) > None

thinRate
(= 0.0)¶ The amount of reducing particle radius (\(\theta_t\)), relative to plastic deformation increment (nonpositive to disable thinning)
[type: Real]

thinRelRMin
(= 0.7)¶ Minimum radius reachable with sphere thinning at plastic deformation, relative to initial particle size (\(r_{\min}^{\mathrm{rel}}\))
[type: Real]

thinExp
(= 1.0)¶ Exponent for reducing the rate of thinning as the minimum radius is being approached (\(\gamma_t\))
[type: Real]

thinRefRad
(= 0.0)¶ Reference radius for thinning; if positive,
thinRateExp
andthinMinExp
are in effect.[type: Real, unit: m]

thinMinExp
(= 0.0)¶ Multiply minimum radius \(r_0\) by \(\left(\frac{r}{r_{\rm thinRefRad}}\right)^{\rm thinMinExp}\) (sizedependent minimum radius).
[type: Real]

thinRateExp
(= 0.0)¶ Multiply thinning rate \(\theta_t\) (
thinRate
) by \(\left(\frac{r}{r_{\rm thinRefRad}}\right)^{\rm thinRateExp}\) (sizedependent minimum radius).[type: Real]

confSigma
(= 0.0)¶ Confinement stress (acting on
contact area
). Negative values will make particles stick together. The strainstress diagram is shifted vertically with this parameter. The value of confinement can be further scaled withconfRefRad
.Note
Energy computation might be incorrect with confinement (not yet checked).
[type: Real]

confRefRad
(= 0.0)¶ If positive, scale the confining stress (
confSigma
) using the value of \(\left(\frac{A}{\pi r_{\rm ref}^2}\right)^{\beta_c}\); this allows to introduce confinement which varies depending on particle size.[type: Real, unit: m]

confExp
(= 1.0)¶ Dimensionless exponent to be used in conjunction with
confRefRad
.[type: Real]

iniEqlb
(= False)¶ Use the initial distance as equilibrium.
[type: bool]

plastSplit
(= False)¶ Track energy dissipated in normal and tangential sliding separately
[type: bool]

plastIx
(= 1)¶ Index of plastically dissipated energy
[type: int, not saved, not accessible from python]

normPlastIx
(= 1)¶ Index of plastically dissipated energy in the normal sense
[type: int, not saved, not accessible from python]

elastPotIx
(= 1)¶ Index for elastic potential energy
[type: int, not saved, not accessible from python]

static
adhesionForce
(uN: float, uNPl: float, ka: float) → float¶ Adhesion force function $h$ evaluated with given parameters
Law2_G3Geom_FrictPhys_IdealElPl¶
Object
→ Functor
→ LawFunctor
→ Law2_G3Geom_FrictPhys_IdealElPl

class
woo.dem.
Law2_G3Geom_FrictPhys_IdealElPl
(*args, **kwargs)¶ Ideally elasticplastic behavior, for use with G3Geom.
Overloaded function.
__init__(self: woo.dem.Law2_G3Geom_FrictPhys_IdealElPl) > None
__init__(self: woo.dem.Law2_G3Geom_FrictPhys_IdealElPl, *args, **kwargs) > None

noSlip
(= False)¶ Disable plastic slipping
[type: bool]

noBreak
(= False)¶ Disable removal of contacts when in tension.
[type: bool]

plastDissipIx
(= 1)¶ Index of plastically dissipated energy
[type: int, not saved, not accessible from python]

elastPotIx
(= 1)¶ Index for elastic potential energy
[type: int, not saved, not accessible from python]

watch
(= Vector2i(1, 1))¶ Print debug information for this couple of IDs
[type: Vector2i]
Law2_L6Geom_FrictPhys_IdealElPl¶
Object
→ Functor
→ LawFunctor
→ Law2_L6Geom_FrictPhys_IdealElPl

class
woo.dem.
Law2_L6Geom_FrictPhys_IdealElPl
(*args, **kwargs)¶ Ideally elasticplastic behavior.
Overloaded function.
__init__(self: woo.dem.Law2_L6Geom_FrictPhys_IdealElPl) > None
__init__(self: woo.dem.Law2_L6Geom_FrictPhys_IdealElPl, *args, **kwargs) > None

iniEqlb
(= False)¶ Consider the intial distance as equilibrium distance (saved in contact data, subtracted from L6Geom.uN); enabling during simulation will only affect newly created contacts; disabling will affect all contacts.
[type: bool]

relRollStiff
(= 0.0)¶ Rolling stiffness relative to
FrictPhys.kn
×charLen
(with w``charLen`` being the sum ofL6Geom.lens
). If nonpositive, there is no rolling/twisting resistance.[type: Real]

relTwistStiff
(= 0.0)¶ Twisting stiffness relative to rolling stiffness (see
relRollStiff
).[type: Real]

rollTanPhi
(= 0.0)¶ Rolling friction angle – the rolling force will not exceed Fn × rollTanPhi. This value is applied separately to twisting as well. If nonpositive, there is no rolling/twisting resistance.
[type: Real, range: 0−1.5708]

noSlip
(= False)¶ Disable plastic slipping
[type: bool]

noBreak
(= False)¶ Disable removal of contacts when in tension.
[type: bool]

noFrict
(= False)¶ Turn off friction computation, it will be always zero regardless of material parameters
[type: bool]

plastDissipIx
(= 1)¶ Index of plastically dissipated energy
[type: int, not saved, not accessible from python]

elastPotIx
(= 1)¶ Index for elastic potential energy
[type: int, not saved, not accessible from python]

brokenIx
(= 1)¶ Index for energy lost in broken contacts with nonzero force
[type: int, not saved, not accessible from python]
Law2_L6Geom_LudingPhys¶
Object
→ Functor
→ LawFunctor
→ Law2_L6Geom_LudingPhys

class
woo.dem.
Law2_L6Geom_LudingPhys
(*args, **kwargs)¶ Contact law implementing
ludingcontactmodel
.Overloaded function.
__init__(self: woo.dem.Law2_L6Geom_LudingPhys) > None
__init__(self: woo.dem.Law2_L6Geom_LudingPhys, *args, **kwargs) > None

wImmediate
(= True)¶ Increment plastic & viscous work in
S.energy
in every step rather than commiting the sum when contact dissolves. Note thatParticle.matState
(if aLudingMatState
) is always updated only when the contact dissolves.[type: bool]

viscIx
(= 1)¶ Index of viscous dissipation.
[type: int, not saved, not accessible from python]

plastIx
(= 1)¶ Index of plastic dissipation.
[type: int, not saved, not accessible from python]
Law2_L6Geom_IcePhys¶
Object
→ Functor
→ LawFunctor
→ Law2_L6Geom_IcePhys

class
woo.dem.
Law2_L6Geom_IcePhys
(*args, **kwargs)¶ Contact law implementing
icecontactmodel
.Overloaded function.
__init__(self: woo.dem.Law2_L6Geom_IcePhys) > None
__init__(self: woo.dem.Law2_L6Geom_IcePhys, *args, **kwargs) > None

iniEqlb
(= True)¶ Set the intial distance as equilibrium distance (saved in
IcePhys.uN0
, subtracted from L6Geom.uN); enabling during simulation will only affect newly created contacts).[type: bool]

elastIx
(= 1)¶ Index of elastic energy (cache).
[type: int, readonly in python]

brokenIx
(= 1)¶ Index of energy which disappeared when contacts broke (cache).
[type: int, readonly in python]

plastIx
(= 1)¶ Index of plastically dissipated energy (cache).
[type: int, readonly in python]
Law2_L6Geom_FrictPhys_LinEl6¶
Object
→ Functor
→ LawFunctor
→ Law2_L6Geom_FrictPhys_LinEl6

class
woo.dem.
Law2_L6Geom_FrictPhys_LinEl6
(*args, **kwargs)¶ Ideally elasticplastic behavior.
Overloaded function.
__init__(self: woo.dem.Law2_L6Geom_FrictPhys_LinEl6) > None
__init__(self: woo.dem.Law2_L6Geom_FrictPhys_LinEl6, *args, **kwargs) > None

charLen
(= 1.0)¶ Characteristic length, which is equal to stiffnesses ratio kNormal/kTwist and kShear/kBend. Must be nonnegative.
[type: Real, unit: m]

elastPotIx
(= 1)¶ Index for elastic potential energy
[type: int, not saved, not accessible from python]
Law2_L6Geom_HertzPhys_DMT¶
Object
→ Functor
→ LawFunctor
→ Law2_L6Geom_HertzPhys_DMT

class
woo.dem.
Law2_L6Geom_HertzPhys_DMT
(*args, **kwargs)¶ Law for Hertz contact with optional adhesion (DMT (DerjaguinMullerToporov) [DMT75]), nonlinear viscosity ([AE11]) The formulation is taken mainly from [Joh87]. The parameters are given through
Cp2_FrictMat_HertzPhys
. More details are given inhertzian_contact_models
.Overloaded function.
__init__(self: woo.dem.Law2_L6Geom_HertzPhys_DMT) > None
__init__(self: woo.dem.Law2_L6Geom_HertzPhys_DMT, *args, **kwargs) > None

noAttraction
(= True)¶ Avoid nonphysical normal attraction which may result from viscous effects by making the normal force zero if there is attraction (\(F_n>0\)). This condition is only applied to elastic and viscous part of the normal force. Adhesion, if present, is not limited. See [AE11], the ‘Model choice’ section (pg. 5), for discussion of this effect. .. note:: It is technically not possible to break the contact completely while there is still geometrical overlap, so only force is set to zero but the contact still exists.
[type: bool]

nCallsIters
¶ Count number of calls of the functor and of iterations in the Halley solver (if used).
[type: OpenMPArrayAccumulator<int>, not shown in the UI, not dumped]

avgIter
(= nan)¶ Average number of Halley iterations per contact when using the Schwarz model (updated ondemand).
[type: Real, readonly in python]

digits
(= 26)¶ Precision for Halley iteration with the Schwarz model, measured in binary digits; the maximum is the number of digits of the floating point type for given platform. Precision above 2/3 of the maximum will very likely have no effect on the result, but it will require extra (few) iterations before converging.
[type: int, range: 1−53]

plastIx
(= 1)¶ Index of plastically dissipated energy.
[type: int, not saved, not accessible from python]

viscNIx
(= 1)¶ Index of viscous dissipation in the normal sense.
[type: int, not saved, not accessible from python]

viscTIx
(= 1)¶ Index of viscous dissipation in the tangent sense.
[type: int, not saved, not accessible from python]

elastPotIx
(= 1)¶ Index for elastic potential energy.
[type: int, not saved, not accessible from python]

dmtIx
(= 1)¶ Index for elastic energy of new/broken contacts.
[type: int, not saved, not accessible from python]

resetCounters
(self: woo.dem.Law2_L6Geom_HertzPhys_DMT) → None¶ Reset nCallsIters and thus avgIter.
LawDispatcher¶
Object
→ Engine
→ Dispatcher
→ LawDispatcher

class
woo.dem.
LawDispatcher
(*args, **kwargs)¶ Dispatcher calling
functors
based on received argument type(s).Overloaded function.
__init__(self: woo.dem.LawDispatcher) > None
__init__(self: woo.dem.LawDispatcher, *args, **kwargs) > None

functors
(= [])¶ Functors active in the dispatch mechanism [overridden below].
[type: vector<shared_ptr<LawFunctor>>]

dispFunctor
(self: woo.dem.LawDispatcher, arg0: woo.dem.CGeom, arg1: woo.dem.CPhys) → woo.dem.LawFunctor¶ Return functor that would be dispatched for given argument(s); None if no dispatch; ambiguous dispatch throws.

dispMatrix
(self: woo.dem.LawDispatcher, names: bool = True) → dict¶ Return dictionary with contents of the dispatch matrix.
Testing contact laws¶
TODO
LawTester¶

class
woo.dem.
LawTester
(*args, **kwargs)¶ Engine for testing contact laws by prescribing various loading scenarios, which are a combination of prescribing force or velocity along given contactlocal axes.
Overloaded function.
__init__(self: woo.dem.LawTester) > None

ids
(= Vector2i(5924305, 0))¶ Ids of particles in contact
[type: Vector2i]

done
(= 'tester.dead=True')¶ Python expression to run once all stages had finished. This is run after
LawTesterStage.done
of the last stage.[type: string]

abWeight
(= 1.0)¶ Float, usually ∈〈0,1〉, determining on how are displacements/rotations distributed between particles (0 for A, 1 for B); intermediate values will apply respective part to each of them.
[type: Real]

f
(= Vector6(0, 0, 0, 0, 0, 0))¶ Force on contact, NaN if contact is broken
[type: Vector6r, readonly in python]

k
(= Vector6(0, 0, 0, 0, 0, 0))¶ Tangent contact stiffness, NaN if there is no contact (or the contact model does not define it). Diagonal of the K matrix in df=Kdu.
[type: Vector6r, readonly in python]

smooF
(= Vector6(0, 0, 0, 0, 0, 0))¶ Smoothed value of generalized contact forces.
[type: Vector6r, readonly in python]

u
(= Vector6(0, 0, 0, 0, 0, 0))¶ Cumulative value of contact displacement, NaN if contact is broken
[type: Vector6r, readonly in python]

smooU
(= Vector6(0, 0, 0, 0, 0, 0))¶ Smoothed value of generalized contact displacements.
[type: Vector6r, readonly in python]

v
(= Vector6(0, 0, 0, 0, 0, 0))¶ Relative velocity on contact; NaN if the contact is broken
[type: Vector6r, readonly in python]

smooV
(= Vector6(0, 0, 0, 0, 0, 0))¶ Smoothed value of generalized contact relative velocity.
[type: Vector6r, readonly in python]

fErrRel
(= Vector6(inf, inf, inf, inf, inf, inf))¶ Relative error of contact force (with respect to smoothed value)
[type: Vector6r, readonly in python]

fErrAbs
(= Vector6(inf, inf, inf, inf, inf, inf))¶ Absolute error of contact force (with respect to smoothed value)
[type: Vector6r, readonly in python]

uErrRel
(= Vector6(inf, inf, inf, inf, inf, inf))¶ Relative error of contact displacement (with respect to smoothed value)
[type: Vector6r, readonly in python]

uErrAbs
(= Vector6(inf, inf, inf, inf, inf, inf))¶ Absolute error of contact displacement (with respect to smoothed value)
[type: Vector6r, readonly in python]

vErrRel
(= Vector6(inf, inf, inf, inf, inf, inf))¶ Relative error of contact velocity (with respect to smoothed value)
[type: Vector6r, readonly in python]

vErrAbs
(= Vector6(inf, inf, inf, inf, inf, inf))¶ Absolute error of contact velocity (with respect to smoothed value)
[type: Vector6r, readonly in python]

smoothErr
(= 1.0)¶ Smoothing factor for computing errors; if negative, set to smooth automatically.
[type: Real]

smooth
(= 0.0001)¶ Smoothing factor for computing smoothF
[type: Real]

stage
(= 0)¶ Current stage to be finished
[type: int, readonly in python]

stageT0
(= 1.0)¶ Time at which this stage was entered
[type: Real, readonly in python]

stages
(= [])¶ Stages to be reached during the testing
[type: vector<shared_ptr<LawTesterStage>>]

maxStageSteps
(= 100000)¶ Throw error if stage takes this many steps
[type: int, not shown in the UI]

fuv
(self: woo.dem.LawTester) → dict¶ Return python dictionary containing f,u,v,smooF,smooU,smooU; useful for plotting with woo.plot.addData(**tester.fuv())

restart
(self: woo.dem.LawTester) → None¶ Reset the tester to initial state; all stages are reset via
LawTesterStage.reset
, thewoo.core.Engine.dead
flag is unset.
LawTesterStage¶

class
woo.dem.
LawTesterStage
(*args, **kwargs)¶ Stage to be reached by LawTester.
Overloaded function.
__init__(self: woo.dem.LawTesterStage) > None
__init__(self: woo.dem.LawTesterStage, *args, **kwargs) > None

values
(= Vector6(0, 0, 0, 0, 0, 0))¶ Prescribed values during this step (DoFordering: x,y,z linear, x,y,z angular)
[type: Vector6r]

whats
(= Vector6i(0, 0, 0, 0, 0, 0))¶ Meaning of values components (DoFodering). The constructor acceps this attribute specified as string of 6 characters, where each of them can be:
.
for imposing nothing,v
for imposing velocity,i
for imposing initial velocity only,f
for imposing force.[type: Vector6i]

until
(= '')¶ Stage finishes when until (python expression) evaluates to True. Besides receiving global variables, several local variables are passed: C (contact object; None if contact does not exist), pA (first particle), pB (second particle), scene (current scene object), tester (LawTester object), stage (LawTesterStage object).
[type: string]

untilEvery
(= 1)¶ Test the
until
expression only every untilEvery steps (this may make the execution faster)[type: int]

done
(= '')¶ Run this python command when the stage finishes
[type: string]

step
(= 0)¶ Step in this stage
[type: int]

time
(= 0.0)¶ Time in this stage
[type: Real]

hadC
(= False)¶ Flag keeping track of whether there was a contact in this stage at all
[type: bool]

hasC
(= False)¶ Flag keeping track of whether there was a contact in this stage at all
[type: bool]

timeC0
(= nan)¶ Time of creating of the last contact (NaN if there has never been one).
[type: Real]

bounces
(= 0)¶ Number of sign changes of the normal relative velocity in this stage
[type: int]

property
broken
¶ Test whether an existing contact broke in this stage; this is useful for saying
until='stage.broken'
(equivalent tostage.hadC and not stage.hasC
). This is different fromuntil='not C'
, since this condition will be satisfied before any contact exists at all.

property
cTime
¶ Time since creation of the last contact (NaN if there has never been one). Useful for testing collision time after the condition
until='stage.rebound'
has been satisfied. Equivalent tostage.timestage.timeC0
.

property
rebound
¶ Test for rebound; rebound is considered complete when sign of relative normal velocity changed more than once (adhesive contacts may never separate once they are created – this catches a single period of the oscillation) or if contact
breaks
. Equivalent tostage.bounces>=2 or stage.broken
.

reset
(self: woo.dem.LawTesterStage) → None¶ Reset this stage to its initial stage such that it can be used again as if new. This is called automatically from
LawTester.restart
.
Stress/strain control¶
TODO
PeriIsoCompressor¶
Object
→ Engine
→ PeriIsoCompressor

class
woo.dem.
PeriIsoCompressor
(*args, **kwargs)¶ Compress/decompress cloud of spheres by controlling periodic cell size until it reaches prescribed average stress, then moving to next stress value in given stress series.
Overloaded function.
__init__(self: woo.dem.PeriIsoCompressor) > None
__init__(self: woo.dem.PeriIsoCompressor, *args, **kwargs) > None

stresses
(= [])¶ Stresses that should be reached, one after another
[type: vector<Real>]

charLen
(= 1.0)¶ Characteristic length, should be something like mean particle diameter (default 1=invalid value))
[type: Real]

maxSpan
(= 1.0)¶ Maximum body span in terms of bbox, to prevent periodic cell getting too small.
[type: Real, readonly in python]

maxUnbalanced
(= 0.0001)¶ if actual unbalanced force is smaller than this number, the packing is considered stable,
[type: Real]

globalUpdateInt
(= 20)¶ how often to recompute average stress, stiffness and unbalanced force
[type: int]

state
(= 0)¶ Where are we at in the stress series
[type: size_t]

doneHook
(= '')¶ Python command to be run when reaching the last specified stress
[type: string]

keepProportions
(= True)¶ Exactly keep proportions of the cell (stress is controlled based on average, not its components
[type: bool]

currUnbalanced
(= nan)¶ Current unbalanced force (updated internally)
[type: Real, readonly in python]

avgStiffness
(= nan)¶ Value of average stiffness (updated internally)
[type: Real, readonly in python]

sigma
(= Vector3(nan, nan, nan))¶ Current value of average stress (update internally)
[type: Vector3r, readonly in python]
WeirdTriaxControl¶
Object
→ Engine
→ WeirdTriaxControl

class
woo.dem.
WeirdTriaxControl
(*args, **kwargs)¶ Engine for independently controlling stress or strain in periodic simulations.
strainStress
contains absolute values for the controlled quantity, andstressMask
determines meaning of those values (0 for strain, 1 for stress): e.g.( 1<<0  1<<2 ) = 1  4 = 5
means thatstrainStress[0]
andstrainStress[2]
are stress values, andstrainStress[1]
is strain.See scripts/test/periodictriax.py for a simple example.
Overloaded function.
__init__(self: woo.dem.WeirdTriaxControl) > None
__init__(self: woo.dem.WeirdTriaxControl, *args, **kwargs) > None

goal
(= Vector3(0, 0, 0))¶ Desired stress or strain values (depending on stressMask), strains defined as
strain(i)=log(Fii)
.Warning
Strains are relative to the
woo.core.Scene.cell.refSize
(reference cell size), not the current one (e.g. at the moment when the new strain value is set).[type: Vector3r]

stressMask
(= 0)¶ mask determining strain/stress (0/1) meaning for goal components
[type: int]

maxStrainRate
(= Vector3(1, 1, 1))¶ Maximum strain rate of the periodic cell.
[type: Vector3r]

maxUnbalanced
(= 0.0001)¶ maximum unbalanced force.
[type: Real]

absStressTol
(= 1000.0)¶ Absolute stress tolerance
[type: Real]

relStressTol
(= 3e05)¶ Relative stress tolerance; if negative, it is relative to the largest stress value along all axes, where strain is prescribed.
[type: Real]

maxStrainedStress
(= nan)¶ Current absmaximum stress in straincontrolled directions; useda as reference when
relStressTol
is negative.[type: Real, readonly in python]

growDamping
(= 0.25)¶ Damping of cell resizing (0=perfect control, 1=no control at all).
[type: Real]

relVol
(= 1.0)¶ For stress computation, use volume of the periodic cell multiplied by this constant.
[type: Real]

globUpdate
(= 5)¶ How often to recompute average stress, stiffness and unbalaced force.
[type: int]

doneHook
(= '')¶ python command to be run when the desired state is reached
[type: string]

stress
(= Matrix3(0, 0, 0, 0, 0, 0, 0, 0, 0))¶ Stress tensor
[type: Matrix3r]

strain
(= Vector3(0, 0, 0))¶ cell strain, updated automatically
[type: Vector3r]

strainRate
(= Vector3(0, 0, 0))¶ cell strain rate, updated automatically
[type: Vector3r]

currUnbalanced
(= nan)¶ current unbalanced force (updated every globUpdate)
[type: Real]

prevGrow
(= Vector3(0, 0, 0))¶ previous cell grow
[type: Vector3r]

mass
(= nan)¶ mass of the cell (user set); if not set, it will be computed as sum of masses of all particles.
[type: Real]

externalWork
(= 0.0)¶ Work input from boundary controller.
[type: Real]

gradVWorkIx
(= 1)¶ Index for work done by velocity gradient, if tracking energy
[type: int, not saved, not accessible from python]
Particle¶
Each particles in DEM is defined by its shape (given by multiple nodes) and other parameters.
Particle¶

class
woo.dem.
Particle
(*args, **kwargs)¶ Particle in DEM
Overloaded function.

id
(= 1)¶ Index in DemField::particles
[type: id_t, readonly in python]

mask
(= 1)¶ Bitmask for collision detection and other (group 1 by default)
[type: uint]

matState
(= None)¶ Material state of the particle (such as damage data and similar)
[type: shared_ptr<
MatState
>]

contacts
(= {})¶ Contacts of this particle, indexed by id of the other particle.
[type: MapParticleContact, not saved, not accessible from python]

property
Ek
¶ Summary kinetic energy of the particle, shorthand for
p.Ekt+p.Ekr
.

property
Ekr
¶ Rotational kinetic energy of the particle, computed ondemand as \(\frac{1}{2}\vec{\omega}^T\mat{T}^T\mat{I}\mat{T}\omega\) (where \(\mat{T}\) is
p.shape.nodes[0].ori
as rotation matrix, \(\mat{I}\) isp.shape.nodes[0].dem.inertia
as diagonal matrix – uninodal particles only (raises exception otherwise). Space deformation is not considered here, seegetEk
.

property
Ekt
¶ Translational kinetic energy of the particle, computed ondemand as \(\frac{1}{2}m\vec{v}^2\) – uninodal particles only (raises exception otherwise). Space deformation is not considered here, see
getEk
.

property
allContacts
¶ Return dictionary mapping
other particles' IDs <Particle.id
toContact
objects, including contacts which are notreal
.

property
angVel
¶ Particle angular velocity; shorthand for
p.shape.nodes[0].dem.angVel
– uninodal particles only (raises exception otherwise).

property
blocked
¶ Blocked degrees of freedom of the particle; shorthand for
p.shape.nodes[0].dem.blocked
– uninodal particles only (raises exception otherwise).

property
con
¶ Return list of
IDs
of contacting particles (real
contacts only); shorthand forp.contacts.keys()
.

property
f
¶ Force on particle; shorthand for
p.shape.nodes[0].dem.force
– uninodal particles only (raises exception otherwise).

getEk
(self: woo.dem.Particle, trans: bool = True, rot: bool = True, scene: woo.core.Scene = None) → float¶ Compute kinetic energy (translational and/or rotational); when scene is given, only fluctuation linear/angular velocity will be considered if periodic boundary conditions are active.

property
impose
¶ Particle imposed constraints; shorthand for
p.shape.nodes[0].dem.impose
– uninodal particles only (raises exception otherwise).

property
inertia
¶ Particle inertia; shorthand for
p.shape.nodes[0].dem.inertia
– uninodal particles only (raises exception otherwise).

static
make
(shape: woo.dem.Shape, mat: woo.dem.Material, fixed: bool = False) → woo.dem.Particle¶ Return Particle instance created from given shape and material; nodes with DemData are automatically added to the shape, mass and inertia is recomuted.

property
mass
¶ Particle mass; shorthand for
p.shape.nodes[0].dem.mass
– uninodal particles only (raises exception otherwise).

property
mat
¶ Material of the particle

property
nodes
¶ List of particle nodes; shorthand for
p.shape.nodes
.

property
ori
¶ Particle orientation; shorthand for
p.shape.nodes[0].ori
– uninodal particles only (raises exception otherwise).

property
pos
¶ Particle position; shorthand for
p.shape.nodes[0].pos
– uninodal particles only (raises exception otherwise).

property
refPos
¶ Reference particle position; shorthand for
p.shape.nodes[0].gl.refPos
, andVector3(nan,nan,nan)
ifgl
is not defined on the node.

property
t
¶ Torque on particle; shorthand for
p.shape.nodes[0].dem.torque
– uninodal particles only (raises exception otherwise).

property
tacts
¶ Return list of
Contact
objects where this particle takes part (real
contacts only); shorthand forp.contact.values()
.

updateMassInertia
(self: woo.dem.Particle) → None¶ Internal use only. Recompute mass and inertia of all particle’s nodes; this function is usually called by particle construction routines; interally calls
Shape::updateMassInertia
and only works for particles without shared nodes.

property
vel
¶ Particle velocity; shorthand for
p.shape.nodes[0].dem.vel
– uninodal particles only (raises exception otherwise).

Shape¶

class
woo.dem.
Shape
(*args, **kwargs)¶ Particle geometry
Overloaded function.

nodes
(= NodeList[])¶ Nodes associated with this particle
[type: vector<shared_ptr<Node> >]

color
(= 0.5129323944043984)¶ Normalized color for rendering; negative values render with wire (rather than solid), \(\text{color}\)>2 means invisible. (use wire, hi and visible to manipulate those)
[type: Real]

asRaw
(self: woo.dem.Shape) → tuple¶

dispHierarchy
(self: woo.dem.Shape, names: bool = True) → list¶ Return list of dispatch classes (from down upwards), starting with the class instance itself, toplevel indexable at last. If names is true (default), return class names rather than numerical indices.

property
dispIndex
¶ Return class index of this instance.

property
equivRadius
¶ Volumetrically equivalent radius of this shape. Returns NaN if the shape is multinodal or infinite.

isInside
(self: woo.dem.Shape, pt: _wooEigen11.Vector3) → bool¶ Fast predicate testing whether pt is inside or outside this shape.

lumpMassInertia
(self: woo.dem.Shape, arg0: woo.core.Node, arg1: float) → tuple¶

setFromRaw
(self: woo.dem.Shape, arg0: _wooEigen11.Vector3, arg1: float, arg2: woo.core.NodeList, arg3: List[float]) → None¶

property
volume
¶ Volume of this shape; returns NaN for multinodal or infinite shapes.

Facet¶

class
woo.dem.
Facet
(*args, **kwargs)¶ Facet (triangle in 3d) particle.
Overloaded function.

fakeVel
(= Vector3(0, 0, 0))¶ Fake velocity when computing contact, in global coordinates (for modeling moving surface modeled using static triangulation); only inplane velocity is meaningful, but this is not enforced.
Note
If the xcomponent is NaN, the meaning is special:
fakeVel
is taken as zero vector and, in addition, local inplane facet’s linear velocity at the contact is taken as zero (rather than linearly interpolated between velocity of nodes).[type: Vector3r]

halfThick
(= 0.0)¶ Geometric thickness (added in all directions)
[type: Real]

n21lim
(= Vector3(nan, nan, nan))¶ Edge & vertex contact: limit value for dotproduct with normal (dotproduct of normal with inplane angle of neighboring facet, perpendicular to the edge).
[type: Vector3r]

area
(self: woo.dem.Facet) → float¶ Return surface area of the facet

computeNeighborAngles
(self: woo.dem.Facet) → None¶ Compute
n21Min
using beighboring facets so that contact direction can be adjusted (only some FacetX functors support that currently).

getCentroid
(self: woo.dem.Facet) → _wooEigen11.Vector3¶ Return centroid of the facet

getNormal
(self: woo.dem.Facet) → _wooEigen11.Vector3¶ Return normal vector of the facet

static
make
(vertices, fakeVel=None, halfThick=0.0, fixed=True, wire=True, color=None, highlight=False, mat=<function defaultMaterial>, visible=True, mask=3, flex=None, __class=<class 'woo.dem.Facet'>)¶ Create facet with given parameters.
 Parameters
vertices ([Vector3,Vector3,Vector3]) – coordinates of vertices in the global coordinate system.
wire (bool) – if
True
, facets are shown as skeleton; otherwise facets are filled
See
woo.utils.sphere
’s documentation for meaning of other parameters.

outerEdgeNormals
(self: woo.dem.Facet) → List[_wooEigen11.Vector3]¶ Return outer edge normal vectors

Rod¶

class
woo.dem.
Rod
(*args, **kwargs)¶ Line element without internal forces, with circular crosssection and hemispherical caps at both ends. Geometrically the same
Capsule
, but with 2 nodes.Overloaded function.

radius
(= nan)¶ Radius of the rod.
[type: Real]

static
make
(vertices, radius, fixed=True, wire=True, color=None, mat=<function defaultMaterial>, visible=True, mask=3, __class=<class 'woo.dem.Rod'>)¶ Create
Rod
with given parameters: Parameters
vertices – endpoints given as coordinates (Vector3) or nodes
radius – radius of the rod
wire – render as wire by default
color – color as scalar (0…1); if not given, random color is assigned
mat – material; if not given, default material is assigned
visible –
mask –

Truss¶

class
woo.dem.
Truss
(*args, **kwargs)¶ Describes line element (cylinder) with optional caps and with free or constrained rotations at either end.
Overloaded function.

l0
(= nan)¶ Initial (usually equilibrium) length
[type: Real]

axialStress
(= 0.0)¶ Current normal stress (informative only)
[type: Real]

preStress
(= 0.0)¶ Prestress (stress at zero strain)
[type: Real]

Sphere¶

class
woo.dem.
Sphere
(*args, **kwargs)¶ Spherical particle.
Overloaded function.

radius
(= nan)¶ Radius.
[type: Real, unit: m]

static
make
(center, radius, mat=<function defaultMaterial>, fixed=False, wire=False, color=None, highlight=False, mask=5, vel=None)¶ Create sphere with given parameters; mass and inertia computed automatically.
 Parameters
center (Vector3) – center
radius (float) – radius
floatorNone – particle’s color as float; random color will be assigned if
None
.mat –
 specify
woo.dem.Particle.material
; different types are accepted: woo.dem.Material
instance: this instance will be usedcallable: will be called without arguments; returned Material value will be used (Material factory object, if you like)
 specify
mask (int) –
woo.dem.Particle.mask
for the body
 Returns
Particle instance with desired characteristics.
Instance of material can be given:
>>> from woo import utils >>> s1=utils.sphere((0,0,0),1,wire=False,color=.7,mat=ElastMat(young=30e9,density=2e3)) >>> s1.shape.wire False >>> s1.shape.color 0.7 >>> s1.mat.density 2000.0
Finally, material can be a callable object (taking no arguments), which returns a Material instance. Use this if you don’t call this function directly (for instance, through woo.pack.randomDensePack), passing only 1 material parameter, but you don’t want material to be shared.
For instance, randomized material properties can be created like this:
>>> import random >>> def matFactory(): return ElastMat(young=1e10*random.random(),density=1e3+1e3*random.random()) ... >>> s2=utils.sphere([0,2,0],1,mat=matFactory) >>> s3=utils.sphere([1,2,0],1,mat=matFactory)

Capsule¶

class
woo.dem.
Capsule
(*args, **kwargs)¶ Cylinder with halfspherical caps on both sides, Mindowski sum of segment with sphere.
Overloaded function.

radius
(= nan)¶ Radius of the capsule – of halfspherical caps and also of the middle part.
[type: Real, unit: m]

shaft
(= nan)¶ Length of the middle segment
[type: Real, unit: m]

endPt
(self: woo.dem.Capsule, i: int) → _wooEigen11.Vector3¶ Return one of capsule endpoints. The first (negative on local \(x\)axis) is returned with *i=0, otherwise the second one is returned.

static
make
(center, radius, shaft, ori=Quaternion((1, 0, 0), 0), fixed=False, color=None, wire=False, mat=<function defaultMaterial>, mask=5)¶ Return a readymade capsule particle.

InfCylinder¶
Object
→ Shape
→ InfCylinder

class
woo.dem.
InfCylinder
(*args, **kwargs)¶ Object representing infinite plane aligned with the coordinate system (axisaligned wall).
Overloaded function.
__init__(self: woo.dem.InfCylinder) > None
__init__(self: woo.dem.InfCylinder, *args, **kwargs) > None

radius
(= nan)¶ Radius of the cylinder
[type: Real]

axis
(= 0)¶ Axis of the normal; can be 0,1,2 for +x, +y, +z respectively (Node’s orientation is disregarded for walls)
[type: int]

glAB
(= Vector2(nan, nan))¶ Endpoints between which the infinite cylinder is drawn, in local coordinate system along
axis
; if NaN, taken from scene view to be visible[type: Vector2r]

static
make
(position, radius, axis, glAB=None, fixed=True, mass=0, color=None, wire=False, angVel=None, mat=<function defaultMaterial>, mask=5)¶ Return a readymade infinite cylinder particle.
Ellipsoid¶

class
woo.dem.
Ellipsoid
(*args, **kwargs)¶ Ellipsoidal particle.
Overloaded function.
__init__(self: woo.dem.Ellipsoid) > None

semiAxes
(= Vector3(nan, nan, nan))¶ Semiprincipal axes.
[type: Vector3r, unit: m]

static
make
(center, semiAxes, ori=Quaternion((1, 0, 0), 0), angVel=None, color=None, mat=<function defaultMaterial>, fixed=False, wire=False, visible=True, mask=5, **kw)¶ Return an
woo.dem.Ellipsoid
particle.
Wall¶

class
woo.dem.
Wall
(*args, **kwargs)¶ Object representing infinite plane aligned with the coordinate system (axisaligned wall).
Overloaded function.

sense
(= 0)¶ Which side of the wall interacts: 1 for negative only, 0 for both, +1 for positive only.
[type: int]

axis
(= 0)¶ Axis of the normal; can be 0,1,2 for +x, +y, +z respectively (Node’s orientation is disregarded for walls)
[type: int]

glAB
(= AlignedBox2((nan, nan), (nan, nan)))¶ Points between which the wall is drawn (if NaN, computed automatically to cover the visible part of the scene)
[type: AlignedBox2r]

static
make
(position, axis, sense=0, glAB=None, fixed=True, mass=0, color=None, mat=<function defaultMaterial>, visible=True, mask=3)¶ Return readymade wall body.
 Parameters
position (floatorVector3orNode) – center of the wall. If float, it is the position along given axis, the other 2 components being zero
axis (∈{0,1,2}) – orientation of the wall normal (0,1,2) for x,y,z (sc. planes yz, xz, xy)
sense (∈{1,0,1}) – sense in which to interact (0: both, 1: negative, +1: positive; see
woo.dem.Wall
)
See
woo.utils.sphere
’s documentation for meaning of other parameters.

static
makeBox
(box, which=(1, 1, 1, 1, 1, 1), **kw)¶ Return box delimited by walls, created by
woo.dem.Wall.make
, which receives most arguments.Wall.glAB
are computed automatically so that walls visually end at the edges.Note
Since
walls
are infinite, they will still interact with other particle beyond this box; usewoo.triangulated.box
for true box with arbitrary orientation. Parameters
box – axisaligned box determining positions of walls.
which – determines which of the 6 walls are created (boolean values), in the order x, y, z, +x, +y, +z. For instance, to create a box which does not have the top, say
which=(1,1,1,1,1,0)
).
 Returns
list of
Particle
objects.
