User-Defined Models (UDMs)
in FLAC & FLAC3D
Constitutive models can be written in the C++ language and
compiled as DLLs (Dynamic Link Libraries) that are loaded
whenever needed during a run. The models run almost as fast as
the built-in models in FLAC, and at the same speed in FLAC3D. For
example, in FLAC3D, a UDM is loaded and used as follows config cppudm
model load userssoft.dll
gen zone bric size 2 2 2
model userssoft
Note that required models must be loaded whenever
FLAC3D is started only the ID number of a model is
saved on a save-file, not the actual model. (Use the INI
file!)
UDMs - continued
All UDMs are instances of C++ classes derived from a base class
called ConstitutiveModel (defined in an Itasca-supplied header
file). For example class UserSsoft : public ConstitutiveModel {};
The base class specifies a number of virtual functions that must
be overridden by same-named functions in the derived class.
These functions contain user-written code that specify how the
model works, the names of properties, and so on. For example,
virtual char *Keyword(void) = 0;
is the base-class function to supply a model name, and
char *UserSsoft::Keyword(void) {return("userssoft");}
is the overriding function that actually specifies the name.
The main task of the UDM is to compute new stresses from
strainrates. It does this via the Run( ) function of the base class:
virtual const char *Run(unsigned uDim,State *pst)=0;
The argument uDim is the code dimensionality (2 for FLAC and 3
for FLAC3D), and State is a structure, as follows struct State {
unsigned char bySubZone, byTotSubZones, byOverlay;
unsigned long mState;
};
double
dSubZoneVolume, dZoneVolume;
STensor
stnE, stnS, stnI;
double
dRotX, dRotY, dRotZ;
double
dDensity, dTemp, dTimeStep;
double
dPPInc, dPorosity, dTMUtility;
bool
bLarge, bTherm, bCreep, bFluid, bViscous;
The current stress tensor is available in stnS, and the strain
increment tensor in stnE, using the STensor structure,
defined (in part) as follows:
struct STensor {
double d11, d22, d33, d12, d13, d23;
};
The UDM Run( ) function must compute new components for
stnS, using the initial values and the components of stnE.
As an example, the Run( ) function for the elastic model in
FLAC3D is coded as follow
const char *ElasticModel::Run(unsigned,State *ps) {
double dE11 = ps->stnE.d11;
double dE22 = ps->stnE.d22;
double dE33 = ps->stnE.d33;
ps->stnS.d11 += (dE22 + dE33) * dE2 + dE11 * dE1;
ps->stnS.d22 += (dE11 + dE33) * dE2 + dE22 * dE1;
ps->stnS.d33 += (dE11 + dE22) * dE2 + dE33 * dE1;
ps->stnS.d12 += ps->stnE.d12 * dG2;
ps->stnS.d13 += ps->stnE.d13 * dG2;
ps->stnS.d23 += ps->stnE.d23 * dG2;
return(0);
}
Note that variables dE1, dE2 and dG2 are property values
stored as part of the ElasticModel class. The model may
return a pointer to a character string if it detects an error
the string is then printed as an error message.
Named properties are associated with the UDM by providing
a Properties( ) member function: e.g.,
const char **ElasticModel::Properties(void) const {
static const char *strKey[]
= { "bulk", "shear", "young", "poisson", 0 };
return(strKey);
}
FLAC3D calls such member functions (for the particular
model installed in a zone) whenever the PROP command is
given this enables the code to know what property names
are associated with the model. If the property name is on the
input line, the code retrieves the value, and passes it to the
UDM by calling the SetProperty( ) function. E.g.,
void ElasticModel::SetProperty(unsigned ul,const double &dVal) {..
The value of ul is the sequence number of the
corresponding property name returned by Properties( )
Several additional virtual member functions are provided in the
ConstitutiveModel base class some important ones are:
virtual const char *Name(void) const=0;
virtual const char **States(void) const=0;
virtual double GetProperty(unsigned ul) const=0;
virtual ConstitutiveModel *Clone(void) const=0;
virtual double ConfinedModulus(void) const=0;
virtual double ShearModulus(void) const=0;
virtual double BulkModulus(void) const=0;
virtual const char *Initialize(unsigned uDim,State *pst)=0;
virtual const char *SaveRestore(ModelSaveObject *mso)=0;
The meaning of each will be discussed.
Finally When a DLL is loaded at run-time by the user, the model
must register itself, by using a particular form of a
constructor call. The following statement in the .cpp file
causes the constructor to be called (with the argument
true) when the DLL file links into FLAC or FLAC3D.
static UserSoft modelInstance(true);
where UserSoft is the class name of the new model. The
code then knows about the new model. To verify this,
give the command print model. The new model should
be listed along with the built-in models.
UDM an example
stress
A FLAC3D user recently wanted a model for
gob broken rock filling a mining opening.
He gave the following relation between
vertical stress and strain:
a
The input to a UDM is strain-increment. It
is possible to re-write the above equation
in terms of strain-increment and stresses
(old - 0 and new - 1):
strain
a (b 0 0 a )
1
ab a 0
However, this is not a complete model, since only one
component of stress/strain is addressed. ( a common
problem with models suggested by clients!). Lets assume that
the equation connects the mean stress with the volumetric
strain, and that there is a constant Poissons ratio.
The mean stress and volumetric strain are:
p0 ( 11 22 33 ) / 3
v 11 22 33
p1
Using the relation derived before,
a (bp0 p0 v a v )
ab a v p0 v
we can derive an apparent bulk modulus
K * ( p1 p0 ) / v
Assuming a constant Poissons ratio, we
obtain the apparent shear modulus
3K * (1 2 )
G
2(1 )
*
Then, the new deviatoric stresses are
calculated as
11d 23 G * (211 22 33 )
d
22
23 G * (2 22 11 33 )
33d 23 G* (2 33 11 22 )
11d 11 p0
where
22d 22 p0
33d 33 p0
d
d
Then, final stresses are: 11 11 11 p1
22 22d 22d p1
33 33d 33d p1
*
and: 12 : 12 2G 12
13 : 13 2G *13
23 : 23 2G * 23
Note that this is a nonlinear, elastic model unloading will follow the
same path as loading. This is fine if the types of simulations
performed always involve loading (such as the convergence of a
progressively-mined tunnel).
To implement the model, we start with the existing elastic
model in C++, and rename the source files and class name.
Thus,
class ElasticModel : public ConstitutiveModel {
public:
enum ModelNum { mnElasticModel=2 };
// rest of class follows
becomes
class GobModel : public ConstitutiveModel {
public:
enum ModelNum { mnGobModel=102 };
// rest of class follows
and so on.
Note that the model ID number should be chosen to avoid
conflicts with existing models. This number is used during
save and restore operations.
UDM final thoughts
The coding of the gob model will be demonstrated
Some hints
1. Check for all potential divide-by-zeros error return.
2. Make sure a reasonable estimate for confined modulus is
returned this is used to ensure stable computations.
3. Exercise a new model with a single, velocity-controlled
zone. When that checks out, gradually increase the
complexity of the tests.
4. Incorporate state variables (properties) that can be used
to diagnose internal problems.