The solution step may represent either a time step, a load increment, or a load
case. The solution steps are grouped together into so called meta steps.
The meta step can be thought as a sequence of
solution steps, with the same set of attributes used to drive the behavior of
engng model.
For each meta step, the engng model typically updates
certain attribute values according to meta step model attributes (see
updateAttributes service) and creates the solution steps
accordingly. This allows to switch to a different time increment,
a different solution control, etc. If no meta step is specified, the engng model
creates a default one for all required solution steps. There are two
services, where engng model attributes are set or updated. The first one,
used for those attributes which do not vary during the solution
of the problem, are initialized in *instanciateYourself* service.
The second service is *updateAttributes*, where the attributes
(with meta step validity) are updated according to a values valid for the
given meta step.
If no meta step is introduced, a default one is created
(with the attributes set to the engng model attributes).
Then there is no difference, whether the attributes are initialized
in instanciateYourself or in updateAttributes, but
the preferred scheme is to read all attributes in instanciateYourself
and to left updateAttributes service empty.

The basic EngngModel tasks are following:

- Assembling governing equations by summing contributions (typically from nodes and elements).
- Solving the problem described by governing equation(s) using the instance of a suitable numerical method. This requires to establish a mapping between numerical method-parameters and EngngModel components of governing equation. EngngModel must map each component of governing equation(s) (which has physical meaning) to the corresponding numerical component. This mapping between physical components to independent numerical components (understood by the numerical method) is important, because it allows the numerical method to be used by many EngngModels with different component meaning and allows to use different numerial methods by EngngModel. This is achieved by using the compulsory numerical component names (see further).
- Providing access to the problem solution. Services for returning unknown values according to their type and mode are provided. These services are used by DOFs to access their corresponding unknowns.
- Terminating the time step by updating the state of the problem domains (nodes and elements, including integration points).
- Managing the problem domains, meta steps, and problem input/output streams.
- Equation numbering.
- Storing and restoring problem state to/from context file.
- Updating the DOF unknown dictionaries if EngngModel supports changes of static system (see the Dof class documentation for detailed explanation). In general, if the static system changes are not supported, then when the DOFs are asked for unknowns, they use their equation numbers to ask EngngModel for corresponding unknowns. The unknown values are therefore stored in the EngngModel and are requested by the DOFs. On the other hand, when the changes of the static system are supported, the equation numbers of DOFs can vary during the solution. Therefore, so called DOF unknown dictionaries are introduced. All unknowns are stored on the DOF level and the DOFs will use in such case their own dictionaries instead of requesting the EngngModel. The EngngModel is then fully responsible for updating this dictionaries for each DOF with all necessary unknowns (see updateDofUnknownsDictionary function).

The complete listing of **EngngModel** class declaration folows.

/* $Header: /home/cvs/bp/oofem/doc/usrman/usrman.tex,v 1.7 2003/04/23 14:19:27 bp Exp $ */ // ************************ // *** CLASS ENGNGMODEL *** // ************************ class EngngModel { protected: /// number of receiver domains int ndomains; /// List of problem domains AList<Domain>* domainList; /// Total number of time steps int numberOfSteps; /// total number of equation in cuurent time step int numberOfEquations; /// total number or prescribed equations in current time step int numberOfPrescribedEquations; /// number of equations per domain IntArray domainNeqs; /// number of prescribed equations per domain IntArray domainPrescribedNeqs; /// renumbering flag int renumberFlag; /// equation numbering completed flag int equationNumberingCompleted; /// number of meta steps int nMetaSteps; /// List of problem metasteps AList<MetaStep>* metaStepList; /// Solution step when IC (initial conditions) apply TimeStep* stepWhenIcApply; /// Currnet time step TimeStep* currentStep ; /// Previous time step TimeStep* previousStep; /// receivers id int number ; /// Path to input stream //char* dataInputFileName ; /// Path to output stream char* dataOutputFileName ; /// Output stream FILE* outputStream; /// Input stream //FILE* inputStream; /// Domain context output mode ContextOutputMode contextOutputMode; int contextOutputStep; ///Export module manager ExportModuleManager* exportModuleManager; /// Domain mode problemMode pMode ; /// solution start time time_t startTime; // initial value of processor time used by program // clock_t startClock; /// master e-model; if defined receiver is in maintained (slave) mode EngngModel* master; /// context EngngModelContext* context; /** flag indicating that the receiver runs in parallel. */ int parallelFlag; public: /** Constructor. Creates Engng model with number i belonging to domain d. */ EngngModel (int i, EngngModel* _master = NULL) ; // constructor /** Constructor. Creates Engng model with number i and input file given by path. */ EngngModel (int i, char* s, EngngModel* _master = NULL); /// Destructor. virtual ~EngngModel () ; // destructor /** Service for accessing particular problem domain. Generates error if no such domain is defined. @param: n pointer to n-th domain is returned */ Domain* giveDomain (int n); /// Returns number of domains in problem. int giveNumberOfDomains () {return ndomains;} /** Service for accessing ErrorEstimator corresponding to particular domain */ virtual ErrorEstimator* giveDomainErrorEstimator (int n) {return NULL;} // input / output /// Returns input file path. //char* giveInputDataFileName () ; /// Returns file descriptor of output file FILE* giveOutputStream () ; /** Returns base output file name to which extensions, like .out .vtk .osf should be added. In current implementation, output file name is simply returned. @param path and base file name will be copied into the array pointed to by dest @param not more than n bytes of src are copied */ char * giveOutputBaseFileName(char *dest, size_t n) {return strncpy (dest, dataOutputFileName, n);} //FILE* giveInputStream () ; /* Returns current time in seconds as returned by time call. @return current time in time_t structure. */ //time_t getTime (); /* Returns an approximation of processor time used by the program. The value returned is the CPU time used so far as a clock_t; to get the number of seconds used, divide by CLOCKS_PER_SEC. Calls clock ANSI C function. The C standard allows for arbitrary values at the start of the program; take the difference between the value returned from a call to this method at the start of the pro- gram and the end to get maximum portability. */ //clock_t getClock (); /** Returns domain context output mode. */ ContextOutputMode giveContextOutputMode () {return contextOutputMode;} /** Returns domain context output step. */ int giveContextOutputStep () {return contextOutputStep;} /** Sets context output mode of receiver. @param contextMode domain context mode. */ void setContextOutputMode (ContextOutputMode contextMode) {contextOutputMode=contextMode;} /** Sets user defined context output mode (it sets contextOutputMode to contextOutputMode), setting contextOutputStep to given value. @param cStep new context output step */ void setUDContextOutputMode (int cStep) {contextOutputMode=USERDEFINED; contextOutputStep = cStep;} /** Sets domain mode to given mode. @param mode domain mode. */ void setProblemMode (problemMode mode) {pMode = mode;} /// Returns domain mode. problemMode giveProblemMode () {return pMode;} /// Sets the renumber flag to TRUE virtual void setRenumberFlag() {this->renumberFlag = 1;} /// Sets the renumber flag to FALSE virtual void resetRenumberFlag() {this->renumberFlag = 0;} /** Performs analysis termination after finishing analysis. */ void terminateAnalysis () ; // solving /** Starts solution process. Implementation should invoke for each time step solveYourselfAt function with time step as parameter. Time steps are created using giveNextStep function (this will set current time step to newly created, and updates previous step). */ virtual void solveYourself (); /** Solves problem for given time step. Should assemble characteristic matrices and vectors if necessary and solve problem using appropriate numerical method. After finishing solution, this->updateYourself function for updating solution state and then this->terminate function (for updating nodal and element values) should be called. */ virtual void solveYourselfAt (TimeStep*) {} //virtual int requiresNewLhs () {return 1;} /** Terminates the solution of time step. Default implementation calls prinOutput() service and if specified, context of whole domain is stored and output for given time step is printed. */ virtual void terminate (TimeStep*); /** Prints the ouput of the solution step (using virtual this->printOutputAtservice) to the stream detemined using this->giveOutputStream() method and calls exportModuleManager to do output. */ virtual void doStepOutput(TimeStep*); /** Saves context of given solution step, if required (determined using this->giveContextOutputMode() method). */ void saveStepContext(TimeStep*); /** Updates internal state after finishing time step. (for example total values may be updated according to previously solved increments). Then element values are also updated (together with related integration points and material statuses). */ virtual void updateYourself (TimeStep* stepN); /** Provides the oportunity to initialize state variables stored in element integration points acording to initial conditions using function initializeYourself() on element level. Should be called when curent time step is time step when IC will aply (see EngngModel::giveNumberOfTimeStepWhenIcApply) somewhere from solveYourselfAt function). Implementation must be provided. Default implementation is empty. */ virtual void initializeYourself (TimeStep*) {} /** Initializes the newly generated discretization state acording to previous solution. This process should typically include restoring old solution, instanciating newly generated domain(s) and by mapping procedure. */ virtual int initializeAdaptive (int stepNumber) {return 0;} /** Returns total number of equations in active (current time steep) time step. The UnknownType parameter allows to distinguis between several possible governing equations, that can be numbered separately. */ virtual int giveNumberOfEquations (EquationID); /** Returns total number of prescribed equations in active (current time steep) time step. The UnknownType parameter allows to distinguis between several possible governing equations, that can be numbered separately. */ virtual int giveNumberOfPrescribedEquations (EquationID); /** Returns number of equations for given domain in active (current time steep) time step. The UnknownType parameter allows to distinguis between several possible governing equations, that can be numbered separately. */ virtual int giveNumberOfDomainEquations (int, EquationID); /** Returns number of prescribed equations for given domain in active (current time steep) time step. The UnknownType parameter allows to distinguis between several possible governing equations, that can be numbered separately. */ virtual int giveNumberOfPrescribedDomainEquations (int, EquationID); //virtual IntArray* GiveBanWidthVector (); // management components /** Provides backward mapping between numerical component and characteristic component on EngngModel level. */ virtual CharType giveTypeOfComponent (NumericalCmpn) {return UnknownCharType;} /** Returns requested unknown. Unknown at give time step is characterized by its type and mode and by its equation number. This function is used by Dofs, when they are requsted for their associated unknowns. @see Dof::giveUnknown method */ virtual double giveUnknownComponent (EquationID, ValueModeType, TimeStep*, Domain*, Dof*) {return 0.0;} virtual double giveUnknownComponent (UnknownType, ValueModeType, TimeStep*, Domain*, Dof*) {return 0.0;} /** Initializes whole problem acording to its description stored in inputStream. Prints header, opens the outFileName, instanciate itself the receicer using using virtual initializeFrom service and instancites all problem domains. */ virtual int instanciateYourself (DataReader* dr, InputRecord* ir, char* outFileName, char* desc) ; /** Initializes receiver acording to object description in input reader. InitString can be imagined as data record in component database belonging to receiver. Receiver may use value-name extracting functions to extract particular field from record.*/ virtual IRResultType initializeFrom (InputRecord* ir); /// Instanciate problem domains by calling their instanciateYourself() service int instanciateDomains (DataReader* dr); /// Instanciate problem meta steps by calling their instanciateYourself() service int instanciateMetaSteps (DataReader *dr); /// Instanciate default metastep, if nmsteps is zero int instanciateDefaultMetaStep (InputRecord* ir); /** Update receiver attributes according to step metaStep attributes. Allows the certain parameters or attributes to be updated for particular metastep. The metastep provides the attributes record, from which the corresponding attributes can be read. The service takes TimeStep as parameter, from which corresponding MetaStep is requested. It is recomended, to implement this service in such way, that multiple calls for steps belonging to same MetaStep does not change response. The default implementation updates the numerical method attributes. @param TimeStep time step. */ virtual void updateAttributes (TimeStep*); /** Update e-model attributes attributes according to step metaStep attributes. Calls updateAttributes. At the end the meta step input reader finish() service is called in order to allow for unread attribute check. */ void initMetaStepAttributes (TimeStep* tStep); /** Stores the state of model to output stream. Stores not only the receiver state, but also same function is invoked for all DofManagers and Elements in associated domain. Note that by storing element context also contexts of all associated integration points (and material statuses) are stored. Stored context is associated with current time step. One time step can have only one associated context. Multiple call to saveContext within same time step owerride previously saved context for this step. By default the stream paprameter is used to store data and is not closed. If stream is NULL, new file descriptor is created and this must be also closed at the end. @param stream - context stream. If NULL then new file descriptor will be openned and closed at the end else the stream given as parameter will be used and not closed at the end. @return contextIOResultType. @exception throws an ContextIOERR exception if error encountered */ virtual contextIOResultType saveContext (FILE *stream, void *obj = NULL) ; /** Restores the state of model from output stream. Restores not only the receiver state, but also same function is invoked for all DofManagers and Elements in associated domain. Note that by restoring element context also contexts of all associated integration points (and material statuses) are restored. Each context is associated with unique time step. Only one context per time step is allowed. Restore context function will restore such contex, which is related (through its step number) to time step number and version given in obj parameter. Restoring context will change current time step in order to correspond to newly restored context. @param stream context file @param obj is a void pointer to an int array containing two values:time step number and version of a context file to be restored. @return contextIOResultType. @exception throws an ContextIOERR exception if error encountered. */ virtual contextIOResultType restoreContext (FILE* stream, void* obj = NULL) ; /** Updates domain links after the domains of receiver have changed. Used mainly after restoring context - the domains may change and this service is then used to update domain variables in all components belonging to receiver like errorestimators, solvers, etc, having domains as attributes. */ virtual void updateDomainLinks() {}; void resolveCorrespondingStepNumber (int&, int&, void* obj); /// Returns current time step. TimeStep* giveCurrentStep () {if (master) return master->giveCurrentStep(); else return currentStep;} /// Returns previous time step. TimeStep* givePreviousStep() {if (master) return master->givePreviousStep(); else return previousStep;} /// Returns next time step (next to current step) of receiver. virtual TimeStep* giveNextStep() {return NULL;} /// Returns the solution step when Initial Conditions (IC) apply virtual TimeStep* giveSolutionStepWhenIcApply() {if (master) return master->giveCurrentStep(); else return stepWhenIcApply;} /// Returns number of first time step used by receiver. virtual int giveNumberOfFirstStep () {if (master) return master->giveNumberOfFirstStep(); else return 1;} /// Return number of meta steps int giveNumberOfMetaSteps () {return nMetaSteps;} /// Returns the i-th meta step MetaStep* giveMetaStep (int i); /// Returns total number of steps. int giveNumberOfSteps() {if (master) return master->giveNumberOfSteps(); else return numberOfSteps ;} /// Returns end of time interest (time corresponding to end of time integration). virtual double giveEndOfTimeOfInterest () {return 0.;} /// Returns the time step number, when initial conditions should apply. virtual int giveNumberOfTimeStepWhenIcApply() {if (master) return master->giveNumberOfTimeStepWhenIcApply(); else return 0;} /// Returns reference to receiver's numerical method virtual NumericalMethod* giveNumericalMethod (TimeStep*) {return NULL;} /// Returns receiver's export mudule manager ExportModuleManager* giveExportModuleManager() {return exportModuleManager;} /** Increases number of equations of receiver's domain and returns newly created equation number. Used mainly by DofManagers to allocate their corresponding equation number if it is not currently allocated. The DofIDItem parameter allows to distinguis between several possible governing equations, that can be numbered separately. */ virtual int giveNewEquationNumber (int domain, DofIDItem) {return ++domainNeqs.at(domain);} /** Increases number of prescribed equations of receiver's domain and returns newly created equation number. Used mainly by DofManagers to allocate their corresponding equation number if it is not currently allocated. The DofIDItem parameter allows to distinguis between several possible governing equations, that can be numbered separately. */ virtual int giveNewPrescribedEquationNumber (int domain, DofIDItem) {return ++domainPrescribedNeqs.at(domain);} /** Assigns context file-descriptor for given step number to stream. Returns nonzero on success. @param stepNumber solution step number to store/restore @param stepVersion version of step @param cmode determines the i/o mode of context file @param errLevel determines the amout of warning messages if errors are encountered, level 0 no warnings reported. */ int giveContextFile (FILE** contextFile, int stepNumber, int stepVersion, ContextFileMode cmode, int errLevel = 1) ; /** Returns true if context file for given step and version is available */ bool testContextFile (int stepNumber, int stepVersion); /** Creates new DataReader for given domain. Returns nonzero on success. @param domainNum domain number @param domainSerNum domain seerial number @param cmode determines the i/o mode of context file */ DataReader* GiveDomainDataReader (int domainNum, int domainSerNum, ContextFileMode cmode) ; /** Updates components mapped to numerical method if necessary during solution process. Some numerical methods may require updating mapped components during solution process (e.g., updating of tanget stiffness when using updated Newton-Raphson method). @param tStep time when component is updated. @param cmpn Numerical component to update. */ virtual void updateComponent (TimeStep* tStep, NumericalCmpn cmpn); /** Initializes solution of new time step. Default implementation resets all internal history variables (in integration points of elements) to previously reached equilibrium values. Can be used for time step restart. */ virtual void initStepIncrements(); /** Forces equation renumbering on given domain. All equation numbers in all dofManagers are invalidated, and new equation numbers are generated starting from domainNeqs entry corresponding to given domain. It will update numberOfEquations variable accordingly. Should be used at startup to force equation numbering and therefore sets numberOfEquations. Must be used if model supports changes of static system to assign new valid equation numbers to dofManagers. */ virtual int forceEquationNumbering (int i); /** Forces equation renumbering on all domains associated to engng model. All equation numbers in all domains for all dofManagers are invalidated, and new equation numbers are generated starting from 1 on each domain. It will update numberOfEquations variable accordingly. Should be used at startup to force equation numbering and therefore sets numberOfEquations. Must be used if model supports changes of static system to assign new valid equation numbers to dofManagers. */ virtual int forceEquationNumbering (); /** Indicates if Engngmodel requires Dofs dictionaries to be updated. If EngngModel does not support changes of static system, the dof frowards the requests for its unknowns to EngngModel, where unknowns are naturaly kept. This is posible, because dof equation number is same during whole solution. But when changes of static system are allowed, several problem arise. For example by solving simple incremental static with allowed static changes, the incremetal displacement vector of structure can not be added to total displacement vector of structure, because equation numbers may have changed, and one can not simply add these vector to obtain new total displacement vector, because uncompatible displacement will be added. To solve this problem, uknown dictionary at dof level has been assumed. Dof then keeps its unknowns in its onw private dictionary. After computing increment of solution, engngModel updates for each dof its unknowns in its dictionary (using updateUnknownsDictionary function). For aforementioned example engngModel updates incremental values but also total value by asking dof for previous total value (dof will use its dictionary, does not asks back EngngModel) adds corresponding increment and updates total value in dictionary. */ virtual int requiresUnknowsDictionaryUpdate () {return 0;} /** Returns true if equation renumbering is required for given solution step. This may of course change the number of equation and in general there is no gauarantee that for a certain dof the same eautiaon will be assigned. So the use of DOF unknowns dictionaries is generally recomended. */ virtual bool requiresEquationRenumbering(TimeStep*) {return false;} //virtual int supportsBoundaryConditionChange () {return 0;} /** Updates necessary values in Dofs unknown dictionaries. @see EngngModel::requiresUnknowsDictionaryUpdate @see Dof::updateUnknownsDictionary */ virtual void updateDofUnknownsDictionary (DofManager*, TimeStep*) {} /** This method is responsible for computing unique dictionary id (ie hash value) from given equationId, valueModeType and timestep. This function is used by particular dofs to access unknown identified by given params from its dictionary using computed index. Usually the hash algorithm shoud produce index that depend on timestep relativelly to actual one to avoid storage of complete history. */ virtual int giveUnknownDictHashIndx (EquationID type, ValueModeType mode, TimeStep* stepN) {return 0;} // we don't directlt call element ->GiveCharacteristicMatrix() function, because some // engngm classes may require special modification of base types supported on // element class level /** Returns characteristic matrix of element. The Element::GiveCharacteristicMatrix function should not be called directly, because EngngModel may require some special modification of characteristic matrices supported on element level. But default implementation does the direct call to element level. @param answer characteristic matrix @param num element number @param type type of CharMatrix requsted @param tStep time step when response is computed @param domain source domain */ virtual void giveElementCharacteristicMatrix (FloatMatrix& answer, int num, CharType type, TimeStep* tStep, Domain* domain) { domain->giveElement(num)->giveCharacteristicMatrix (answer, type, tStep);} /** Returns characteristic vector of element. The Element::GiveCharacteristicVector function should not be called directly, because EngngModel may require some special modification of characteristic vectors supported on element level. But default implementation does the direct call to element level. @param answer characteristic vector @param num element number @param type type of vector requsted @param tStep time step when response is computed @param domain source domain */ virtual void giveElementCharacteristicVector (FloatArray& answer, int num, CharType type, ValueModeType mode, TimeStep* tStep, Domain* domain) { domain->giveElement(num)->giveCharacteristicVector (answer, type, mode, tStep);} protected: /** Assembles characteristic matrix of required type into given sparse matrix. @param answer assembled matrix @param tStep time step, when answer is assembled. @param ut determines type of equation and corresponding element code numbers @param type characterisctic components of type type are requsted from elements and assembled. @param domain source domain */ virtual void assemble (SparseMtrx *answer, TimeStep* tStep, EquationID ut, CharType type, Domain* domain) ; /** Assembles characteristic matrix of required type into given sparse matrix. @param answer assembled matrix @param tStep time step, when answer is assembled. @param r_id determines type of equation and corresponding element code numbers for matrix rows @param c_id determines type of equation and corresponding element code numbers for matrix columns @param type characterisctic components of type type are requsted from elements and assembled. @param domain source domain */ virtual void assemble (SparseMtrx *answer, TimeStep* tStep, EquationID r_id, EquationID c_id, CharType type, Domain* domain) ; /** Assembles characteristic vector of required type into given vector. @param answer assembled vector @param tStep time step, when answer is assembled. @param type characterisctic components of type type are requsted from dofManagers/elements and assembled. */ //virtual void assemble (FloatArray&, TimeStep*, CharType type, Domain* domain) ; /** Assembles characteristic vector of required type from dofManagers into given vector. @param answer assembled vector @param tStep time step, when answer is assembled. @param type characterisctic components of type type are requsted from dofManagers and assembled using code numbers. */ virtual void assembleVectorFromDofManagers (FloatArray&, TimeStep*, EquationID ut, CharType type, ValueModeType mode, Domain* domain) ; /** Assembles prescribed characteristic vector of required type from dofManagers into given vector. @param answer assembled vector @param tStep time step, when answer is assembled. @param type characterisctic components of type type are requsted from dofManagers and assembled using prescribed eqn numbers. */ void assemblePrescribedVectorFromDofManagers (FloatArray&, TimeStep*, EquationID, CharType type, ValueModeType mode, Domain* domain) ; /** Assembles characteristic vector of required type from elements into given vector. @param answer assembled vector @param tStep time step, when answer is assembled. @param type characterisctic components of type type are requsted from elements and assembled using using code numbers. */ void assembleVectorFromElements (FloatArray&, TimeStep*, EquationID, CharType type, ValueModeType mode, Domain* domain) ; /** Assembles prescribed characteristic vector of required type from elements into given vector. @param answer assembled vector @param tStep time step, when answer is assembled. @param type characterisctic components of type type are requsted from elements and assembled using prescribed eqn numbers. */ void assemblePrescribedVectorFromElements (FloatArray&, TimeStep*, EquationID, CharType type, ValueModeType mode, Domain* domain) ; public: // consistency check /** Allows programmer to test some receiver's internal data, before computation begins. @return nonzero if receiver check is o.k. */ virtual int checkConsistency () {return 1;} // returns nonzero if o.k. /** Allows programmer to test problem its internal data, before computation begins. @return nonzero if receiver check is o.k. */ int checkProblemConsistency (); // returns nonzero if o.k. /** Prints output of receiver to ouput domain stream, for given time step. Corresponding function for element gauss points is invoked (gaussPoint::printOutputAt). */ virtual void printOutputAt (FILE *, TimeStep*) ; // input / output /// Prints stete of receiver. Usefull for debugging. void printYourself () ; /** DOF printing routine. Called by DofManagers to print Dof specific part. Dof class provides component printing routines, but emodel is responsible for what will be printed at DOF level. @param stream output stream @param iDof dof to be processed @param atTime solution step */ virtual void printDofOutputAt (FILE* stream, Dof* iDof, TimeStep* atTime) = 0; // identification /// Returns class name of the receiver. virtual const char* giveClassName () const { return "EngngModel" ;} /// Returns classType id of receiver. virtual classType giveClassID () const { return EngngModelClass ;} /// Returns nonzero if receiver does incremental analysis. virtual int isIncremental () {return 0;} /// Returns nonzero if nonlocal stiffness option activated. virtual int useNonlocalStiffnessOption () {return 0;} /// retun true if receiver in parallel mode bool isParallel () {return (parallelFlag != 0);} /** Indicates type of non linear computation (total or updated formulation). This is used for example on Nodal level to update coordinates if updated formulation is done, or on element level, when non linear contributions are computed. */ virtual fMode giveFormulation () {return UNKNOWN;} // for non-linear computation /* Returns Load Response Mode of receiver. This value indicates, whether nodes and elements should assemble total or incremental load vectors. virtual LoadResponseMode giveLoadResponseMode () {return TotalLoad;} */ /// Context requesting service EngngModelContext* giveContext () {return this->context;} /** Returns number of slave problems */ virtual int giveNumberOfSlaveProblems() {return 0;} /**Returns i-th slave problem */ virtual EngngModel* giveSlaveProblem (int i) {return NULL;} /** Returns the Equation scaling flag, which is used to indicate that governing equation(s) are scaled, or non-dimensionalized */ virtual bool giveEquationScalingFlag () {return false;} /// Returns the scale factor for given variable type virtual double giveVariableScale (VarScaleType varId) {return 1.0;} /**@name error and warning reporting methods These methods will print error (or warning) message using oofem default loggers. Do not use these methods directly, to avoid specify file and line parameters. More preferably, use these methods via corresponding OOFEM_CLASS_ERROR and OOFEM_CLASS_WARNING macros, that will include file and line parameters automatically. Uses variable number of arguments, so a format string followed by optional argumens is expected (according to printf conventions). @param file source file name, where error encountered (where error* function called) @param line source file line number, where error encountered */ //@{ /// prints error message and exits void error (char* file, int line, char *format, ...) const ; /// prints warning message void warning (char* file, int line, char *format, ...) const ; //@} }; typedef EngngModel Problem;

The key method declared by **EngngModel** is
*solveYourself*, which starts the solution. It loops over all
metasteps. For each metastep, the loop over corresponding solution steps is
performed. For each solution step, the value of currentStep attribute
is updated by invoking *giveNextStep()* service, and
the *solveYourselfAt* is
called, performing the solution for given step. The currentStep is
an attribute of EngngModel class. At the very beginning, it is set to
NULL or is initialized to the step from which analysis is restarted.

void EngngModel :: solveYourself () { int imstep, jstep; int smstep=1, sjstep=1; MetaStep* activeMStep; #ifdef TIME_REPORT oofem_timeval tstart; #endif // restart support - if currentStep is set already, start from the // next one if (this->currentStep) { smstep = this->currentStep->giveMetaStepNumber(); sjstep = this->giveMetaStep(smstep)-> giveStepRelativeNumber(this->currentStep->giveNumber()) + 1; } for (imstep = smstep; imstep<= nMetaSteps; imstep++) { activeMStep = this->giveMetaStep(imstep); for (jstep = sjstep; jstep <= activeMStep->giveNumberOfSteps(); jstep++) { #ifdef TIME_REPORT ::getUtime(tstart); #endif this->giveNextStep(); // update attributes according to new meta step attributes if (jstep == sjstep) this->updateAttributes (this->giveCurrentStep()); this->solveYourselfAt(this->giveCurrentStep()); #ifdef TIME_REPORT oofem_timeval ut; ::getRelativeUtime (ut, tstart); printf ("\nEngngModel info: user time consumed by solution step %d: %.2fs\n", jstep, (double)(ut.tv_sec+ut.tv_usec/(double)OOFEM_USEC_LIM)); #endif } } }

The *solveYourselfAt* typically assembles characteristic matrices and vectors
and solve the problem using the suitable numerical method. After
finishing the solution,
the *updateYourself* service for updating solution state and
then *terminate* method (for updating nodal and element
values) should be called to consistently update the state of all
components. The implementation should be provided by derived classes
(see section 3.4 for an example).

The implementation of *updateYourself* service loops over all
problem domains and calls corresponding update service for all DOF
managers and elements. The *terminate* service prints the
required outputs and optionally saves the
context file (if required), so the solution can be restarted from this
saved state later. Both services are virtual, so they can be easily
tailored to specific needs.

void EngngModel :: updateYourself (TimeStep* stepN) { int idomain, ndomains = this->giveNumberOfDomains(); int j, nnodes; Domain* domain; for (idomain = 1; idomain <= ndomains; idomain++) { domain= this->giveDomain(idomain); # ifdef VERBOSE VERBOSE_PRINT0("Updating domain ",domain->giveNumber()) # endif nnodes = domain->giveNumberOfDofManagers (); for( j=1;j<=nnodes;j++) { domain->giveDofManager(j)->updateYourself(stepN) ; } # ifdef VERBOSE VERBOSE_PRINT0("Updated nodes & sides ",nnodes) # endif Element* elem; int nelem = domain->giveNumberOfElements (); for (j=1 ; j<=nelem ; j++) { elem = domain -> giveElement(j) ; #ifdef __PARALLEL_MODE // skip remote elements (these are used as mirrors // of remote elements on other domains, when nonlocal // constitutive models are used. // Their introduction is necessary to allow local // averaging on domains without fine grain // communication between domains) if (elem->giveParallelMode () == Element_remote) continue; #endif elem -> updateYourself(stepN); } # ifdef VERBOSE VERBOSE_PRINT0("Updated Elements ",nelem) # endif } } void EngngModel :: terminate (TimeStep* stepN) { FILE* File = this->giveOutputStream(); // print output this->printOutputAt (File, stepN); // save context if required // default - save only if ALWAYS is set ( see cltypes.h ) if ((this->giveContextOutputMode() == ALWAYS) || (this->giveContextOutputMode() == REQUIRED)) { this->saveContext(NULL); } else if (this->giveContextOutputMode() == USERDEFINED) { if (stepN->giveNumber()%this->giveContextOutputStep() == 0) this->saveContext(NULL); } }

The implementations of services for characteristic components assembly
are provided. They simply loop over nodes or elements (depending on
the character of the requested component) of the given domain, requesting the
corresponding component contributions and corresponding code numbers.
The component contributions are assembled (using code numbers) into
a target array or matrix. The implementation of *assemble* for
characteristic vectors has to determine whether the contribution comes
from node or element. The implementation presented here uses the
hard-wired decision rules (adapted for structural analysis),
which in other cases leads the overloading of basic implementation.
The better solution will be probably to call some virtual service,
which returns the source of contribution (nodal or element
contribution) and then to perform corresponding loop.

void EngngModel :: assemble (SparseMtrx* answer, TimeStep* tStep, EquationID ut, CharType type, Domain* domain) // // assembles matrix answer by calling // element(i) -> giveCharacteristicMatrix ( type, tStep ); // for each element in domain // and assembling every contribution to answer // // { int ielem; IntArray loc ; FloatMatrix mat; Element *element; if (answer == NULL) _error("assemble: NULL pointer encountered."); int nelem = domain -> giveNumberOfElements (); for ( ielem = 1; ielem <= nelem ; ielem++ ) { element = domain -> giveElement(ielem); #ifdef __PARALLEL_MODE // skip remote elements (these are used as mirrors of remote eleemnts on other domains // when nonlocal constitutive models are used. They introduction is necessary to // allow local averaging on domains without fine grain communication between domains). if (element->giveParallelMode () == Element_remote) continue; #endif element -> giveLocationArray (loc, ut); this->giveElementCharacteristicMatrix(mat, ielem, type, tStep, domain ); if (mat.isNotEmpty()) { if (answer -> assemble (loc, mat) == 0) _error("assemble: sparse matrix assemble error"); } } answer->assembleBegin(); answer->assembleEnd(); } void EngngModel :: assembleVectorFromDofManagers (FloatArray& answer, TimeStep* tStep, EquationID ut, CharType type, ValueModeType mode, Domain* domain) // // assembles matrix answer by calling // node(i) -> computeLoadVectorAt (tStep); // for each element in domain // and assembling every contribution to answer // // { int i ; IntArray loc ; FloatArray charVec ; DofManager *node ; int nnode = domain -> giveNumberOfDofManagers(); for (i = 1; i <= nnode ; i++ ) { node = domain -> giveDofManager(i); node -> computeLoadVectorAt (charVec, tStep, mode); if(charVec.giveSize()) { node -> giveCompleteLocationArray (loc); answer.assemble (charVec, loc) ; } } } void EngngModel :: assembleVectorFromElements (FloatArray& answer, TimeStep* tStep, EquationID ut, CharType type, ValueModeType mode, Domain* domain) // // assembles matrix answer by calling // element(i) -> giveCharacteristicMatrix ( type, tStep ); // for each element in domain // and assembling every contribution to answer // // { int i ; IntArray loc ; FloatArray charVec ; Element *element ; int nelem = domain -> giveNumberOfElements (); for (i = 1; i <= nelem ; i++ ) { element = domain -> giveElement(i); #ifdef __PARALLEL_MODE // skip remote elements (these are used as mirrors of remote eleemnts on other domains // when nonlocal constitutive models are used. They introduction is necessary to // allow local averaging on domains without fine grain communication between domains). if (element->giveParallelMode () == Element_remote) continue; #endif element -> giveLocationArray (loc, ut); this -> giveElementCharacteristicVector (charVec, i, type, mode, tStep, domain); if(charVec.giveSize()) answer.assemble (charVec, loc) ; } } void EngngModel :: assemblePrescribedVectorFromDofManagers (FloatArray& answer, TimeStep* tStep, EquationID ut, CharType type, ValueModeType mode, Domain* domain) // // assembles matrix answer by calling // node(i) -> computeLoadVectorAt (tStep); // for each element in domain // and assembling every contribution to answer // // { int i ; IntArray loc ; FloatArray charVec ; DofManager *node ; int nnode = domain -> giveNumberOfDofManagers(); for (i = 1; i <= nnode ; i++ ) { node = domain -> giveDofManager(i); node -> computeLoadVectorAt (charVec, tStep, mode); if(charVec.giveSize()) { node -> giveCompletePrescribedLocationArray (loc); answer.assemble (charVec, loc) ; } } } void EngngModel :: assemblePrescribedVectorFromElements (FloatArray& answer, TimeStep* tStep, EquationID ut, CharType type, ValueModeType mode, Domain* domain) // // assembles matrix answer by calling // element(i) -> giveCharacteristicMatrix ( type, tStep ); // for each element in domain // and assembling every contribution to answer // // { int i ; IntArray loc ; FloatArray charVec ; Element *element ; int nelem = domain -> giveNumberOfElements (); for (i = 1; i <= nelem ; i++ ) { element = domain -> giveElement(i); #ifdef __PARALLEL_MODE // skip remote elements (these are used as mirrors of remote eleemnts on other domains // when nonlocal constitutive models are used. They introduction is necessary to // allow local averaging on domains without fine grain communication between domains). if (element->giveParallelMode () == Element_remote) continue; #endif element -> givePrescribedLocationArray (loc, ut); if (loc.containsOnlyZeroes()) continue; this -> giveElementCharacteristicVector (charVec, i, type, mode, tStep, domain); if(charVec.giveSize()) answer.assemble (charVec, loc) ; } }

Borek Patzak 2018-01-02