Problem representation - Engineering model

Engng model is an abstraction for the problem under consideration. It represents the type of analysis to be performed. Base class declares and implements the basic general services for assembling characteristic components and services for starting the solution step and its termination. Derived classes ``know'' the form of governing equation and the physical meaning of particular components. They are responsible for forming the governing equation for each solution step, usually by summing contributions from particular elements and nodes.

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:

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