Guidelines for developing user defined subroutines.
Posted: Fri Oct 23, 2015 8:41 pm
1. Introduction
User defined features are implemented through C++ classes. Usually there are two types of user defined features: list and object. A list can refer to a list of finite elements, e.g. 4-node Tetrahedral element list with constant strain; an object can refer to a material model, e.g. elasticity model.
In this article, we will show how to implement the 4-node Tetrahedral element list and elastic material.
The user subroutines are usually put into a so-called driver file - user.cpp, which looks like:
2. Input file
The corresponding inputs are
For the user defined material tagged myMaterial, three parameters are defined; for the user defined list tagged myElement, one element is created.
3. User defined object class
Important notice
4. User defined list class
The user defined list for an element formulation usually includes two classes: class for the list itself, which is the container of the elements; and class of the element.
Important notice for the list class (ttL_myElement)
Appendix A. update read()/readLst() to processCommand()
Since MARS version 2015.1.05, the old way to process input is replaced by the processCommand() to reduce code duplication.
Import Notice
Code similar to
should be replaced by
Appendix B. source code and input file
User defined features are implemented through C++ classes. Usually there are two types of user defined features: list and object. A list can refer to a list of finite elements, e.g. 4-node Tetrahedral element list with constant strain; an object can refer to a material model, e.g. elasticity model.
In this article, we will show how to implement the 4-node Tetrahedral element list and elastic material.
The user subroutines are usually put into a so-called driver file - user.cpp, which looks like:
- Code: Select all
#include "mars.h" // includes the declarations of all MARS core functionalities
#include "myMaterial.cpp"
#include "myElement.cpp"
// --------------------------------------------------------------------
// createUserDefinedList(...) and readRstUserDefineList(...) must always be defined
obLst *Model::createUserDefinedList (string nam, Reader *rdr) {
string lbl = rdr->getShortLabel();
if (lbl == "myElement")
return new ttL_myElement(nam);
return NULL;
}
obLst *Model::readRstUserDefinedList (RstReader *rst, string nam) {
return NULL;
}
// --------------------------------------------------------------------
// createUserDefinedObject(...) and readRstUserDefinedObject(...) must always be defined
Obj *Model::createUserDefinedObject (string nam, Reader *rdr) {
string lbl = rdr->getShortLabel();
if (lbl == "myMaterial")
return new myMaterial(nam);
return NULL;
}
Obj *Model::readRstUserDefinedObject (RstReader *rst, string nam) {
return NULL;
}
2. Input file
The corresponding inputs are
- Code: Select all
UserDefinedObject CONC myMaterial {
Density 2500 kg/m3
YoungModulus 3e4 MPa
PoissonsRatio 0.2
}
//----------------------------
UserDefinedList PRTC myElement {
Material CONC
InsertNodeList {
lengthUnits cm
InputFormat IBXYZB
ReadNodes 4
1 OOO 0 0 1 OOO
2 OOO 0 0 0 OOO
3 OOO 0 1 0 OOO
4 OOO 1 0 0 OOO
Select cz < 0.1 cm
Make NodeList base
Set Translations XXX
Select all
Select cz > 0.9 cm
Make NodeList tip
Set Translations XOX
Select all
}
ReadObjects 1
1 1 2 3 4
Plotting enabled
}
For the user defined material tagged myMaterial, three parameters are defined; for the user defined list tagged myElement, one element is created.
3. User defined object class
- Code: Select all
class myMaterial : public Material {
private:
real lmb, twg, ps1, ps2, blk;
real ymdDt, lmbDt, twgDt, ps1Dt, ps2Dt;
public:
myMaterial(string nm) : Material(nm) { init0(); }
void int0();
~myMaterial() { }
void init();
virtual processCommand(Reader *, string);
void execAtEveryStep();
void calcStrsHx(real *, real *) const;
void writeRstName(RstWriter *);
void writeRst(RstWriter *);
void readRst(RstReader *);
};
Important notice
- use init0() in the class constructor to set default values to member variables
- MARS AUTOMATICALLY calls Object::readObjInput(), which REPEATLY calls processCommand() to process input file
- MARS AUTOMATICALLY calls myMaterial::init() after the input is read
- use myMaterial::init() to initialize the object with the parameters read from input
- put the validity checks in myMaterial::init()
4. User defined list class
The user defined list for an element formulation usually includes two classes: class for the list itself, which is the container of the elements; and class of the element.
- Code: Select all
class myElement : public DeformableTet {
public:
myElement() { }
~myElement() { }
void init(ReferenceSystem *rs) { DeformableTet::init(rs); }
void whatAmI() { cout << "myElement" << endl; };
void reset();
real calcForces(Node **, real *);
void setUpStiffnessMatrix(real **);
};
- Code: Select all
class ttL_myElement : public ttLst {
private:
public:
ttL_myElement() { initList(); }
ttL_myElement(string nm) : ttLst(nm) { initList(); }
void initList() { }
~ttL_myElement() { }
Object *createNewObject() { return new myElement(); }
void setMaterial(Material *m) { mat = m; };
void setNodeList(ndLst *nL) { ndL = nL; };
void setStaticVariables();
bool processCommand(Reader *, string);
void initialize();
real calcFrc();
void writeRst(RstWriter *) { }
void readRst(RstReader *) { }
};
Important notice for the list class (ttL_myElement)
- class ttL_myElement is the list container of the elements, which are the objects
- use initLst() in the constructor to set default values to member variables, if any
- MARS AUTOMATICALLY calls obLst::readListInput(), which REPEATLY calls processCommand() to process input file
- MARS AUTOMATICALLY calls ttL_myElement::initialize() after the input is read,
- in ttL_myElement::initialize(), call myElement::init() to initialize the objects as well
- put the validity checks in ttL_myElement::initialize()
Appendix A. update read()/readLst() to processCommand()
Since MARS version 2015.1.05, the old way to process input is replaced by the processCommand() to reduce code duplication.
Import Notice
- MARS NO LONGER AUTOMATICALLY call read() for object type classes or readLst() for list type classes, instead processCommand() is called
- If procesCommand() is not needed, change read() to readObjInput() and readLst() to readListInput(), respectively. This will override Object::read() and obLst::readListInput().
Code similar to
- Code: Select all
void myMaterial::read (Reader *rdr) {
while (true) {
rdr->readLine();
string lbl = rdr->getShortLabel();
string lb3 = lbl.substr(0,3);
if (lbl.at(0) == '/' || lbl.at(0) == '}')
break;
else if (lb3 == "Den" || lb3 == "dns")
dns = rdr->readDensity();
else if (lb3 == "You")
ymd = rdr->readStress();
else if (lb3 == "Poi")
psn = rdr->getFloat();
else
rdr->error("Invalid entry in myMaterial");
}
Material::check(rdr); // move to ::init()
init(); // remove, called automatically by MARS once reading is done
}
should be replaced by
- Code: Select all
bool myMaterial::processCommand (Reader *rdr, string lbl) {
if (lbl == "Density")
dns = rdr->readDensity();
else if (lbl == "YoungModulus")
ymd = rdr->readStress();
else if (lbl == "PoissonsRatio")
psn = rdr->getFloat();
else if (Material::processCommand(rdr, lbl) { // code reuse, use parent class to process common inputs
} else
return false
return true;
}
Appendix B. source code and input file