class LinearStatic : public StructuralEngngModel { /* This class implements LinearStatic Engineering problem. Multiple loading works only if linear elastic material (such as isoLE) is used. (Other non-linear materials kepp load history, so such multiple loading will cause that next step will be assumed as new load increment, not the total new load). Because they always copute real stresses acording to reached strain state, they are not able to respond to linear analysis. DESCRIPTION: Solution of this problem is series of loading cases, maintained as sequence of time-steps. This solution is in form of linear equation system Ax=b TASK: Creating Numerical method for solving Ax=b Interfacing Numerical method to Elements Managing time steps */ protected: SparseMtrx* stiffnessMatrix; FloatArray loadVector; FloatArray displacementVector; LinSystSolverType solverType; SparseMtrxType sparseMtrxType; /// Numerical method used to solve the problem SparseLinearSystemNM *nMethod; int initFlag; #ifdef __PETSC_MODULE Vec _loadVec, _dispVec; #endif public: LinearStatic (int i, EngngModel* _master = NULL) ; ~LinearStatic () {delete stiffnessMatrix; if (nMethod) delete nMethod;} // solving void solveYourself (); void solveYourselfAt (TimeStep *); //int requiresNewLhs () {return 0;} /** Updates nodal values (calls also this->updateDofUnknownsDictionary for updating dofs unknowns dictionaries if model supports changes of static system). The element internal state update is also forced using updateInternalState service. */ virtual void updateYourself (TimeStep*) ; double giveUnknownComponent ( EquationID, ValueModeType, TimeStep*, Domain*, Dof*); contextIOResultType saveContext (FILE* stream, void *obj = NULL) ; contextIOResultType restoreContext (FILE* stream, void *obj = NULL); void updateDomainLinks(); TimeStep* giveNextStep (); NumericalMethod* giveNumericalMethod (TimeStep*); //void printReactionForces (TimeStep *); void terminate (TimeStep*); IRResultType initializeFrom (InputRecord* ir); // consistency check virtual int checkConsistency (); // returns nonzero if o.k. /** 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); // identification const char* giveClassName () const { return "LinearStatic";} classType giveClassID () const { return LinearStaticClass;} fMode giveFormulation () { return TL; } #ifdef __PARALLEL_MODE /** Determines the space necessary for send/receive buffer. It uses related communication map pattern to determine the maximum size needed. @param commMap communication map used to send/receive messages @param buff communication buffer @return upper bound of space needed */ int estimateMaxPackSize (IntArray& commMap, CommunicationBuffer& buff, int packUnpackType) ; #endif } ;
The listing of the LinearStatic class implementation follows. First, the giveNumericalMethod returns the numerical method, which will be used. The new instance is created if not defined according to nMethod attribute, which is initialized from input (see instanciateYourself). Note, that thanks to the general interface, defined by the NumericalMethod class and the component mapping approach, the further communication with the numerical method uses only the interface declared by the base NumerialMethod class and therefore there is no need to worry about particular numerical method details.
NumericalMethod* LinearStatic :: giveNumericalMethod (TimeStep* atTime) // only one has reason for LinearStatic // - SolutionOfLinearEquations { if (nMethod) return nMethod ; SparseLinearSystemNM* nm; if (solverType == ST_Direct) { nm = (SparseLinearSystemNM*) new LDLTFactorization (1,this->giveDomain(1),this); nMethod = nm; return nm; } else { nm = (SparseLinearSystemNM*) new IMLSolver (1,this->giveDomain(1),this); nMethod = nm; return nm; } } IRResultType LinearStatic :: initializeFrom (InputRecord* ir) { // Required by IR_GIVE_FIELD macro const char *__keyword, *__proc = "initializeFrom"; IRResultType result; StructuralEngngModel::initializeFrom (ir); int val = 0; IR_GIVE_OPTIONAL_FIELD (ir, val, "lstype"); // Macro solverType = (LinSystSolverType) val; val = 0; IR_GIVE_OPTIONAL_FIELD (ir, val, "smtype"); // Macro sparseMtrxType = (SparseMtrxType) val; return IRRT_OK; } double LinearStatic :: giveUnknownComponent (EquationID chc, ValueModeType mode, TimeStep* tStep, Domain* d, Dof* dof) // returns unknown quantity like displaacement, velocity of equation eq // This function translates this request to numerical method language { int eq = dof->giveEquationNumber(); if (eq == 0) _error ("giveUnknownComponent: invalid equation number"); if (tStep != this->giveCurrentStep ()) { _error ("giveUnknownComponent: unknown time step encountered"); return 0.; } if (chc != EID_MomentumBalance) { _error ("giveUnknownComponent: Unknown is of undefined CharType for this problem"); return 0.; } switch (mode) { case VM_Total: case VM_Incremental: if (displacementVector.isNotEmpty()) return displacementVector.at(eq); else return 0.; // return nMethod-> giveUnknownComponent (LinearEquationSolution, eq); default: _error ("giveUnknownComponent: Unknown is of undefined type for this problem"); } return 0.; } TimeStep* LinearStatic :: giveNextStep () { int istep = this->giveNumberOfFirstStep(); //int mstep = 1; StateCounterType counter = 1; delete previousStep; if (currentStep != NULL) { istep = currentStep->giveNumber() + 1 ; counter = currentStep->giveSolutionStateCounter() + 1; } previousStep = currentStep; currentStep = new TimeStep (istep,this, 1, (double) istep, 0., counter); // time and dt variables are set eq to 0 for staics - has no meaning return currentStep; } void LinearStatic :: solveYourselfAt (TimeStep* tStep) { // // creates system of governing eq's and solves them at given time step // // first assemble problem at current time step if (initFlag) { #ifdef VERBOSE OOFEM_LOG_INFO("Assembling stiffness matrix\n"); #endif // // first step assemble stiffness Matrix // /* IntArray* mht = this -> GiveBanWidthVector (); stiffnessMatrix = new Skyline (); stiffnessMatrix -> checkSizeTowardsBanWidth (mht) ; delete mht; */ stiffnessMatrix = ::CreateUsrDefSparseMtrx(sparseMtrxType); // new Skyline (); if (stiffnessMatrix==NULL) _error ("solveYourselfAt: sparse matrix creation failed"); //stiffnessMatrix = new DynCompCol (); //stiffnessMatrix = new CompCol (); stiffnessMatrix->buildInternalStructure (this, 1, EID_MomentumBalance); this -> assemble (stiffnessMatrix, tStep, EID_MomentumBalance, StiffnessMatrix, this->giveDomain(1)); // // alocate space for displacementVector // //displacementVector = new FloatArray (this->giveNumberOfEquations()); displacementVector.resize (this->giveNumberOfEquations(EID_MomentumBalance)); displacementVector.zero(); #ifdef __PETSC_MODULE if (solverType == ST_Petsc) { this->givePetscContext(1, EID_MomentumBalance)->createVecGlobal (&_loadVec); this->givePetscContext(1, EID_MomentumBalance)->createVecGlobal (&_dispVec); } #endif initFlag = 0; } #ifdef VERBOSE OOFEM_LOG_INFO("Assembling load\n"); #endif #ifdef __PETSC_MODULE // direct interface to PETSC if (solverType == ST_Petsc) { this->petsc_assembleVectorFromElements(_loadVec, tStep, EID_MomentumBalance, ElementForceLoadVector, VM_Total, this->giveDomain(1)); this->petsc_assembleVectorFromElements(_loadVec, tStep, EID_MomentumBalance, ElementNonForceLoadVector, VM_Total, this->giveDomain(1)); this->petsc_assembleVectorFromDofManagers(_loadVec, tStep, EID_MomentumBalance, NodalLoadVector, VM_Total, this->giveDomain(1)) ; VecAssemblyBegin(_loadVec); VecAssemblyEnd (_loadVec); this->giveNumericalMethod(tStep); #ifdef VERBOSE OOFEM_LOG_INFO("Solving ...\n"); #endif //nMethod -> solveYourselfAt(tStep); PetscSolver *ps = dynamic_cast<PetscSolver*>(nMethod); PetscSparseMtrx* psm = dynamic_cast<PetscSparseMtrx*>(stiffnessMatrix); ps -> petsc_solve (psm, _loadVec, _dispVec); this->givePetscContext(1, EID_MomentumBalance)->scatterG2N (_dispVec, &displacementVector, INSERT_VALUES); } else #endif { // // assembling the element part of load vector // //loadVector = new FloatArray (this->giveNumberOfEquations()); loadVector.resize (this->giveNumberOfEquations(EID_MomentumBalance)); loadVector.zero(); this->assembleVectorFromElements(loadVector, tStep, EID_MomentumBalance, ElementForceLoadVector, VM_Total, this->giveDomain(1)); this->assembleVectorFromElements(loadVector, tStep, EID_MomentumBalance, ElementNonForceLoadVector, VM_Total, this->giveDomain(1)); // // assembling the nodal part of load vector // this->assembleVectorFromDofManagers(loadVector, tStep, EID_MomentumBalance, NodalLoadVector, VM_Total, this->giveDomain(1)) ; // // set-up numerical model // this->giveNumericalMethod(tStep); /* nMethod -> setSparseMtrxAsComponent ( LinearEquationLhs , stiffnessMatrix) ; nMethod -> setFloatArrayAsComponent ( LinearEquationRhs , &loadVector) ; nMethod -> setFloatArrayAsComponent ( LinearEquationSolution, &displacementVector) ; */ // // call numerical model to solve arised problem // #ifdef VERBOSE OOFEM_LOG_INFO("Solving ...\n"); #endif //nMethod -> solveYourselfAt(tStep); nMethod -> solve (stiffnessMatrix, &loadVector, &displacementVector); } tStep->incrementStateCounter(); // update solution state counter // // update nodes, elements, etc. this->updateYourself(this->giveCurrentStep()); } void LinearStatic :: updateYourself (TimeStep* stepN) { this->updateInternalState(stepN); StructuralEngngModel::updateYourself(stepN); } contextIOResultType LinearStatic :: saveContext (FILE* stream, void *obj) // // saves state variable - displacement vector // { contextIOResultType iores; int closeFlag = 0; if (stream==NULL) { if (!this->giveContextFile(&stream,this->giveCurrentStep()->giveNumber(), contextMode_write)) THROW_CIOERR(CIO_IOERR); // override closeFlag = 1; } if ((iores = StructuralEngngModel :: saveContext (stream)) != CIO_OK) THROW_CIOERR(iores); if ((iores = displacementVector.storeYourself(stream)) != CIO_OK) THROW_CIOERR(iores); if (closeFlag) fclose (stream); // ensure consistent records return CIO_OK; } contextIOResultType LinearStatic :: restoreContext (FILE* stream, void *obj) // // restore state variable - displacement vector // { contextIOResultType iores; int closeFlag = 0; int istep = this->resolveCorrespondingStepNumber (obj); if (stream == NULL) { if (!this->giveContextFile(&stream, istep, contextMode_read)) THROW_CIOERR(CIO_IOERR); // override closeFlag = 1; } if ((iores=StructuralEngngModel::restoreContext(stream,obj))!=CIO_OK) THROW_CIOERR(iores); if ((iores=displacementVector.restoreYourself(stream))!=CIO_OK) THROW_CIOERR(iores); if (closeFlag) fclose (stream); // ensure consistent records return CIO_OK; } void LinearStatic:: terminate(TimeStep* tStep) { StructuralEngngModel :: terminate (tStep); this->printReactionForces (tStep, 1); } int LinearStatic::checkConsistency () { // check internal consistency // if success returns nonzero int i, nelem; Element* ePtr; StructuralElement* sePtr; Domain* domain = this->giveDomain(1); nelem = domain->giveNumberOfElements(); // check for proper element type for (i=1; i<= nelem; i++) { ePtr = domain->giveElement(i); sePtr = DYNAMIC_CAST (StructuralElement, ePtr); if (sePtr == NULL) { printf ("Error: Element %d has no StructuralElement base\n",i); return 0; } } EngngModel :: checkConsistency (); return 1; } void LinearStatic::updateDomainLinks () { EngngModel::updateDomainLinks(); this->giveNumericalMethod(giveCurrentStep())->setDomain (this->giveDomain(1)); }
Borek Patzak 2018-01-02