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