void NonLinearStatic :: updateComponent(TimeStep *tStep, NumericalCmpn cmpn, Domain *d) // // updates some component, which is used by numerical method // to newly reached state. used mainly by numerical method // when new tangent stiffness is needed during finding // of new equilibrium stage. // { switch ( cmpn ) { case NonLinearLhs: if ( stiffMode == nls_tangentStiffness ) { stiffnessMatrix->zero(); // zero stiffness matrix #ifdef VERBOSE OOFEM_LOG_DEBUG("Assembling tangent stiffness matrix\n"); #endif this->assemble(*stiffnessMatrix, tStep, TangentAssembler(TangentStiffness), EModelDefaultEquationNumbering(), d); } else if ( ( stiffMode == nls_secantStiffness ) || ( stiffMode == nls_secantInitialStiffness && initFlag ) ) { #ifdef VERBOSE OOFEM_LOG_DEBUG("Assembling secant stiffness matrix\n"); #endif stiffnessMatrix->zero(); // zero stiffness matrix this->assemble(*stiffnessMatrix, tStep, TangentAssembler(SecantStiffness), EModelDefaultEquationNumbering(), d); initFlag = 0; } else if ( ( stiffMode == nls_elasticStiffness ) && ( initFlag || ( this->giveMetaStep( tStep->giveMetaStepNumber() )->giveFirstStepNumber() == tStep->giveNumber() ) ) ) { #ifdef VERBOSE OOFEM_LOG_DEBUG("Assembling elastic stiffness matrix\n"); #endif stiffnessMatrix->zero(); // zero stiffness matrix this->assemble(*stiffnessMatrix, tStep, TangentAssembler(ElasticStiffness), EModelDefaultEquationNumbering(), d); initFlag = 0; } else { // currently no action , this method is mainly intended to // assemble new tangent stiffness after each iteration // when secantStiffMode is on, we use the same stiffness // during iteration process } break; case InternalRhs: #ifdef VERBOSE OOFEM_LOG_DEBUG("Updating internal forces\n"); #endif // update internalForces and internalForcesEBENorm concurrently this->giveInternalForces(internalForces, true, d->giveNumber(), tStep); break; default: OOFEM_ERROR("Unknown Type of component."); } }
void NonLinearStatic :: assemble(SparseMtrx *answer, TimeStep *tStep, EquationID ut, CharType type, const UnknownNumberingScheme &s, Domain *domain) { #ifdef TIME_REPORT Timer timer; timer.startTimer(); #endif LinearStatic :: assemble(answer, tStep, ut, type, s, domain); if ( ( nonlocalStiffnessFlag ) && ( type == TangentStiffnessMatrix ) ) { // add nonlocal contribution int ielem, nelem = domain->giveNumberOfElements(); for ( ielem = 1; ielem <= nelem; ielem++ ) { ( ( StructuralElement * ) ( domain->giveElement(ielem) ) )->addNonlocalStiffnessContributions(* answer, s, tStep); } // print storage statistics answer->printStatistics(); } #ifdef TIME_REPORT timer.stopTimer(); OOFEM_LOG_DEBUG( "NonLinearStatic: User time consumed by assembly: %.2fs\n", timer.getUtime() ); #endif }
void NonLinearStatic :: assemble(SparseMtrx &answer, TimeStep *tStep, const MatrixAssembler &ma, const UnknownNumberingScheme &s, Domain *domain) { #ifdef TIME_REPORT Timer timer; timer.startTimer(); #endif LinearStatic :: assemble(answer, tStep, ma, s, domain); if ( ( nonlocalStiffnessFlag ) && dynamic_cast< const TangentAssembler* >(&ma) ) { // add nonlocal contribution for ( auto &elem : domain->giveElements() ) { static_cast< StructuralElement * >( elem.get() )->addNonlocalStiffnessContributions(answer, s, tStep); } // print storage statistics answer.printStatistics(); } #ifdef TIME_REPORT timer.stopTimer(); OOFEM_LOG_DEBUG( "NonLinearStatic: User time consumed by assembly: %.2fs\n", timer.getUtime() ); #endif }
void B3SolidMaterial :: predictParametersFrom(double fc, double c, double wc, double ac, double t0, double alpha1, double alpha2) { /* * Prediction of model parameters - estimation from concrete composition * and strength * * fc - 28-day standard cylinder compression strength in MPa * c - cement content of concrete in kg/m^3 * wc - ratio (by weight) of water to cementitious material * ac - ratio (by weight) of aggregate to cement * t0 - age when drying begins (in days) * alpha1, alpha2 - influence of cement type and curing * * The prediction of the material parameters of the present model * is restricted to Portland cement concretes with the following * parameter ranges: * * 2500 <= fc <= 10000 [psi] (psi = 6895 Pa) * 10 <= c <= 45 [lb ft-3] (lb ft-3 = 16.03 kg m-3) * 0.3 <= wc <= 0.85 * 2.5 <= ac <= 13.5 * * * alpha1 = 1.0 for type I cement; * = 0.85 for type II cement; * = 1.1 for type III cement; * * alpha2 = 0.75 for steam-cured specimens; * = 1.2 for specimens sealed during curing; * = 1.0 for specimens cured in water or 100% relative humidity. * */ // Basic creep parameters // q1 = 0.6e6 / E28; // replaced by the formula dependent on fc q1 = 126.74271 / sqrt(fc); q2 = 185.4 * pow(c, 0.5) * pow(fc, -0.9); // [1/TPa] q3 = 0.29 * pow(wc, 4.) * q2; q4 = 20.3 * pow(ac, -0.7); // Shrinkage parameters if ( this->shMode == B3_AverageShrinkage ) { kt = 85000 * pow(t0, -0.08) * pow(fc, -0.25); // 85000-> result in [days/m^2] or 8.5-> result in [days/cm^2] EpsSinf = alpha1 * alpha2 * ( 1.9e-2 * pow(w, 2.1) * pow(fc, -0.28) + 270. ); // exponent corrected: -0.25 -> -0.28 // Drying creep parameter q5 = 7.57e5 * ( 1. / fc ) * pow(EpsSinf, -0.6); } char buff [ 1024 ]; sprintf(buff, "q1=%lf q2=%lf q3=%lf q4=%lf q5=%lf kt=%lf EpsSinf=%lf", q1, q2, q3, q4, q5, kt, EpsSinf); OOFEM_LOG_DEBUG("B3mat[%d]: estimated params: %s\n", this->number, buff); }
void NonLinearStatic :: updateLoadVectors(TimeStep *tStep) { MetaStep *mstep = this->giveMetaStep( tStep->giveMetaStepNumber() ); bool isLastMetaStep = ( tStep->giveNumber() == mstep->giveLastStepNumber() ); if ( controlMode == nls_indirectControl ) { //if ((tStep->giveNumber() == mstep->giveLastStepNumber()) && ir->hasField("fixload")) { if ( isLastMetaStep ) { if ( !mstep->giveAttributesRecord()->hasField(_IFT_NonLinearStatic_donotfixload) ) { OOFEM_LOG_INFO("Fixed load level\n"); //update initialLoadVector initialLoadVector.add(loadLevel, incrementalLoadVector); initialLoadVectorOfPrescribed.add(loadLevel, incrementalLoadVectorOfPrescribed); incrementalLoadVector.zero(); incrementalLoadVectorOfPrescribed.zero(); this->loadInitFlag = 1; } //if (!mstep->giveAttributesRecord()->hasField("keepll")) this->loadLevelInitFlag = 1; } } else { // direct control //update initialLoadVector after each step of direct control //(here the loading is not proportional) OOFEM_LOG_DEBUG("Fixed load level\n"); initialLoadVector.add(loadLevel, incrementalLoadVector); initialLoadVectorOfPrescribed.add(loadLevel, incrementalLoadVectorOfPrescribed); incrementalLoadVector.zero(); incrementalLoadVectorOfPrescribed.zero(); this->loadInitFlag = 1; } // if (isLastMetaStep) { if ( isLastMetaStep && !mstep->giveAttributesRecord()->hasField(_IFT_NonLinearStatic_donotfixload) ) { #ifdef VERBOSE OOFEM_LOG_INFO("Reseting load level\n"); #endif if ( mstepCumulateLoadLevelFlag ) { cumulatedLoadLevel += loadLevel; } else { cumulatedLoadLevel = 0.0; } this->loadLevel = 0.0; } }
void NonlocalMaterialExtensionInterface :: updateDomainBeforeNonlocAverage(TimeStep *tStep) { Domain *d = this->giveDomain(); if ( d->giveNonlocalUpdateStateCounter() == tStep->giveSolutionStateCounter() ) { return; // already updated } OOFEM_LOG_DEBUG ("Updating Before NonlocAverage\n"); for ( auto &elem : d->giveElements() ) { elem->updateBeforeNonlocalAverage(tStep); } // mark last update counter to prevent multiple updates d->setNonlocalUpdateStateCounter( tStep->giveSolutionStateCounter() ); }
void DynCompCol :: printStatistics() const { int j, nz_ = 0; #ifndef DynCompCol_USE_STL_SETS for ( j = 0; j < nColumns; j++ ) { nz_ += rowind_ [ j ]->giveSize(); } #else for ( j = 0; j < nColumns; j++ ) { nz_ += columns [ j ].size(); #endif OOFEM_LOG_DEBUG("DynCompCol info: neq is %d, nelem is %d\n", nColumns, nz_); } /*********************/ /* Array access */ /*********************/ double &DynCompCol :: at(int i, int j) { // increment version this->version++; #ifndef DynCompCol_USE_STL_SETS /* * for (int t=1; t<=columns_[j-1]->giveSize(); t++) * if (rowind_[j-1]->at(t) == (i-1)) return columns_[j-1]->at(t); * printf ("DynCompCol::operator(): Array accessing exception -- out of bounds.\n"); * exit(1); * return columns_[0]->at(1); // return to suppress compiler warning message */ int rowIndx; if ( ( rowIndx = this->giveRowIndx(j - 1, i - 1) ) ) { return columns_ [ j - 1 ]->at(rowIndx); } OOFEM_ERROR("Array accessing exception -- (%d,%d) out of bounds", i, j); return columns_ [ 0 ]->at(1); // return to suppress compiler warning message #else return this->columns [ j - 1 ] [ i - 1 ]; #endif }
void NlDEIDynamic :: solveYourselfAt(TimeStep *tStep) { // // Creates system of governing eq's and solves them at given time step. // Domain *domain = this->giveDomain(1); int neq = this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ); int nman = domain->giveNumberOfDofManagers(); DofManager *node; int i, k, j, jj; double coeff, maxDt, maxOm = 0.; double prevIncrOfDisplacement, incrOfDisplacement; if ( initFlag ) { #ifdef VERBOSE OOFEM_LOG_DEBUG("Assembling mass matrix\n"); #endif // // Assemble mass matrix. // this->computeMassMtrx(massMatrix, maxOm, tStep); if ( drFlag ) { // If dynamic relaxation: Assemble amplitude load vector. loadRefVector.resize(neq); loadRefVector.zero(); this->computeLoadVector(loadRefVector, VM_Total, tStep); #ifdef __PARALLEL_MODE // Compute the processor part of load vector norm pMp this->pMp = 0.0; double my_pMp = 0.0, coeff = 1.0; int eqNum, ndofman = domain->giveNumberOfDofManagers(); dofManagerParallelMode dofmanmode; DofManager *dman; for ( int dm = 1; dm <= ndofman; dm++ ) { dman = domain->giveDofManager(dm); dofmanmode = dman->giveParallelMode(); // Skip all remote and null dofmanagers coeff = 1.0; if ( ( dofmanmode == DofManager_remote ) || ( ( dofmanmode == DofManager_null ) ) ) { continue; } else if ( dofmanmode == DofManager_shared ) { coeff = 1. / dman->givePartitionsConnectivitySize(); } // For shared nodes we add locally an average = 1/givePartitionsConnectivitySize()*contribution, for ( Dof *dof: *dman ) { if ( dof->isPrimaryDof() && ( eqNum = dof->__giveEquationNumber() ) ) { my_pMp += coeff * loadRefVector.at(eqNum) * loadRefVector.at(eqNum) / massMatrix.at(eqNum); } } } // Sum up the contributions from processors. MPI_Allreduce(& my_pMp, & pMp, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); #else this->pMp = 0.0; for ( i = 1; i <= neq; i++ ) { pMp += loadRefVector.at(i) * loadRefVector.at(i) / massMatrix.at(i); } #endif // Solve for rate of loading process (parameter "c") (undamped system assumed), if ( dumpingCoef < 1.e-3 ) { c = 3.0 * this->pyEstimate / pMp / Tau / Tau; } else { c = this->pyEstimate * Tau * dumpingCoef * dumpingCoef * dumpingCoef / pMp / ( -3.0 / 2.0 + dumpingCoef * Tau + 2.0 * exp(-dumpingCoef * Tau) - 0.5 * exp(-2.0 * dumpingCoef * Tau) ); } } initFlag = 0; } if ( tStep->isTheFirstStep() ) { // // Special init step - Compute displacements at tstep 0. // displacementVector.resize(neq); displacementVector.zero(); previousIncrementOfDisplacementVector.resize(neq); previousIncrementOfDisplacementVector.zero(); velocityVector.resize(neq); velocityVector.zero(); accelerationVector.resize(neq); accelerationVector.zero(); for ( j = 1; j <= nman; j++ ) { node = domain->giveDofManager(j); for ( Dof *dof: *node ) { // Ask for initial values obtained from // bc (boundary conditions) and ic (initial conditions) // all dofs are expected to be DisplacementVector type. if ( !dof->isPrimaryDof() ) { continue; } jj = dof->__giveEquationNumber(); if ( jj ) { displacementVector.at(jj) = dof->giveUnknown(VM_Total, tStep); velocityVector.at(jj) = dof->giveUnknown(VM_Velocity, tStep); accelerationVector.at(jj) = dof->giveUnknown(VM_Acceleration, tStep); } } } // // Set-up numerical model. // // Try to determine the best deltaT, maxDt = 2.0 / sqrt(maxOm); if ( deltaT > maxDt ) { // Print reduced time step increment and minimum period Tmin OOFEM_LOG_RELEVANT("deltaT reduced to %e, Tmin is %e\n", maxDt, maxDt * M_PI); deltaT = maxDt; tStep->setTimeIncrement(deltaT); } for ( j = 1; j <= neq; j++ ) { previousIncrementOfDisplacementVector.at(j) = velocityVector.at(j) * ( deltaT ); displacementVector.at(j) -= previousIncrementOfDisplacementVector.at(j); } #ifdef VERBOSE OOFEM_LOG_RELEVANT( "\n\nSolving [Step number %8d, Time %15e]\n", tStep->giveNumber(), tStep->giveTargetTime() ); #endif return; } // end of init step #ifdef VERBOSE OOFEM_LOG_DEBUG("Assembling right hand side\n"); #endif displacementVector.add(previousIncrementOfDisplacementVector); // Update solution state counter tStep->incrementStateCounter(); // Compute internal forces. this->giveInternalForces(internalForces, false, 1, tStep); if ( !drFlag ) { // // Assembling the element part of load vector. // this->computeLoadVector(loadVector, VM_Total, tStep); // // Assembling additional parts of right hand side. // loadVector.subtract(internalForces); } else { // Dynamic relaxation // compute load factor pt = 0.0; #ifdef __PARALLEL_MODE double my_pt = 0.0, coeff = 1.0; int eqNum, ndofman = domain->giveNumberOfDofManagers(); dofManagerParallelMode dofmanmode; DofManager *dman; for ( int dm = 1; dm <= ndofman; dm++ ) { dman = domain->giveDofManager(dm); dofmanmode = dman->giveParallelMode(); // skip all remote and null dofmanagers coeff = 1.0; if ( ( dofmanmode == DofManager_remote ) || ( dofmanmode == DofManager_null ) ) { continue; } else if ( dofmanmode == DofManager_shared ) { coeff = 1. / dman->givePartitionsConnectivitySize(); } // For shared nodes we add locally an average= 1/givePartitionsConnectivitySize()*contribution. for ( Dof *dof: *dman ) { if ( dof->isPrimaryDof() && ( eqNum = dof->__giveEquationNumber() ) ) { my_pt += coeff * internalForces.at(eqNum) * loadRefVector.at(eqNum) / massMatrix.at(eqNum); } } } // Sum up the contributions from processors. MPI_Allreduce(& my_pt, & pt, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); #else for ( k = 1; k <= neq; k++ ) { pt += internalForces.at(k) * loadRefVector.at(k) / massMatrix.at(k); } #endif pt = pt / pMp; if ( dumpingCoef < 1.e-3 ) { pt += c * ( Tau - tStep->giveTargetTime() ) / Tau; } else { pt += c * ( 1.0 - exp( dumpingCoef * ( tStep->giveTargetTime() - Tau ) ) ) / dumpingCoef / Tau; } loadVector.resize( this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ) ); for ( k = 1; k <= neq; k++ ) { loadVector.at(k) = pt * loadRefVector.at(k) - internalForces.at(k); } // Compute relative error. double err = 0.0; #ifdef __PARALLEL_MODE double my_err = 0.0; for ( int dm = 1; dm <= ndofman; dm++ ) { dman = domain->giveDofManager(dm); dofmanmode = dman->giveParallelMode(); // Skip all remote and null dofmanagers. coeff = 1.0; if ( ( dofmanmode == DofManager_remote ) || ( dofmanmode == DofManager_null ) ) { continue; } else if ( dofmanmode == DofManager_shared ) { coeff = 1. / dman->givePartitionsConnectivitySize(); } // For shared nodes we add locally an average= 1/givePartitionsConnectivitySize()*contribution. for ( Dof *dof: *dman ) { if ( dof->isPrimaryDof() && ( eqNum = dof->__giveEquationNumber() ) ) { my_err += coeff * loadVector.at(eqNum) * loadVector.at(eqNum) / massMatrix.at(eqNum); } } } // Sum up the contributions from processors. MPI_Allreduce(& my_err, & err, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); #else for ( k = 1; k <= neq; k++ ) { err = loadVector.at(k) * loadVector.at(k) / massMatrix.at(k); } #endif err = err / ( pMp * pt * pt ); OOFEM_LOG_RELEVANT("Relative error is %e, loadlevel is %e\n", err, pt); } for ( j = 1; j <= neq; j++ ) { coeff = massMatrix.at(j); loadVector.at(j) += coeff * ( ( 1. / ( deltaT * deltaT ) ) - dumpingCoef * 1. / ( 2. * deltaT ) ) * previousIncrementOfDisplacementVector.at(j); } // // Set-up numerical model // /* it is not necesary to call numerical method * approach used here is not good, but effective enough * inverse of diagonal mass matrix is done here */ // // call numerical model to solve arised problem - done localy here // #ifdef VERBOSE OOFEM_LOG_RELEVANT( "\n\nSolving [Step number %8d, Time %15e]\n", tStep->giveNumber(), tStep->giveTargetTime() ); #endif // NM_Status s = nMethod->solve(*massMatrix, loadVector, displacementVector); // if ( !(s & NM_Success) ) { // OOFEM_ERROR("No success in solving system. Ma=f"); // } for ( i = 1; i <= neq; i++ ) { prevIncrOfDisplacement = previousIncrementOfDisplacementVector.at(i); incrOfDisplacement = loadVector.at(i) / ( massMatrix.at(i) * ( 1. / ( deltaT * deltaT ) + dumpingCoef / ( 2. * deltaT ) ) ); accelerationVector.at(i) = ( incrOfDisplacement - prevIncrOfDisplacement ) / ( deltaT * deltaT ); velocityVector.at(i) = ( incrOfDisplacement + prevIncrOfDisplacement ) / ( 2. * deltaT ); previousIncrementOfDisplacementVector.at(i) = incrOfDisplacement; } }
void FETICommunicator :: setUpCommunicationMaps(EngngModel *pm) { int i, j, l, maxRec; int globaldofmannum, localNumber, ndofs; int numberOfBoundaryDofMans; int source, tag; IntArray numberOfPartitionBoundaryDofMans(size); StaticCommunicationBuffer commBuff(MPI_COMM_WORLD); EModelDefaultEquationNumbering dn; // FETIBoundaryDofManager *dofmanrec; // Map containing boundary dof managers records, the key is corresponding global number // value is corresponding local master dof manager number map< int, int, less< int > >BoundaryDofManagerMap; // communication maps of slaves IntArray **commMaps = new IntArray * [ size ]; // location array IntArray locNum; Domain *domain = pm->giveDomain(1); // check if receiver is master if ( this->rank != 0 ) { _error("FETICommunicator::setUpCommunicationMaps : rank 0 (master) expected as receiver"); } // resize receive buffer commBuff.resize( commBuff.givePackSize(MPI_INT, 1) ); // // receive data // for ( i = 1; i < size; i++ ) { commBuff.iRecv(MPI_ANY_SOURCE, FETICommunicator :: NumberOfBoundaryDofManagersMsg); while ( !commBuff.testCompletion(source, tag) ) { ; } // unpack data commBuff.unpackInt(j); #ifdef __VERBOSE_PARALLEL OOFEM_LOG_DEBUG("[process rank %3d]: %-30s: Received data from partition %3d (received %d)\n", rank, "FETICommunicator :: setUpCommunicationMaps : received number of boundary dofMans", source, j); #endif numberOfPartitionBoundaryDofMans.at(source + 1) = j; commBuff.init(); } MPI_Barrier(MPI_COMM_WORLD); // determine the total number of boundary dof managers at master int nnodes = domain->giveNumberOfDofManagers(); j = 0; for ( i = 1; i <= nnodes; i++ ) { if ( domain->giveDofManager(i)->giveParallelMode() == DofManager_shared ) { j++; } } numberOfPartitionBoundaryDofMans.at(1) = j; // // receive list of bounadry dof managers with corresponding number of dofs from each partition // // resize the receive buffer to fit all messages maxRec = 0; for ( i = 0; i < size; i++ ) { if ( numberOfPartitionBoundaryDofMans.at(i + 1) > maxRec ) { maxRec = numberOfPartitionBoundaryDofMans.at(i + 1); } } commBuff.resize( 2 * maxRec * commBuff.givePackSize(MPI_INT, 1) ); // resize communication maps acordingly for ( i = 0; i < size; i++ ) { j = numberOfPartitionBoundaryDofMans.at(i + 1); commMaps [ i ] = new IntArray(j); } // add local master contribution first // loop over all dofmanager data received i = 0; for ( j = 1; j <= numberOfPartitionBoundaryDofMans.at(1); j++ ) { // fing next shared dofman while ( !( domain->giveDofManager(++i)->giveParallelMode() == DofManager_shared ) ) { ; } globaldofmannum = domain->giveDofManager(i)->giveGlobalNumber(); domain->giveDofManager(i)->giveCompleteLocationArray(locNum, dn); ndofs = 0; for ( l = 1; l <= locNum.giveSize(); l++ ) { if ( locNum.at(l) ) { ndofs++; } } // add corresponding entry to master map of boundary dof managers if ( ( localNumber = BoundaryDofManagerMap [ globaldofmannum ] ) == 0 ) { // no local counterpart exist // create it boundaryDofManList.push_back( FETIBoundaryDofManager(globaldofmannum, 0, ndofs) ); // remember the local number; actual position in vector is localNumber-1 localNumber = BoundaryDofManagerMap [ globaldofmannum ] = ( boundaryDofManList.size() ); boundaryDofManList.back().addPartition(0); } else { // update the corresponding record boundaryDofManList [ localNumber - 1 ].addPartition(0); if ( boundaryDofManList [ localNumber - 1 ].giveNumberOfDofs() != ndofs ) { _error("FETICommunicator :: setUpCommunicationMaps : ndofs size mismatch"); } } // remember communication map for particular partition commMaps [ 0 ]->at(j) = localNumber; } // // receive data from slave partitions // for ( i = 1; i < size; i++ ) { commBuff.iRecv(MPI_ANY_SOURCE, FETICommunicator :: BoundaryDofManagersRecMsg); while ( !commBuff.testCompletion(source, tag) ) { ; } // unpack data #ifdef __VERBOSE_PARALLEL OOFEM_LOG_DEBUG("[process rank %3d]: %-30s: Received data from partition %3d\n", rank, "FETICommunicator :: setUpCommunicationMaps : received boundary dofMans records", source); #endif // loop over all dofmanager data received for ( j = 1; j <= numberOfPartitionBoundaryDofMans.at(source + 1); j++ ) { commBuff.unpackInt(globaldofmannum); commBuff.unpackInt(ndofs); // add corresponding entry to master map of boundary dof managers if ( ( localNumber = BoundaryDofManagerMap [ globaldofmannum ] ) == 0 ) { // no local counterpart exist // create it boundaryDofManList.push_back( FETIBoundaryDofManager(globaldofmannum, 0, ndofs) ); // remember the local number; actual position in vector is localNumber-1 localNumber = BoundaryDofManagerMap [ globaldofmannum ] = ( boundaryDofManList.size() ); boundaryDofManList.back().addPartition(source); } else { // update the corresponding record boundaryDofManList [ localNumber - 1 ].addPartition(source); if ( boundaryDofManList [ localNumber - 1 ].giveNumberOfDofs() != ndofs ) { _error("FETICommunicator :: setUpCommunicationMaps : ndofs size mismatch"); } } // remember communication map for particular partition commMaps [ source ]->at(j) = localNumber; } commBuff.init(); } MPI_Barrier(MPI_COMM_WORLD); // // assign code numbers to boundary dofs // numberOfEquations = 0; numberOfBoundaryDofMans = boundaryDofManList.size(); for ( i = 1; i <= numberOfBoundaryDofMans; i++ ) { boundaryDofManList [ i - 1 ].setCodeNumbers(numberOfEquations); // updates numberOfEquations } // store the commMaps for ( i = 0; i < size; i++ ) { if ( i != 0 ) { this->giveProcessCommunicator(i)->setToSendArry(engngModel, * commMaps [ i ], 0); this->giveProcessCommunicator(i)->setToRecvArry(engngModel, * commMaps [ i ], 0); } else { masterCommMap = * commMaps [ i ]; } delete commMaps [ i ]; } delete commMaps; MPI_Barrier(MPI_COMM_WORLD); #ifdef __VERBOSE_PARALLEL VERBOSEPARALLEL_PRINT("FETICommunicator::setUpCommunicationMaps", "communication maps setup finished", rank); #endif }
void AbaqusUserMaterial :: giveRealStressVector(FloatArray &answer, MatResponseForm form, GaussPoint *gp, const FloatArray &reducedStrain, TimeStep *tStep) { AbaqusUserMaterialStatus *ms = static_cast< AbaqusUserMaterialStatus * >( this->giveStatus(gp) ); /* User-defined material name, left justified. Some internal material models are given names starting with * the “ABQ_” character string. To avoid conflict, you should not use “ABQ_” as the leading string for * CMNAME. */ //char cmname[80]; MaterialMode mMode = gp->giveMaterialMode(); // Sizes of the tensors. int ndi; int nshr; ///@todo Check how to deal with large deformations. ///@todo Check order of entries in the Voigt notation (which order does Abaqus use? convert to that). if ( mMode == _3dMat ) { ndi = 3; nshr = 3; } else if ( mMode == _PlaneStress ) { ndi = 2; nshr = 1; } else if ( mMode == _PlaneStrain ) { ndi = 3; nshr = 1; } /*else if ( mMode == _3dMat_F ) { * ndi = 3; * nshr = 6; * } */ else if ( mMode == _1dMat ) { ndi = 1; nshr = 0; } else { ndi = nshr = 0; OOFEM_ERROR2( "AbaqusUserMaterial :: giveRealStressVector : unsupported material mode (%s)", __MaterialModeToString(mMode) ); } int ntens = ndi + nshr; FloatArray stress(ntens); FloatArray strain = ms->giveStrainVector(); FloatArray strainIncrement; strainIncrement.beDifferenceOf(reducedStrain, strain); FloatArray state = ms->giveStateVector(); FloatMatrix jacobian(ntens, ntens); int numProperties = this->properties.giveSize(); // Temperature and increment double temp = 0.0, dtemp = 0.0; // Times and increment double dtime = tStep->giveTimeIncrement(); ///@todo Check this. I'm just guessing. Maybe intrinsic time instead? double time [ 2 ] = { tStep->giveTargetTime() - dtime, tStep->giveTargetTime() }; double pnewdt = 1.0; ///@todo Right default value? umat routines may change this (although we ignore it) /* Specific elastic strain energy, plastic dissipation, and “creep” dissipation, respectively. These are passed * in as the values at the start of the increment and should be updated to the corresponding specific energy * values at the end of the increment. They have no effect on the solution, except that they are used for * energy output. */ double sse, spd, scd; // Outputs only in a fully coupled thermal-stress analysis: double rpl = 0.0; // Volumetric heat generation per unit time at the end of the increment caused by mechanical working of the material. FloatArray ddsddt(ntens); // Variation of the stress increments with respect to the temperature. FloatArray drplde(ntens); // Variation of RPL with respect to the strain increments. double drpldt = 0.0; // Variation of RPL with respect to the temperature. /* An array containing the coordinates of this point. These are the current coordinates if geometric * nonlinearity is accounted for during the step (see “Procedures: overview,” Section 6.1.1); otherwise, * the array contains the original coordinates of the point */ FloatArray coords; gp->giveElement()->computeGlobalCoordinates( coords, * gp->giveCoordinates() ); ///@todo Large deformations? /* Rotation increment matrix. This matrix represents the increment of rigid body rotation of the basis * system in which the components of stress (STRESS) and strain (STRAN) are stored. It is provided so * that vector- or tensor-valued state variables can be rotated appropriately in this subroutine: stress and * strain components are already rotated by this amount before UMAT is called. This matrix is passed in * as a unit matrix for small-displacement analysis and for large-displacement analysis if the basis system * for the material point rotates with the material (as in a shell element or when a local orientation is used).*/ FloatMatrix drot(3, 3); drot.beUnitMatrix(); /* Characteristic element length, which is a typical length of a line across an element for a first-order * element; it is half of the same typical length for a second-order element. For beams and trusses it is a * characteristic length along the element axis. For membranes and shells it is a characteristic length in * the reference surface. For axisymmetric elements it is a characteristic length in the * plane only. * For cohesive elements it is equal to the constitutive thickness.*/ double celent = 0.0; /// @todo Include the characteristic element length /* Array containing the deformation gradient at the beginning of the increment. See the discussion * regarding the availability of the deformation gradient for various element types. */ FloatMatrix dfgrd0(3, 3); /* Array containing the deformation gradient at the end of the increment. The components of this array * are set to zero if nonlinear geometric effects are not included in the step definition associated with * this increment. See the discussion regarding the availability of the deformation gradient for various * element types. */ FloatMatrix dfgrd1(3, 3); int noel = gp->giveElement()->giveNumber(); // Element number. int npt = 0; // Integration point number. int layer = 0; // Layer number (for composite shells and layered solids).. int kspt = 0.0; // Section point number within the current layer. int kstep = 0; // Step number. int kinc = 0; // Increment number. ///@todo No idea about these parameters double predef; double dpred; OOFEM_LOG_DEBUG("AbaqusUserMaterial :: giveRealStressVector - Calling subroutine"); this->umat(stress.givePointer(), // STRESS state.givePointer(), // STATEV jacobian.givePointer(), // DDSDDE & sse, // SSE & spd, // SPD & scd, // SCD & rpl, // RPL ddsddt.givePointer(), // DDSDDT drplde.givePointer(), // DRPLDE & drpldt, // DRPLDT strain.givePointer(), // STRAN strainIncrement.givePointer(), // DSTRAN time, // TIME & dtime, // DTIME & temp, // TEMP & dtemp, // DTEMP & predef, // PREDEF & dpred, // DPRED this->cmname, // CMNAME & ndi, // NDI & nshr, // NSHR & ntens, // NTENS & numState, // NSTATV properties.givePointer(), // PROPS & numProperties, // NPROPS coords.givePointer(), // COORDS drot.givePointer(), // DROT & pnewdt, // PNEWDT & celent, // CELENT dfgrd0.givePointer(), // DFGRD0 dfgrd1.givePointer(), // DFGRD1 & noel, // NOEL & npt, // NPT & layer, // LAYER & kspt, // KSPT & kstep, // KSTEP & kinc); // KINC ms->letTempStrainVectorBe(reducedStrain); ms->letTempStressVectorBe(stress); ms->letTempStateVectorBe(state); ms->letTempTangentBe(jacobian); answer = stress; OOFEM_LOG_DEBUG("AbaqusUserMaterial :: giveRealStressVector - Calling subroutine was successful"); }
NM_Status SpoolesSolver :: solve(SparseMtrx *A, FloatArray *b, FloatArray *x) { int errorValue, mtxType, symmetryflag; int seed = 30145, pivotingflag = 0; int *oldToNew, *newToOld; double droptol = 0.0, tau = 1.e300; double cpus [ 10 ]; int stats [ 20 ]; ChvManager *chvmanager; Chv *rootchv; InpMtx *mtxA; DenseMtx *mtxY, *mtxX; // first check whether Lhs is defined if ( !A ) { _error("solveYourselfAt: unknown Lhs"); } // and whether Rhs if ( !b ) { _error("solveYourselfAt: unknown Rhs"); } // and whether previous Solution exist if ( !x ) { _error("solveYourselfAt: unknown solution array"); } if ( x->giveSize() != b->giveSize() ) { _error("solveYourselfAt: size mismatch"); } Timer timer; timer.startTimer(); if ( A->giveType() != SMT_SpoolesMtrx ) { _error("solveYourselfAt: SpoolesSparseMtrx Expected"); } mtxA = ( ( SpoolesSparseMtrx * ) A )->giveInpMtrx(); mtxType = ( ( SpoolesSparseMtrx * ) A )->giveValueType(); symmetryflag = ( ( SpoolesSparseMtrx * ) A )->giveSymmetryFlag(); int i; int neqns = A->giveNumberOfRows(); int nrhs = 1; /* convert right-hand side to DenseMtx */ mtxY = DenseMtx_new(); DenseMtx_init(mtxY, mtxType, 0, 0, neqns, nrhs, 1, neqns); DenseMtx_zero(mtxY); for ( i = 0; i < neqns; i++ ) { DenseMtx_setRealEntry( mtxY, i, 0, b->at(i + 1) ); } if ( ( Lhs != A ) || ( this->lhsVersion != A->giveVersion() ) ) { // // lhs has been changed -> new factorization // Lhs = A; this->lhsVersion = A->giveVersion(); if ( frontmtx ) { FrontMtx_free(frontmtx); } if ( newToOldIV ) { IV_free(newToOldIV); } if ( oldToNewIV ) { IV_free(oldToNewIV); } if ( frontETree ) { ETree_free(frontETree); } if ( symbfacIVL ) { IVL_free(symbfacIVL); } if ( mtxmanager ) { SubMtxManager_free(mtxmanager); } if ( graph ) { Graph_free(graph); } /* * ------------------------------------------------- * STEP 3 : find a low-fill ordering * (1) create the Graph object * (2) order the graph using multiple minimum degree * ------------------------------------------------- */ int nedges; graph = Graph_new(); adjIVL = InpMtx_fullAdjacency(mtxA); nedges = IVL_tsize(adjIVL); Graph_init2(graph, 0, neqns, 0, nedges, neqns, nedges, adjIVL, NULL, NULL); if ( msglvl > 2 ) { fprintf(msgFile, "\n\n graph of the input matrix"); Graph_writeForHumanEye(graph, msgFile); fflush(msgFile); } frontETree = orderViaMMD(graph, seed, msglvl, msgFile); if ( msglvl > 0 ) { fprintf(msgFile, "\n\n front tree from ordering"); ETree_writeForHumanEye(frontETree, msgFile); fflush(msgFile); } /* * ---------------------------------------------------- * STEP 4: get the permutation, permute the front tree, * permute the matrix and right hand side, and * get the symbolic factorization * ---------------------------------------------------- */ oldToNewIV = ETree_oldToNewVtxPerm(frontETree); oldToNew = IV_entries(oldToNewIV); newToOldIV = ETree_newToOldVtxPerm(frontETree); newToOld = IV_entries(newToOldIV); ETree_permuteVertices(frontETree, oldToNewIV); InpMtx_permute(mtxA, oldToNew, oldToNew); if ( symmetryflag == SPOOLES_SYMMETRIC || symmetryflag == SPOOLES_HERMITIAN ) { InpMtx_mapToUpperTriangle(mtxA); } InpMtx_changeCoordType(mtxA, INPMTX_BY_CHEVRONS); InpMtx_changeStorageMode(mtxA, INPMTX_BY_VECTORS); symbfacIVL = SymbFac_initFromInpMtx(frontETree, mtxA); if ( msglvl > 2 ) { fprintf(msgFile, "\n\n old-to-new permutation vector"); IV_writeForHumanEye(oldToNewIV, msgFile); fprintf(msgFile, "\n\n new-to-old permutation vector"); IV_writeForHumanEye(newToOldIV, msgFile); fprintf(msgFile, "\n\n front tree after permutation"); ETree_writeForHumanEye(frontETree, msgFile); fprintf(msgFile, "\n\n input matrix after permutation"); InpMtx_writeForHumanEye(mtxA, msgFile); fprintf(msgFile, "\n\n symbolic factorization"); IVL_writeForHumanEye(symbfacIVL, msgFile); fflush(msgFile); } Tree_writeToFile(frontETree->tree, (char*)"haggar.treef"); /*--------------------------------------------------------------------*/ /* * ------------------------------------------ * STEP 5: initialize the front matrix object * ------------------------------------------ */ frontmtx = FrontMtx_new(); mtxmanager = SubMtxManager_new(); SubMtxManager_init(mtxmanager, NO_LOCK, 0); FrontMtx_init(frontmtx, frontETree, symbfacIVL, mtxType, symmetryflag, FRONTMTX_DENSE_FRONTS, pivotingflag, NO_LOCK, 0, NULL, mtxmanager, msglvl, msgFile); /*--------------------------------------------------------------------*/ /* * ----------------------------------------- * STEP 6: compute the numeric factorization * ----------------------------------------- */ chvmanager = ChvManager_new(); ChvManager_init(chvmanager, NO_LOCK, 1); DVfill(10, cpus, 0.0); IVfill(20, stats, 0); rootchv = FrontMtx_factorInpMtx(frontmtx, mtxA, tau, droptol, chvmanager, & errorValue, cpus, stats, msglvl, msgFile); ChvManager_free(chvmanager); if ( msglvl > 0 ) { fprintf(msgFile, "\n\n factor matrix"); FrontMtx_writeForHumanEye(frontmtx, msgFile); fflush(msgFile); } if ( rootchv != NULL ) { fprintf(msgFile, "\n\n matrix found to be singular\n"); exit(-1); } if ( errorValue >= 0 ) { fprintf(msgFile, "\n\n error encountered at front %d", errorValue); exit(-1); } /*--------------------------------------------------------------------*/ /* * -------------------------------------- * STEP 7: post-process the factorization * -------------------------------------- */ FrontMtx_postProcess(frontmtx, msglvl, msgFile); if ( msglvl > 2 ) { fprintf(msgFile, "\n\n factor matrix after post-processing"); FrontMtx_writeForHumanEye(frontmtx, msgFile); fflush(msgFile); } /*--------------------------------------------------------------------*/ } /* * ---------------------------------------------------- * STEP 4: permute the right hand side * ---------------------------------------------------- */ DenseMtx_permuteRows(mtxY, oldToNewIV); if ( msglvl > 2 ) { fprintf(msgFile, "\n\n right hand side matrix after permutation"); DenseMtx_writeForHumanEye(mtxY, msgFile); } /* * ------------------------------- * STEP 8: solve the linear system * ------------------------------- */ mtxX = DenseMtx_new(); DenseMtx_init(mtxX, mtxType, 0, 0, neqns, nrhs, 1, neqns); DenseMtx_zero(mtxX); FrontMtx_solve(frontmtx, mtxX, mtxY, mtxmanager, cpus, msglvl, msgFile); if ( msglvl > 2 ) { fprintf(msgFile, "\n\n solution matrix in new ordering"); DenseMtx_writeForHumanEye(mtxX, msgFile); fflush(msgFile); } /*--------------------------------------------------------------------*/ /* * ------------------------------------------------------- * STEP 9: permute the solution into the original ordering * ------------------------------------------------------- */ DenseMtx_permuteRows(mtxX, newToOldIV); if ( msglvl > 0 ) { fprintf(msgFile, "\n\n solution matrix in original ordering"); DenseMtx_writeForHumanEye(mtxX, msgFile); fflush(msgFile); } // DenseMtx_writeForMatlab(mtxX, "x", msgFile) ; /*--------------------------------------------------------------------*/ /* fetch data to oofem vectors */ double *xptr = x->givePointer(); for ( i = 0; i < neqns; i++ ) { DenseMtx_realEntry(mtxX, i, 0, xptr + i); // printf ("x(%d) = %e\n", i+1, *(xptr+i)); } // DenseMtx_copyRowIntoVector(mtxX, 0, x->givePointer()); timer.stopTimer(); OOFEM_LOG_DEBUG( "SpoolesSolver info: user time consumed by solution: %.2fs\n", timer.getUtime() ); /* * ----------- * free memory * ----------- */ DenseMtx_free(mtxX); DenseMtx_free(mtxY); /*--------------------------------------------------------------------*/ return ( 1 ); }
void FreeWarping :: 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_DEBUG("Assembling stiffness matrix\n"); #endif // // first step assemble stiffness Matrix // stiffnessMatrix = classFactory.createSparseMtrx(sparseMtrxType); if ( stiffnessMatrix == NULL ) { OOFEM_ERROR("sparse matrix creation failed"); } stiffnessMatrix->buildInternalStructure( this, 1, EModelDefaultEquationNumbering() ); this->assemble( *stiffnessMatrix, tStep, TangentAssembler(TangentStiffness), EModelDefaultEquationNumbering(), this->giveDomain(1) ); initFlag = 0; } #ifdef VERBOSE OOFEM_LOG_DEBUG("Assembling load\n"); #endif // // allocate space for displacementVector // displacementVector.resize( this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ) ); displacementVector.zero(); // // assembling the load vector // loadVector.resize( this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ) ); loadVector.zero(); this->assembleVector( loadVector, tStep, ExternalForceAssembler(), VM_Total, EModelDefaultEquationNumbering(), this->giveDomain(1) ); // // internal forces (from Dirichlet b.c's, or thermal expansion, etc.) // // no such forces exist for the free warping problem /* FloatArray internalForces( this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ) ); internalForces.zero(); this->assembleVector( internalForces, tStep, InternalForceAssembler(), VM_Total, EModelDefaultEquationNumbering(), this->giveDomain(1) ); loadVector.subtract(internalForces); */ this->updateSharedDofManagers(loadVector, EModelDefaultEquationNumbering(), ReactionExchangeTag); // // set-up numerical model // this->giveNumericalMethod( this->giveMetaStep( tStep->giveMetaStepNumber() ) ); // // call numerical model to solve arose problem // #ifdef VERBOSE OOFEM_LOG_INFO("\n\nSolving ...\n\n"); #endif NM_Status s = nMethod->solve(*stiffnessMatrix, loadVector, displacementVector); if ( !( s & NM_Success ) ) { OOFEM_ERROR("No success in solving system."); } tStep->incrementStateCounter(); // update solution state counter }
int DynCompCol :: buildInternalStructure(EngngModel *eModel, int di, const UnknownNumberingScheme &s) { /* * int neq = eModel -> giveNumberOfDomainEquations (di); * **#ifndef DynCompCol_USE_STL_SETS * IntArray loc; * Domain* domain = eModel->giveDomain(di); * int nelem = domain -> giveNumberOfElements() ; * int i,ii,j,jj,n, indx; * Element* elem; * IntArray colItems(neq); * // allocation map * char* map = new char[neq*neq]; * if (map == NULL) { * printf ("CompCol::buildInternalStructure - map creation failed"); * exit (1); * } * * for (i=0; i<neq*neq; i++) * map[i]=0; * * * for (n=1 ; n<=nelem ; n++) { * elem = domain -> giveElement(n); * elem -> giveLocationArray (loc) ; * * for (i=1 ; i <= loc.giveSize() ; i++) { * if ((ii = loc.at(i))) { * for (j=1; j <= loc.giveSize() ; j++) { * if ((jj=loc.at(j))) * if (map[(ii-1)*neq+jj-1] == 0) { * map[(ii-1)*neq+jj-1] = 1; * colItems.at(ii) ++; * } * } * } * } * } * * if (rowind_) { * for (i=0; i< nColumns; i++) delete this->rowind_[i]; * delete this->rowind_; * } * rowind_ = (IntArray**) new (IntArray*)[neq]; * for (j=0; j<neq; j++) rowind_[j] = new IntArray(colItems(j)); * * indx = 1; * for (j=0; j<neq; j++) { // column loop * indx = 1; * for (i=0; i<neq; i++) { // row loop * if (map[i*neq+j]) { * rowind_[j]->at(indx) = i; * indx++; * } * } * } * * // delete map * delete (map); * * // allocate value array * if (columns_) { * for (i=0; i< nColumns; i++) delete this->columns_[i]; * delete this->columns_; * } * columns_= (FloatArray**) new (FloatArray*)[neq]; * int nz_ = 0; * for (j=0; j<neq; j++) { * columns_[j] = new FloatArray (colItems(j)); * nz_ += colItems(j); * } * * printf ("\nDynCompCol info: neq is %d, nelem is %d\n",neq,nz_); **#else * int i,j; * if (columns) { * for (i=0; i< nColumns; i++) delete this->columns[i]; * delete this->columns; * } * columns= new std::map<int, double>*[neq]; * for (j=0; j<neq; j++) { * columns[j] = new std::map<int, double>; * } * **#endif * * nColumns = nRows = neq; * // increment version * this->version++; * * return true; */ int neq = eModel->giveNumberOfDomainEquations(di, s); #ifndef DynCompCol_USE_STL_SETS IntArray loc; Domain *domain = eModel->giveDomain(di); int nelem = domain->giveNumberOfElements(); int i, ii, j, jj, n; Element *elem; nColumns = nRows = neq; if ( rowind_ ) { for ( i = 0; i < nColumns; i++ ) { delete this->rowind_ [ i ]; } delete this->rowind_; } rowind_ = ( IntArray ** ) new IntArray * [ neq ]; for ( j = 0; j < neq; j++ ) { rowind_ [ j ] = new IntArray(); } // allocate value array if ( columns_ ) { for ( i = 0; i < nColumns; i++ ) { delete this->columns_ [ i ]; } delete this->columns_; } columns_ = ( FloatArray ** ) new FloatArray * [ neq ]; for ( j = 0; j < neq; j++ ) { columns_ [ j ] = new FloatArray(); } for ( n = 1; n <= nelem; n++ ) { elem = domain->giveElement(n); elem->giveLocationArray(loc, s); for ( i = 1; i <= loc.giveSize(); i++ ) { if ( ( ii = loc.at(i) ) ) { for ( j = 1; j <= loc.giveSize(); j++ ) { if ( ( jj = loc.at(j) ) ) { this->insertRowInColumn(ii - 1, jj - 1); } } } } } // loop over active boundary conditions int nbc = domain->giveNumberOfBoundaryConditions(); std :: vector< IntArray >r_locs; std :: vector< IntArray >c_locs; for ( int i = 1; i <= nbc; ++i ) { ActiveBoundaryCondition *bc = dynamic_cast< ActiveBoundaryCondition * >( domain->giveBc(i) ); if ( bc != NULL ) { bc->giveLocationArrays(r_locs, c_locs, UnknownCharType, s, s); for ( std :: size_t k = 0; k < r_locs.size(); k++ ) { IntArray &krloc = r_locs [ k ]; IntArray &kcloc = c_locs [ k ]; for ( int i = 1; i <= krloc.giveSize(); i++ ) { if ( ( ii = krloc.at(i) ) ) { for ( int j = 1; j <= kcloc.giveSize(); j++ ) { if ( ( jj = kcloc.at(j) ) ) { this->insertRowInColumn(jj - 1, ii - 1); } } } } } } } int nz_ = 0; for ( j = 0; j < neq; j++ ) { nz_ += this->rowind_ [ j ]->giveSize(); } OOFEM_LOG_DEBUG("DynCompCol info: neq is %d, nelem is %d\n", neq, nz_); #else nColumns = nRows = neq; columns.resize( neq ); for ( auto &col: columns ) { col.clear(); } #endif // increment version this->version++; return true; }
int DSSMatrix :: buildInternalStructure(EngngModel *eModel, int di, const UnknownNumberingScheme &s) { IntArray loc; Domain *domain = eModel->giveDomain(di); int neq = eModel->giveNumberOfDomainEquations(di, s); unsigned long indx; // allocation map std :: vector< std :: set< int > >columns(neq); unsigned long nz_ = 0; for ( auto &elem : domain->giveElements() ) { elem->giveLocationArray(loc, s); for ( int ii : loc ) { if ( ii > 0 ) { for ( int jj : loc ) { if ( jj > 0 ) { columns [ jj - 1 ].insert(ii - 1); } } } } } // loop over active boundary conditions std::vector<IntArray> r_locs; std::vector<IntArray> c_locs; for ( auto &gbc : domain->giveBcs() ) { ActiveBoundaryCondition *bc = dynamic_cast< ActiveBoundaryCondition * >( gbc.get() ); if ( bc != NULL ) { bc->giveLocationArrays(r_locs, c_locs, UnknownCharType, s, s); for (std::size_t k = 0; k < r_locs.size(); k++) { IntArray &krloc = r_locs[k]; IntArray &kcloc = c_locs[k]; for ( int ii : krloc ) { if ( ii > 0 ) { for ( int jj : kcloc ) { if ( jj > 0 ) { columns [ jj - 1 ].insert(ii - 1); } } } } } } } for ( int i = 0; i < neq; i++ ) { nz_ += columns [ i ].size(); } unsigned long *rowind_ = new unsigned long [ nz_ ]; unsigned long *colptr_ = new unsigned long [ neq + 1 ]; if ( ( rowind_ == NULL ) || ( colptr_ == NULL ) ) { OOFEM_ERROR("free store exhausted, exiting"); } indx = 0; for ( int j = 0; j < neq; j++ ) { // column loop colptr_ [ j ] = indx; for ( auto &val : columns [ j ] ) { // row loop rowind_ [ indx++ ] = val; } } colptr_ [ neq ] = indx; _sm.reset( new SparseMatrixF(neq, NULL, rowind_, colptr_, 0, 0, true) ); if ( !_sm ) { OOFEM_FATAL("free store exhausted, exiting"); } /* * Assemble block to equation mapping information */ bool _succ = true; int _ndofs, _neq, ndofmans = domain->giveNumberOfDofManagers(); int ndofmansbc = 0; ///@todo This still misses element internal dofs. // count number of internal dofmans on active bc for ( auto &bc : domain->giveBcs() ) { ndofmansbc += bc->giveNumberOfInternalDofManagers(); } int bsize = 0; if ( ndofmans > 0 ) { bsize = domain->giveDofManager(1)->giveNumberOfDofs(); } long *mcn = new long [ (ndofmans+ndofmansbc) * bsize ]; long _c = 0; if ( mcn == NULL ) { OOFEM_FATAL("free store exhausted, exiting"); } for ( auto &dman : domain->giveDofManagers() ) { _ndofs = dman->giveNumberOfDofs(); if ( _ndofs > bsize ) { _succ = false; break; } for ( Dof *dof: *dman ) { if ( dof->isPrimaryDof() ) { _neq = dof->giveEquationNumber(s); if ( _neq > 0 ) { mcn [ _c++ ] = _neq - 1; } else { mcn [ _c++ ] = -1; // no corresponding row in sparse mtrx structure } } else { mcn [ _c++ ] = -1; // no corresponding row in sparse mtrx structure } } for ( int i = _ndofs + 1; i <= bsize; i++ ) { mcn [ _c++ ] = -1; // no corresponding row in sparse mtrx structure } } // loop over internal dofmans of active bc for ( auto &bc : domain->giveBcs() ) { int ndman = bc->giveNumberOfInternalDofManagers(); for (int idman = 1; idman <= ndman; idman ++) { DofManager *dman = bc->giveInternalDofManager(idman); _ndofs = dman->giveNumberOfDofs(); if ( _ndofs > bsize ) { _succ = false; break; } for ( Dof *dof: *dman ) { if ( dof->isPrimaryDof() ) { _neq = dof->giveEquationNumber(s); if ( _neq > 0 ) { mcn [ _c++ ] = _neq - 1; } else { mcn [ _c++ ] = -1; // no corresponding row in sparse mtrx structure } } } for ( int i = _ndofs + 1; i <= bsize; i++ ) { mcn [ _c++ ] = -1; // no corresponding row in sparse mtrx structure } } } if ( _succ ) { _dss->SetMatrixPattern(_sm.get(), bsize); _dss->LoadMCN(ndofmans+ndofmansbc, bsize, mcn); } else { OOFEM_LOG_INFO("DSSMatrix: using assumed block structure"); _dss->SetMatrixPattern(_sm.get(), bsize); } _dss->PreFactorize(); // zero matrix, put unity on diagonal with supported dofs _dss->LoadZeros(); delete[] mcn; OOFEM_LOG_DEBUG("DSSMatrix info: neq is %d, bsize is %d\n", neq, nz_); // increment version this->version++; return true; }
NM_Status DynamicRelaxationSolver :: solve(SparseMtrx &k, FloatArray &R, FloatArray *R0, FloatArray *iR, FloatArray &X, FloatArray &dX, FloatArray &F, const FloatArray &internalForcesEBENorm, double &l, referenceLoadInputModeType rlm, int &nite, TimeStep *tStep) { // residual, iteration increment of solution, total external force FloatArray rhs, ddX, RT, X_0, X_n, X_n1, M; double RRT; int neq = X.giveSize(); NM_Status status = NM_None; bool converged, errorOutOfRangeFlag; ParallelContext *parallel_context = engngModel->giveParallelContext( this->domain->giveNumber() ); if ( engngModel->giveProblemScale() == macroScale ) { OOFEM_LOG_INFO("DRSolver: Iteration"); if ( rtolf.at(1) > 0.0 ) { OOFEM_LOG_INFO(" ForceError"); } if ( rtold.at(1) > 0.0 ) { OOFEM_LOG_INFO(" DisplError"); } OOFEM_LOG_INFO("\n----------------------------------------------------------------------------\n"); } // compute total load R = R+R0 l = 1.0; RT = R; if ( R0 ) { RT.add(* R0); } RRT = parallel_context->localNorm(RT); RRT *= RRT; ddX.resize(neq); ddX.zero(); X_0 = X; X_n = X_0; X_n1 = X_0; // Compute the mass "matrix" (lumped, only storing the diagonal) M.resize(neq); M.zero(); engngModel->assembleVector(M, tStep, LumpedMassVectorAssembler(), VM_Total, EModelDefaultEquationNumbering(), domain); double Le = -1.0; for ( auto &elem : domain->giveElements() ) { double size = elem->computeMeanSize(); if ( Le < 0 || Le >= size ) { Le = size; } } for ( nite = 0; ; ++nite ) { // Compute the residual engngModel->updateComponent(tStep, InternalRhs, domain); rhs.beDifferenceOf(RT, F); converged = this->checkConvergence(RT, F, rhs, ddX, X, RRT, internalForcesEBENorm, nite, errorOutOfRangeFlag); if ( errorOutOfRangeFlag ) { status = NM_NoSuccess; dX.zero(); X.zero(); OOFEM_WARNING("Divergence reached after %d iterations", nite); break; } else if ( converged && ( nite >= minIterations ) ) { status |= NM_Success; break; } else if ( nite >= nsmax ) { OOFEM_LOG_DEBUG("Maximum number of iterations reached\n"); break; } double density = 1.; double lambda = 210e9; double mu = 210e9; double c = sqrt((lambda + 2*mu) / density); double dt = 0.25 * Le / c; double alpha = 0.1 / dt; printf("dt = %e\n", dt); for ( int j = 0; j < neq; ++j ) { //M * x'' + C*x' * dt = rhs * dt*dt X[j] = rhs[j] * dt * dt / M[j] - ( -2*X_n1[j] + X_n[j] ) - alpha * (X_n1[j] - X_n[j]) * dt; } X_n = X_n1; X_n1 = X; dX.beDifferenceOf(X, X_0); tStep->incrementStateCounter(); // update solution state counter tStep->incrementSubStepNumber(); } return status; }
NM_Status GJacobi :: solve(FloatMatrix &a, FloatMatrix &b, FloatArray &eigv, FloatMatrix &x) // // this function solve the generalized eigenproblem using the Generalized // jacobi iteration // // { int nsweep, nr; double eps, eptola, eptolb, akk, ajj, ab, check, sqch, d1, d2, den, ca, cg, ak, bk, xj, xk; double aj, bj; int jm1, kp1, km1, jp1; if ( a.giveNumberOfRows() != b.giveNumberOfRows() || !a.isSquare() || !b.isSquare() ) { OOFEM_ERROR("A matrix, B mtrix -> size mismatch"); } int n = a.giveNumberOfRows(); eigv.resize(n); x.resize(n, n); // // Create temporary arrays // FloatArray d(n); // // Initialize EigenValue and EigenVector Matrices // for ( int i = 1; i <= n; i++ ) { // if((a.at(i,i) <= 0. ) && (b.at(i,i) <= 0.)) // OOFEM_ERROR("Matrices are not positive definite"); d.at(i) = a.at(i, i) / b.at(i, i); eigv.at(i) = d.at(i); } x.beUnitMatrix(); if ( n == 1 ) { return NM_Success; } // // Initialize sweep counter and begin iteration // nsweep = 0; nr = n - 1; do { nsweep++; # ifdef DETAILED_REPORT OOFEM_LOG_DEBUG("*GJacobi*: sweep number %4d\n", nsweep); #endif // // check if present off-diagonal element is large enough to require zeroing // eps = pow(0.01, ( double ) nsweep); eps *= eps; for ( int j = 1; j <= nr; j++ ) { int jj = j + 1; for ( int k = jj; k <= n; k++ ) { eptola = ( a.at(j, k) * a.at(j, k) ) / ( a.at(j, j) * a.at(k, k) ); eptolb = ( b.at(j, k) * b.at(j, k) ) / ( b.at(j, j) * b.at(k, k) ); if ( ( eptola < eps ) && ( eptolb < eps ) ) { continue; } // // if zeroing is required, calculate the rotation matrix elements ca and cg // akk = a.at(k, k) * b.at(j, k) - b.at(k, k) * a.at(j, k); ajj = a.at(j, j) * b.at(j, k) - b.at(j, j) * a.at(j, k); ab = a.at(j, j) * b.at(k, k) - a.at(k, k) * b.at(j, j); check = ( ab * ab + 4.0 * akk * ajj ) / 4.0; if ( fabs(check) < GJacobi_ZERO_CHECK_TOL ) { check = fabs(check); } else if ( check < 0.0 ) { OOFEM_ERROR("Matrices are not positive definite"); } sqch = sqrt(check); d1 = ab / 2. + sqch; d2 = ab / 2. - sqch; den = d1; if ( fabs(d2) > fabs(d1) ) { den = d2; } if ( den != 0.0 ) { // strange ! ca = akk / den; cg = -ajj / den; } else { ca = 0.0; cg = -a.at(j, k) / a.at(k, k); } // // perform the generalized rotation to zero // if ( ( n - 2 ) != 0 ) { jp1 = j + 1; jm1 = j - 1; kp1 = k + 1; km1 = k - 1; if ( ( jm1 - 1 ) >= 0 ) { for ( int i = 1; i <= jm1; i++ ) { aj = a.at(i, j); bj = b.at(i, j); ak = a.at(i, k); bk = b.at(i, k); a.at(i, j) = aj + cg * ak; b.at(i, j) = bj + cg * bk; a.at(i, k) = ak + ca * aj; b.at(i, k) = bk + ca * bj; } } if ( ( kp1 - n ) <= 0 ) { for ( int i = kp1; i <= n; i++ ) { // label 140 aj = a.at(j, i); bj = b.at(j, i); ak = a.at(k, i); bk = b.at(k, i); a.at(j, i) = aj + cg * ak; b.at(j, i) = bj + cg * bk; a.at(k, i) = ak + ca * aj; b.at(k, i) = bk + ca * bj; } } if ( ( jp1 - km1 ) <= 0 ) { // label 160 for ( int i = jp1; i <= km1; i++ ) { aj = a.at(j, i); bj = b.at(j, i); ak = a.at(i, k); bk = b.at(i, k); a.at(j, i) = aj + cg * ak; b.at(j, i) = bj + cg * bk; a.at(i, k) = ak + ca * aj; b.at(i, k) = bk + ca * bj; } } } // label 190 ak = a.at(k, k); bk = b.at(k, k); a.at(k, k) = ak + 2.0 *ca *a.at(j, k) + ca *ca *a.at(j, j); b.at(k, k) = bk + 2.0 *ca *b.at(j, k) + ca *ca *b.at(j, j); a.at(j, j) = a.at(j, j) + 2.0 *cg *a.at(j, k) + cg * cg * ak; b.at(j, j) = b.at(j, j) + 2.0 *cg *b.at(j, k) + cg * cg * bk; a.at(j, k) = 0.0; b.at(j, k) = 0.0; // // update the eigenvector matrix after each rotation // for ( int i = 1; i <= n; i++ ) { xj = x.at(i, j); xk = x.at(i, k); x.at(i, j) = xj + cg * xk; x.at(i, k) = xk + ca * xj; } // label 200 } } // label 210 // // update the eigenvalues after each sweep // #ifdef DETAILED_REPORT OOFEM_LOG_DEBUG("GJacobi: a,b after sweep\n"); a.printYourself(); b.printYourself(); #endif for ( int i = 1; i <= n; i++ ) { // in original uncommented // if ((a.at(i,i) <= 0.) || (b.at(i,i) <= 0.)) // error ("solveYourselfAt: Matrices are not positive definite"); eigv.at(i) = a.at(i, i) / b.at(i, i); } // label 220 # ifdef DETAILED_REPORT OOFEM_LOG_DEBUG("GJacobi: current eigenvalues are:\n"); eigv.printYourself(); OOFEM_LOG_DEBUG("GJacobi: current eigenvectors are:\n"); x.printYourself(); # endif // // check for convergence // for ( int i = 1; i <= n; i++ ) { // label 230 double tol = rtol * d.at(i); double dif = ( eigv.at(i) - d.at(i) ); if ( fabs(dif) > tol ) { goto label280; } } // label 240 // // check all off-diagonal elements to see if another sweep is required // eps = rtol * rtol; for ( int j = 1; j <= nr; j++ ) { int jj = j + 1; for ( int k = jj; k <= n; k++ ) { double epsa = ( a.at(j, k) * a.at(j, k) ) / ( a.at(j, j) * a.at(k, k) ); double epsb = ( b.at(j, k) * b.at(j, k) ) / ( b.at(j, j) * b.at(k, k) ); if ( ( epsa < eps ) && ( epsb < eps ) ) { continue; } goto label280; } } // label 250 // // fill out bottom triangle of resultant matrices and scale eigenvectors // break; // goto label255 ; // // update d matrix and start new sweep, if allowed // label280: d = eigv; } while ( nsweep < nsmax ); // label255: for ( int i = 1; i <= n; i++ ) { for ( int j = 1; j <= n; j++ ) { a.at(j, i) = a.at(i, j); b.at(j, i) = b.at(i, j); } // label 260 } for ( int j = 1; j <= n; j++ ) { double bb = sqrt( fabs( b.at(j, j) ) ); for ( int k = 1; k <= n; k++ ) { x.at(k, j) /= bb; } } // label 270 return NM_Success; }
void NonLinearStatic :: proceedStep(int di, TimeStep *tStep) { // // creates system of governing eq's and solves them at given time step // // first assemble problem at current time step // if ( initFlag ) { // // first step create space for stiffness Matrix // if ( !stiffnessMatrix ) { stiffnessMatrix.reset( classFactory.createSparseMtrx(sparseMtrxType) ); } if ( !stiffnessMatrix ) { OOFEM_ERROR("sparse matrix creation failed"); } if ( nonlocalStiffnessFlag ) { if ( !stiffnessMatrix->isAsymmetric() ) { OOFEM_ERROR("stiffnessMatrix does not support asymmetric storage"); } } stiffnessMatrix->buildInternalStructure( this, di, EModelDefaultEquationNumbering() ); } #if 0 if ( ( mstep->giveFirstStepNumber() == tStep->giveNumber() ) ) { #ifdef VERBOSE OOFEM_LOG_INFO("Resetting load level\n"); #endif if ( mstepCumulateLoadLevelFlag ) { cumulatedLoadLevel += loadLevel; } else { cumulatedLoadLevel = 0.0; } this->loadLevel = 0.0; } #endif if ( loadInitFlag || controlMode == nls_directControl ) { #ifdef VERBOSE OOFEM_LOG_DEBUG("Assembling reference load\n"); #endif // // assemble the incremental reference load vector // this->assembleIncrementalReferenceLoadVectors(incrementalLoadVector, incrementalLoadVectorOfPrescribed, refLoadInputMode, this->giveDomain(di), tStep); loadInitFlag = 0; } if ( tStep->giveNumber() == 1 ) { int neq = this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ); totalDisplacement.resize(neq); totalDisplacement.zero(); incrementOfDisplacement.resize(neq); incrementOfDisplacement.zero(); } // // -> BEGINNING OF LOAD (OR DISPLACEMENT) STEP <- // // // set-up numerical model // this->giveNumericalMethod( this->giveMetaStep( tStep->giveMetaStepNumber() ) ); // // call numerical model to solve arise problem // #ifdef VERBOSE OOFEM_LOG_RELEVANT( "\n\nSolving [step number %5d.%d, time = %e]\n\n", tStep->giveNumber(), tStep->giveVersion(), tStep->giveIntrinsicTime() ); #endif if ( this->initialGuessType == IG_Tangent ) { #ifdef VERBOSE OOFEM_LOG_RELEVANT("Computing initial guess\n"); #endif FloatArray extrapolatedForces; this->assembleExtrapolatedForces( extrapolatedForces, tStep, TangentStiffnessMatrix, this->giveDomain(di) ); extrapolatedForces.negated(); this->updateComponent( tStep, NonLinearLhs, this->giveDomain(di) ); SparseLinearSystemNM *linSolver = nMethod->giveLinearSolver(); OOFEM_LOG_RELEVANT("solving for increment\n"); linSolver->solve(*stiffnessMatrix, extrapolatedForces, incrementOfDisplacement); OOFEM_LOG_RELEVANT("initial guess found\n"); totalDisplacement.add(incrementOfDisplacement); } else if ( this->initialGuessType != IG_None ) { OOFEM_ERROR("Initial guess type: %d not supported", initialGuessType); } else { incrementOfDisplacement.zero(); } //totalDisplacement.printYourself(); if ( initialLoadVector.isNotEmpty() ) { numMetStatus = nMethod->solve(*stiffnessMatrix, incrementalLoadVector, & initialLoadVector, totalDisplacement, incrementOfDisplacement, internalForces, internalForcesEBENorm, loadLevel, refLoadInputMode, currentIterations, tStep); } else { numMetStatus = nMethod->solve(*stiffnessMatrix, incrementalLoadVector, NULL, totalDisplacement, incrementOfDisplacement, internalForces, internalForcesEBENorm, loadLevel, refLoadInputMode, currentIterations, tStep); } ///@todo Martin: ta bort!!! //this->updateComponent(tStep, NonLinearLhs, this->giveDomain(di)); ///@todo Use temporary variables. updateYourself() should set the final values, while proceedStep should be callable multiple times for each step (if necessary). / Mikael OOFEM_LOG_RELEVANT("Equilibrium reached at load level = %f in %d iterations\n", cumulatedLoadLevel + loadLevel, currentIterations); prevStepLength = currentStepLength; }
SparseMtrx *Skyline :: factorized() { // Returns the receiver in U(transp).D.U Crout factorization form. int aci, aci1, acj, acj1, ack, ack1, ac, acs, acri, acrk, n; double s, g; #ifdef TIME_REPORT Timer timer; timer.startTimer(); #endif /************************/ /* matrix elimination */ /************************/ if ( isFactorized ) { return this; } n = this->giveNumberOfRows(); // report skyline statistics OOFEM_LOG_DEBUG("Skyline info: neq is %d, nwk is %d\n", n, this->nwk); for ( int k = 2; k <= n; k++ ) { /* smycka pres sloupce matice */ ack = adr.at(k); ack1 = adr.at(k + 1); acrk = k - ( ack1 - ack ) + 1; for ( int i = acrk + 1; i < k; i++ ) { /* smycka pres prvky jednoho sloupce matice */ aci = adr.at(i); aci1 = adr.at(i + 1); acri = i - ( aci1 - aci ) + 1; if ( acri < acrk ) { ac = acrk; } else { ac = acri; } acj = k - ac + ack; acj1 = k - i + ack; acs = i - ac + aci; s = 0.0; for ( int j = acj; j > acj1; j-- ) { s += mtrx [ j ] * mtrx [ acs ]; acs--; } mtrx [ acj1 ] -= s; } /* uprava diagonalniho prvku */ s = 0.0; for ( int i = ack1 - 1; i > ack; i-- ) { g = mtrx [ i ]; acs = adr.at(acrk); acrk++; mtrx [ i ] /= mtrx [ acs ]; s += mtrx [ i ] * g; } mtrx [ ack ] -= s; } isFactorized = true; #ifdef TIME_REPORT timer.stopTimer(); OOFEM_LOG_DEBUG( "Skyline info: user time consumed by factorization: %.2fs\n", timer.getUtime() ); #endif // increment version //this->version++; return this; }
NM_Status GJacobi :: solve(FloatMatrix *a, FloatMatrix *b, FloatArray *eigv, FloatMatrix *x) //void GJacobi :: solveYourselfAt (TimeStep* tNow) // // this function solve the generalized eigenproblem using the Generalized // jacobi iteration // // { int i, j, k, nsweep, nr, jj; double eps, eptola, eptolb, akk, ajj, ab, check, sqch, d1, d2, den, ca, cg, ak, bk, xj, xk; double aj, bj, tol, dif, epsa, epsb, bb; int jm1, kp1, km1, jp1; // first check whether Amatrix is defined if ( !a ) { _error("solveYourselfAt: unknown A matrix"); } // and whether Bmatrix if ( !b ) { _error("solveYourselfAt: unknown Bmatrx"); } if ( ( a->giveNumberOfRows() != b->giveNumberOfRows() ) || ( !a->isSquare() ) || ( !b->isSquare() ) ) { _error("solveYourselfAt: A matrix, B mtrix -> size mismatch"); } int n = a->giveNumberOfRows(); // // Check output arrays // if ( !eigv ) { _error("solveYourselfAt: unknown eigv array"); } if ( !x ) { _error("solveYourselfAt: unknown x mtrx "); } if ( eigv->giveSize() != n ) { _error("solveYourselfAt: eigv size mismatch"); } if ( ( !x->isSquare() ) || ( x->giveNumberOfRows() != n ) ) { _error("solveYourselfAt: x size mismatch"); } // // Create temporary arrays // FloatArray *d = new FloatArray(n); // // Initialize EigenValue and EigenVector Matrices // for ( i = 1; i <= n; i++ ) { // if((a->at(i,i) <= 0. ) && (b->at(i,i) <= 0.)) // _error ("solveYourselfAt: Matrices are not positive definite"); d->at(i) = a->at(i, i) / b->at(i, i); eigv->at(i) = d->at(i); } for ( i = 1; i <= n; i++ ) { for ( j = 1; j <= n; j++ ) { x->at(i, j) = 0.0; } x->at(i, i) = 1.0; } if ( n == 1 ) { return NM_Success; } // // Initialize sweep counter and begin iteration // nsweep = 0; nr = n - 1; do { nsweep++; # ifdef DETAILED_REPORT OOFEM_LOG_DEBUG("*GJacobi*: sweep number %4d\n", nsweep); #endif // // check if present off-diagonal element is large enough to require zeroing // eps = pow(0.01, ( double ) nsweep); eps *= eps; for ( j = 1; j <= nr; j++ ) { jj = j + 1; for ( k = jj; k <= n; k++ ) { eptola = ( a->at(j, k) * a->at(j, k) ) / ( a->at(j, j) * a->at(k, k) ); eptolb = ( b->at(j, k) * b->at(j, k) ) / ( b->at(j, j) * b->at(k, k) ); if ( ( eptola < eps ) && ( eptolb < eps ) ) { continue; } // // if zeroing is required, calculate the rotation matrix elements ca and cg // akk = a->at(k, k) * b->at(j, k) - b->at(k, k) * a->at(j, k); ajj = a->at(j, j) * b->at(j, k) - b->at(j, j) * a->at(j, k); ab = a->at(j, j) * b->at(k, k) - a->at(k, k) * b->at(j, j); check = ( ab * ab + 4.0 * akk * ajj ) / 4.0; if ( fabs(check) < GJacobi_ZERO_CHECK_TOL ) { check = fabs(check); } else if ( check < 0.0 ) { _error("solveYourselfAt: Matrices are not positive definite"); } sqch = sqrt(check); d1 = ab / 2. + sqch; d2 = ab / 2. - sqch; den = d1; if ( fabs(d2) > fabs(d1) ) { den = d2; } if ( den != 0.0 ) { // strange ! ca = akk / den; cg = -ajj / den; } else { ca = 0.0; cg = -a->at(j, k) / a->at(k, k); } // // perform the generalized rotation to zero // if ( ( n - 2 ) != 0 ) { jp1 = j + 1; jm1 = j - 1; kp1 = k + 1; km1 = k - 1; if ( ( jm1 - 1 ) >= 0 ) { for ( i = 1; i <= jm1; i++ ) { aj = a->at(i, j); bj = b->at(i, j); ak = a->at(i, k); bk = b->at(i, k); a->at(i, j) = aj + cg * ak; b->at(i, j) = bj + cg * bk; a->at(i, k) = ak + ca * aj; b->at(i, k) = bk + ca * bj; } } if ( ( kp1 - n ) <= 0 ) { for ( i = kp1; i <= n; i++ ) { // label 140 aj = a->at(j, i); bj = b->at(j, i); ak = a->at(k, i); bk = b->at(k, i); a->at(j, i) = aj + cg * ak; b->at(j, i) = bj + cg * bk; a->at(k, i) = ak + ca * aj; b->at(k, i) = bk + ca * bj; } } if ( ( jp1 - km1 ) <= 0 ) { // label 160 for ( i = jp1; i <= km1; i++ ) { aj = a->at(j, i); bj = b->at(j, i); ak = a->at(i, k); bk = b->at(i, k); a->at(j, i) = aj + cg * ak; b->at(j, i) = bj + cg * bk; a->at(i, k) = ak + ca * aj; b->at(i, k) = bk + ca * bj; } } } // label 190 ak = a->at(k, k); bk = b->at(k, k); a->at(k, k) = ak + 2.0 *ca *a->at(j, k) + ca *ca *a->at(j, j); b->at(k, k) = bk + 2.0 *ca *b->at(j, k) + ca *ca *b->at(j, j); a->at(j, j) = a->at(j, j) + 2.0 *cg *a->at(j, k) + cg * cg * ak; b->at(j, j) = b->at(j, j) + 2.0 *cg *b->at(j, k) + cg * cg * bk; a->at(j, k) = 0.0; b->at(j, k) = 0.0; // // update the eigenvector matrix after each rotation // for ( i = 1; i <= n; i++ ) { xj = x->at(i, j); xk = x->at(i, k); x->at(i, j) = xj + cg * xk; x->at(i, k) = xk + ca * xj; } // label 200 } } // label 210 // // update the eigenvalues after each sweep // #ifdef DETAILED_REPORT OOFEM_LOG_DEBUG("GJacobi: a,b after sweep\n"); a->printYourself(); b->printYourself(); #endif for ( i = 1; i <= n; i++ ) { // in original uncommented // if ((a->at(i,i) <= 0.) || (b->at(i,i) <= 0.)) // error ("solveYourselfAt: Matrices are not positive definite"); eigv->at(i) = a->at(i, i) / b->at(i, i); } // label 220 # ifdef DETAILED_REPORT OOFEM_LOG_DEBUG("GJacobi: current eigenvalues are:\n"); eigv->printYourself(); OOFEM_LOG_DEBUG("GJacobi: current eigenvectors are:\n"); x->printYourself(); # endif // // check for convergence // for ( i = 1; i <= n; i++ ) { // label 230 tol = rtol * d->at(i); dif = ( eigv->at(i) - d->at(i) ); if ( fabs(dif) > tol ) { goto label280; } } // label 240 // // check all off-diagonal elements to see if another sweep is required // eps = rtol * rtol; for ( j = 1; j <= nr; j++ ) { jj = j + 1; for ( k = jj; k <= n; k++ ) { epsa = ( a->at(j, k) * a->at(j, k) ) / ( a->at(j, j) * a->at(k, k) ); epsb = ( b->at(j, k) * b->at(j, k) ) / ( b->at(j, j) * b->at(k, k) ); if ( ( epsa < eps ) && ( epsb < eps ) ) { continue; } goto label280; } } // label 250 // // fill out bottom triangle of resultant matrices and scale eigenvectors // break; // goto label255 ; // // update d matrix and start new sweep, if allowed // label280: for ( i = 1; i <= n; i++ ) { d->at(i) = eigv->at(i); } } while ( nsweep < nsmax ); // label255: for ( i = 1; i <= n; i++ ) { for ( j = 1; j <= n; j++ ) { a->at(j, i) = a->at(i, j); b->at(j, i) = b->at(i, j); } // label 260 } for ( j = 1; j <= n; j++ ) { bb = sqrt( fabs( b->at(j, j) ) ); for ( k = 1; k <= n; k++ ) { x->at(k, j) /= bb; } } // label 270 solved = 1; delete d; return NM_Success; }
int CompCol :: buildInternalStructure(EngngModel *eModel, int di, const UnknownNumberingScheme &s) { /* * IntArray loc; * Domain* domain = eModel->giveDomain(di); * int neq = eModel -> giveNumberOfDomainEquations (di); * int nelem = domain -> giveNumberOfElements() ; * int i,ii,j,jj,n, indx; * Element* elem; * // allocation map * char* map = new char[neq*neq]; * if (map == NULL) { * printf ("CompCol::buildInternalStructure - map creation failed"); * exit (1); * } * * for (i=0; i<neq*neq; i++) * map[i]=0; * * * this->nz_ = 0; * * for (n=1 ; n<=nelem ; n++) { * elem = domain -> giveElement(n); * elem -> giveLocationArray (loc) ; * * for (i=1 ; i <= loc.giveSize() ; i++) { * if ((ii = loc.at(i))) { * for (j=1; j <= loc.giveSize() ; j++) { * if ((jj=loc.at(j))) { * if (map[(ii-1)*neq+jj-1] == 0) { * map[(ii-1)*neq+jj-1] = 1; * this->nz_ ++; * } * } * } * } * } * } * * rowind_.resize (nz_); * colptr_.resize (neq+1); * indx = 0; * for (j=0; j<neq; j++) { // column loop * colptr_(j) = indx; * for (i=0; i<neq; i++) { // row loop * if (map[i*neq+j]) { * rowind_(indx) = i; * indx++; * } * } * } * colptr_(neq) = indx; * * // delete map * delete (map); * * // allocate value array * val_.resize(nz_); * val_.zero(); * * printf ("\nCompCol info: neq is %d, nwk is %d\n",neq,nz_); * * dim_[0] = dim_[1] = nColumns = nRows = neq; * * // increment version * this->version++; * * return true; */ IntArray loc; Domain *domain = eModel->giveDomain(di); int neq = eModel->giveNumberOfDomainEquations(di, s); int nelem = domain->giveNumberOfElements(); int i, ii, j, jj, n, indx; Element *elem; // allocation map std :: vector< std :: set< int > > columns(neq); /* * std::set<int> **columns = new std::set<int>*[neq]; * for (j=0; j<neq; j++) { * columns[j] = new std::set<int>; * } */ this->nz_ = 0; for ( n = 1; n <= nelem; n++ ) { elem = domain->giveElement(n); elem->giveLocationArray(loc, s); for ( i = 1; i <= loc.giveSize(); i++ ) { if ( ( ii = loc.at(i) ) ) { for ( j = 1; j <= loc.giveSize(); j++ ) { if ( ( jj = loc.at(j) ) ) { columns [ jj - 1 ].insert(ii - 1); } } } } } // loop over active boundary conditions int nbc = domain->giveNumberOfBoundaryConditions(); std :: vector< IntArray >r_locs; std :: vector< IntArray >c_locs; for ( int i = 1; i <= nbc; ++i ) { ActiveBoundaryCondition *bc = dynamic_cast< ActiveBoundaryCondition * >( domain->giveBc(i) ); if ( bc != NULL ) { bc->giveLocationArrays(r_locs, c_locs, UnknownCharType, s, s); for ( std :: size_t k = 0; k < r_locs.size(); k++ ) { IntArray &krloc = r_locs [ k ]; IntArray &kcloc = c_locs [ k ]; for ( int i = 1; i <= krloc.giveSize(); i++ ) { if ( ( ii = krloc.at(i) ) ) { for ( int j = 1; j <= kcloc.giveSize(); j++ ) { if ( ( jj = kcloc.at(j) ) ) { columns [ jj - 1 ].insert(ii - 1); } } } } } } } for ( i = 0; i < neq; i++ ) { this->nz_ += columns [ i ].size(); } rowind_.resize(nz_); colptr_.resize(neq + 1); indx = 0; for ( j = 0; j < neq; j++ ) { // column loop colptr_(j) = indx; for ( int row: columns [ j ] ) { // row loop rowind_(indx++) = row; } } colptr_(neq) = indx; /* * // delete map * for (i=0; i< neq; i++) {columns[i]->clear(); delete columns[i];} * delete columns; */ // allocate value array val_.resize(nz_); val_.zero(); OOFEM_LOG_DEBUG("CompCol info: neq is %d, nwk is %d\n", neq, nz_); dim_ [ 0 ] = dim_ [ 1 ] = nColumns = nRows = neq; // increment version this->version++; return true; }
NM_Status TrustRegionSolver3 :: solve(SparseMtrx &k, FloatArray &R, FloatArray *R0, FloatArray &X, FloatArray &dX, FloatArray &F, const FloatArray &internalForcesEBENorm, double &l, referenceLoadInputModeType rlm, int &nite, TimeStep *tStep) { // residual, iteration increment of solution, total external force FloatArray rhs, ddX, RT; double RRT; int neq = X.giveSize(); bool converged, errorOutOfRangeFlag; ParallelContext *parallel_context = engngModel->giveParallelContext( this->domain->giveNumber() ); if ( engngModel->giveProblemScale() == macroScale ) { OOFEM_LOG_INFO("NRSolver: Iteration"); if ( rtolf.at(1) > 0.0 ) { OOFEM_LOG_INFO(" ForceError"); } if ( rtold.at(1) > 0.0 ) { OOFEM_LOG_INFO(" DisplError"); } OOFEM_LOG_INFO("\n----------------------------------------------------------------------------\n"); } l = 1.0; NM_Status status = NM_None; this->giveLinearSolver(); // compute total load R = R+R0 RT = R; if ( R0 ) { RT.add(* R0); } RRT = parallel_context->localNorm(RT); RRT *= RRT; ddX.resize(neq); ddX.zero(); double old_res = 0.0; double trial_res = 0.0; bool first_perturbation = true; FloatArray eig_vec, pert_eig_vec; double pert_tol = 0.0e1; nite = 0; for ( nite = 0; ; ++nite ) { // Compute the residual engngModel->updateComponent(tStep, InternalRhs, domain); rhs.beDifferenceOf(RT, F); old_res = rhs.computeNorm(); // convergence check converged = this->checkConvergence(RT, F, rhs, ddX, X, RRT, internalForcesEBENorm, nite, errorOutOfRangeFlag); if ( errorOutOfRangeFlag ) { status = NM_NoSuccess; OOFEM_WARNING("Divergence reached after %d iterations", nite); break; } else if ( converged && ( nite >= minIterations ) ) { status |= NM_Success; break; } else if ( nite >= nsmax ) { OOFEM_LOG_DEBUG("Maximum number of iterations reached\n"); break; } engngModel->updateComponent(tStep, NonLinearLhs, domain); //////////////////////////////////////////////////////////////////////////// // Step calculation: Solve trust-region subproblem PetscSparseMtrx &A = dynamic_cast< PetscSparseMtrx& >(k); IntArray loc_u; // Check if k is positive definite double smallest_eig_val = 0.0; // Dirty hack for weakly periodic boundary conditions PrescribedGradientBCWeak *bc = dynamic_cast<PrescribedGradientBCWeak*>(domain->giveBc(1)); if( bc ) { if ( engngModel->giveProblemScale() == macroScale ) { printf("Found PrescribedGradientBCWeak.\n"); } auto Kuu = std::dynamic_pointer_cast<PetscSparseMtrx>( bc->giveKuu(loc_u, tStep) ); calcSmallestEigVal(smallest_eig_val, eig_vec, *Kuu); if ( engngModel->giveProblemScale() == macroScale ) { printf("smallest_eig_val: %e\n", smallest_eig_val); } } else { calcSmallestEigVal(smallest_eig_val, eig_vec, A); } double lambda = 0.0; if(smallest_eig_val < 0.0) { lambda = -smallest_eig_val; A.addDiagonal(lambda, loc_u); } linSolver->solve(k, rhs, ddX); // Remove lambda from the diagonal again if(smallest_eig_val < 0.0) { A.addDiagonal(-lambda, loc_u); } // Constrain the increment to stay within the trust-region double increment_ratio = 1.0; double maxInc = 0.0; for ( double inc : ddX ) { if(fabs(inc) > maxInc) { maxInc = fabs(inc); } } if(maxInc > mTrustRegionSize) { if ( engngModel->giveProblemScale() == macroScale ) { printf("Restricting increment. maxInc: %e\n", maxInc); } ddX.times(mTrustRegionSize/maxInc); increment_ratio = mTrustRegionSize/maxInc; } if( smallest_eig_val < pert_tol ) { if ( engngModel->giveProblemScale() == macroScale ) { printf("Negative eigenvalue detected.\n"); printf("Perturbing in lowest eigenvector direction.\n"); } if(first_perturbation || (nite%mEigVecRecalc==0) ) { pert_eig_vec.resize( ddX.giveSize() ); for(int i = 0; i < loc_u.giveSize(); i++) { pert_eig_vec( loc_u(i)-1 ) = eig_vec(i); } // Rescale eigenvector such that the L_inf norm is 1. double max_eig_vec = 0.0; for ( double inc : pert_eig_vec ) { if(fabs(inc) > max_eig_vec) { max_eig_vec = fabs(inc); } } pert_eig_vec.times(1./max_eig_vec); first_perturbation = false; } double c = maxInc; if(c > mTrustRegionSize) { c = mTrustRegionSize; } if( ddX.dotProduct(pert_eig_vec) < 0.0 ) { c *= -1.0; } ddX.add( c*mBeta, pert_eig_vec ); } if ( engngModel->giveProblemScale() == macroScale ) { printf("smallest_eig_val: %e increment_ratio: %e\n", smallest_eig_val, increment_ratio ); } X.add(ddX); dX.add(ddX); //////////////////////////////////////////////////////////////////////////// // Acceptance of trial point engngModel->updateComponent(tStep, InternalRhs, domain); rhs.beDifferenceOf(RT, F); trial_res = rhs.computeNorm(); double rho_k = 1.0; if(old_res > 1.0e-12) { rho_k = ( old_res - trial_res )/( 0.99*increment_ratio*old_res ); } //////////////////////////////////////////////////////////////////////////// // Trust-region radius update if( rho_k >= mEta2 ) { // printf("Very successful update.\n"); // Parameter on p.782 in Conn et al. double alpha1 = 2.5; if ( alpha1*maxInc > mTrustRegionSize ) { mTrustRegionSize = alpha1*mTrustRegionSize; } } else { if( !(rho_k >= mEta1 && rho_k < mEta2) ) { if(nite > 1000) { // Only contract trust-region size in case of emergency // Parameter on p.782 in Conn et al. double alpha2 = 0.5; mTrustRegionSize = alpha2*mTrustRegionSize; } } } tStep->incrementStateCounter(); // update solution state counter tStep->incrementSubStepNumber(); engngModel->giveExportModuleManager()->doOutput(tStep, true); } // Modify Load vector to include "quasi reaction" if ( R0 ) { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R.at( prescribedEqs.at(i) ) = F.at( prescribedEqs.at(i) ) - R0->at( prescribedEqs.at(i) ) - R.at( prescribedEqs.at(i) ); } } else { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R.at( prescribedEqs.at(i) ) = F.at( prescribedEqs.at(i) ) - R.at( prescribedEqs.at(i) ); } } this->lastReactions.resize(numberOfPrescribedDofs); #ifdef VERBOSE if ( numberOfPrescribedDofs ) { // print quasi reactions if direct displacement control used OOFEM_LOG_INFO("\n"); OOFEM_LOG_INFO("NRSolver: Quasi reaction table \n"); OOFEM_LOG_INFO("NRSolver: Node Dof Displacement Force\n"); double reaction; for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { reaction = R.at( prescribedEqs.at(i) ); if ( R0 ) { reaction += R0->at( prescribedEqs.at(i) ); } lastReactions.at(i) = reaction; OOFEM_LOG_INFO("NRSolver: %-15d %-15d %-+15.5e %-+15.5e\n", prescribedDofs.at(2 * i - 1), prescribedDofs.at(2 * i), X.at( prescribedEqs.at(i) ), reaction); } OOFEM_LOG_INFO("\n"); } #endif return status; }
void XFEMStatic :: updateLoadVectors(TimeStep *tStep) { MetaStep *mstep = this->giveMetaStep( tStep->giveMetaStepNumber() ); bool isLastMetaStep = ( tStep->giveNumber() == mstep->giveLastStepNumber() ); if ( controlMode == nls_indirectControl ) { //todo@: not checked //if ((tStep->giveNumber() == mstep->giveLastStepNumber()) && ir->hasField("fixload")) { if ( isLastMetaStep ) { if ( !mstep->giveAttributesRecord()->hasField(_IFT_NonLinearStatic_donotfixload) ) { OOFEM_LOG_INFO("Fixed load level\n"); //update initialLoadVector if ( initialLoadVector.isEmpty() ) { initialLoadVector.resize( incrementalLoadVector.giveSize() ); } incrementalLoadVector.times(loadLevel); initialLoadVector.add(incrementalLoadVector); incrementalLoadVectorOfPrescribed.times(loadLevel); initialLoadVectorOfPrescribed.add(incrementalLoadVectorOfPrescribed); incrementalLoadVector.zero(); incrementalLoadVectorOfPrescribed.zero(); this->loadInitFlag = 1; } //if (!mstep->giveAttributesRecord()->hasField("keepll")) this->loadLevelInitFlag = 1; } } else { // direct control //update initialLoadVector after each step of direct control //(here the loading is not proportional) /*if ( initialLoadVector.isEmpty() ) { * initialLoadVector.resize( incrementalLoadVector.giveSize() ); * } */ OOFEM_LOG_DEBUG("Fixed load level\n"); int neq = this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ); // 1 stands for domain? // printf("Before: "); // incrementalLoadVector.printYourself(); if ( incrementalLoadVector.giveSize() != neq ) { //initialLoadVector.resize( incrementalLoadVector.giveSize() ); // initialLoadVector.printYourself(); // initialLoadVector.resize( 0 ); FloatArray incrementalLoadVectorNew; setValsFromDofMap(incrementalLoadVectorNew, incrementalLoadVector); incrementalLoadVector = incrementalLoadVectorNew; } // printf("After: "); // incrementalLoadVector.printYourself(); incrementalLoadVector.times(loadLevel); /////////////////////////////////////////////////////////////////// // Map values in the old initialLoadVector to the new initialLoadVector // printf("Before: "); // initialLoadVector.printYourself(); if ( initialLoadVector.giveSize() != neq ) { //initialLoadVector.resize( incrementalLoadVector.giveSize() ); // initialLoadVector.printYourself(); // initialLoadVector.resize( 0 ); FloatArray initialLoadVectorNew; setValsFromDofMap(initialLoadVectorNew, initialLoadVector); initialLoadVector = initialLoadVectorNew; } // printf("After: "); // initialLoadVector.printYourself(); /////////////////////////////////////////////////////////////////// initialLoadVector.add(incrementalLoadVector); incrementalLoadVectorOfPrescribed.times(loadLevel); initialLoadVectorOfPrescribed.add(incrementalLoadVectorOfPrescribed); incrementalLoadVector.zero(); incrementalLoadVectorOfPrescribed.zero(); this->loadInitFlag = 1; } // if (isLastMetaStep) { if ( isLastMetaStep && !mstep->giveAttributesRecord()->hasField(_IFT_NonLinearStatic_donotfixload) ) { #ifdef VERBOSE OOFEM_LOG_INFO("Reseting load level\n"); #endif if ( mstepCumulateLoadLevelFlag ) { cumulatedLoadLevel += loadLevel; } else { cumulatedLoadLevel = 0.0; } this->loadLevel = 0.0; } }
void ProblemCommunicator :: setUpCommunicationMapsForRemoteElementMode(EngngModel *pm, bool excludeSelfCommFlag) { //int nnodes = domain->giveNumberOfDofManagers(); Domain *domain = pm->giveDomain(1); int i, j, partition; if ( this->mode == ProblemCommMode__REMOTE_ELEMENT_MODE ) { /* * Initially, each partition knows for which nodes a receive * is needed (and can therefore compute easily the recv map), * but does not know for which nodes it should send data to which * partition. Hence, the communication setup is performed by * broadcasting "send request" lists of nodes for which * a partition expects to receive data (ie. of those nodes * which the partition uses, but does not own) to all * collaborating processes. The "send request" list are * converted into send maps. */ // receive maps can be build locally, // but send maps should be assembled from broadcasted lists (containing // expected receive nodes) of remote partitions. // first build local receive map IntArray domainNodeRecvCount(size); const IntArray *partitionList; //DofManager *dofMan; Element *element; int domainRecvListSize = 0, domainRecvListPos = 0; int nelems; int result = 1; nelems = domain->giveNumberOfElements(); for ( i = 1; i <= nelems; i++ ) { partitionList = domain->giveElement(i)->givePartitionList(); if ( domain->giveElement(i)->giveParallelMode() == Element_remote ) { // size of partitionList should be 1 <== only ine master for ( j = 1; j <= partitionList->giveSize(); j++ ) { if ( !( excludeSelfCommFlag && ( this->rank == partitionList->at(j) ) ) ) { domainRecvListSize++; domainNodeRecvCount.at(partitionList->at(j) + 1)++; } } } } // build maps simultaneously IntArray pos(size); IntArray **maps = new IntArray * [ size ]; for ( i = 0; i < size; i++ ) { maps [ i ] = new IntArray( domainNodeRecvCount.at(i + 1) ); } // allocate also domain receive list to be broadcasted IntArray domainRecvList(domainRecvListSize); if ( domainRecvListSize ) { for ( i = 1; i <= nelems; i++ ) { // test if element is remote one element = domain->giveElement(i); if ( element->giveParallelMode() == Element_remote ) { domainRecvList.at(++domainRecvListPos) = element->giveGlobalNumber(); partitionList = domain->giveElement(i)->givePartitionList(); // size of partitionList should be 1 <== only ine master for ( j = 1; j <= partitionList->giveSize(); j++ ) { if ( !( excludeSelfCommFlag && ( this->rank == partitionList->at(j) ) ) ) { partition = partitionList->at(j); maps [ partition ]->at( ++pos.at(partition + 1) ) = i; } } } } } // set up domains recv communicator maps for ( i = 0; i < size; i++ ) { this->setProcessCommunicatorToRecvArry(this->giveProcessCommunicator(i), * maps [ i ]); //this->giveDomainCommunicator(i)->setToRecvArry (this->engngModel, *maps[i]); } /* * #ifdef __VERBOSE_PARALLEL * for (i=0; i<size; i++) { * fprintf (stderr, "domain %d-%d: domainCommRecvsize is %d\n",rank,i,this->giveDomainCommunicator(i)->giveRecvBuff()->giveSize() ); * printf ("domain %d-%d: reecv map:",rank,i); * this->giveDomainCommunicator(i)->giveToRecvMap()->printYourself(); * } *#endif */ // delete local maps for ( i = 0; i < size; i++ ) { delete maps [ i ]; } delete [] maps; // to assemble send maps, we must analyze broadcasted remote domain send lists // and we must also broadcast our send list. #ifdef __VERBOSE_PARALLEL VERBOSEPARALLEL_PRINT("ProblemCommunicator::setUpCommunicationMaps", "Remote Element-cut broadcasting started", rank); #endif StaticCommunicationBuffer commBuff(MPI_COMM_WORLD); IntArray remoteDomainRecvList; IntArray toSendMap; int localExpectedSize, globalRecvSize; int sendMapPos, sendMapSize, globalDofManNum; // determine the size of receive buffer using AllReduce operation #ifndef IBM_MPI_IMPLEMENTATION localExpectedSize = domainRecvList.givePackSize(commBuff); #else localExpectedSize = domainRecvList.givePackSize(commBuff) + 1; #endif #ifdef __USE_MPI result = MPI_Allreduce(& localExpectedSize, & globalRecvSize, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); if ( result != MPI_SUCCESS ) { _error("setUpCommunicationMaps: MPI_Allreduce failed"); } #else WARNING: NOT SUPPORTED MESSAGE PARSING LIBRARY #endif #ifdef __VERBOSE_PARALLEL VERBOSEPARALLEL_PRINT("ProblemCommunicator::setUpCommunicationMaps", "Finished reducing receiveBufferSize", rank); #endif // resize to fit largest received message commBuff.resize(globalRecvSize); // resize toSend map to max possible size toSendMap.resize(globalRecvSize); for ( i = 0; i < size; i++ ) { // loop over domains commBuff.init(); if ( i == rank ) { //current domain has to send its receive list to all domains // broadcast domainRecvList #ifdef __VERBOSE_PARALLEL VERBOSEPARALLEL_PRINT("ProblemCommunicator::setUpCommunicationMaps", "Broadcasting own send list", rank); #endif commBuff.packIntArray(domainRecvList); result = commBuff.bcast(i); if ( result != MPI_SUCCESS ) { _error("setUpCommunicationMaps: commBuff broadcast failed"); } #ifdef __VERBOSE_PARALLEL VERBOSEPARALLEL_PRINT("ProblemCommunicator::setUpCommunicationMaps", "Broadcasting own send list finished", rank); #endif } else { #ifdef __VERBOSE_PARALLEL OOFEM_LOG_DEBUG("[process rank %3d]: %-30s: Receiving broadcasted send map from partition %3d\n", rank, "ProblemCommunicator :: unpackAllData", i); #endif // receive broadcasted lists result = commBuff.bcast(i); if ( result != MPI_SUCCESS ) { _error("setUpCommunicationMaps: commBuff broadcast failed"); } #ifdef __VERBOSE_PARALLEL OOFEM_LOG_DEBUG("[process rank %3d]: %-30s: Receiving broadcasted send map from partition %3d finished\n", rank, "ProblemCommunicator :: unpackAllData", i); #endif // unpack remote receive list if ( !commBuff.unpackIntArray(remoteDomainRecvList) ) { _error("ProblemCommunicator::setUpCommunicationMaps: unpack remote receive list failed"); } // find if remote elements are in local partition // if yes add them into send map for correcponding i-th partition sendMapPos = 0; sendMapSize = 0; // determine sendMap size for ( j = 1; j <= nelems; j++ ) { // loop over local elements element = domain->giveElement(j); if ( element->giveParallelMode() == Element_local ) { globalDofManNum = element->giveGlobalNumber(); // test id globalDofManNum is in remoteDomainRecvList if ( remoteDomainRecvList.findFirstIndexOf(globalDofManNum) ) { sendMapSize++; } } } toSendMap.resize(sendMapSize); for ( j = 1; j <= nelems; j++ ) { // loop over local elements element = domain->giveElement(j); if ( element->giveParallelMode() == Element_local ) { globalDofManNum = element->giveGlobalNumber(); // test id globalDofManNum is in remoteDomainRecvList if ( remoteDomainRecvList.findFirstIndexOf(globalDofManNum) ) { // add this local DofManager number to sed map for active partition toSendMap.at(++sendMapPos) = j; } } } // end loop over local DofManagers // set send map to i-th process communicator this->setProcessCommunicatorToSendArry(this->giveProcessCommunicator(i), toSendMap); /* * #ifdef __VERBOSE_PARALLEL * fprintf (stderr, "domain %d-%d: domainCommSendsize is %d\n",rank,i,this->giveDomainCommunicator(i)->giveSendBuff()->giveSize() ); * printf ("domain %d-%d: send map:",rank,i); * this->giveDomainCommunicator(i)->giveToSendMap()->printYourself(); * *#endif */ //this->giveDomainCommunicator(i)->setToSendArry (this->engngModel, toSendMap); } // end receiving broadcasted lists #ifdef __VERBOSE_PARALLEL VERBOSEPARALLEL_PRINT("ProblemCommunicator::setUpCommunicationMaps", "Receiving broadcasted send maps finished", rank); #endif } // end loop over domains } else { _error("setUpCommunicationMapsForRemoteElementMode: unknown mode"); } }
NM_Status NRSolver :: solve(SparseMtrx &k, FloatArray &R, FloatArray *R0, FloatArray &X, FloatArray &dX, FloatArray &F, const FloatArray &internalForcesEBENorm, double &l, referenceLoadInputModeType rlm, int &nite, TimeStep *tStep) // // this function solve the problem of the unbalanced equilibrium // using NR scheme // // { // residual, iteration increment of solution, total external force FloatArray rhs, ddX, RT; double RRT; FloatArray norm; norm = internalForcesEBENorm; int neq = X.giveSize(); bool converged, errorOutOfRangeFlag; ParallelContext *parallel_context = engngModel->giveParallelContext( this->domain->giveNumber() ); if ( engngModel->giveProblemScale() == macroScale ) { OOFEM_LOG_INFO("NRSolver: Iteration"); if ( rtolf.at(1) > 0.0 ) { OOFEM_LOG_INFO(" ForceError"); } if ( rtold.at(1) > 0.0 ) { OOFEM_LOG_INFO(" DisplError"); } OOFEM_LOG_INFO("\n----------------------------------------------------------------------------\n"); } l = 1.0; NM_Status status = NM_None; this->giveLinearSolver(); // compute total load R = R+R0 RT = R; if ( R0 ) { RT.add(* R0); } RRT = parallel_context->localNorm(RT); RRT *= RRT; ddX.resize(neq); ddX.zero(); // Fetch the matrix before evaluating internal forces. // This is intentional, since its a simple way to drastically increase convergence for nonlinear problems. // (This old tangent is just used) // This improves convergence for many nonlinear problems, but not all. It may actually // cause divergence for some nonlinear problems. Therefore a flag is used to determine if // the stiffness should be evaluated before the residual (default yes). /ES engngModel->updateComponent(tStep, NonLinearLhs, domain); if ( this->prescribedDofsFlag ) { if ( !prescribedEqsInitFlag ) { this->initPrescribedEqs(); } applyConstraintsToStiffness(k); } nite = 0; do { // Compute the residual engngModel->updateComponent(tStep, InternalRhs, domain); rhs.beDifferenceOf(RT, F); if ( this->prescribedDofsFlag ) { this->applyConstraintsToLoadIncrement(nite, k, rhs, rlm, tStep); } // convergence check converged = this->checkConvergence(RT, F, rhs, ddX, X, RRT, internalForcesEBENorm, nite, errorOutOfRangeFlag); if ( errorOutOfRangeFlag ) { status = NM_NoSuccess; OOFEM_WARNING("Divergence reached after %d iterations", nite); break; } else if ( converged && ( nite >= minIterations ) ) { break; } else if ( nite >= nsmax ) { OOFEM_LOG_DEBUG("Maximum number of iterations reached\n"); break; } if ( nite > 0 || !mCalcStiffBeforeRes ) { if ( ( NR_Mode == nrsolverFullNRM ) || ( ( NR_Mode == nrsolverAccelNRM ) && ( nite % MANRMSteps == 0 ) ) ) { engngModel->updateComponent(tStep, NonLinearLhs, domain); applyConstraintsToStiffness(k); } } if ( ( nite == 0 ) && ( deltaL < 1.0 ) ) { // deltaL < 1 means no increment applied, only equilibrate current state rhs.zero(); R.zero(); ddX = rhs; } else { linSolver->solve(k, rhs, ddX); } // // update solution // if ( this->lsFlag && ( nite > 0 ) ) { // Why not nite == 0 ? // line search LineSearchNM :: LS_status LSstatus; double eta; this->giveLineSearchSolver()->solve(X, ddX, F, R, R0, prescribedEqs, 1.0, eta, LSstatus, tStep); } else if ( this->constrainedNRFlag && ( nite > this->constrainedNRminiter ) ) { ///@todo This doesn't check units, it is nonsense and must be corrected / Mikael if ( this->forceErrVec.computeSquaredNorm() > this->forceErrVecOld.computeSquaredNorm() ) { OOFEM_LOG_INFO("Constraining increment to be %e times full increment...\n", this->constrainedNRalpha); ddX.times(this->constrainedNRalpha); } //this->giveConstrainedNRSolver()->solve(X, & ddX, this->forceErrVec, this->forceErrVecOld, status, tStep); } X.add(ddX); dX.add(ddX); tStep->incrementStateCounter(); // update solution state counter tStep->incrementSubStepNumber(); nite++; // iteration increment engngModel->giveExportModuleManager()->doOutput(tStep, true); } while ( true ); // end of iteration status |= NM_Success; solved = 1; // Modify Load vector to include "quasi reaction" if ( R0 ) { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R.at( prescribedEqs.at(i) ) = F.at( prescribedEqs.at(i) ) - R0->at( prescribedEqs.at(i) ) - R.at( prescribedEqs.at(i) ); } } else { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R.at( prescribedEqs.at(i) ) = F.at( prescribedEqs.at(i) ) - R.at( prescribedEqs.at(i) ); } } this->lastReactions.resize(numberOfPrescribedDofs); #ifdef VERBOSE if ( numberOfPrescribedDofs ) { // print quasi reactions if direct displacement control used OOFEM_LOG_INFO("\n"); OOFEM_LOG_INFO("NRSolver: Quasi reaction table \n"); OOFEM_LOG_INFO("NRSolver: Node Dof Displacement Force\n"); double reaction; for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { reaction = R.at( prescribedEqs.at(i) ); if ( R0 ) { reaction += R0->at( prescribedEqs.at(i) ); } lastReactions.at(i) = reaction; OOFEM_LOG_INFO("NRSolver: %-15d %-15d %-+15.5e %-+15.5e\n", prescribedDofs.at(2 * i - 1), prescribedDofs.at(2 * i), X.at( prescribedEqs.at(i) ), reaction); } OOFEM_LOG_INFO("\n"); } #endif return status; }
NM_Status StaggeredSolver :: solve(SparseMtrx &k, FloatArray &R, FloatArray *R0, FloatArray &Xtotal, FloatArray &dXtotal, FloatArray &F, const FloatArray &internalForcesEBENorm, double &l, referenceLoadInputModeType rlm, int &nite, TimeStep *tStep) { // residual, iteration increment of solution, total external force FloatArray RHS, rhs, ddXtotal, RT; double RRTtotal; int neq = Xtotal.giveSize(); NM_Status status; bool converged, errorOutOfRangeFlag; ParallelContext *parallel_context = engngModel->giveParallelContext( this->domain->giveNumber() ); if ( engngModel->giveProblemScale() == macroScale ) { OOFEM_LOG_INFO("StaggeredSolver: Iteration"); if ( rtolf.at(1) > 0.0 ) { OOFEM_LOG_INFO(" ForceError"); } if ( rtold.at(1) > 0.0 ) { OOFEM_LOG_INFO(" DisplError"); } OOFEM_LOG_INFO("\n----------------------------------------------------------------------------\n"); } l = 1.0; status = NM_None; this->giveLinearSolver(); // compute total load R = R+R0 RT = R; if ( R0 ) { RT.add(* R0); } RRTtotal = parallel_context->localNorm(RT); RRTtotal *= RRTtotal; ddXtotal.resize(neq); ddXtotal.zero(); // Fetch the matrix before evaluating internal forces. // This is intentional, since its a simple way to drastically increase convergence for nonlinear problems. // (This old tangent is just used) // This improves convergence for many nonlinear problems, but not all. It may actually // cause divergence for some nonlinear problems. Therefore a flag is used to determine if // the stiffness should be evaluated before the residual (default yes). /ES //------------------------------------------------- // Compute external forces int numDofIdGroups = this->UnknownNumberingSchemeList.size(); FloatArray RRT(numDofIdGroups); for ( int dG = 0; dG < numDofIdGroups; dG++ ) { this->fExtList[dG].beSubArrayOf( RT, locArrayList[dG] ); RRT(dG) = this->fExtList[dG].computeSquaredNorm(); } int nStaggeredIter = 0; do { // Staggered iterations for ( int dG = 0; dG < (int)this->UnknownNumberingSchemeList.size(); dG++ ) { printf("\nSolving for dof group %d \n", dG+1); engngModel->updateComponent(tStep, NonLinearLhs, domain); this->stiffnessMatrixList[dG] = k.giveSubMatrix( locArrayList[dG], locArrayList[dG]); if ( this->prescribedDofsFlag ) { if ( !prescribedEqsInitFlag ) { this->initPrescribedEqs(); } applyConstraintsToStiffness(k); } nite = 0; do { // Compute the residual engngModel->updateComponent(tStep, InternalRhs, domain); RHS.beDifferenceOf(RT, F); this->fIntList[dG].beSubArrayOf( F, locArrayList[dG] ); rhs.beDifferenceOf(this->fExtList[dG], this->fIntList[dG]); RHS.zero(); RHS.assemble(rhs, locArrayList[dG]); if ( this->prescribedDofsFlag ) { this->applyConstraintsToLoadIncrement(nite, k, rhs, rlm, tStep); } // convergence check IntArray &idArray = UnknownNumberingSchemeList[dG].dofIdArray; converged = this->checkConvergenceDofIdArray(RT, F, RHS, ddXtotal, Xtotal, RRTtotal, internalForcesEBENorm, nite, errorOutOfRangeFlag, tStep, idArray); if ( errorOutOfRangeFlag ) { status = NM_NoSuccess; OOFEM_WARNING("Divergence reached after %d iterations", nite); break; } else if ( converged && ( nite >= minIterations ) ) { break; } else if ( nite >= nsmax ) { OOFEM_LOG_DEBUG("Maximum number of iterations reached\n"); break; } if ( nite > 0 || !mCalcStiffBeforeRes ) { if ( ( NR_Mode == nrsolverFullNRM ) || ( ( NR_Mode == nrsolverAccelNRM ) && ( nite % MANRMSteps == 0 ) ) ) { engngModel->updateComponent(tStep, NonLinearLhs, domain); this->stiffnessMatrixList[dG] = k.giveSubMatrix( locArrayList[dG], locArrayList[dG]); applyConstraintsToStiffness(*this->stiffnessMatrixList[dG]); } } if ( ( nite == 0 ) && ( deltaL < 1.0 ) ) { // deltaL < 1 means no increment applied, only equilibrate current state rhs.zero(); R.zero(); ddX[dG] = rhs; } else { status = linSolver->solve(*this->stiffnessMatrixList[dG], rhs, ddX[dG]); } // // update solution // if ( this->lsFlag && ( nite > 0 ) ) { // Why not nite == 0 ? // line search LineSearchNM :: LS_status LSstatus; double eta; this->giveLineSearchSolver()->solve( X[dG], ddX[dG], fIntList[dG], fExtList[dG], R0, prescribedEqs, 1.0, eta, LSstatus, tStep); } else if ( this->constrainedNRFlag && ( nite > this->constrainedNRminiter ) ) { if ( this->forceErrVec.computeSquaredNorm() > this->forceErrVecOld.computeSquaredNorm() ) { printf("Constraining increment to be %e times full increment...\n", this->constrainedNRalpha); ddX[dG].times(this->constrainedNRalpha); } } X[dG].add(ddX[dG]); dX[dG].add(ddX[dG]); // Update total solution (containing all dofs) Xtotal.assemble(ddX[dG], locArrayList[dG]); dXtotal.assemble(ddX[dG], locArrayList[dG]); ddXtotal.zero(); ddXtotal.assemble(ddX[dG], locArrayList[dG]); tStep->incrementStateCounter(); // update solution state counter tStep->incrementSubStepNumber(); nite++; // iteration increment engngModel->giveExportModuleManager()->doOutput(tStep, true); } while ( true ); // end of iteration } printf("\nStaggered iteration (all dof id's) \n"); // Check convergence of total system RHS.beDifferenceOf(RT, F); converged = this->checkConvergence(RT, F, RHS, ddXtotal, Xtotal, RRTtotal, internalForcesEBENorm, nStaggeredIter, errorOutOfRangeFlag); if ( converged && ( nStaggeredIter >= minIterations ) ) { break; } nStaggeredIter++; } while ( true ); // end of iteration status |= NM_Success; solved = 1; // Modify Load vector to include "quasi reaction" if ( R0 ) { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R.at( prescribedEqs.at(i) ) = F.at( prescribedEqs.at(i) ) - R0->at( prescribedEqs.at(i) ) - R.at( prescribedEqs.at(i) ); } } else { for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { R.at( prescribedEqs.at(i) ) = F.at( prescribedEqs.at(i) ) - R.at( prescribedEqs.at(i) ); } } this->lastReactions.resize(numberOfPrescribedDofs); #ifdef VERBOSE if ( numberOfPrescribedDofs ) { // print quasi reactions if direct displacement control used OOFEM_LOG_INFO("\n"); OOFEM_LOG_INFO("StaggeredSolver: Quasi reaction table \n"); OOFEM_LOG_INFO("StaggeredSolver: Node Dof Displacement Force\n"); double reaction; for ( int i = 1; i <= numberOfPrescribedDofs; i++ ) { reaction = R->at( prescribedEqs.at(i) ); if ( R0 ) { reaction += R0->at( prescribedEqs.at(i) ); } lastReactions.at(i) = reaction; OOFEM_LOG_INFO("StaggeredSolver: %-15d %-15d %-+15.5e %-+15.5e\n", prescribedDofs.at(2 * i - 1), prescribedDofs.at(2 * i), X.at( prescribedEqs.at(i) ), reaction); } OOFEM_LOG_INFO("\n"); } #endif return status; }
void AbaqusUserMaterial :: giveFirstPKStressVector_3d(FloatArray &answer, GaussPoint *gp, const FloatArray &vF, TimeStep *tStep) { AbaqusUserMaterialStatus *ms = static_cast< AbaqusUserMaterialStatus * >( this->giveStatus(gp) ); /* User-defined material name, left justified. Some internal material models are given names starting with * the “ABQ_” character string. To avoid conflict, you should not use “ABQ_” as the leading string for * CMNAME. */ //char cmname[80]; // Sizes of the tensors. int ndi = 3; int nshr = 3; int ntens = ndi + nshr; FloatArray stress(9); // PK1 FloatArray strainIncrement; // compute Green-Lagrange strain FloatArray strain; FloatArray vS; FloatMatrix F, E; F.beMatrixForm(vF); E.beTProductOf(F, F); E.at(1, 1) -= 1.0; E.at(2, 2) -= 1.0; E.at(3, 3) -= 1.0; E.times(0.5); strain.beSymVectorFormOfStrain(E); strainIncrement.beDifferenceOf(strain, ms->giveStrainVector()); FloatArray state = ms->giveStateVector(); FloatMatrix jacobian(9, 9); // dPdF int numProperties = this->properties.giveSize(); // Temperature and increment double temp = 0.0, dtemp = 0.0; // Times and increment double dtime = tStep->giveTimeIncrement(); ///@todo Check this. I'm just guessing. Maybe intrinsic time instead? double time [ 2 ] = { tStep->giveTargetTime() - dtime, tStep->giveTargetTime() }; double pnewdt = 1.0; ///@todo Right default value? umat routines may change this (although we ignore it) /* Specific elastic strain energy, plastic dissipation, and “creep” dissipation, respectively. These are passed * in as the values at the start of the increment and should be updated to the corresponding specific energy * values at the end of the increment. They have no effect on the solution, except that they are used for * energy output. */ double sse, spd, scd; // Outputs only in a fully coupled thermal-stress analysis: double rpl = 0.0; // Volumetric heat generation per unit time at the end of the increment caused by mechanical working of the material. FloatArray ddsddt(ntens); // Variation of the stress increments with respect to the temperature. FloatArray drplde(ntens); // Variation of RPL with respect to the strain increments. double drpldt = 0.0; // Variation of RPL with respect to the temperature. /* An array containing the coordinates of this point. These are the current coordinates if geometric * nonlinearity is accounted for during the step (see “Procedures: overview,” Section 6.1.1); otherwise, * the array contains the original coordinates of the point */ FloatArray coords; gp->giveElement()->computeGlobalCoordinates( coords, gp->giveNaturalCoordinates() ); ///@todo Large deformations? /* Rotation increment matrix. This matrix represents the increment of rigid body rotation of the basis * system in which the components of stress (STRESS) and strain (STRAN) are stored. It is provided so * that vector- or tensor-valued state variables can be rotated appropriately in this subroutine: stress and * strain components are already rotated by this amount before UMAT is called. This matrix is passed in * as a unit matrix for small-displacement analysis and for large-displacement analysis if the basis system * for the material point rotates with the material (as in a shell element or when a local orientation is used).*/ FloatMatrix drot(3, 3); drot.beUnitMatrix(); /* Characteristic element length, which is a typical length of a line across an element for a first-order * element; it is half of the same typical length for a second-order element. For beams and trusses it is a * characteristic length along the element axis. For membranes and shells it is a characteristic length in * the reference surface. For axisymmetric elements it is a characteristic length in the * plane only. * For cohesive elements it is equal to the constitutive thickness.*/ double celent = 0.0; /// @todo Include the characteristic element length /* Array containing the deformation gradient at the beginning of the increment. See the discussion * regarding the availability of the deformation gradient for various element types. */ FloatMatrix dfgrd0(3, 3); /* Array containing the deformation gradient at the end of the increment. The components of this array * are set to zero if nonlinear geometric effects are not included in the step definition associated with * this increment. See the discussion regarding the availability of the deformation gradient for various * element types. */ FloatMatrix dfgrd1(3, 3); dfgrd0.beMatrixForm( ms->giveFVector() ); dfgrd1.beMatrixForm(vF); int noel = gp->giveElement()->giveNumber(); // Element number. int npt = 0; // Integration point number. // We intentionally ignore the layer number since that is handled by the layered cross-section in OOFEM. int layer = 0; // Layer number (for composite shells and layered solids).. int kspt = 0; // Section point number within the current layer. int kstep = tStep->giveMetaStepNumber(); // Step number. int kinc = 0; // Increment number. ///@todo No idea about these parameters double predef; double dpred; // Change to Abaqus's component order stress.changeComponentOrder(); strain.changeComponentOrder(); strainIncrement.changeComponentOrder(); OOFEM_LOG_DEBUG("AbaqusUserMaterial :: giveRealStressVector - Calling subroutine"); this->umat(stress.givePointer(), // STRESS state.givePointer(), // STATEV jacobian.givePointer(), // DDSDDE & sse, // SSE & spd, // SPD & scd, // SCD & rpl, // RPL ddsddt.givePointer(), // DDSDDT drplde.givePointer(), // DRPLDE & drpldt, // DRPLDT strain.givePointer(), // STRAN strainIncrement.givePointer(), // DSTRAN time, // TIME & dtime, // DTIME & temp, // TEMP & dtemp, // DTEMP & predef, // PREDEF & dpred, // DPRED this->cmname, // CMNAME & ndi, // NDI & nshr, // NSHR & ntens, // NTENS & numState, // NSTATV properties.givePointer(), // PROPS & numProperties, // NPROPS coords.givePointer(), // COORDS drot.givePointer(), // DROT & pnewdt, // PNEWDT & celent, // CELENT dfgrd0.givePointer(), // DFGRD0 dfgrd1.givePointer(), // DFGRD1 & noel, // NOEL & npt, // NPT & layer, // LAYER & kspt, // KSPT & kstep, // KSTEP & kinc); // KINC // Change to OOFEM's component order stress.changeComponentOrder(); strain.changeComponentOrder(); strainIncrement.changeComponentOrder(); jacobian.changeComponentOrder(); if ( mStressInterpretation == 0 ) { FloatMatrix P, cauchyStress; P.beMatrixForm(stress); FloatArray vP; vP.beVectorForm(P); cauchyStress.beProductTOf(P, F); cauchyStress.times( 1.0 / F.giveDeterminant() ); FloatArray vCauchyStress; vCauchyStress.beSymVectorForm(cauchyStress); ms->letTempStrainVectorBe(strain); ms->letTempStressVectorBe(vCauchyStress); ms->letTempStateVectorBe(state); ms->letTempTangentBe(jacobian); ms->letTempPVectorBe(vP); ms->letTempFVectorBe(vF); answer = vP; } else { FloatArray vP; FloatMatrix P, sigma, F_inv; F_inv.beInverseOf(F); sigma.beMatrixForm(stress); P.beProductOf(F, sigma); vP.beVectorForm(P); answer = vP; // Convert from sigma to S FloatMatrix S; S.beProductOf(F_inv, P); vS.beSymVectorForm(S); // @todo Should convert from dsigmadE to dSdE here // L2=detF*matmul( matmul ( inv(op_a_V9(F,F), cm-op_a_V9(ident,Tau)-op_b_V9(Tau,ident) ), inv(op_a_V9(Ft,Ft))) ms->letTempStrainVectorBe(strain); ms->letTempStressVectorBe(vS); ms->letTempStateVectorBe(state); ms->letTempTangentBe(jacobian); ms->letTempPVectorBe(vP); ms->letTempFVectorBe(vF); } OOFEM_LOG_DEBUG("AbaqusUserMaterial :: giveRealStressVector_3d - Calling subroutine was successful"); }
int CompCol :: buildInternalStructure(EngngModel *eModel, int di, EquationID ut, const UnknownNumberingScheme &s) { /* * IntArray loc; * Domain* domain = eModel->giveDomain(di); * int neq = eModel -> giveNumberOfDomainEquations (di); * int nelem = domain -> giveNumberOfElements() ; * int i,ii,j,jj,n, indx; * Element* elem; * // allocation map * char* map = new char[neq*neq]; * if (map == NULL) { * printf ("CompCol::buildInternalStructure - map creation failed"); * exit (1); * } * * for (i=0; i<neq*neq; i++) * map[i]=0; * * * this->nz_ = 0; * * for (n=1 ; n<=nelem ; n++) { * elem = domain -> giveElement(n); * elem -> giveLocationArray (loc) ; * * for (i=1 ; i <= loc.giveSize() ; i++) { * if ((ii = loc.at(i))) { * for (j=1; j <= loc.giveSize() ; j++) { * if ((jj=loc.at(j))) { * if (map[(ii-1)*neq+jj-1] == 0) { * map[(ii-1)*neq+jj-1] = 1; * this->nz_ ++; * } * } * } * } * } * } * * rowind_.resize (nz_); * colptr_.resize (neq+1); * indx = 0; * for (j=0; j<neq; j++) { // column loop * colptr_(j) = indx; * for (i=0; i<neq; i++) { // row loop * if (map[i*neq+j]) { * rowind_(indx) = i; * indx++; * } * } * } * colptr_(neq) = indx; * * // delete map * delete (map); * * // allocate value array * val_.resize(nz_); * val_.zero(); * * printf ("\nCompCol info: neq is %d, nwk is %d\n",neq,nz_); * * dim_[0] = dim_[1] = nColumns = nRows = neq; * * // increment version * this->version++; * * return true; */ IntArray loc; Domain *domain = eModel->giveDomain(di); int neq = eModel->giveNumberOfDomainEquations(di, ut); int nelem = domain->giveNumberOfElements(); int i, ii, j, jj, n, indx; Element *elem; // allocation map std :: vector< std :: set< int > >columns(neq); /* * std::set<int> **columns = new std::set<int>*[neq]; * for (j=0; j<neq; j++) { * columns[j] = new std::set<int>; * } */ this->nz_ = 0; for ( n = 1; n <= nelem; n++ ) { elem = domain->giveElement(n); elem->giveLocationArray(loc, ut, s); for ( i = 1; i <= loc.giveSize(); i++ ) { if ( ( ii = loc.at(i) ) ) { for ( j = 1; j <= loc.giveSize(); j++ ) { if ( ( jj = loc.at(j) ) ) { columns [ jj - 1 ].insert(ii - 1); } } } } } for ( i = 0; i < neq; i++ ) { this->nz_ += columns [ i ].size(); } rowind_.resize(nz_); colptr_.resize(neq + 1); indx = 0; std :: set< int > :: iterator pos; for ( j = 0; j < neq; j++ ) { // column loop colptr_(j) = indx; for ( pos = columns [ j ].begin(); pos != columns [ j ].end(); ++pos ) { // row loop rowind_(indx++) = * pos; } } colptr_(neq) = indx; /* * // delete map * for (i=0; i< neq; i++) {columns[i]->clear(); delete columns[i];} * delete columns; */ // allocate value array val_.resize(nz_); val_.zero(); OOFEM_LOG_DEBUG("CompCol info: neq is %d, nwk is %d\n", neq, nz_); dim_ [ 0 ] = dim_ [ 1 ] = nColumns = nRows = neq; // increment version this->version++; return true; }
void DDLinearStatic :: solveYourselfAt(TimeStep *tStep) { /** * Perform DD * Currently this is completely specific, but needs to be generalized * by perhaps creating an DD_interface class to do set of functions */ /**************************************************************************/ int NumberOfDomains = this->giveNumberOfDomains(); // Loop through all the giveNumberOfDomains for (int i = 1; i<= NumberOfDomains; i++) { //Domain *domain = this->giveDomain(i); /// Create a spatial localizer which in effect has services for locating points in element etc. //SpatialLocalizer *sl = domain->giveSpatialLocalizer(); // Perform DD solution at this time step, solution will depend on quantities in the input file /// @todo these have to be defined and initialized earlier /// Each domain for the DD case can have only one material... throw error otherwise //// Also the DD_domains should be intialized with these materials properties during input //// Here i am just using values from input file for algorithmic convenience /* dd::OofemInterface * interface = new dd::OofemInterface(this); */ dd::Domain dd_domain(70e-3, 0.3, NULL); dd::SlipSystem ss0 = dd::SlipSystem(0.0, 0.25e-3); dd_domain.addSlipSystem(&ss0); dd::SlipPlane sp0 = dd::SlipPlane(&dd_domain, &ss0, 0.0); dd::ObstaclePoint o0 = dd::ObstaclePoint(&dd_domain, &sp0, -0.25, 20.0e3); dd::ObstaclePoint o1 = dd::ObstaclePoint(&dd_domain, &sp0, 0.25, 20.0e3); double e = dd_domain.getModulus(); double nu = dd_domain.getPassionsRatio(); double mu = e / (2. * ( 1. + nu)); double fact = mu * ss0.getBurgersMagnitude() / ( 2 * M_PI * (1. - nu)); dd::SourcePoint s1 = dd::SourcePoint(&dd_domain, &sp0, 0, 25e-6, fact / 25e-6); for( dd_domain.dtNo = 1; dd_domain.dtNo < dd_domain.dtNomax; dd_domain.dtNo++) { std::cerr << "Total dislocs in domain: " << sp0.getContainer<dd::DislocationPoint>().size() << "\n"; std::cerr << "Dislocs: " << sp0.dumpToString<dd::DislocationPoint>() << "\n"; std::cerr.flush(); dd_domain.updateForceCaches(); for(auto point : dd_domain.getContainer<dd::DislocationPoint>()) { dd::Vector<2> force, forceGradient; dd::Vector<3> stress; force = dd::Vector<2>({0.0,0.0}); //point->sumCaches(force, forceGradient, stress); force = point->cachedForce(); stress = point->cachedStress(); std::cout << "Cached Force at " << point->slipPlanePosition() << ": " << point->getBurgersSign() << " " << force[0] << " " << stress[2] << " " << point->slipPlanePosition() << "\n"; } dd_domain.updateForceCaches(); dd_domain.moveDislocations(1.0e-11, 1.0e-18); s1.spawn(1, 5); /* for(int bcNo = 1; bcNo <= giveDomain(i)->giveNumberOfBoundaryConditions(); bcNo++) { ManualBoundaryCondition * bc = dynamic_cast<ManualBoundaryCondition *>(giveDomain(i)->giveBc(bcNo)); if(bc == nullptr || bc->giveType() != DirichletBT) { continue; } dd::Vector<2> bcContribution; Domain * d = bc->giveDomain(); Set * set = d->giveSet(bc->giveSetNumber()); for(int nodeNo : set->giveNodeList()) { Node * node = static_cast<Node *>(d->giveDofManager(nodeNo)); for (auto &dofid : bc->giveDofIDs()) { Dof * dof = node->giveDofWithID(dofid); interface->giveNodalBcContribution(node, bcContribution); // TODO: Determine the dimensions without pointer checking double toAdd; if(dof->giveDofID() == D_u) { toAdd = bcContribution[0]; } else if(dof->giveDofID() == D_v) { toAdd = bcContribution[1]; } else { OOFEM_ERROR("DOF must be x-disp or y-disp"); } bc->addManualValue(dof, toAdd); } } std::cout << "BC Contribution: " << bcContribution[0] << " " << bcContribution[1] << "\n"; } */ //delete interface; } // end dtNo loop } /**************************************************************************/ // // 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_DEBUG("Assembling stiffness matrix\n"); #endif // // first step assemble stiffness Matrix // stiffnessMatrix.reset( classFactory.createSparseMtrx(sparseMtrxType) ); if ( !stiffnessMatrix ) { OOFEM_ERROR("sparse matrix creation failed"); } stiffnessMatrix->buildInternalStructure( this, 1, EModelDefaultEquationNumbering() ); this->assemble( *stiffnessMatrix, tStep, TangentAssembler(TangentStiffness), EModelDefaultEquationNumbering(), this->giveDomain(1) ); initFlag = 0; } #ifdef VERBOSE OOFEM_LOG_DEBUG("Assembling load\n"); #endif // // allocate space for displacementVector // displacementVector.resize( this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ) ); displacementVector.zero(); // // assembling the load vector // loadVector.resize( this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ) ); loadVector.zero(); this->assembleVector( loadVector, tStep, ExternalForceAssembler(), VM_Total, EModelDefaultEquationNumbering(), this->giveDomain(1) ); // // internal forces (from Dirichlet b.c's, or thermal expansion, etc.) // FloatArray internalForces( this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ) ); internalForces.zero(); this->assembleVector( internalForces, tStep, InternalForceAssembler(), VM_Total, EModelDefaultEquationNumbering(), this->giveDomain(1) ); loadVector.subtract(internalForces); this->updateSharedDofManagers(loadVector, EModelDefaultEquationNumbering(), ReactionExchangeTag); // // set-up numerical model // this->giveNumericalMethod( this->giveMetaStep( tStep->giveMetaStepNumber() ) ); // // call numerical model to solve arose problem // #ifdef VERBOSE OOFEM_LOG_INFO("\n\nSolving ...\n\n"); #endif NM_Status s = nMethod->solve(*stiffnessMatrix, loadVector, displacementVector); if ( !( s & NM_Success ) ) { OOFEM_ERROR("No success in solving system."); } tStep->incrementStateCounter(); // update solution state counter }
NM_Status LineSearchNM :: solve(FloatArray *r, FloatArray *dr, FloatArray *F, FloatArray *R, FloatArray *R0, IntArray &eqnmask, double lambda, double &etaValue, LS_status &status, TimeStep *tNow) { int ico, ii, ils, neq = r->giveSize(); double s0, si; FloatArray g(neq), rb(neq); // Compute inner product at start and stop if positive g = * R; g.times(lambda); if ( R0 ) { g.add(*R0); } g.subtract(*F); for ( ii = 1; ii <= eqnmask.giveSize(); ii++ ) { g.at( eqnmask.at(ii) ) = 0.0; } s0 = ( -1.0 ) * g.dotProduct(* dr); if ( s0 >= 0.0 ) { //printf ("\nLineSearchNM::solve starting inner product uphill, val=%e",s0); OOFEM_LOG_DEBUG("LS: product uphill, eta=%e\n", 1.0); r->add(*dr); tNow->incrementStateCounter(); // update solution state counter engngModel->updateComponent(tNow, InternalRhs, domain); etaValue = 1.0; status = ls_ok; return NM_Success; } // keep original total displacement r rb = * r; eta.resize(this->max_iter + 1); prod.resize(this->max_iter + 1); // prepare starting product ratios and step lengths prod.at(1) = 1.0; eta.at(1) = 0.0; eta.at(2) = 1.0; // following counter shows how many times the max or min step length has been reached ico = 0; // begin line search loop for ( ils = 2; ils <= this->max_iter; ils++ ) { // update displacements for ( ii = 1; ii <= neq; ii++ ) { r->at(ii) = rb.at(ii) + this->eta.at(ils) * dr->at(ii); } tNow->incrementStateCounter(); // update solution state counter // update internal forces according to new state engngModel->updateComponent(tNow, InternalRhs, domain); // compute out-of balance forces g in new state g = * R; g.times(lambda); if ( R0 ) { g.add(*R0); } g.subtract(*F); for ( ii = 1; ii <= eqnmask.giveSize(); ii++ ) { g.at( eqnmask.at(ii) ) = 0.0; } // compute current inner-product ratio si = ( -1.0 ) * g.dotProduct(*dr) / s0; prod.at(ils) = si; // check if line-search tolerance is satisfied if ( fabs(si) < ls_tolerance ) { dr->times( this->eta.at(ils) ); //printf ("\nLineSearchNM::solve tolerance satisfied for eta=%e, ils=%d", eta.at(ils),ils); OOFEM_LOG_DEBUG( "LS: ils=%d, eta=%e\n", ils, eta.at(ils) ); etaValue = eta.at(ils); status = ls_ok; return NM_Success; } // call line-search routine to get new estimate of eta.at(ils) this->search(ils, prod, eta, this->amplifFactor, this->maxEta, this->minEta, ico); if ( ico == 2 ) { break; // exit the loop } } // end line search loop // exceeded no of ls iterations of ls failed //if (ico == 2) printf("\nLineSearchNM::solve max or min step length has been reached two times"); //else printf("\nLineSearchNM::solve reached max number of ls searches"); OOFEM_LOG_DEBUG( "LS: ils=%d, ico=%d, eta=%e\n", ils, ico, eta.at(ils) ); /* update F before */ for ( ii = 1; ii <= neq; ii++ ) { r->at(ii) = rb.at(ii) + dr->at(ii); } tNow->incrementStateCounter(); // update solution state counter engngModel->updateComponent(tNow, InternalRhs, domain); etaValue = 1.0; status = ls_failed; return NM_NoSuccess; }
SparseMtrx *Skyline :: factorized() { // Returns the receiver in U(transp).D.U Crout factorization form. int i, j, k, aci, aci1, acj, acj1, ack, ack1, ac, acs, acri, acrk, n; double s, g; #ifdef TIME_REPORT //clock_t tstart = clock(); oofem_timeval tstart; getUtime(tstart); #endif /************************/ /* matrix elimination */ /************************/ if ( isFactorized ) { return this; } n = this->giveNumberOfRows(); // report skyline statistics OOFEM_LOG_DEBUG("Skyline info: neq is %d, nwk is %d\n", n, this->nwk); for ( k = 2; k <= n; k++ ) { /* smycka pres sloupce matice */ ack = adr->at(k); ack1 = adr->at(k + 1); acrk = k - ( ack1 - ack ) + 1; for ( i = acrk + 1; i < k; i++ ) { /* smycka pres prvky jednoho sloupce matice */ aci = adr->at(i); aci1 = adr->at(i + 1); acri = i - ( aci1 - aci ) + 1; if ( acri < acrk ) { ac = acrk; } else { ac = acri; } acj = k - ac + ack; acj1 = k - i + ack; acs = i - ac + aci; s = 0.0; for ( j = acj; j > acj1; j-- ) { s += mtrx [ j ] * mtrx [ acs ]; acs--; } mtrx [ acj1 ] -= s; } /* uprava diagonalniho prvku */ s = 0.0; for ( i = ack1 - 1; i > ack; i-- ) { g = mtrx [ i ]; acs = adr->at(acrk); acrk++; mtrx [ i ] /= mtrx [ acs ]; s += mtrx [ i ] * g; } mtrx [ ack ] -= s; } isFactorized = true; #ifdef TIME_REPORT //printf ("Skyline info: user time consumed by factorization: %.2lfs\n", (clock()-tstart)/(double)CLOCKS_PER_SEC); oofem_timeval ut; getRelativeUtime(ut, tstart); OOFEM_LOG_DEBUG( "Skyline info: user time consumed by factorization: %.2fs\n", ( double ) ( ut.tv_sec + ut.tv_usec / ( double ) OOFEM_USEC_LIM ) ); #endif // increment version //this->version++; return this; }