24. AGX Terrain

agxTerrain is a library of classes that is used to model a wide variety of earthmoving scenarios such as bulldozing, wheel loading, excavation and trenching. The deformable agxTerrain::Terrain model is based on a regular 3D grid data structure and an overlapping surface height field. The terrain can be deformed by interacting agxTerrain::Shovel objects to perform different operations, such as digging, push/pull and grading.

../_images/earth_moving.png

The underlying terrain data model consists of a 3D grid of cells, containing terrain data such as mass, compaction and soil type information. The terrain surface is represented as a 2D height field that is updated when the underlying grid structure is changed, mainly through excavation.

Mass is moved in the terrain via interacting agxTerrain::Shovels that converts solid cells to dynamic mass in the form of soil particles with 6-degrees of freedom. The dynamic soil is pushed via the shovel through kinematic coupling. A mass aggregate body is constructed from the dynamics mass in failure zones predicted from soil mechanics theory using terrain material properties. These aggregates create a resistance to the shovel due to their inertia, acting through contacts in the soil failure plane. The dynamic soil is merged back into the terrain when approaching a steady state on the terrain surface.

Python tutorials and examples can be found in the data/tutorials/agxTerrain folder of the AGX Dynamics installation.

This User Manual section focus on the practical application of the terrain module. We refer to the academic paper 1 for a more in-depth explanation of the underlying mathematical and physical models.

24.1. Workflow

The main classes that the user interacts with when working with agxTerrain is as follows:

agxTerrain::Terrain

The deformable terrain object.

agxTerrain::Shovel

Shovel object that converts solid mass in an agxTerrain::Terrain object to Dynamic mass via an active zone.

agxTerrain::TerrainMaterial

Object that holds material properties used to characterize soil behavior such as compaction, soil particle dynamics and bulk properties.

agxTerrain::TerrainProperties

Object that holds generic terrain properties such as disable/enable for different features and locking terrain borders.

agxTerrain::SoilSimulationInterface

Interface for controlling the soil simulation governing dynamic soil behavior.

agxTerrain::TerrainGridControl

Controller for accessing and controlling the underlying terrain data on grid element level.

The overall work flow for setting up a terrain model is as follows:

  1. Create a agxTerrain::Terrain object from resolution data or an existing height field.

  2. Create and configure agxTerrain::Shovel objects by specifying a shovel body, cutting edge, top edge and cutting direction.

  3. Configure the Terrain Material Configuration. For example, change the default agxTerrain::TerrainMaterial and specify other soil type domains.

  4. Setup contact materials between the terrain and external objects, especially the shovel-terrain contact materials.

  5. Calibrate excavation resistance by configuring shovel-terrain contact material and soil properties.

  6. (Optional) Modify the terrain properties via the agxTerrain::TerrainProperties class.

  7. (Optional) Modify the terrain grid structure using the agxTerrain::TerrainGridControl class.

  8. (Optional) Configure the dynamic soil.

24.2. Terrain

agxTerrain::Terrain is the main class of the agxTerrain library and represents the actual deformable terrain object. It supports the following features:

The underlying terrain data model consists of a 3D grid of cells. Terrain data such as mass, compaction and soil type information is stored discretely in each cell. The terrain surface is represented as a 2D height field that is updated when the underlying grid structure is changed, mainly through excavation.

Surface terrain data, such as terrain height, is accessed by specifying a 2D x and y coordinate called terrain index, which references a single discrete surface grid point on the terrain. The origin (x:0, y:0) is in the lower leftmost gridpoint and the maximum coordinate in the upper rightmost gridpoint ( x: resolutionX-1, y: resolutionY-1 )

../_images/terrain_index_outline.png

Fig. 24.1 Figure showing the index mapping of the agxTerrain::Terrain gridpoints. The origin (x:0, y:0) is in the lower leftmost gridpoint and the maximum coordinate in the upper rightmost gridpoint ( x: resolutionX-1, y: resolutionY-1 )

24.2.1. Terrain Setup

An agxTerrain::Terrain object can either be created by specifying the 2D size and resolution data or by using an existing height field. The data cells in the terrain is symmetric by design which means that the user is constrained to setting resolution and cell size to ensure that we have a valid data structure.

Note

It is also possible to create a terrain using an arbitrary geometry via the Terrain Pager.

The following code can be used to create a terrain by specifying the 2D size and resolution data:

// Construct a Terrain with 101-by-101 elements with element size 0.1 m
// and a maximum depth of 2.5 m and it to the simulation
agxTerrainRef terrain = new agxTerrain::Terrain(51, 51, 0.2, 2.5);
sim->add(terrain);

maximumDepth is the maximum depth below 0 that the terrain can have in it’s local z-direction. The elementSize sets the uniform size of the 3D grid cells in the terrain structure. The total length of the terrain in either axis will thus become (resolutionX-1) * elementSize in either direction.

Creating a terrain object from an existing height field is done by using the following method:

agxCollide::HeightFieldRef heightField = ... // Create the height field
// Supply height field object and a maximum depth in meters for the terrain
agxTerrain::TerrainRef terrain = agxTerrain::Terrain::createFromHeightField(heightField, 0.5);

Warning

The specified height field must have symmetric scale. I.e. the distance between vertices in x-direction must be the same as in y-direction. An agx::LOGGER_WARNING will tell you if you have a unsymmetrical height field scale and a nullptr will be return from the function.

Below follows some common operations on the terrain to access data:

size_t res = 51;
agxTerrainRef terrain = new agxTerrain::Terrain(51, 51, 0.2, 2.5);
sim->add(terrain);

// Returns the local height of the terrain at the lower left corner
terrain->getHeight(0,0);

// Returns the surface world position of the terrain at upper right corner index 50,50
terrain->getSurfacePositionWorld(res-1,res-1);

24.3. Shovel

Note

Only agxTerrain::Shovels can perform excavation and digging operations in the Terrain. Note that terrain compaction can be performed by all bodies.

agxTerrain::Shovel objects are used in order to deform the terrain. A shovel is an object that can represent different types of tools used in earthmoving operations: excavator bucket, wheel loader bucket and a bulldozer blade. The shovel deforms the terrain during digging and deformation operations that creates failure/active zones that converts solid mass in the terrain to dynamic mass. The shovel experiences feedback forces from penetration resistance and soil aggregates that are generated from the masses in the active zones. The shovel can also compress the soil when no excavation is in progress.

../_images/basic_shovel.png

Fig. 24.2 Figure of a simple two-body agxTerrain::Shovel digging in a agxTerrain::Terrain object, converting solid mass to dynamic soil particle mass in the active zone ( light blue wedges in front, to the side and in the back of the shovel ).

A shovel can deform the terrain via the following applications:

Digging

This is done by driving the shovel in the cutting direction into the terrain, converting solid mass to dynamic mass. See Fig. 24.3 left.

Push/Pull

This is done via doing push/pull operations with the sides or backside of the shovel. See Fig. 24.3 middle.

Grading

This is moving the soil using the backside of the shovel. See Fig. 24.3 right.

../_images/shovel_deformation.png

Fig. 24.3 Figure showing the different excavation operations of a shovel.

24.3.1. Shovel Setup

A shovel is created from a rigid body model of the shovel using a different set of vectors. A top edge, cutting edge and cutting direction needs to be specified by the user in local body coordinates and should coincide with the geometry. Both simple box geometries and more complex mesh shapes can be used.

../_images/shovel_setup.png

Fig. 24.4 Figure of the basic components needed in order to create a shovel. A Rigid body representing the shovel object. A top edge is placed on the upper confines of the expected digging area, a cutting edge is placed on the lowest confines of the digging are and a cutting direction is placed along the expected cutting direction of the shovel which is parallel to the bottom plate of the shovel.

The placement of the vectors should be as described below and visualised in Fig. 24.5:

  • The top edge should ideally be placed at the upper confines of the cross-sectional digging area.

  • The cutting edge should coincide with the lowest edge fo the shovel that is expected to initially cut the soil soil. It should be placed at the base of the shovel teeth geometry of they exist.

  • The cutting direction should be placed along the direction of the bottom plate of the shovel.

../_images/excavator_bucket.png

Fig. 24.5 Figure showing the shovel vector placement for an excavator bucket. The cutting direction should be placed parallel to the bottom plate of the shovel. The cutting edge should be placed at the tip of the shovel and the base of the teeth geometry.

A shovel is created via the following constructor and then added to the terrain:

agxTerrain::ShovelRef shovel = agxTerrain::Shovel( agx::RigidBody* shovelBody,
                                                   const agx::Line& topEdge,
                                                   const agx::Line& cuttingEdge,
                                                   const agx::Vec3& cuttingVector );
terrain->add(shovel)

See shovel settings for various options that is used to modify shovel behaviour.

24.4. Terrain Material Configuration

The agxTerrain::TerrainMaterial objects govern internal terrain behaviour and contains dynamic soil interaction parameters, internal soil contact parameters, angle of repose, compaction, etc, which may vary depending on soil type.

The agxTerrain::Terrain holds a default agxTerrain::TerrainMaterial, which applies everywhere unless other soil types are added. There are get/set methods for interacting with the default agxTerrain::TerrainMaterial:

// Get the currently assigned default terrain material
agxTerrain::TerrainMaterialRef defaultTerrainMaterial = terrain->getTerrainMaterial();

// Create a new TerrainMaterial with default parameters, and set it as the default terrain material
agxTerrain::TerrainMaterialRef terrainMaterial = new agxTerrain::TerrainMaterial()
terrain.setTerrainMaterial(terrainMaterial)

It is also possible to add several other agxTerrain::TerrainMaterial to the terrain, representing different soil types in different regions. To do this, use the addTerrainMaterial method:

agxTerrain::Terrain::addTerrainMaterial(agxTerrain::TerrainMaterial* terrainMaterial);
agxTerrain::Terrain::addTerrainMaterial(agxTerrain::TerrainMaterial* terrainMaterial, agxCollide::Geometry* geometry);

The first method only adds the terrain material to the terrain, without assigning it to any area. The second method adds the terrain material to the overlap between the terrain and the geometry. This is the part of the terrain below the height field and the geometry that intersects.

If a terrain material has been added, it can be removed entirely, together with any domain assignment, with the removeTerrainMaterial method:

agxTerrain::Terrain::removeTerrainMaterial(agxTerrain::TerrainMaterial* terrainMaterial);

If the user wants to keep the assigned domain but simply change the material, there is a method for that aswell:

bool agxTerrain::Terrain::exchangeTerrainMaterial(TerrainMaterial* oldTerrainMaterial, TerrainMaterial* newTerrainMaterial);

Note

The default terrain material can not be removed, but it can be exchanged.

agxTerrain::TerrainMaterial properties can be configured according to the desired effects. There is also pre-calibrated material presets for the agxTerrain::TerrainMaterial objects to choose from, if you do not wish to specify their properties manually. The user can also specify their own presets. All preset materials can be found under the data/MaterialLibrary/TerrainMaterials in the AGX Dynamics installation folder.

Note

We recommended that new users start with a material preset as a starting point before manually configuring their own TerrainMaterial.

Refer to the agxTerrain::TerrainMaterial section to get an overview of all available soil parameters.

24.5. Setup Contact Materials

There are 5 types of interactions that the terrain can have:

Shovel-Terrain

This is the interaction between the shovel and the terrain that happens via aggregate formation during excavation and deformation. The contact parameters here are derived from the contact materials specified between the shovel and the terrain. See calibration of excavation resistance.

Object-Terrain

This is the interaction between the terrain and external objects such as wheels and tracks.

Particle-Object

The interaction between the dynamic soil and the external object, such as shovels and tracks.

Particle-Particle

The interactions between the dynamic soil particles.

Particle-Terrain

The interactions between the dynamic soil particles and the terrain surface.

Each of these interactions depend on the defined contact materials between the relevant materials.

24.5.1. Internal Materials

In the case of interactions with the terrain, every agxTerrain::TerrainMaterial in the terrain has a link to an internal associated agx::Material. To access the associated materials with any terrain material, use the following get/set methods:

agx::Material* Terrain::getAssociatedMaterial(TerrainMaterial* terrainMaterial);
bool Terrain::setAssociatedMaterial(TerrainMaterial* terrainMaterial, agx::Material* material);

If no additional terrain materials have been added, the getMaterial method can be used to get all the relevant internal materials:

agx::Material* getMaterial(agxTerrain::Terrain::MaterialType type) const;

Where the type variable is either:

MaterialType::TERRAIN

This is the default material set on the terrain surface. This material can be extracted and used to construct contact material parameters between the terrain ground and vehicle.

MaterialType::PARTICLE

The internal material for the dynamic soil particles in the terrain internal simulation. This material is used for interactions with the dynamic soil.

The total Shovel-Terrain interaction feedback is a combination of agxTerrain::TerrainMaterial and agx::Material properties. This can be configured in the following ways:

  1. Specifying the agxTerrain::TerrainMaterial objects in the Terrain. There are pre-calibrated material presets for the agxTerrain::TerrainMaterial objects to choose from, if you do not wish to specify their properties manually.

  2. Extracting the associated agx::Material instances from the terrain in order to create shovel-terrain contact materials for objects interacting with the terrain. This will affect interaction force feedback with the tool.

Note

The coupling between the Shovel and the dynamics soil particles are kinematic. The force feedback on the shovel comes from contact with soil aggregates that are constructed from the particles. So the defined Shovel <-> Terrain contact materials is what is driving excavation and penetration resistance.

24.5.2. Shovel - Terrain Contact Materials

The contact materials specified between the shovel and the terrain are some of the primary determinants of excavation resistance. The contact properties are used in the shovel-aggregate contacts for all excavation modes. It is also used in regular geometry contacts between the shovel and the terrain when excavation mode is active. For each soil type added to the terrain instance there is a contact material between that soil types associated material and the shovels material.

To set up the contact material for the default part of the terrain, the following code can be used:

agx::MaterialRef shovelMaterial = new agx::Material("Shovel");
simulation->add(shovelMaterial);

// ... set the shovel material on the shovel bodies
agxUtil::setBodyMaterial(shovelBody, shovelMaterial);

agx::MaterialRef terrainMaterial = terrain->getMaterial( agxTerrain::Terrain::MaterialType::TERRAIN );
agx::ContactMaterialRef shovelTerrainCM = new agx::ContactMaterial( shovelMaterial, terrainMaterial );
shovelTerrainCM->setFrictionCoefficient( 0.4 );
shovelTerrainCM->setYoungsModulus( 1e8 );
shovelTerrainCM->setRestitution( 0.0 );
shovelTerrainCM->setAdhesion( 0, 0 );
simulation->add( shovelTerrainCM );

To set up the contact material with a part of the terrain where another soil type was added, the following code can be used:

agx::MaterialRef shovelMaterial = new agx::Material("Shovel");
simulation->add(shovelMaterial);
// Get and add a terrain material
agxTerrain::TerrainMaterial dirt = terrain->getLibraryMaterial("dirt_1");
terrain->addTerrainMaterial(dirt);
// Get the associated material
agx::Material dirtAgxMaterial = terrain->getAssociatedMaterial(dirt);
// Define the contact material between dirt<->shovel
agx::ContactMaterialRef shovelDirtCM = new agx::ContactMaterial( shovelMaterial, dirtAgxMaterial );
shovelDirtCM->setFrictionCoefficient( 0.4 );
shovelDirtCM->setYoungsModulus( 1e8 );
shovelDirtCM->setRestitution( 0.0 );
shovelDirtCM->setAdhesion( 0, 0 );
simulation->add( shovelDirtCM );

Refer to the section Terrain material configuration for a description of how to add different soil types to the terrain and the section on internal materials to configure associated materials with the terrain materials.

Note

When the shovel interacts with a part of the terrain that intersects two or more regions where there are different soil types, the contact material properties are averaged.

24.5.3. Object - Terrain Contact Materials

The Object-Terrain contact materials can be used to calibrate the interaction between the terrain and external objects such as wheels or tracks. The code to setup these contact materials are similar to how the Shovel-Terrain contact materials are defined. Just use the agx::Material of the object instead of the shovel!

agx::MaterialRef objectMaterial = new agx::Material("ExternalObject");
simulation->add(objectMaterial);

// ... set the object material on the external bodies
agxUtil::setBodyMaterial(externalObjectBody, objectMaterial);

agx::MaterialRef terrainMaterial = terrain->getMaterial( agxTerrain::Terrain::MaterialType::TERRAIN );
agx::ContactMaterialRef objectTerrainCM = new agx::ContactMaterial( objectMaterial, terrainMaterial );
objectTerrainCM->setFrictionCoefficient( 0.4 );
simulation->add( objectTerrainCM );
// Get and add another terrain material
agxTerrain::TerrainMaterial dirt = terrain->getLibraryMaterial("dirt_1");
terrain->addTerrainMaterial(dirt);
// Get the associated material
agx::Material dirtAgxMaterial = terrain->getAssociatedMaterial(dirt);
// Define the contact material between dirt<->shovel
agx::ContactMaterialRef objectDirtCM = new agx::ContactMaterial( objectMaterial, dirtAgxMaterial );
simulation->add( objectDirtCM );

Refer to the section Terrain material configuration for a description of how to add different soil types to the terrain and the section on internal materials to configure associated materials with the terrain materials.

Note

If the external object interacts with a part of the terrain that intersects two or more regions where there are different soil types, the contact material properties are averaged.

24.6. Calibration of Excavation Resistance

The terrain generates excavation resistance through the following effects:

Separation resistance

Generated by digging and pushing soil in the forward digging direction.

Penetration Resistance

Force generated via penetration of the cutting plate in the cutting direction.

Deformation Contact Forces

Similar to the separation forces but generated during push/pull/grading operations.

Generic Contact Forces

These are the regular contact forces when no excavation mode is active.

Note

It is recommended that the user always check their excavation forces during terrain setup. This is in order to properly asses the feasibility of the forces and phenomena that is generating feedback.

The force feedback that is generated from a terrain on a shovel can be extracted by the following methods:

bool Terrain::getPenetrationForce(const Shovel* shovel, agx::Vec3& force, agx::Vec3& torque) const;

agx::Vec3 Terrain::getSeparationContactForce( const Shovel* shovel ) const;

agx::Vec3 Terrain::getDeformationContactForce(const Shovel* shovel) const;

agx::Vec3 Terrain::getContactForce( const Shovel* shovel ) const;

The main ways to adjust these are:

  1. Contact properties between the shovel and the terrain aggregate. This is controlled by the contact material specified between the shovel geometries and the different soil types in the terrain instance. See contact materials. This affects both penetration resistance and separation/deformation resistance.

  2. Terrain Material properties, such as soil density, stiffness and friction angle. This determines soil aggregate weight and also internal contact properties, i.e contacts between the aggregate and the terrain.

  3. Adjust the penetration resistance by modifying the PenetrationForceScaling parameter.

24.6.1. Contact material calibration

The following properties are the most relevant when calibrating the contact materials between the shovel and terrain.

YoungsModulus

Determines the stiffness in the shovel <-> terrain contacts.

FrictionCoefficient

Adjusts the friction force between the shovel and terrain.

24.6.2. Terrain Material

The following parameters determines the internal contact and shape properties of the soil aggregates. Most of them are found the in the bulk properties but some are also found in excavation contact properties. To see how to add/remove terrain materials, please refer to the section on Terrain material configuration.

YoungsModulus

Determines the stiffness in the aggregate <-> terrain contacts.

Cohesion

Affects the force feedback from the terrain via setting a cohesion value in the aggregate <-> terrain contacts. Also affects the cohesion of the dynamic mass hat might lead to higher measured masses.

FrictionAngle

This affects the angle of the failure zones and also determines the friction coefficient in the aggregate <-> terrain contacts.

Density

Affects the total mass of the soil aggregates formed in the shovel active zone.

ExcavationStiffnessMultiplier

Scales the bulk Young’s modulus applied in the shovel <-> aggregate contact in order to allow the user to fine-tune the excavation force.

AggregateStiffnessMultiplier

Scales the bulk Young’s modulus applied in the aggregate <-> terrain contact in order to allow the user to fine-tune the excavation force.

24.6.3. Calibration of Penetration Force

The user can explicitly control the penetration force either by apply a scaling factor or a maximum cap on the penetration force:

shovel->setPenetrationForceScaling(5.0)
shovel->setMaxPenetrationForce(10000) // In Newton

Note

The need to apply a scalar scaling factor on the penetration model is due to the fact that shovels have different geometry and cutter formation that interact in a way that the current model is unable to capture. Therefore it might be necessary to calibrate the scaling factor to achieve the desired initial breach force.

24.6.4. Suggested calibration workflow

This section provides a sample workflow for calibrating agxTerrain. This list assumes that the user has access to benchmark data from either theory or a experimental test that they wish to reproduce in agxTerrain:

  • First ensure that the TerrainMaterial->BulkProperties holds the same parameters as the real world soil used in the experiments. Also use values obtained from experiments and literature. Density is especially important.

  • Ensure that the final mass in the shovel agrees with the end mass in the test specified. This involves modifying the following bulk properties:

    • Update Bulk Properties - Swell Factor This determines how the material grows or swells after excavation, emulates de-compaction of soil into a loosely packed state.

    • Update Bulk Properties - Bulk density.

    • Update Bulk Properties - Cohesion. High cohesion values will cause the material to stick together more, creating more material in the shovel.

  • Calibrate the Penetration Resistance Force Scaling so that the force feedback during the initial breach agrees with measured data. Recommended start interval 10-16.

  • Modify BulkProperties.

    • Young’s Modulus.

    • Friction Angle.

    • Cohesion.

  • Contact material between Shovel and terrain (Suggested parameters).

    • Friction.

    • Young’s modulus.

  • Excavation Contact Properties (Suggested parameters, Used as a ‘last resort’).

    • AggregateStiffnessMultiplier.

    • ExcavationStiffnessMultiplier.

Note

CompactionProperties does not affect force feedback during excavation.

24.7. Terrain Paging

Terrain paging exists to solve the following problems:

  • One needs a large area to operate in, which results in excessively high direct memory usage.

  • One needs a resolution and an area that together result in excessively high direct memory usage.

  • There are multiple machines that need to operate on terrain simultaneously at too great a distance for a terrain to handle it (due to memory usage).

  • The terrain is defined in a format that does not allow for direct creation via an API in agxTerrain, for example, a triangle mesh.

This is achieved via the agxTerrain::TerrainPager class. It has a virtual 2D grid with square tiles in which it can load in agxTerrain::Terrain instances as needed. The Terrain instances are unloaded again when they are not needed any longer.

/**
 Constructor. Specifies tile information and the 2D-plane used for dynamic terrain tiles.

 The TerrainPager do not mirror all the different parameters a terrain exposes,
 instead a template terrain is used for settings.

 To support excavation, the terrain tiles have an optional margin. This margin can
 be set so that the excavation is performed within one tile and correct soil wedges
 are formed.

 Example: tileResolution = 301, tileOverlap 10, tileElementSize = 0.25, ....

          Each tile then becomes (301-1)*0.25 = 75m x 75m
          The overlap on each side will be 10*0.25 = 2.5m

 \param tileResolution    Specifies the number of height values for each dimension for (tile+margin).
 \param tileOverlap       Specifies the number of height values that should overlap between two tiles.
 \param tileElementSize   Size in meters for one element. Same as distance between two height values.
 \param maximumDepth      How deep in meters the terrain can be excavated
 \param referencePoint    A world reference point for where the terrain is located
 \param referenceRotation A rotation that will transform the Z-axis to the up direction at the referencePoint
 \param templateTerrain   A template terrain whose settings will be used for the terrain tiles.
 */

 TerrainPager(size_t tileResolution, size_t tileOverlap, agx::Real tileElementSize, agx::Real maximumDepth,
              agx::Vec3 refPoint, agx::Quat refRotation,
              agxTerrain::Terrain* templateTerrain );

Note

It is important that the edges of two adjacent tiles match. To handle this and support excavation, adjacent tiles can have an overlap. When excavation is performed, the soil wedges are kept within a tile and to have non-truncated soil wedges. The overlap should be larger than both the length of the cutting edge interacting with the terrain aswell as twice the expected maximum length of a soil-wedge (which depends on how deep excavation in the terrain will be performed).

Warning

Adding a Terrain instance to a Simulation will also set some Solver parameters that the terrain needs and cause the Simulation update task to be rebuilt. It is not supported to rebuild the update task when it is executing, that is, during Simulation::stepForward. It can cause Simulation::stepForward to not return.

The TerrainPager must be able to add and remove terrains during stepFoward. Hence, Simulation::add( TerrainPager) prepares the Simulation by setting the same solver parameters that Simulation::add( Terrain ) would do, preventing a later task rebuild.

After a TerrainPager has been added to a Simulation, it is not supported to change any of the following solver parameters: - setUseParallelPgs - setUse32bitGranularBodySolver - setUseGranularWarmStarting Also, adding a TerrainPager to the Simulation will change the BroadPhase Algorithm used by Space to HIERARCHICAL_GRID. It is not supported to change it to SWEEP_AND_PRUNE.

24.7.1. Tracking bodies / shovels

To know which tiles that should have Terrain instances, bodies and shovels can be added to the agxTerrain::TerrainPager for tracking. Each tracked item have two radiuses associated with them:

  • The required radius: All tiles within this radius must be in the Simulation for agxSDK::Simulation::stepForward to be able to proceed. Can cause stepForward to wait while the tile processing occurs in the background.

  • The preload radius: Tiles within this radius will be preloaded in the background and inserted into the Simulation when ready.

../_images/TerrainPagerTiles.png

Fig. 24.6 Figure that shows a tracked item in blue, required tiles in dark gray and tiles within the preload radius in light gray. Normally the tiles are much larger than in this example image and fewer tiles are active.

The value for the required radius should be selected so that all geometries attached to the body that may interact with the terrain are enclosed within the radius. The value for the preload radius should be chosen so that tiles may be loaded into memory well before they will be needed in the simulation to avoid hickups. This means the higher the expected maximum velocity the higher the preload radius relative to the required radius.

/**
Adds a RigidBody to the terrain pager. The pager will make sure that terrain tiles
within the required radius are present in the Simulation before stepping and tiles
within the preload radius will be loaded and inserted when available.
*/
bool add( agx::RigidBody* body, agx::Real requiredTileRadius, agx::Real preloadTileRadius );


/**
Remove body so that the terrain pager no longer uses the body when determining
which terrain tiles that are needed.
*/
bool remove( agx::RigidBody* body );

24.7.2. TerrainDataSource

The TerrainPager must also have a TerrainDataSource from which it can request height data for the needed tiles. The first time a tile is needed, heights are requested. If the tile is paged out then the height values are stored to disk. If it is needed again the possibly modified values are read from file and not requested from the data source.

There is one class that implements the TerrainDataSource interface: agxTerrain::TerrainRasterizer. The TerrainRasterizer should be given source geometry (e.g. large heightfield(s)) which it will then sample with raycasting to get height values at the needed positions.

Note

When implementing a custom data source in languages other than C++ using the AGX bindings, the ExternalTerrainDataSource class should be inherited instead of the TerrainDataSource class and serialization of the data source is disabled

24.7.3. Paged Terrain settings

The TerrainPager do not expose the material settings for the terrain tiles. Instead, one of the arguments to the TerrainPager constructor is a template terrain. Each time a terrain tile is inserted into the simulation, the template settings are applied to the new tile.

/**
Fetches the template terrain.
The settings for the template terrain are used on new terrain tiles
when they are inserted into the simulation.

\see applyChangesToTemplateTerrain
*/
agxTerrain::Terrain* getTemplateTerrain();

/**
Signals to the TerrainPager that the template terrain has been updated
and that any changes to the template terrain should be applied to the
active terrain tiles in the pager.
*/
void applyChangesToTemplateTerrain();

Each time a new Terrain instance is inserted into the Simulation, the TerrainPager triggers an event, tileLoadEvent, and in the same way when removing a Terrain tileUnloadEvent is triggered. With these events it it also possible to customize tiles settings per tile.

Compaction data for paged out tiles is not stored by default. If this is needed the method TerrainPager::setShouldStoreCompaction( bool, size_t ) can control this and specify how many voxels below the surface that should be stored.

Note

The amount of stored data per paged tile will increase greatly if maximumCompactionDepth is set too high.

24.7.4. Serialization

The terrain pager has two ways of serialization. There is a full state serialization using InputArchive and OutputArchive and there is a serialization of modified terrain height data.

The full state serialization use the functions void TerrainPager::store(agxStream::OutputArchive& out) const and void TerrainPager::restore(agxStream::InputArchive& in).

Part of the state held by the terrain pager can be paged out to disk (see TerrainPager::setFileCacheDirectory). The files in that directory are needed along with the serialized archive. If needed, the paged out data can be embedded in the archive. This is controlled via TerrainPager::setEmbedCacheFilesInArchive( bool ).

Furthermore, compaction data is not stored by default. If this is needed the method TerrainPager::setShouldStoreCompaction( bool, size_t ) can control this and specify how many voxels below the surface that should be stored.

Note

The amount of stored data per paged tile will increase greatly if maximumCompactionDepth is set too high.

The serialization for the changed heights uses the methods void TerrainPager::store( agxTerrain::TileModificationVector& storeData ); void TerrainPager::restore( const agxTerrain::TileModificationVector& restoreData ); this is described in more detail below.

24.7.5. Store / restore of terrain height data

There are custom store/restore functions which can be used for serialization of paged terrains heights if needed.

If TerrainPager::setShouldStoreDeltas is enabled, then terrain pager will start collecting height changes internally. Unless these values are fetched periodically, the internal structure will keep growing. These delta changes can be fetched via void TerrainPager::store( agxTerrain::TileModificationVector& storeData );. The output is written to storeData and will contain the changes since last time the function was called. After store has been called, the TerrainPager will clear its internal buffer with changes.

To restore the system, void TerrainPager::restore( const agxTerrain::TileModificationVector& restoreData ); should be used. The restoreData should be the aggregated state from all the store deltas. This will give the terrain pager a set of changes which should be applied to a tile after the height data has been requested from the terrain data source.

24.7.6. Terrain paging tutorials

A full example of how the TerrainPager and TerrainRasterizer can be used along with dynamic loading/unloading of Terrain tiles can be seen in data/python/agxTerrain/basic_paging_example.agxPy.

There is also an example which uses a kinematic body to control which tiles that are preloaded and performs efficient raycast measurements of the terrain height data/python/agxTerrain/paging_depth_measurements.agxPy.

There is also a tutorial showing bulldozing with a terrain pager data/python/agxTerrain/tutorials/agxTerrain/tutorial_bulldozing_terrain_paging.agxPy.

24.8. Terrain Model

This section contains model descriptions of the different parts in the agxTerrain::Terrain object.

24.8.1. Terrain Grid Structure

The terrain data is stored underlying 3D grid structure. It is usually accessed either on the surface using 2D grid coordinates or in 3D space using full 3D grid coordinates. The data that is stored in the grid is the following:

Surface terrain data, such as terrain height, is accessed by specifying a terrain surface index, which references a single discrete surface grid point on the terrain. The terrain surface index consists of 2D x and y coordinates with origin (x:0, y:0) in the lower leftmost gridpoint and the maximum coordinate in the upper rightmost gridpoint ( x: resolutionX-1, y: resolutionY-1 ) in the terrain surface structure.

../_images/TerrainGrid.png

Fig. 24.7 Figure that shows the indexing and grid layout of the agxTerrain in the x/y surface plane. The blue points denote grid center points that coincide with the surface heightfield vertices. The orange grid denotes the cell boundaries. The indexing starts in the lower left corner with x:0,y:0 and goes to the upper right corner x:resolutionX-1, y:resolutionY-1.

To access full spatial data, a 3D grid coordinate is specified using the same 2D surface index as above but also with an added depth index. The origin of the depth index is defined where the surface height of the terrain is zero.

../_images/TerrainGridZ.png

Fig. 24.8 Figure that illustrates the layout of the depth index in the terrain cell structure via cross-section view in the x/z plane. The orange grid shows the cell boundraries in the terrain structure and the blue points shows the height field vertex height positions. The local terrain center z position of the grid cell with depth index 0 is defined where the height of the coupled heightfield is zero. The lowest allowable z index corresponds to the grid cell where the maximumDepth reaches.

3D grid data can be accessed via the TerrainGridControl interface. If the user wants to extract the depth index for the terrain surface given a surface index the following code can be used:

/**
Find terrain surface depth index given the terrain index x,y coordinates.
\param terrainIndex - The specified 2D terrain surface index.
\return The terrain depth index (z) at the surface.
*/
int TerrainGridControl::findSurfaceIndex(const agx::Vec2i& terrainIndex) const;

24.8.2. Mass Data

Each grid cell contains information about how much solid terrain mass it contains. It is represented as cell occupancy. Assuming nominal compaction (1.0), each cell can have an occupancy value that can range from 0.0 (empty) to 1.0 (full). If the cell has a compaction value other than 1.0, the amount of solid occupancy that can be stored in a grid cell changes according to:

\[\phi_{{max}_i} = \phi_{max} * c_i\]

where \(\phi_{{max}_i}\) is the new maximum occupancy that can be stored in cell \(i\), \(\phi_{max}\) is the nominal maximum occupancy that can be stored in a cell (1.0) and \(c_i\) is the compaction in cell \(i\). This effectively means that more mass can be contained in dense packed soil and less in looser soil.

24.8.3. Accessing Grid Data

Grid data can be modified or inspected at the grid level through the agxTerrain::TerrainGridControl which can be accessed from the Terrain object:

auto gridControl = terrain->getTerrainGridControl();
// Get the mass occupancy of the terrain 3D cell at (0, 0, 0)
compaction gridControl->getOccupancy(agx::Vec3i(0, 0, 0));

Terrain solid mass is modified in the occupancy format top-down on the terrain surface at a 2D index. Either is it added via specifying the amount occupancy or by filling/removing up to a certain height or layer.

Note

The terrain does not support discontinuous terrain mass in the z-direction due to the nature of the surface heightfield. That is why mass can only be added/removed columnwise top-down on the terrain surface.

The following snippet shows some functions that enables the user to do this:

float addSolidOccupancyInColumn(const agx::Vec2i& terrainIndex, float occupancy, float compaction, bool shouldAvalanche = true);
float removeSolidOccupancyInColumn(const agx::Vec2i& terrainIndex, float occupancy, bool shouldAvalanche = true);
float addSolidOccupancyLayerInColum(const agx::Vec2i& terrainIndex, agx::Real layerHeight, float compaction, bool shouldAvalanche = true);
float addSolidOccupancyInColumnToHeight(const agx::Vec2i& terrainIndex, agx::Real height, float compaction, bool shouldAvalanche = true);

The following snippet shows how to add a layer of loose soil on top of the terrain surface via the agxTerrain::TerrainGridControl object:

auto gridControl     = terrain->getTerrainGridControl();
auto terrainMaterial = terrain->getTerrainMaterial()->getBulkProperties();

// Add a loose layer of 0.5 m on top of the terrain that has compaction according to the swell factor
agx::Real compaction = 1.0 / terrainMaterial->getSwellFactor();
agx::Real height     = 0.5; // height in meters
for ( int x = 0; x < terrain->getResolutionX(); x++ )
  for ( int y = 0; y < terrain->getResolutionY(); y++ )
  {
    gridControl->addSolidOccupancyLayerInColum( { x, y },
                                                height,
                                                compaction,
                                                true );
  }

Often one wants to extract the depth index for the terrain surface given a surface index:

/**
Find terrain surface depth index given the terrain index x,y coordinates.
\param terrainIndex - The specified 2D terrain surface index.
\return The terrain depth index (z) at the surface.
*/
int TerrainGridControl::findSurfaceIndex(const agx::Vec2i& terrainIndex) const;

24.9. Terrain Properties

The general properties of the terrain is stored in a agxTerrain::TerrainProperties object which can be accessed:

agxTerrain::TerrainProperties* properties =  terrain->getTerrainProperties()

These properties contains useful options for locking terrain border height, enable/disable for various terrain functions.

The following function locks the terrain borders from changing due to avalanching or merging.

properties->setEnableLockedBorders(true)

The following function removes particles that are outside the bounds of the terrain:

properties->setDeleteSoilParticlesOutsideBounds(true)

The following function set the lowest speed limit for soil particles before they start to merge back into the terrain:

properties->setSoilMergeSpeedThreshold(0.06)

The following function set the maximum volume that can be activated in the terrain due to shovel excavation operations:

properties->setMaximumParticleActivationVolume(0.5)

The following function scales the penetration resistance with the speed of the shovel in the terrain:

properties->setPenetrationForceVelocityScaling(0.05)

Particle size can be scaled in the simulation to either increase or decrease the amount of soil particle created during excavation. The scaling parameters multiplies with the target nominal radius of the particles:

properties->setSoilParticleSizeScaling(1.2)

24.10. Terrain Material

agxTerrain::TerrainMaterial is used to describe the material properties of the soil in agxTerrain. The properties are grouped internally in objects according to the phenomena they affect:

BulkProperties

These properties govern general bulk behaviour such as soil density, failure zone shape and excavation forces.

CompactionProperties

These properties govern behaviour of the soil compaction.

ParticleProperties

These properties govern the soil particle dynamics. Mostly contains parameters for the contact material in-between particles and particle <-> terrain contacts.

ExcavationContactProperties

These properties govern the contact model of the internal terrain <-> aggregate and the shovel <-> aggregate contacts.

24.10.1. BulkProperties

The bulk properties govern the general bulk behaviour of the terrain, such as failure zone shape, soil density and feedback forces. It contains the following parameters:

YoungsModulus

The bulk stiffness of the material in Pa. This affects the stiffness in the internal aggregate<->terrain contacts.

Cohesion

Describes the internal cohesion of the material in Newton. This affects the force feedback from the terrain. It also determines the cohesion in aggregate<->terrain contacts.

FrictionAngle

Describes the internal friction angle of the material. This affects the angle of the failure zones and angle of repose in a 1-to 1 ratio for the avalanching algorithm. It also determines the friction coefficient in aggregate<->terrain contacts.

Density

Describes the density of the soil in kg/m3. This translates to the specific density of the solid soil and the bulk density of the dynamic soil (i.e soil particles).

Maximum Density

Describes the maximum density of the soil in kg/m3. This implicitly determines the maximum compaction of the material.

Swell Factor

Specifies the fractional increase in bulk volume that occurs when solid soil is converted to dynamic soil.

Dilatancy Angle

Specifies the dilatancy angle of the mateiral. Used in Penetration resistance calculations.

Poisson's Ratio

Specifies the Poisson’s ratio of the mateiral. Used in Penetration resistance calculations.

Adhesion Overlap Factor

Adhesion Overlap Factor is the fraction of the soil particle radius that is allowed to overlap. This is used to simulate adhesion. Default value is 0.05

Delta Repose Angle

The delta repose angle increases the base angle of repose of the material on top of the internal angle of friction. Default value is 0.0

Note

The Swell Factor is inversely correlated to the compaction level of the dynamic soil when it is merged back to the terrain.

The bulk properties can be accessed and modified via the TerrainMaterial object:

auto terrainMaterial = terrain->getTerrainMaterial()
auto bulkProperties = terrainMaterial->getBulkProperties()
bulkProperties->setDensity( 1.4e3 )
bulkProperties->setFrictionAngle( 23.0 * ( 180.0 / agx::PI ) )
bulkProperties->setSwellFactor( 1.05 )
bulkProperties->setAdhesionOverlapFactor( 0.07 )

24.10.2. Excavation Contact Properties

The excavation contact properties govern the some of the contact dynamics between the shovel, soil aggregates and the terrain during excavation and deformation. Bulk Material properties are used to set parameters such as stiffness, friction and cohesion in the terrain-aggregate and terrain-shovel contacts, but the excavation contact properties allows to user to access and manipulate the underlying contact model. The contact model between the soil aggregate and terrain aims to model elasto-plastic behaviour with a maximum depth limit and decay factors. There is also parameters for controlling the stiffness of the shovel-aggregate contact interface.

ExcavationStiffnessMultiplier

This adjust the stiffness of the shovel-aggregate contacts by multiplying the Young’s Modulus of the material that is set to the contact. See aggregate<->terrain contacts.

Depth Increase Factor

Specifies the rate of depth increase in the aggregate-terrain contact when excavating and deforming.

Depth Decay Factor

Specifies the rate of depth decay in the aggregate-terrain during the separation stage of the excavation and deformation contact.

Maximum Depth

Specifies the maximum depth of the aggregate-terrain contact.

Maximum Aggregate Force

Sets the maximum normal force that can be applied in the aggregate-terrain contact.

The excavation properties can be accessed and modified via the TerrainMaterial object:

auto terrainMaterial = terrain->getTerrainMaterial();
auto excavationProperties = terrainMaterial->getExcavationContactProperties();
excavationProperties->setExcavationStiffnessMultiplier(0.05);

24.10.3. Compaction Properties

The compaction properties govern how the soil compacts under pressure generated from terrain contacts. See the soil compaction section for model details.

Hardening Ke

Hardening constant that determines how Young’s Modulus changes with compaction.

Hardening Ne

Hardening constant that determines how Young’s Modulus changes with compaction.

preconsolidationStress

The initial consolidation stress that the soil in the bank state ( compaction = 1.0 ). Only stresses above this may increase compaction levels.

compactionTimeRelaxationConstant

The time relaxation constant that limits the rate of density changes due to compaction.

stressCutOffFraction

Determines the fraction of the surface stress that will determine when to stop propagating stress down into the soil.

angleOfReposeCompactionRate

Determines how angle of repose should change with varying compaction.

The compaction properties can be accessed and modified via the TerrainMaterial object:

auto terrainMaterial = terrain->getTerrainMaterial();
auto compactionProperties = terrainMaterial->getCompactionProperties();
compactionProperties->setCompressionIndex(0.05);

24.10.4. Particle Properties

The particle properties determines the properties for the 6-DOF particles representing dynamic soil and also the contact parameters in particle <-> particle contact and particle <-> terrain interactions. Data about soil particles can be accessed via the soil simulation interface.

Density

Determines the specific particle density. This is implicitly set via the density parameter in bulk properties.

Particle Young's Modulus

Sets the Young’s Modulus (Pa) for the particle agx::Material and the internal particle <-> particle contacts.

Particle Restitution

Sets the restitution of the particle <-> particle contacts.

Particle Surface Friction

Sets the friction of the particle <-> particle contacts.

Particle Rolling Resistance

Sets the rolling resistance of the particle <-> particle contacts.

Particle Cohesion

Sets the cohesion (Pa) of the particle <-> particle contacts.

Particle-Terrain Young's Modulus

Sets the the Young’s Modulus (Pa) of the particle <-> terrain contacts.

Particle Terrain Restitution

Sets the restitution of the particle <-> terrain contacts.

Particle Terrain Surface Friction

Sets the friction of the particle <-> terrain contacts.

Particle Terrain Rolling Resistance

Sets the rolling resistance of the particle <-> terrain contacts.

Particle-Terrain Cohesion

Sets the cohesion (Pa) of the particle <-> terrain contacts.

The particle properties can be extracted via the TerrainMaterial object:

auto terrainMaterial = terrain->getTerrainMaterial()
auto particleProperties = terrainMaterial->getParticleProperties()
particleProperties->setParticleRestitution(0.05)

24.11. Material Library

agxTerrain comes with a pre-existing library of agxTerrain::TerrainMaterial presets for different common soils that can be used. The available material presets are stored as external files in JSON format and are from parsed the default material library folder in AGX Dynamics: data/MaterialLibrary/TerrainMaterials. Users can also create their own material presets files representing other soil types specific to their use cases and add those to the material library folder or load them via the TerrainMaterialLibrary and TerrainMaterialReadWriter classes.

24.11.1. Loading a TerrainMaterial Preset

Loading a material preset into an agxTerrain::Terrain object is done like so:

if( terrain->loadLibraryMaterial( agx::String& filename ) );
  std::cout << "Material preset " << filename << "loaded successfully."

This loads the terrain material as the default terrain material. See Terrain Material Configuration for more information.

If the user wishes to load a terrain material and add it as an additional soil type to the terrain instance, the getLibraryMaterial can be used:

agxTerrain::TerrainMateiralRef terrainMaterial = terrain->getLibraryMaterial( agx::String& filename );
if( terrainMaterial != nullptr )
  std::cout << "Material preset " << filename << "loaded successfully."

The profiles that can be set correspond to the default set of .json files in the AGX Dynamics installation: data/MaterialLibrary/TerrainMaterials. The available default material presets can be extracted by using the following method:

terrain->getAvailableLibraryMaterials();

The default set of presets are as follows:

gravel_1

Represents typical material properties for coarse gravel.

sand_1

Represents typical material properties for fine sand.

dirt_1

Represents typical material properties for cohesive dirt.

Warning

Changing the bulk material properties or internal contact material parameters will invalidate the previous settings applied from the material library. The profile must be applied again in order to get the properties back.

24.11.2. agxTerrain::TerrainMaterialLibrary

agxTerrain::TerrainMaterialLibrary is a utility class that helps handling folders of JSON files specifying agxTerrain::TerrainMaterial presets. It parses a specified folder of files and stores verified material presets in tables according to material name. This class is used by the agxTerrain::Terrain::loadLibraryMaterial when loading material presets. By default, this library folder contains the default TerrainMaterial presets in AGX Dynamics. The user can specify their own folder with JSON files.

The following method loads a material profile according to material name in the specified library folder:

/**
Create an agxTerrain::TerrainMaterial object from one of the existing library
presets, derived from the .json files in the specified library folder. The default location
of the preset folder contains the default material preset of AGX Dynamics.
Note - Existing library materials can be extracted via the getAvailableLibraryMaterials() method:
\param materialName - the name of the material preset to load.
\param librayFolder - The path to the folder containing all the terrain material preset files.
\return a TerrainMaterial object created from the specified material preset or nullptr if the creation failed.
*/
static agxTerrain::TerrainMaterial* loadMaterialProfile( const agx::String& materialName,
                                                         const agx::String& librayFolder = DEFAULT_TERRAIN_MATERIAL_LIBRARY_FOLDER );

The following method prints all available valid material presets in the specified library folder:

/**
Get the available TerrainMaterial presets from the existing.json files in the specified
material library folder. The default location of the preset folder contains the default
material preset of AGX Dynamics.
\param librayFolder - The path to the folder containing all the terrain material preset files.
\return a vector containing the available TerrainMaterial presets from the existing
        .json files in the specified material library folder.
*/
static agx::StringVector getAvailableLibraryMaterials( const agx::String& librayFolder = DEFAULT_TERRAIN_MATERIAL_LIBRARY_FOLDER );

24.11.3. agxTerrain::TerrainMaterialReadWriter

The agxTerrain::TerrainMaterialReadWriter class is used to store and read material profiles in .json format and is used by the agxTerrain::TerrainMaterialLibrary. The following methods are used to read and store files:

/**
Read TerrainMateiral configuration from a file in JSON format into a TerrainMaterial object.
\param filename - the filename of the file containing the terrain material configuration in JSON format.
\param terrainMaterial - the TerrainMaterial object that will be initialized with the data from the JSON file.
\return true if the file was successfully read, false otherwise.
*/
static bool readFile( const agx::String& filename, TerrainMaterial* terrainMaterial );
/**
Write a TerrainMaterial configuration to a file in JSON format.
\param terrainMaterial - the TerrainMaterial object that will be written to the JSON file.
\param filename - the filename of the file where the the terrain material configuration will be written in JSON format.
\return true if the file was successfully written, false otherwise.
*/
static bool writeFile( const TerrainMaterial* terrainMaterial, const agx::String& filename );

24.11.4. TerrainMaterial .json files

The basic preset file structure is in JSON format that the reflects the underlying class layout of the TerrainMaterial class. Below follows a sample file for the preset dirt_1 where comments describing the parameter units have been added:

{
  "BulkProperties" : {
      "adhesionOverlapFactor" : 0.050,       // Dimensionless
      "cohesion" : 12000.0,                  // Pa
      "density" : 1300.0,                    // kg/m3
      "dilatancyAngle" : 0.2268928027592629, // radians
      "frictionAngle" : 0.7504915783575616,  // radians
      "maximumDensity" : 2000.0,             // kg/m3
      "poissonsRatio" : 0.150,               // Dimensionless
      "swellFactor" : 1.280,                 // Dimensionless
      "youngsModulus" : 5000000.0,           // Pa
      "deltaReposeAngle": 0.0                // radians
  },
  "CompactionProperties" : {
      "angleOfReposeCompactionRate" : 24.0,        // Dimensionless
      "bankStatePhi" : 0.6666666666666666,         // Dimensionless
      "compactionTimeRelaxationConstant" : 0.050,  // Dimensionless
      "compressionIndex" : 0.110,                  // Dimensionless
      "hardeningConstantKE" : 1.0,                 // Dimensionless
      "hardeningConstantNE" : 0.08333333333333333, // Dimensionless
      "preconsolidationStress" : 98000.0,          // Pa
      "stressCutOffFraction" : 0.010               // Dimensionless
  },
  "ExcavationContactProperties" : {
      "aggregateStiffnessMultiplier" : 0.050,       // Dimensionless
      "depthDecayFactor" : 2.0,                     // Dimensionless
      "depthIncreaseFactor" : 1.0,                  // Dimensionless
      "excavationStiffnessMultiplier" : 1.0,        // Dimensionless
      "maximumAggregateNormalForce" : "inf",        // N
      "maximumContactDepth" : 1.0                   // m
  },
  "ParticleProperties" : {
      "particleCohesion" : 200.0,                   // Pa
      "particleFriction" : 0.40,                    // Dimensionless
      "particleRestitution" : 0.0,                  // Dimensionless
      "particleRollingResistance" : 0.10,           // Dimensionless
      "particleTerrainCohesion" : 200.0,            // Pa
      "particleTerrainFriction" : 0.70,             // Dimensionless
      "particleTerrainRestitution" : 0.0,           // Dimensionless
      "particleTerrainRollingResistance" : 0.70,    // Dimensionless
      "particleTerrainYoungsModulus" : 100000000.0, // Pa
      "particleYoungsModulus" : 10000000.0          // Pa
  },
  "name" : "DIRT_1"
}

24.12. Shovel Settings

The following are some of the more useful generic settings for configuring the Shovel object:

void setNoMergeExtensionDistance(agx::Real extensionDistance)

This function expands the no merge zone around the shovel, where dynamic soil is not allowed to merge with the terrain, with the specified distance in every axis of the bounding box. The default value is 0.5 m.

void setVerticalBladeSoilMergeDistance(agx::Real verticalSoilBladeMergeDistance);

Specifies the distance where dynamic soil instantly merges up to the blade cutting edge along the gravity direction, if the specified distance intersects with the terrain surface.

Note

This is useful for bulldozing and grading operations where the leveling process requires continuously merging soil in the gap between the shovel cutting edge and the terrain surface.

void setEnableParticleFreeDeformers(bool enable);

This function enables/disables the deformers of the shovel to interact with the terrain without creating particles.

24.12.1. Excavation Mode Settings

Each excavation plane have individual settings which allows the user to control aspects of the digging depending on the type of operation. The settings are store in a Shovel::ExcavationSettings object that can be extracted from the Shovel object. The user can use this object, for example, specify if individual excavation planes should be enabled or create dynamic soil. The following snippet shows how to disable the left and right planes and the dynamic soil creation for the back plane.

shovel->getExcavationSettings( agxTerrain::Shovel::ExcavationMode::DEFORM_LEFT )->setEnable( false )
shovel->getExcavationSettings( agxTerrain::Shovel::ExcavationMode::DEFORM_RIGHT )->setEnable( false )
shovel->getExcavationSettings( agxTerrain::Shovel::ExcavationMode::DEFORM_BACK )->setEnableCreateDynamicMass( false )

24.12.1.1. Overriding Contact Material in Excavation Modes

The user can override the contact material between the shovel and the terrain for certain excavation modes. This can be desirable if different excavation modes should experience different resistance. This is done on a shovel-terrain basis and uses the following function:

/**
Explicitly set contact material properties in a shovel-aggregate contact for a specific
excavation mode for a specific shovel-terrain pair. This overrides the shovel-terrain contact
material properties that are used in the default case.
\param shovel - The specified shovel.
\param contactMaterial - The contact material to be set in the aggregate contact.
\param excavationMode - The specified excavation mode that corresponds to the aggregate.
\note - this returns false if the shovel is not set to the terrain.
\return true if the contact material was successfully set, false otherwise.
*/
bool setShovelAggregateContactMaterial( const Shovel* shovel,
                                        agx::ContactMaterial* contactMaterial,
                                        Shovel::ExcavationMode mode = Shovel::ExcavationMode::PRIMARY );

The following example illustrates overriding the default contact material used in the back deformer with a custom contact material.

terrainMaterial = terrain->getMaterial( agxTerrain::Terrain::MaterialType::TERRAIN )
shovelTerrainContactMaterial = agx::ContactMaterial( shovelMaterial,
                                                    terrainMaterial )
shovelTerrainContactMaterial->setYoungsModulus( 1e5 )
shovelTerrainContactMaterial->setFrictionCoefficient( 0.2 )
shovelTerrainContactMaterial->setRestitution( 0.0 )
shovelTerrainContactMaterial->setAdhesion( 0.0, 0.0 )
simulation->add( shovelTerrainContactMaterial )
terrain.setShovelAggregateContactMaterial( shovel,
                                           shovelTerrainContactMaterial,
                                           Shovel::ExcavationMode::DEFORM_BACK )

Note

In order to reset the contact material to the default shovel-terrain contact material, simply use the method above with nullptr as the contactMaterial argument.

24.13. Angle of Repose

agxTerrain can model soil repose effects when changes in the terrain surface causes the soil angle between two adjacent elements to exceed the specified angle of repose of the material. The base angle of repose of a material, in the bank state umodified by compaction, is given by adding the internal angle of friction and the delta repose angle:

\[\psi_{r} = \psi + \delta \psi_{r}\]

Where \(\psi_{r}\) is the effective repose angle of the material, \(\psi\) is the internal friction angle and \(\delta \psi_{r}\) is the delta repose angle of the material.

Local soil compaction modifies the angle of repose for specified grid elements at a rate specified by the angleOfReposeCompactionRate.

24.14. Soil Compaction

Soil compaction determines how much soil mass that can exist inside a terrain 3D grid element. The default compaction value for a grid element is 1.0 which is defined as the bank state. As the compaction level changes, so does the local material properties in that grid element such as Young’s Modulus and angle of repose. Every material has a swell factor which determines the fractional increase in soil volume during excavation which also decreases the compaction.

../_images/soil_compaction.png

Fig. 24.9 Figure showing a wheel loader scene during excavation that illustrates terrain soils of different compaction levels through lightness rendering. Dark surface patches in the soil shows wheel tracks from compressed soil with a compaction level higher than the nominal compaction. The lighter areas show soils of looser compaction resulting from excavation or avalanching where it grows in volume according to the swell factor of the material. Soil of loose compaction offers less resistance and is easier to compress.

Default compaction for an initialized terrain is 1.0 in all terrain grid elements. Compaction can be set for all grid cells via the following function:

/**
Set a compaction for all current active solid grid elements in the Terrain object.
\note - the terrain grid elements all start with a the nominal compaction value of 1.0, of which all
user specified bulk parameters correspond to.
\param compaction - The compaction value to set to every voxel in the terrain (Default: 1.0)
\param replaceCompactedSoil - True if all voxels which already have a compaction value (compaction != 1.0)
                              should get overwritten.
*/
void setCompaction(agx::Real compaction, bool replaceCompactedSoil=true) const;

The TerrainGridControl class can be used to access and set the compaction value for single grid cells at the surface or at a 3D grid index.

float TerrainGridControl::getCompaction(const agx::Vec2i& terrainIndex, int z) const;
float TerrainGridControl::getSurfaceCompaction(const agx::Vec2i& terrainIndex) const;
void TerrainGridControl::setCompaction(const agx::Vec3i& terrainIndex, float compaction, bool compressOccupancy = false);
void TerrainGridControl::setSurfaceCompaction(const agx::Vec2i& terrainIndex, float compaction, bool compressOccupancy = false, bool compressToBottom = false);

Compaction can also be set from the surface to a specified depth:

void TerrainGridControl::setSurfaceCompactionToDepth(const agx::Vec2i& terrainIndex, float compaction, float depth);

The soil is normally compacted via contacts from external geometries that generates surface terrain contacts where the contact area is calculated from the voxels that the geometry is overlapping. A uniform surface stress in the voxel contact patch is estimated from the contact force and the estimated area. The active terrain contacts that generate soil pressure can be extracted from the terrain and it’s properties extracted:

auto terrainContacts = terrain->getTerrainContacts();
for( const auto& c : terrainContacts )
{
  auto geometry           = c.getGeometry();
  agx::Real surfaceStress = c.getSurfaceStress();
  agx::Real area          = c.getArea();
}

Pressure propagates down into the soil by approximating the surface in each voxel as a uniform plate. The pressure thus decays according to the formula:

\[\sigma^{v}_{z}(z) = \sigma_s \left[ 1 - \left( \frac{z}{\sqrt{A_s + z^2}} \right)^3 \right]\]

where \(\sigma^{v}_{z}(z)\) is the local stress in depth \(z\) from the surface, \(A_s\) is the plate area and \(\sigma_s\) is the uniform surface stress.

The soil is compacted in a grid cell if it exceeds the local preconsolidation stress from earlier compactions or the starting preconsolidation stress. The level of compaction is determined by the specified compression index and the preconsolidation stress in the Compaction Properties. The compression index is defined as a logarithmic dependence between the change in compaction/void ratio from stress:

\[C_c = \frac{ e_0 - e_1 }{ \ln{ \sigma / \sigma_0 } }\]

The new density in a grid cell is thus calculated via the following expression:

\[\rho = \rho_0 [ 1 + \phi_0 C_c \ln{ \frac{ \sigma }{ \sigma_0 } } ]\]

where the \({\phi}_0\) is the volume fraction of the material, \(\sigma_0\) the preconsolidation stress of the material, \(C_c\) the compression index of the material, \(\sigma\) the local stress and \(\rho_0\) the density if the material at compaction 1.0 (i.e the bank state).

This is then used to calculate the compaction level at grid cell \(i\):

\[c_i = \rho / {\rho}_0\]

One can apply a time relaxation to the rate of compaction changes in the terrain. It is governed by the following equation:

\[f_t = 1 - \exp[ - t_c/\tau ]\]

where \(\tau\) is the time relaxation constant and \(t_c\) is the contact duration time. The timefactor is multiplied with the estimated density changes and approaches 1.0 as the contact time increases.

The parameters for the soil compaction algorithms can be found and adjusted in the CompactionProperties object.

24.14.1. Material changes from compaction

Some material properties change locally from compaction level.

24.14.1.1. Young’s Modulus

The local Young’s Modulus in a grid element changes according to the following relation:

\[E_{bulk} = E^{0}_{bulk} \left[ 1.0 \pm k_E \left[ \frac{ \rho }{ \rho_0 } - 1.0 \right]^{n_e} \right]\]

where \(E_0\) is the bulk elasticity in the bank state and \(k_e\) and \(n_e\) are hardening parameters that have default values of 1.0 and 0.5 respectively.

24.14.1.2. Swelling

When solid soil undergoes transformation to dynamic soil during excavation, the soil particle bulk volume expands according to the specified Swell Factor of the material. When the dynamic soil is transformed back to solid during merge it will have a compaction level according to:

\[c_i = 1.0 / S_f\]

where \(c_i\) is the local compaction at grid element i and \(S_f\) is the Swell Factor.

24.14.1.3. Angle of Repose

The local angle of repose changes with varying compaction levels by adjusting the allowed relative heights between two grid elements by using the following formulation:

\[\begin{split}h_r &= \tan{ \psi_{r} } L \\ h_r &= h_r m \\ m &= 2 ^ { M ( max( 0.0, c_i - ( 1.0 ) ) ) }\end{split}\]

where \(M\) is a constant, \(\psi_{r}\) is the effective repose angle of the material, \(L\) is the length of a grid cell, \(c_i\) is the local compaction level at cell i. This effectively means that compaction levels above 1.0 increases the angle of repose for the material.

24.15. Dynamic Soil

Dynamic mass is created in the active zone intersection between the Shovel and the Terrain. It consists of both fluid mass and soil particles.

Soil particles are expressed in the form of 6-degrees of freedom (6-DOF) soil particles with hertzian contact dynamics, Coulomb friction and rolling resistance. The user can access and create soil particles via the soil simulation interface. The soil particles created from the shovel active zone intersection is simulated in the main simulation and can interact with other objects. By default, only the particles see the shovels as kinematic objects. This means that the particles themselves do not give force feedback to the shovels. The mass in the active zone, from both dynamic and solid mass, is used in the construction of the active zone aggregate that generates force feedback on the shovel through created contacts.

Note

The number of active soil particles depends on the amount of grid points touched by the dig volume which is a function of both blade size, dig depth, terrain resolution and dig length. A larger volume of influence means increased numbers of touched grid points and created particles which leads to an increase in computational time.

Soil particles are created when the active zone of the shovel touches new grid points. Fluid mass is generated if the shovel continues to remove mass from the same grid point and is then spread onto existing particles in the area, increasing their size. The fluid mass movement is integrated using a velocity field in the terrain grid generated from the shovels and the soil particles. If there are no particles that the fluid can merge to, it will merge back to the terrain.

Particles are also resized locally to cluster around a nominal radius. This is calculated from the resulting element size upon construction of the terrain object. It is also modified by the material swell factor and estimated packing ratio of the particles so that the total bulk volume of the particles created should correspond to the volume excavated, modified by the expected volume swelling. This radius can be extracted by using the following function:

agx::Real getParticleNominalRadius()

The radius that the particles cluster around can be altered using the soil particle scaling factor. What this does is that it alters the average radius of the soil particles, this can be used either to reduce the number of particles in the simulation to gain a potentially significant performance increase, or by increasing the number of soil particles to increase fidelity or better dynamic soil visuals. This scaling factor can be set and extracted using the following functions respectively:

void getProperties()->setSoilParticleSizeScaling( 1.5 )
agx::Real getProperties()->getSoilParticleSizeScaling()

The contact network between the soil particles is solved using an iterative Parallel-Projected-Gauss-Seidel Solver (PPGS) together with the rest of the system. It is enabled in the simulation as soon as a terrain instance is added. The user can also set the fidelity of the solver by adjusting the setNumPPGSRestingIterations which sets the number of iterations used in the PPGS solver. Increasing the iteration number typically results in the better solution and may be necessary when the particle counts increases in the simulation in order to get correct bulk behavior with stable particle piles that merge properly with the terrain. The default number is 25 iterations:

simulation->getSolver()->setNumPPGSRestingIterations( 25 );
simulation->getSolver()->setUseParallelPgs( false );

Warning

The PPGS solver currently disables island partitioning which means that performance will be lost if the scene contains multiple self-contained systems.

24.15.1. SoilSimulationInterface

Users can extract the agxTerrain::SoilSimulationInterface to access and create soil particle data in the terrain. The currently active dynamic soil particles in a simulation can be accessed via the following function:

auto soilSimulationInterface = terrain->getSoilSimulationInterface();
agx::Real totalMass{ 0.0 };
agx::Real averageRadius{ 0.0 };
auto soilParticles = soilSimulationInterface->getSoilParticles();
for ( auto& particle : soilParticles )
{
  totalMass += particle->getMass();
  averageRadius += particle->getRadius();
  agx::Vec3 position = particle->getPosition();
  agx::Vec3 velocity = particle->getVelocity();
}
averageRadius /= soilParticles.size();

Note

Do note that changing either mass, material or radius will change the mass of the particle and thus violate mass conservation.

Warning

It is not recommended to change particle properties such as mass and material as those are derived from the Terrain instance.

Individual soil particles can be created and removed manually:

auto soilSimulationInterface = terrain->getSoilSimulationInterface();
agx::Real radius = terrain->getParticleNominalRadius();
agx::Vec3 position{ 0.0, 0.0, 1.0 };
agx::Vec3 velocity{ 0.0, 0.0, 0.0 };
auto soilParticle = soilSimulationInterface->createSoilParticle(radius, position, velocity);
soilParticle->setPosition( ... );
soilParticle->setVelocity( ... );
...
soilSimulationInterface->removeSoilParticle( soilParticle );

Before doing any operations on the particles in the terrain, it can be useful to check if the particle is valid or not already removed:

auto soilParticles = soilSimulationInterface->getSoilParticles();
for ( auto& particle : soilParticles )
{
  if ( soilSimulationInterface.isValid( p )
  {
    ...
  }
}

Soil particle collisions can be controlled via the collision group system in agxCollide::Space and added to the created soil particles via the soil interface:

// Create a collision group and add it to all particles
agx::Name collisionGroup { "myCollisionGroup" };
soilSimulationInterface->addCollisionGroup( collisionGroup );

/**
Disable collisions between the objects that have the specified group. This will prevent particles
from colliding with eachother.
*/
simulation->getSpace()->setEnablePair( collisionGroup, collisionGroup, false );

The current active bulk volume of soil particles can be extracted by using the following function:

/**
\return soil particle bulk volume (m3) active in the simulation.
\note - the bulk volume is the specific volume of all particles divided with the
        estimated particle packing fraction (0.67)
*/
agx::Real calculateSoilParticleBulkVolume() const;

The internal GranularBodySystem used for simulating the soil particles can be extracted and used with other objects, such as a agx::ParticleEmittter to create masses of soil particles.

agx::Physics::GranularBodySystem* getGranularBodySystem() const;

Warning

When using an emitter with the GranularBodySystem, the emitter particle material should be the same as the particle material of the terrain that the emitted particles should belong to! The particle material is used by different terrains in the simulation to determine which particle belongs to which terrain instance.

24.15.2. Custom soil failure volume

In certain cases it is desirable to be able to trigger soil conversion into dynamic soil particles manually without the terrain interacting with a shovel. This can be achieved by creating a soil failure volume and providing it to the terrain. The following code showcases how to trigger soil failure in a 1x1x1 box:

agxCollide::Box failureVolume = agxCollide::Box(0.5,0.5,0.5);
terrain->convertToDynamicMassInShape(failureVolume);

24.16. Excavation Model

We refer to the published academic paper 1 for a more in-depth explanation of the mathematical model for agxTerrain. This section will only provide a brief overview of the different components of the model.

When creating a shovel from the specified edges deformation planes are created from the geometry of the shovel. When the shovel performs excavation operations in the terrain active zones against the deformation planes. The active zones consists of discretized soil wedges that are created from soil mechanics theory.

../_images/shovel_model.png

Fig. 24.10 The left images illustrate a digging tool with a cutting edge e c (red line), separating plate n c (red face), deformer edge e d (blue line), deformer face n d (blue face) and top edge e t (yellow line). The inner shape is indicated with the dashed lines. The normal n fill of the secondary separation plate range from n c to n ct depending on the fill ratio of the inner shape. The three active zones, discretized by vertical wedges, is illustrated from the rear (upper right) and from above (lower right).

Four different excavation are automatically constructed from the edges that are active in soil deformation:

Primary

This is the primary excavation mode of the shovel that is driven by the separation plate. Defined by the top edge and cutting edge and cutting direction.

Deformer Back

This is the deformer plane defined by the underside of the shovel. Used in grading and push operations.

Deformer Left

This is the deformer plane to the left side of the shovel. Used in grading and push operations.

Deformer Right

This is the deformer plane to the right side of the shovel. Used in grading and push operations.

These individual planes can be configured.

24.16.1. Mass deformation model

As the shovel moves through the terrain it converts solid mass into dynamic mass in the active zone, consisting and internal fluid and particle mass:

../_images/soil_deformation_model.png

Fig. 24.11 As a blade and its active zone moves into the terrain a, new solid voxels are resolved into particles or fluidized mass that form the aggregate body. The voxel height value, corresponding to the solid occupancy, is found by projection to the failure plane of the active zone. When the blade is raised b, the gap is filled by solid mass converted from fluidized or particle mass in the vicinity of the edge.

24.16.2. Excavation Resistance Model

Force feedback in the separation and deformation mode is generated by aggregate rigid bodies bodies created from dynamic and solid mass in the shovel active zones. Contacts are created both between the shovel and the aggregate and the aggregate and terrain. The resulting forces depend on the contact materials properties derived from the agxTerrain::TerrainMaterial bulk properties and also the contact material between the shovel and the terrain that is used for the shovel-aggregate contacts.

../_images/aggregate_zones.png

Fig. 24.12 Figure showing the aggregate formation during excavation. Primary separation resistance is denoted in red and the deformer zones are denoted in green. The resulting aggregate contacts for aggregate <-> terrain and aggregate <-> shovel are denoted in orange. The blue lines denote the direction of the soil wedges that are created in the terrain via calculation using the Fundamental Earth Moving model (FFE) and the material bulk properties. These soil wedge shapes are the basis for the failure zone that ultimately form the soil aggregates in the separation and deformer zones.

24.16.3. Penetration Resistance Model

Pure penetration occur when a thin tool moves straight into the terrain, displacing only the soil necessary for fitting the tool. Buckets are often penetrated deep into the soil before separation (cutting) starts. The penetration resistance experienced by a tool consists of two main parts: from the teeth (or edge) and from the primary separating plate. The resistance from the separating plate contacting the soil is simply modeled by a frictional force proportional to the passive earth pressure in the soil. The pressure on the teeth during penetration can be modeled by using the cavity expansion model. The penetration force acts in the cutting direction of the Shovel.

../_images/penetration_resistance.png

Fig. 24.13 Figure illustrating the shovel <-> terrain interaction during a wheel loader digging process. The penetration resistance works in the cutting direction parallel to the separation plate of the bucket and is expressed as a prismatic velocity constraint with force limits according to the penetration model theory.

24.17. Performance notes

The performance of agxTerrain depends on the number of dynamic soil particles in the simulation. The number of active soil particles depends on the amount of grid points touched by the dig volume, which in turn is a function of both blade size, dig depth, terrain resolution and dig length. A larger volume of influence means increased numbers of grid points and more particles, and thus an increase in computational time.

The number of solver iterations set via setSolverIterations via SoilSimulationInterface also determines the overall performance. Increasing the solver iterations is needed when particle count increases in order to get stable soil piles. A low iterations count relative to the amount of particles will results in an error that introduces numerical vibrational noise in the contact forces, causing the particle piles to “melt”. A typical cue of when to increase solver iterations is when the particles are unable to merge with the terrain due to this numerical noise.

Do note that the material parametrization of the terrain, with the exception of terrain resolutions, does not overtly affect the performance. This means that soil behavior should be achieved without compromising performance.

References

1(1,2)

Servin, M., Berglund, T. & Nystedt, S. A multiscale model of terrain dynamics for real-time earthmoving simulation. Adv. Model. and Simul. in Eng. Sci. 8, 11 (2021). link

24.18. FAQ

24.18.2. Answers

Why do I get an error of “bad soil wedges” during excavation?

This error occurs when the soil wedge geometries are improperly constructed, due to a faulty shovel setup. The problem is typically associated with misaligned vectors, specifically in the top edge or cutting edge directions. To resolve the error, consider adjusting the orientations of these vectors to ensure proper alignment.

Why is my shovel not digging?

There are several reasons why your shovel might not be digging. First, take a look at the Shovel setup section here in the User Manual. The vectors specified in the schematic can be seen in debug mode, which is accessed by pressing g in agxViewer. If that does not help, try to resolve the following questions:

  • Is the cutting direction vector specified in the correct direction?

  • Is the cutting edge vector actually aligned with the shovel geometry?

  • Is the shovel added to the terrain you want it to dig in?

  • Is the terrain added to the simulation?

There are also several tutorials where shovels are setup from simpler geometric shapes in the data\python\tutorials\agxTerrain folder.

How can I reduce the amount of soil particles in the simulation without lowering the terrain resolution?

The amount of particles in the simulation can be adjusted with the following method:

auto* properties = terrain->getProperties();
// Increase the particle radius by a factor of two.
properties->setSoilParticleSizeScaling(2.0);

This scaling factor modifies the nominal radius of the created soil particles with a scalar factor. Increasing the nominal radius will adjust the soil mass resizing algorithm to increase the particle size and correspondingly reduce the amount of particles in the simulation.

How can I modify the digging resistance?

The digging resistance encountered during excavation is a combination of several forces. The primary approach for modifying digging resistance includes fine-tuning the contact material properties between the shovel and terrain. This affects both penetration, separation and deformation resistance. Additionally, tweaking the terrain material properties, such as soil density and friction angle, can change contact forces between aggregate and terrain.

The effective terrain material properties used in the force calculations are also affected by the local compaction in the terrain, which also can be adjusted manually. There is also a PenetrationForceScaling parameter which can be used to adjust the penetration resistance.

The User Manual provides a dedicated chapter on the Calibration of excavation resistance, and there is also a chapter on soil compaction, which we urge you to read in case you are interested in modifying the digging resistance.

How do I measure the amount of material in a bucket?

One way to do this is to measure the total weight of the soil aggregates in the shovel.

There are two kinds of aggregates that are created:

  • Inner body = the inner body inside the confines of the shovel.

  • Wedge bodies = the soil wedge bodies that are created during excavation.

To get the amount of material inside the confines of the bucket, use the following method:

agx::Real innerBodyMass = terrain->getToolCollection(shovel)->getSoilParticleAggregate()->getMass();

To get the amount of material in the wedge bodies, use the following method:

agx::Real  wedgeBodyMass = terrain->getToolCollection(shovel)->getSoilParticleAggregate()->getTotalAggregateMass() - innerBodyMass;

Of course, you can use the following method to get the combined mass for all aggregates formed in and on the shovel.

terrain->getToolCollection(shovel)->getSoilParticleAggregate()->getTotalAggregateMass();

How can I calculate the amount of transported/excavated material?

This is quite complicated to achieve but possible. During each dig cycle, a moment where the shovel contains the amount that is excavated/transported needs to be identified.

Preferably this is while the shovel is raised above the ground. In that moment we measure the amount of material in the bucket, and then we dump the contents of the shovel somewhere. The amount measured during the repeated dig cycles then needs to be summed up in the end, to find out how much material has been transported/excavated during the simulation.

Note that there is a method on the terrain which can be called in every POST-step to get the last excavated volume in [m^3]:

agx::Real lastExcavatedVolume = terrain->getLastExcavatedVolume();

This is the volume which is transformed into dynamic mass in each timestep and not that which is captured by the shovel.

How can I use the terrain on the bed of a truck?

This is achieved by adding the terrain geometry to the truck’s rigid body:

// Given that truck is an agx::RigidBody
truck->add(bedTerrain->getGeometry());

The bedTerrain must be constructed to fit onto the bed of the truck. To allow tipping, failure zones also have to be constructed which trigger the conversion of the solid terrain into dynamic mass when the bed is tipped to a certain angle. How this is done is shown in the tutorial tutorial_soil_failure_volume.agxPy.

How can I simulate mud so that I sink down with the vehicle?

You can simulate the sinking into the terrain by using soil compaction. How much the vehicle sinks is defined by the terrain materials compaction properties, which are accessed via the following method:

auto compactionProperties = terrainMaterial->getCompactionProperties()

Where the terrain material is in the desired area. The tutorial tutorial_compressed_soil.agxPy shows some basics of manipulating the compaction properties of a terrain material to allow sinkage of external objects.

How can I “reset” the terrain quickly to its initial state?

This can be achieved by saving the terrain heights in the initial state and then later setting the heights again. Use the following methods:

agx::RealVector initialHeights = terrain->getResizedHeightField(1, 1);
//... later in the simulation, use the initialHeights to reset the height field:
terrain->setHeights(initialHeights);

The setHeights method also takes a resetCompaction parameter, which by default resets the compaction values in the terrain. This means if you have changed the compaction values manually with the terrain->setCompaction(agx::Real compaction) call, this needs to be repeated. Similarly, if you have added any additional terrain material configurations, the information of which terrain material existed in the excavated terrain may have been lost and need to be reapplied again. Also, if you have performed some sort of excavation operation you might also need to remove lingering particles. This can be achieved via the granular system:

auto soilParticles = terrain->getSoilSimulationInterface()->getSoilParticles();
for(auto sp : soilParticles)
  terrain->getSoilSimulationInterface()->removeSoilParticle(sp);

How do I adjust the static angle of repose in my simulations?

The angle of repose is controlled via the following terrain material parameters:

// The friction angle(radians) has 1:1 relationship with the angle of repose of the material
bulkProperties->setFrictionAngle(0.7);

// The delta repose angle (radians) that is applied on the friction angle when determining the angle of repose of a material.
bulkProperties->setDeltaReposeAngle(0.15);

You can adjust these to get the angle of repose you want. It is also worth noting that soil compaction also modifies the local angle of repose.

How can I simulate dry or wet sand?

You can simulate both dry and wet sand by adjusting specific terrain material parameters. Two key parameters to focus on are bulk density and bulk cohesion, and the internal friction angle plays a role as well. Dry sand typically has a lower bulk density than wet sand, reflecting the absence of added moisture. On the other hand, simulating wet sand involves increasing the bulk density, as water contributes to the overall mass.

In granular materials with particles exceeding 0.1 mm in diameter, repulsive forces usually dominate. However, as moisture content rises, bulk cohesion may increase due to capillary forces and chemical reactions at particle contact points. It’s important to note that excessive water content can lead to pore pressure, diminishing attractive contact forces and thereby reducing internal friction, a parameter influenced by the internal friction angle. Consequently, bulk cohesion may decrease as capillary forces diminish.

In summary, manipulating the terrain material properties of bulk density, bulk cohesion, and the internal friction angle allows for the accurate simulation of both dry and wet sand conditions.