Methodology

Base Class for Constitutive Models

The object-oriented programming approach described in the Introduction is exploited in FLAC3D’s support for user-written constitutive models. A base class provides a framework for actual constitutive models, which are classes derived from the base class. The base class, called ConstitutiveModel, is an “abstract” class. It declares a number of “pure virtual” member functions (signified by the =0 syntax appended to the function prototypes). This means that no object of this base class can be created, and any derived-class object must supply real member functions to replace every one of the pure virtual functions of ConstitutiveModel.

Full documentation of ConstitutiveModel is provided in Programmer’s Interface. See the models namespace.

Member Functions

Any derived constitutive-model class must provide actual functions to replace the virtual member-functions in ConstitutiveModel.

The model class definition should also contain a constructor that must invoke the base constructor. In all cases, the derived-class constructor should be called with no parameters, as in the clone member function. Initialization of data members may be performed by the constructor, as illustrated here. In this example, the symbols bulk_, shear_, etc. are the data members for the derived model.

Typical Model Constructor

ModelExample::ModelExample()
             :bulk_(0.0), shear_(0.0), cohesion_(0.0), friction_(0.0), dilation_(0.0),
              tension_(0.0), e1_(0.0), e2_(0.0), g2_(0.0), nph_(0.0), csn_(0.0), sc1_(0.0),
              sc2_(0.0), sc3_(0.0), bisc_(0.0), e21_(0.0), rnps_(0.0)
{}

Registration of Models

Each user-written constitutive model is compiled into a DLL that must be instantiated in the FLAC3D process. By convention, there are four exported functions in a DLL used as a plugin to FLAC3D: getName(), getMajorVersion(), getMinorVersion() and createInstance(). You must also provide a stub function called DllMain(), which is called when the library is loaded and unloaded from the system. For example, this is how these functions appear for the Hoek-Brown model:

int _stdcall DllMain(void *,unsigned, void *)
{
    return 1;
}

extern "C" EXPORT_TAG const char *getName()
{
    return "modelhoekbrown";
}

extern "C" EXPORT_TAG unsigned getMajorVersion()
{
    return models::ConstitutiveModel::getMajorVersion();
}

extern "C" EXPORT_TAG unsigned getMinorVersion()
{
    return MINOR_VERSION;
}

extern "C" EXPORT_TAG void *createInstance()
{
    models::ModelHoek *m = new models::ModelHoek();
    return (void *)m;
}

The EXPORT_TAG macro indicates that these functions should be exported from the DLL.

The DllMain() function is always the same.

The exported DLL function getName() should always return a string that begins with the word “model”. This indicates that the DLL is a constitutive model plugin. In the above example, the string “modelhoekbrown” is returned by the exported DLL function getName(). The getName() method of the ConstitutiveModel class returns the string “hoekbrown” (without “model” prefixed to the name as in the getName() function that is exported). This convention of prefixing the exported name with “model” should be followed. The ConstitutiveModel’s getName() function must return a unique string (this is the method used to distinguish constitutive models from each other).

The getMajorVersion() function should not be altered. The major version is determined by the base constitutive model DLL, and indicates binary compatibility. By convention, this number will also be indicated in the file name of the DLL you produce.

The getMinorVersion() function indicates the minor version update of your constitutive model. If new properties are added to a constitutive model, for example, it might not be save file-compatible with an older version. In this case, the minor version number (defined in file “version.txt”) would be incremented by 1.

The createInstance() function actually creates and returns an instance of your class. This is stored in a registry and used (via the clone() function) to create all other instances.

Information Passed between Model and Program during Cycling

The most important link between FLAC3D and a user-written model is the member-function run(unsigned nDim, State *ps), which computes the mechanical response of the model during cycling. A structure, State (defined in “state.h”), is used to transfer information to and from the model.

Full documentation of State is also provided in the models namespace of the programmer’s interface documentation (available in the on-screen Help menu).

The main task of member-function run() is to compute new stresses from strain increments. In a nonlinear model, it is also useful to communicate the internal state of the model, so that the state may be plotted and printed. For example, the supplied models indicate whether they are currently yielding or have yielded in the past. Each subzone may set the variable state_, which records the state of a model as a series of bits that can be on or off (1 or 0). Each bit can be associated with a message that is displayed on the screen. The string returned by member function States contains sub-strings corresponding to bit positions that the model may set in state_. The first sub-string refers to bit 0, the second to bit 1, and so on. Several bits may be set simultaneously. For example, both shear and tensile yield may occur together. The bit assignment is described below. The operation of the state logic may be appreciated by consulting any of the nonlinear model files (e.g., “modelexample.cpp”).

State Indicators of Zones

A zone in FLAC3D is composed of tetrahedral subzones, and each tetrahedron has a member variable that maintains its current state indicator. The member variable has 32 bits that can be used to represent a maximum of 16 distinct states. The state indicator bits are used by built-in constitutive models to denote plastic failure of tetrahedra in a zone. See Table 1 for bit assignment and the corresponding failure state for built-in constitutive models.


Table 1: Failure states and bit assignments
    Hex Decimal Binary
shear_now = 0x0001 1 0000 0000 0000 0001
tension_now = 0x0002 2 0000 0000 0000 0010
shear_past = 0x0004 4 0000 0000 0000 0100
tension_past = 0x0008 8 0000 0000 0000 1000
joint_shear_now = 0x0010 16 0000 0000 0001 0000
joint_tension_now = 0x0020 32 0000 0000 0010 0000
joint_shear_past = 0x0040 64 0000 0000 0100 0000
joint_tension_past = 0x0080 128 0000 0000 1000 0000
volume_now = 0x0100 256 0000 0001 0000 0000
volume_past = 0x0200 512 0000 0010 0000 0000
unused = 0x0400 1024 0000 0100 0000 0000
unused = 0x0800 2048 0000 1000 0000 0000
unused = 0x1000 4096 0001 0000 0000 0000
unused = 0x2000 8192 0010 0000 0000 0000
unused = 0x4000 16384 0100 0000 0000 0000
unused = 0x8000 32768 1000 0000 0000 0000

For user-defined constitutive models, the user can create a named state and assign any particular bit for that state, and subsequently update the tetrahedral state indicator variable. The named states in Table 1 are used by built-in constitutive models to update the failure states of tetrahedral subzones, and show one particular use of the state indicator variable. If a user uses the state indicator variable to indicate failure states in their own model, they should make sure that there is no conflict with failure state constants of built-in models if they plan to use both of them in an analysis.

The named states in Table 1 are used by many built-in models to update the tetrahedral subzone state indicator.

FLAC3D calls the constitutive model function run() for each tetrahedron that makes up the zone, to update its stress values. Typically, the state indicator is also updated in this process by the constitutive model. For built-in models, the state indicator denotes the failure state of the tetrahedron. This is updated by the constitutive model using the logical “or” (|) operation with the tetrahedron state indicator variable and the current failure state calculated by the constitutive model. The user should take care to appropriately set or un-set all previous states updated prior to the current state calculated by the constitutive model. The state of a tetrahedron can then be checked using the logical “and” (&) operator with the state variable and desired user-defined state.

Suppose a tetrahedron is undergoing failure in tension and shear. This failure state is stored in the state indicator of the tetrahedron. The built-in constitutive model updates the state variable:

  1. Initially, check the current state and set/un-set state indicator, appropriately. For example,

    if (s->state_ & shear_now) s->state_ |= shear_past;
    s->state_ &= ~shear_now;
    if (s->state_ & tension_now) s->state_ |= tension_past;
    s->state_ &= ~tension_now;
    
  2. Calculate the current state of the tetrahedron.

  3. Update the state if necessary. For example,

    s->state_ |= shear_now;
    s->state_ |= tension_now;
    

The result of the preceding operations is that the first and second bits are set for that particular tetrahedron. Additionally, during initialization (step a), the third and the fourth bits are also set. The FISH function zone.state returns a value of 15, the decimal equivalent of the first four bits being set.

Users can use the FISH logical zone.state to find out the failure state at any point in the analysis. Users can also split the output into additive powers of two, and find out all distinct failure states. For example, if zone.state returns 15, then 15 can be written as 15 = 1 + 2 + 4 + 8 (additive powers of two), and from Table 1, the zone is in shear and tensile failure, and had shear and tensile failure in the past.