Difference between revisions of "Material Point Reservoir"

From OSUPDOCS
Jump to navigation Jump to search
 
(48 intermediate revisions by the same user not shown)
Line 2: Line 2:
== Introduction ==
== Introduction ==


Simulations in NairnMPM are currently limited to a fixed number of particles. To allow for simulations options to delete particles or inject particles, the code implements a reservoir of material points. This reservoir is currently only implemented in [[OSParticulas]] but will be moved to NairnMPM soon.
Standard simulations in NairnMPM ar limited to a fixed number of particles. To allow for simulation options that delete particles or inject particles, the code implements a reservoir of material points.


The reservoir is created automically for all simulations (unless you are using an [[Explicit FEA Mesh Generation#Explicit MPM Grid|unstructured grid]], which is uncommon because many features are lost for such grids). For most simulations, the reservoir handles all options that might [[#Deleting Particles|delete particles]] and happens automatically without your input commands needing extra commands to set eservoir properties. Some features (which currently are only in [[MPM_Input_Files#Custom Tasks|custom tasks]]) can inject particles into the simulation. To use any such custom task, your input commands should [[#Fill the Reservoir|pre-fill the reservoir]] with particles type needed for that task..
The reservoir is created automatically for all simulations (unless you are using an [[Explicit FEA Mesh Generation#Explicit MPM Grid|unstructured grid]], which is uncommon because many features are lost for such grids). The reservoir handles all options that might [[#Deleting Particles|delete particles]] and happens automatically without your input commands needing extra commands to set reservoir properties. Other reservour options are typically implemented in [[MPM_Input_Files#Custom Tasks|custom tasks]]. For example the [[FluidSource Custom Task]] can inject particles at some fixed rate at a predetermined location. The development of new reservoir features can be done by [[Writing a Custom Task|writing new custom tasks]] and using [[#Adding Reservoir Methods to a Custom Task|reservoir methods defined below]]. When a [[MPM_Input_Files#Custom Tasks|custom task]] might inject particles, your input commands should [[#Fill the Reservoir|pre-fill the reservoir]] with particles of the type needed for that task.


== Deleting Particles ==
== Deleting Particles ==


Any feature that deletes particles, moves those particle into the reservoir. These reservoir tasks happen automatically. You input commands only need to invoke options that delete particles. The current options are:
Any feature that deletes particles, moves those particle into the reservoir. These reservoir tasks happen automatically. Your input commands only need to invoke options that delete particles. The current options are:


* [[LeaveLimit Command]] - if this command's <tt>(maxNum)</tt> parameter is negative, particles that leave the grid are deleted from the simulation.
* [[LeaveLimit Command]] - if this command's <tt>(maxNum)</tt> parameter is negative, particles that leave the grid are deleted from the simulation.
* [[DeleteLimit Command]] - if this command's <tt>(maxNum)</tt> parameter is greater than 1, particles that develop nan are deleted from the simulation.
* [[DeleteLimit Command]] - if this command's <tt>(maxNum)</tt> parameter is greater than 1, particles that develop <tt>nan</tt> are deleted from the simulation.
* [[DeleteDamaged Custom Task]] - this task can delete damaged particles after decohesion.
* [[DeleteDamaged Custom Task]] - this task can delete damaged particles after decohesion.
* [[JWLPlusPlus Material]] - this material has an option to delete gas particles a sufficient distance from the ignition site.
* [[JWLPlusPlus Material]] - this material has an option to delete gas particles a sufficient distance from the ignition site.
Line 21: Line 21:
* [[FluidSource Custom Task]] - to inject liquid particles at a specified rate, location, and direction.
* [[FluidSource Custom Task]] - to inject liquid particles at a specified rate, location, and direction.


User-written custom tasks can also inject particles and more documentation on writing such tasks will be provided soon.
User-written custom tasks can also inject particles. Information on adding reservoir features to a custom task is given [[#Adding Reservoir Methods to a Custom Task|below]].


== Filling the Reservoir ==
== Filling the Reservoir ==


To allow custom tasks to inject particles, the reservoir normally needs to be seeded with enough material points for the injection process. The command to fill the reservoir in scripted files is:
To allow custom tasks to inject particles, the reservoir needs to be seeded with enough material points for the injection process. The command to fill the reservoir in scripted files is:


  Fill (num),(matid),<(lx)>,<(ly)>,<(lz)>
  Fill (num),(matid),<(lx)>,<(ly)>,<(lz)>
Line 43: Line 43:
== Adding Reservoir Methods to a Custom Task ==
== Adding Reservoir Methods to a Custom Task ==


The reservoir class is automatically added to all simulations (unless you are using an [[Explicit FEA Mesh Generation#Explicit MPM Grid|unstructured grid]]). To write code that uses the reservoir, your custom task should include the <tt>NairnMPM_Class/Reservoir.hpp</tt>. This header defines global variable as pointed to the create <rr>Reservoir</tt> class:
The reservoir class is automatically added to all simulations (unless you are using an [[Explicit FEA Mesh Generation#Explicit MPM Grid|unstructured grid]]). To write code that uses the reservoir, your custom task should include the <tt>NairnMPM_Class/Reservoir.hpp</tt>. This header defines a global variable that provides a pointer to the created <tt>Reservoir</tt> class:


   extern Reservoir *mpmReservoir
   extern Reservoir *mpmReservoir
Line 63: Line 63:
Whenever your task determines that a particle should be injected, call:
Whenever your task determines that a particle should be injected, call:


  MPMBase *Reservoir::InjectParticle(Vector *location,Vector *lpart,int matid)
  mpmReservoir->InjectParticle(Vector *location,Vector *lpart,int matid)


where
where


* <tt>location</tt> is pointer to vector for injection location
* <tt>location</tt> is pointer to vector for injection location
* <tt>lpart</tt> is point to desired absolute size for the injected particle
* <tt>lpart</tt> is pointer to vector with desired absolute size for the injected particle (for 2D simulations, the z coordinated is never accessed).
* <tt>matid</tt> is the desired material ID for the injected particle
* <tt>matid</tt> is the desired material ID for the injected particle


The method returns a pointer to the material point that was injected. The particle will be cleared to properties that would exist at the start of a simulation, If needed, your custom tasks can set any material point properties, provided they are consistent with simulation needs. If the reservoir is empty (or just empty of the type of requested particle type), this method will return <tt>NULL</tt>.
The method returns a pointer to the material point that was injected. The particle will be reset to properties that would exist at the start of a simulation. If needed, your custom task can set any material point properties, provided they are consistent with simulation needs. If the reservoir is empty (or just empty for the requested type), this method returns <tt>NULL</tt>. '''Warning''': see instructions on [[#Parallel Coding|parallel coding]] when this method is needed in a block of parallel code.


The reservoir maintains separate lists of particles sorted by size and material ID. Normally, you want to fill reservoir with needed size and material ID and then retrieve from those lists when needed by your task. Some options with these parameters are:
The reservoir maintains separate lists of particles sorted by size and material ID. Normally, you want to [[#Filling the Reservoir|fill the reservoir]] with needed sizes and material IDs and then retrieve from those lists when needed by your task. Some options with these parameters are:


# <tt>lpart = NULL</tt> - pass <tt>NULL</tt> in this parameter means you do not care about particle size. The method will return the first particle found that matches <tt>matid</tt>. This option might be common for a simulations in which all particles are the same size and your custom tasks has no need to every change particle size.
# <tt>lpart = NULL</tt> - passing <tt>NULL</tt> in this parameter means you do not care about particle size. The method will return the first particle found that matches <tt>matid</tt>. This option might be common for a simulations in which all particles are the same size and your custom tasks has no need to ever change particle size.
# <tt>*lpart</tt> has unknown size - if you request a particle size that is not in the reservoir, this method will find a particle that matches <tt>matid</tt> and change its size to your requested size. The mass of the particle will also scale to the new size. Note that for visualization efficiency, it is better to avoid changing particle sizes. Thus, if possible, you should [[#Filling the Reservoir|fill the reservoir]] will all sizes needed by your custom tasks. For some tasks, however, the needed size might depend on simulation time. For such tasks, this method handles size changes and writes information to the <tt>PtDims.txt</tt> results file that visualization tools use to plot particles correctly even when they change size during a simulation.
# <tt>*lpart</tt> has unknown size - if you request a particle size that is not in the reservoir, this method will find a particle that matches <tt>matid</tt> and change its size to your requested size. The mass of the particle will scale to the new size and information will be written to the <tt>PtDims.txt</tt> results file that visualization tools use to plot particles correctly even when they change size during a simulation. Note that for visualization efficiency, it is better to avoid changing particle sizes. Thus, if possible, you should [[#Filling the Reservoir|fill the reservoir]] will all sizes needed by your custom task. Some tasks, however, might not know the needed size until a simulation is running. This method will handle size changes needed by such tasks.
# <tt>matid&lt;=0</tt> - using this setting means you will accept any material type in the reservoir. The first one found will be returned. This option might be common for a simulations in which all particles are the same material type.
# <tt>matid&lt;=0</tt> - using this setting means you will accept any material type in the reservoir. The first one found will be returned. This option is acceptable for simulations in which all particles are the same material type.


=== Delete a Particle ===
=== Delete a Particle ===
Line 83: Line 83:
To delete a particle, call:
To delete a particle, call:


  void Reservoir::DeleteParticle(MPMBase *mpmptr)
  mpmReservoir->DeleteParticle(MPMBase *mpmptr)


where <tt>mpmptr</tt> is pointer to material point to be deleted. All properties of the particle will be reset to initial conditions. If needed, the particle size will be changed to match size for a list in the reservoir. If size is changed, the mass will be rescaled and information written to the <tt>PtDims.txt</tt> results file.
where <tt>mpmptr</tt> is pointer to material point to be deleted. All properties of the particle will be reset to initial conditions. If needed, the particle size will be changed to match size for a list in the reservoir. If size is changed, the mass will be rescaled and information will be written to the <tt>PtDims.txt</tt> results file. '''Warning''': see instructions on [[#Parallel Coding|parallel coding]] when this method is needed in a block of parallel code.
 
=== Parallel Coding ===
 
Note that neither [[#Inject a Particle|<tt>InjectParticle()</tt>]] nor [[#Delete a Particle|<tt>DeleteParticle()</tt>]] are thread safe. Their use depends on style of a parallel block of code. Neither method can be called at all in parallel code that assigns each thread to a patch on the MPM grid. The reason is that particle injection and deletion change pointers needed by patch looping. For parallel scaling, the best approach when injecting or deleting is needed in such blocks is to build a list of particles to be injected or deleted. When the parallel block over patches is done, inject or delete particle in those lists during the reduction phase for that parallel coding. You can see an example of this approach that deletes particles in the <tt>ResetElementsTask.cpp</tt> class.
 
Within other parallel blocks (<i>e.g.</i>, loops over nodes or particles), both [[#Inject a Particle|<tt>InjectParticle()</tt>]] and [[#Delete a Particle|<tt>DeleteParticle()</tt>]] can be callsed, but they can only be used by one thread at a time. In other words, calls to these methods need to be within OpenMP critical blocks:
 
// Inject particle only in single thread
#pragma omp critical (reservoir)
{
      mpmReservoir->InjectParticeParticle(mptr,&lp,matid);
}
// Delete particle only in single thread
#pragma omp critical (reservoir)
{
      mpmReservoir->DeleteParticle(mptr);
}


=== Changing a Particle Size ===
=== Changing a Particle Size ===
Line 91: Line 109:
To change the size of any particle without moving it to the reservoir, call
To change the size of any particle without moving it to the reservoir, call


  void Reservoir::ChangeParticleSize(MPMBase *mptr,Vector *lpart)
  mpmReservoir->ChangeParticleSize(MPMBase *mptr,Vector *lpart)
 
where <tt>mptr</tt> is pointer to the material point and <tt>lpart</tt> is the new absolute size. The reason to use this method is to change size without changing other material point properties. This method handles re-scaling of the mass, changing the size, and writing information to the <tt>PtDims.txt</tt> results file. Your custom task is responsible for determining that the size change does not cause numerical artifacts. For example, the size change might need to go along with changes to other particle properties. '''Warning''': Although this method can be used in any type of parallel block, to avoid potential race conditions saving information about particle size changes, it should be called in an OpenMP critical block:


where <tt>mptr</tt> is pointer to the material point and <tt>lpart</tt> is the new absolute size. The reason to use this methods is to change size without changing other material point properties. The method handles rescaling the mass, changing the size, and writing information to the <tt>PtDims.txt</tt> results file. Your custom tasks is responsible for determinng the size change does not cause numerical artifacts. For example, the size change might need other particle properties need to be changes as well.
// Change size only in single thread
#pragma omp critical (reservoir)
{
      mpmReservoir->ChangeParticleSize(mptr,&lp);
}

Latest revision as of 08:21, 14 January 2023

Introduction

Standard simulations in NairnMPM ar limited to a fixed number of particles. To allow for simulation options that delete particles or inject particles, the code implements a reservoir of material points.

The reservoir is created automatically for all simulations (unless you are using an unstructured grid, which is uncommon because many features are lost for such grids). The reservoir handles all options that might delete particles and happens automatically without your input commands needing extra commands to set reservoir properties. Other reservour options are typically implemented in custom tasks. For example the FluidSource Custom Task can inject particles at some fixed rate at a predetermined location. The development of new reservoir features can be done by writing new custom tasks and using reservoir methods defined below. When a custom task might inject particles, your input commands should pre-fill the reservoir with particles of the type needed for that task.

Deleting Particles

Any feature that deletes particles, moves those particle into the reservoir. These reservoir tasks happen automatically. Your input commands only need to invoke options that delete particles. The current options are:

  • LeaveLimit Command - if this command's (maxNum) parameter is negative, particles that leave the grid are deleted from the simulation.
  • DeleteLimit Command - if this command's (maxNum) parameter is greater than 1, particles that develop nan are deleted from the simulation.
  • DeleteDamaged Custom Task - this task can delete damaged particles after decohesion.
  • JWLPlusPlus Material - this material has an option to delete gas particles a sufficient distance from the ignition site.

Injecting Particles

Some simulations might work better by injecting particles as needed rather then starting will all particles already in place. In the future, built-in feature that inject particle might be added, but currently particle injection is only done in custom tasks. The only custom task that injects particles is:

User-written custom tasks can also inject particles. Information on adding reservoir features to a custom task is given below.

Filling the Reservoir

To allow custom tasks to inject particles, the reservoir needs to be seeded with enough material points for the injection process. The command to fill the reservoir in scripted files is:

Fill (num),(matid),<(lx)>,<(ly)>,<(lz)>

In XML files, the reservoir is filled using a Fill element that must be within the single <MaterialPoints> element in the input file:

 <MaterialPoints>
   <Fill num='(num)' mat='(matid)' lx='(lx)' ly='(ly)' lz='(lz)'/>
 </MaterialPoints>

where

  • (num) is the number of material points to put into the reservoir.
  • (matid) is the material ID for a previously defined material (which must be a material number in XML files).
  • (lx), (ly), and (lz) optionally specify the size of the material point in length units. If these optional parameters are not provided, the material points will use the default size for the simulation (as set using the PtsPerElement command). When a custom task injects particles of a certain size, that size must made available in the reservoir by use a matching size in this command.

Adding Reservoir Methods to a Custom Task

The reservoir class is automatically added to all simulations (unless you are using an unstructured grid). To write code that uses the reservoir, your custom task should include the NairnMPM_Class/Reservoir.hpp. This header defines a global variable that provides a pointer to the created Reservoir class:

 extern Reservoir *mpmReservoir

Your custom tasks can use the following features of the reservoir.

Custom Tasks Initialization

The custom task Initialize() method is called for each custom task before the simulation begins. It is good practice for this method to verify the reserviour is available. Typical code to start the Initialize() method is:

// requires reservoir
if(mpmReservoir==NULL)
{   throw CommonException("This custom task requires an available reservoir (i.e., a structured grid)",
                          "MyCustomTasks::Initialize");
}

Inject a Particle

Whenever your task determines that a particle should be injected, call:

mpmReservoir->InjectParticle(Vector *location,Vector *lpart,int matid)

where

  • location is pointer to vector for injection location
  • lpart is pointer to vector with desired absolute size for the injected particle (for 2D simulations, the z coordinated is never accessed).
  • matid is the desired material ID for the injected particle

The method returns a pointer to the material point that was injected. The particle will be reset to properties that would exist at the start of a simulation. If needed, your custom task can set any material point properties, provided they are consistent with simulation needs. If the reservoir is empty (or just empty for the requested type), this method returns NULL. Warning: see instructions on parallel coding when this method is needed in a block of parallel code.

The reservoir maintains separate lists of particles sorted by size and material ID. Normally, you want to fill the reservoir with needed sizes and material IDs and then retrieve from those lists when needed by your task. Some options with these parameters are:

  1. lpart = NULL - passing NULL in this parameter means you do not care about particle size. The method will return the first particle found that matches matid. This option might be common for a simulations in which all particles are the same size and your custom tasks has no need to ever change particle size.
  2. *lpart has unknown size - if you request a particle size that is not in the reservoir, this method will find a particle that matches matid and change its size to your requested size. The mass of the particle will scale to the new size and information will be written to the PtDims.txt results file that visualization tools use to plot particles correctly even when they change size during a simulation. Note that for visualization efficiency, it is better to avoid changing particle sizes. Thus, if possible, you should fill the reservoir will all sizes needed by your custom task. Some tasks, however, might not know the needed size until a simulation is running. This method will handle size changes needed by such tasks.
  3. matid<=0 - using this setting means you will accept any material type in the reservoir. The first one found will be returned. This option is acceptable for simulations in which all particles are the same material type.

Delete a Particle

To delete a particle, call:

mpmReservoir->DeleteParticle(MPMBase *mpmptr)

where mpmptr is pointer to material point to be deleted. All properties of the particle will be reset to initial conditions. If needed, the particle size will be changed to match size for a list in the reservoir. If size is changed, the mass will be rescaled and information will be written to the PtDims.txt results file. Warning: see instructions on parallel coding when this method is needed in a block of parallel code.

Parallel Coding

Note that neither InjectParticle() nor DeleteParticle() are thread safe. Their use depends on style of a parallel block of code. Neither method can be called at all in parallel code that assigns each thread to a patch on the MPM grid. The reason is that particle injection and deletion change pointers needed by patch looping. For parallel scaling, the best approach when injecting or deleting is needed in such blocks is to build a list of particles to be injected or deleted. When the parallel block over patches is done, inject or delete particle in those lists during the reduction phase for that parallel coding. You can see an example of this approach that deletes particles in the ResetElementsTask.cpp class.

Within other parallel blocks (e.g., loops over nodes or particles), both InjectParticle() and DeleteParticle() can be callsed, but they can only be used by one thread at a time. In other words, calls to these methods need to be within OpenMP critical blocks:

// Inject particle only in single thread
#pragma omp critical (reservoir)
{
     mpmReservoir->InjectParticeParticle(mptr,&lp,matid);
}

// Delete particle only in single thread
#pragma omp critical (reservoir)
{
     mpmReservoir->DeleteParticle(mptr);
}

Changing a Particle Size

To change the size of any particle without moving it to the reservoir, call

mpmReservoir->ChangeParticleSize(MPMBase *mptr,Vector *lpart)

where mptr is pointer to the material point and lpart is the new absolute size. The reason to use this method is to change size without changing other material point properties. This method handles re-scaling of the mass, changing the size, and writing information to the PtDims.txt results file. Your custom task is responsible for determining that the size change does not cause numerical artifacts. For example, the size change might need to go along with changes to other particle properties. Warning: Although this method can be used in any type of parallel block, to avoid potential race conditions saving information about particle size changes, it should be called in an OpenMP critical block:

// Change size only in single thread
#pragma omp critical (reservoir)
{
     mpmReservoir->ChangeParticleSize(mptr,&lp);
}