IRResultType RCSDNLMaterial :: initializeFrom(InputRecord *ir) { IRResultType result; // Required by IR_GIVE_FIELD macro //RCSDEMaterial::instanciateFrom (ir); result = this->giveLinearElasticMaterial()->initializeFrom(ir); if ( result != IRRT_OK ) return result; result = StructuralNonlocalMaterialExtensionInterface :: initializeFrom(ir); if ( result != IRRT_OK ) return result; IR_GIVE_FIELD(ir, Ft, _IFT_RCSDNLMaterial_ft); IR_GIVE_FIELD(ir, SDTransitionCoeff, _IFT_RCSDNLMaterial_sdtransitioncoeff); IR_GIVE_FIELD(ir, SDTransitionCoeff2, _IFT_RCSDNLMaterial_sdtransitioncoeff2); if ( SDTransitionCoeff2 > 1.0 ) { SDTransitionCoeff2 = 1.0; } if ( SDTransitionCoeff2 < 0.0 ) { SDTransitionCoeff2 = 0.0; } IR_GIVE_FIELD(ir, R, _IFT_RCSDNLMaterial_r); if ( R < 0.0 ) { R = 0.0; } if ( ir->hasField(_IFT_RCSDNLMaterial_ef) ) { // if ef is specified, Gf is computed acordingly IR_GIVE_FIELD(ir, this->ef, _IFT_RCSDNLMaterial_ef); this->Gf = this->Ft * this->ef; } else if ( ir->hasField(_IFT_RCSDNLMaterial_gf) ) { // otherwise if Gf is specified, ef is computed acordingly IR_GIVE_FIELD(ir, this->Gf, _IFT_RCSDNLMaterial_gf); this->ef = this->Gf / this->Ft; } else { OOFEM_WARNING("cannot determine Gf and ef from input data"); return IRRT_BAD_FORMAT; } return IRRT_OK; }
void MPSDamMaterial :: initDamaged(double kappa, FloatArray &principalDirection, GaussPoint *gp, TimeStep *tStep) { double le = 0.; MPSDamMaterialStatus *status = static_cast< MPSDamMaterialStatus * >( this->giveStatus(gp) ); if ( this->timeDepFracturing ) { this->initDamagedFib(gp, tStep); } double e0 = this->givee0(gp); double gf = this->givegf(gp); double wf = 0.; if ( softType == ST_Disable_Damage ) { return; } else if ( softType == ST_Exponential_Cohesive_Crack ) { // exponential softening wf = gf / E / e0; // wf is the crack opening } else if ( softType == ST_Linear_Cohesive_Crack ) { // linear softening law wf = 2. * gf / E / e0; // wf is the crack opening } else { OOFEM_ERROR("Gf unsupported for softening type softType = %d", softType); } if ( ( kappa > e0 ) && ( status->giveDamage() == 0. ) ) { status->setCrackVector(principalDirection); le = gp->giveElement()->giveCharacteristicSize(gp, principalDirection, ecsMethod); status->setCharLength(le); if ( gf != 0. && e0 >= ( wf / le ) ) { // case for a given fracture energy OOFEM_WARNING("Fracturing strain %e is lower than the elastic strain e0=%e, possible snap-back. Element number %d, wf %e, le %e. Increase fracturing strain or decrease element size by at least %f", wf / le, e0, gp->giveElement()->giveLabel(), wf, le, e0/(wf/le) ); if ( checkSnapBack ) { OOFEM_ERROR(""); } } } }
IRResultType IMLSolver :: initializeFrom(InputRecord *ir) { IRResultType result; // Required by IR_GIVE_FIELD macro int val; val = 0; IR_GIVE_OPTIONAL_FIELD(ir, val, _IFT_IMLSolver_stype); solverType = ( IMLSolverType ) val; tol = 1.e-5; IR_GIVE_OPTIONAL_FIELD(ir, tol, _IFT_IMLSolver_lstol); maxite = 200; IR_GIVE_OPTIONAL_FIELD(ir, maxite, _IFT_IMLSolver_lsiter); val = 0; IR_GIVE_OPTIONAL_FIELD(ir, val, _IFT_IMLSolver_lsprecond); precondType = ( IMLPrecondType ) val; // create preconditioner if ( precondType == IML_DiagPrec ) { M = new DiagPreconditioner(); } else if ( precondType == IML_VoidPrec ) { M = new VoidPreconditioner(); } else if ( precondType == IML_ILU_CompRowPrec ) { M = new CompRow_ILUPreconditioner(); } else if ( precondType == IML_ILU_CompColPrec ) { M = new CompCol_ILUPreconditioner(); } else if ( precondType == IML_ICPrec ) { M = new CompCol_ICPreconditioner(); } else { OOFEM_WARNING("unknown preconditioner type"); return IRRT_BAD_FORMAT; } // initialize precond attributes return M->initializeFrom(ir); }
int MPIBuffer :: packArray(MPI_Comm communicator, const void *src, int n, MPI_Datatype type) { int _size; // ask MPI for packing size for integer _size = this->givePackSize(communicator, type, n); if ( ( this->curr_pos + _size > this->size ) ) { // reallocate itself if ( isDynamic ) { if ( this->resize(this->curr_pos + _size + __CommunicationBuffer_ALLOC_CHUNK) == 0 ) { return 0; } } else { OOFEM_WARNING("CommunicationBuffer :: packIntArray: Resize requested in static mode"); return 0; } } void *__src = const_cast< void * >(src); // throw away const return ( MPI_Pack(__src, n, type, this->buff, this->size, & this->curr_pos, communicator) == MPI_SUCCESS ); }
IRResultType IntElPoint :: initializeFrom(InputRecord *ir) { IRResultType result; // Required by IR_GIVE_FIELD macro result = StructuralInterfaceElement :: initializeFrom(ir); if ( result != IRRT_OK ) { return result; } if ( ir->hasField(_IFT_IntElPoint_refnode) && ir->hasField(_IFT_IntElPoint_normal) ) { OOFEM_WARNING("Ambiguous input: 'refnode' and 'normal' cannot both be specified"); return IRRT_BAD_FORMAT; } IR_GIVE_OPTIONAL_FIELD(ir, referenceNode, _IFT_IntElPoint_refnode); IR_GIVE_OPTIONAL_FIELD(ir, normal, _IFT_IntElPoint_normal); this->area = 1.0; // Default area ///@todo Make non-optional? /JB IR_GIVE_OPTIONAL_FIELD(ir, this->area, _IFT_IntElPoint_area); this->computeLocalSlipDir(normal); return IRRT_OK; }
int StructuralEngngModel :: checkConsistency() { Domain *domain = this->giveDomain(1); int nelem = domain->giveNumberOfElements(); // check for proper element type for ( int i = 1; i <= nelem; i++ ) { Element *ePtr = domain->giveElement(i); StructuralElement *sePtr = dynamic_cast< StructuralElement * >(ePtr); StructuralInterfaceElement *siePtr = dynamic_cast< StructuralInterfaceElement * >(ePtr); StructuralElementEvaluator *see = dynamic_cast< StructuralElementEvaluator * >(ePtr); if ( sePtr == NULL && see == NULL && siePtr == NULL ) { OOFEM_WARNING("element %d has no Structural support", i); return 0; } } EngngModel :: checkConsistency(); return 1; }
int NonStationaryTransportProblem :: checkConsistency() { // check internal consistency // if success returns nonzero int nelem; Domain *domain = this->giveDomain(1); nelem = domain->giveNumberOfElements(); // check for proper element type for ( int i = 1; i <= nelem; i++ ) { Element *ePtr = domain->giveElement(i); TransportElement *sePtr = dynamic_cast< TransportElement * >(ePtr); if ( sePtr == NULL ) { OOFEM_WARNING("Element %d has no TransportElement base", ePtr->giveNumber()); return 0; } } EngngModel :: checkConsistency(); return 1; }
IRResultType Beam2d :: initializeFrom(InputRecord *ir) { IRResultType result; // Required by IR_GIVE_FIELD macro // first call parent BeamBaseElement :: initializeFrom(ir); if ( ir->hasField(_IFT_Beam2d_dofstocondense) ) { IntArray val; IR_GIVE_FIELD(ir, val, _IFT_Beam2d_dofstocondense); if ( val.giveSize() >= 6 ) { OOFEM_WARNING("wrong input data for condensed dofs"); return IRRT_BAD_FORMAT; } DofIDItem mask[] = { D_u, D_w, R_v }; this->numberOfCondensedDofs = val.giveSize(); for ( int i = 1; i <= val.giveSize(); i++ ) { if ( val.at(i) <= 3 ) { if ( ghostNodes [ 0 ] == NULL ) { ghostNodes [ 0 ] = new ElementDofManager(1, giveDomain(), this); } ghostNodes [ 0 ]->appendDof( new MasterDof(ghostNodes [ 0 ], mask [ val.at(i) - 1 ]) ); } else { if ( ghostNodes [ 1 ] == NULL ) { ghostNodes [ 1 ] = new ElementDofManager(1, giveDomain(), this); } ghostNodes [ 1 ]->appendDof( new MasterDof(ghostNodes [ 1 ], mask [ val.at(i) - 4 ]) ); } } } return IRRT_OK; }
void StructuralMaterialEvaluator :: solveYourself() { Domain *d = this->giveDomain(1); MaterialMode mode = _3dMat; FloatArray initialStrain(6); gps.clear(); gps.reserve(d->giveNumberOfMaterialModels()); for ( int i = 1; i <= d->giveNumberOfMaterialModels(); i++ ) { std :: unique_ptr< GaussPoint > gp = std::make_unique<GaussPoint>(nullptr, i, FloatArray(0), 1, mode); gps.emplace_back( std :: move(gp) ); // Initialize the strain vector; StructuralMaterialStatus *status = static_cast< StructuralMaterialStatus * >( d->giveMaterial(i)->giveStatus( gps[i-1].get() ) ); status->letStrainVectorBe(initialStrain); } std :: string outname = this->giveOutputBaseFileName() + ".matdata"; this->outfile.open( outname.c_str() ); this->timer.startTimer(EngngModelTimer :: EMTT_AnalysisTimer); TimeStep *tStep = giveNextStep(); // Note, strain == strain-rate (kept as strain for brevity) int maxiter = 100; // User input? FloatArray stressC, deltaStrain, strain, stress, res; stressC.resize( sControl.giveSize() ); res.resize( sControl.giveSize() ); FloatMatrix tangent, reducedTangent; for ( int istep = 1; istep <= this->numberOfSteps; ++istep ) { this->timer.startTimer(EngngModelTimer :: EMTT_SolutionStepTimer); for ( int imat = 1; imat <= d->giveNumberOfMaterialModels(); ++imat ) { GaussPoint *gp = gps[imat-1].get(); StructuralMaterial *mat = static_cast< StructuralMaterial * >( d->giveMaterial(imat) ); StructuralMaterialStatus *status = static_cast< StructuralMaterialStatus * >( mat->giveStatus(gp) ); strain = status->giveStrainVector(); // Update the controlled parts for ( int j = 1; j <= eControl.giveSize(); ++j ) { int p = eControl.at(j); strain.at(p) = d->giveFunction( cmpntFunctions.at(p) )->evaluateAtTime( tStep->giveIntrinsicTime() ); } for ( int j = 1; j <= sControl.giveSize(); ++j ) { int p = sControl.at(j); stressC.at(j) = d->giveFunction( cmpntFunctions.at(p) )->evaluateAtTime( tStep->giveIntrinsicTime() ); } //strain.add(-100, {6.27e-06, 6.27e-06, 6.27e-06, 0, 0, 0}); for ( int iter = 1; iter < maxiter; iter++ ) { #if 0 // Debugging: mat->give3dMaterialStiffnessMatrix(tangent, TangentStiffness, gp, tStep); tangent.printYourself("# tangent"); strain.zero(); mat->giveRealStressVector_3d(stress, gp, strain, tStep); FloatArray strain2; tangent.solveForRhs(stress, strain2); strain2.printYourself("# thermal expansion"); break; #endif strain.printYourself("Macro strain guess"); mat->giveRealStressVector_3d(stress, gp, strain, tStep); for ( int j = 1; j <= sControl.giveSize(); ++j ) { res.at(j) = stressC.at(j) - stress.at( sControl.at(j) ); } OOFEM_LOG_INFO("*** Time step: %d (t = %.2e), Material %d, Iteration: %d, Residual = %e (tolerance %.2e)\n", istep, tStep->giveIntrinsicTime(), imat, iter, res.computeNorm(), tolerance); if ( res.computeNorm() <= tolerance ) { break; } else { if ( tangent.giveNumberOfRows() == 0 || !keepTangent ) { mat->give3dMaterialStiffnessMatrix(tangent, TangentStiffness, gp, tStep); } // Pick out the stress-controlled part; reducedTangent.beSubMatrixOf(tangent, sControl, sControl); // Update stress-controlled part of the strain reducedTangent.solveForRhs(res, deltaStrain); //deltaStrain.printYourself("deltaStrain"); for ( int j = 1; j <= sControl.giveSize(); ++j ) { strain.at( sControl.at(j) ) += deltaStrain.at(j); } } } if ( res.computeNorm() > tolerance ) { OOFEM_WARNING("Residual did not converge!"); } // This material model has converged, so we update it and go on to the next. gp->updateYourself(tStep); } this->timer.stopTimer(EngngModelTimer :: EMTT_SolutionStepTimer); this->doStepOutput(tStep); tStep = giveNextStep(); } this->timer.stopTimer(EngngModelTimer :: EMTT_AnalysisTimer); this->outfile.close(); }
void QWedge_ht :: NodalAveragingRecoveryMI_computeNodalValue(FloatArray &answer, int node, InternalStateType type, TimeStep *tStep) { answer.clear(); OOFEM_WARNING("IP values will not be transferred to nodes. Use ZZNodalRecovery instead (parameter stype 1)"); }
void LineSurfaceTension :: computeTangent(FloatMatrix &answer, TimeStep *tStep) { #if 1 ///@todo Not sure if it's a good idea to use this tangent. answer.resize(4,4); answer.zero(); #else domainType dt = this->giveDomain()->giveDomainType(); int ndofs = this->computeNumberOfDofs(EID_MomentumBalance); Node *node1, *node2; double x1, x2, y1, y2, dx, dy, vx, vy, length, width, gamma_s; gamma_s = this->giveMaterial()->give('g',NULL); node1 = giveNode(1); node2 = giveNode(2); x1 = node1->giveCoordinate(1); x2 = node2->giveCoordinate(1); y1 = node1->giveCoordinate(2); y2 = node2->giveCoordinate(2); dx = x2-x1; dy = y2-y1; length = sqrt(dx*dx + dy*dy); vx = dx/length; vy = dy/length; FloatArray Ah(4); Ah.at(1) = -vx; Ah.at(2) = -vy; Ah.at(3) = vx; Ah.at(4) = vy; FloatMatrix NpTNp(4,4); NpTNp.zero(); NpTNp.at(1,1) = 1; NpTNp.at(2,2) = 1; NpTNp.at(3,3) = 1; NpTNp.at(4,4) = 1; NpTNp.at(1,3) = -1; NpTNp.at(2,4) = -1; NpTNp.at(3,1) = -1; NpTNp.at(4,2) = -1; answer.resize(ndofs,ndofs); answer.zero(); if (dt == _3dAxisymmMode) { OOFEM_WARNING("Not tested"); FloatArray Bh(4); Bh.zero(); Bh.at(1) = 1; Bh.at(3) = 1; // It was simpler to write this in index notation. // Also using 0-based, to reduce typing double rJinv = (x1+x2)/length; answer.zero(); for (int i = 0; i < 4; i++) for (int j = 0; j < 4; j++) { answer(i,j) = M_PI*(Ah(i)*Bh(j) + Bh(i)*Ah(j)+ rJinv*(NpTNp(i,j) - Ah(i)*Ah(j))); } } else { width = 1; answer.beDyadicProductOf(Ah,Ah); answer.add(NpTNp); answer.times(width/length); } answer.times(gamma_s); #endif }
void Quad1MindlinShell3D :: computeBmatrixAt(GaussPoint *gp, FloatMatrix &answer, int li, int ui) { FloatArray n, ns; FloatMatrix dn, dns; const FloatArray &localCoords = gp->giveNaturalCoordinates(); this->interp.evaldNdx( dn, localCoords, FEIVertexListGeometryWrapper(lnodes) ); this->interp.evalN( n, localCoords, FEIVoidCellGeometry() ); answer.resize(8, 4 * 5); answer.zero(); // enforce one-point reduced integration if requested if ( this->reducedIntegrationFlag ) { FloatArray lc(2); lc.zero(); // set to element center coordinates this->interp.evaldNdx( dns, lc, FEIVertexListGeometryWrapper(lnodes) ); this->interp.evalN( ns, lc, FEIVoidCellGeometry() ); } else { dns = dn; ns = n; } // Note: This is just 5 dofs (sixth column is all zero, torsional stiffness handled separately.) for ( int i = 0; i < 4; ++i ) { ///@todo Check the rows for both parts here, to be consistent with _3dShell material definition // Part related to the membrane (columns represent coefficients for D_u, D_v) answer(0, 0 + i * 5) = dn(i, 0);//eps_x = du/dx answer(1, 1 + i * 5) = dn(i, 1);//eps_y = dv/dy answer(2, 0 + i * 5) = dn(i, 1);//gamma_xy = du/dy+dv/dx answer(2, 1 + i * 5) = dn(i, 0); // Part related to the plate (columns represent the dofs D_w, R_u, R_v) ///@todo Check sign here answer(3 + 0, 2 + 2 + i * 5) = dn(i, 0);// kappa_x = d(fi_y)/dx answer(3 + 1, 2 + 1 + i * 5) =-dn(i, 1);// kappa_y = -d(fi_x)/dy answer(3 + 2, 2 + 2 + i * 5) = dn(i, 1);// kappa_xy=d(fi_y)/dy-d(fi_x)/dx answer(3 + 2, 2 + 1 + i * 5) =-dn(i, 0); // shear strains answer(3 + 3, 2 + 0 + i * 5) = dns(i, 0);// gamma_xz = fi_y+dw/dx answer(3 + 3, 2 + 2 + i * 5) = ns(i); answer(3 + 4, 2 + 0 + i * 5) = dns(i, 1);// gamma_yz = -fi_x+dw/dy answer(3 + 4, 2 + 1 + i * 5) = -ns(i); } #if 0 // Experimental MITC4 support. // Based on "Short communication A four-node plate bending element based on mindling/reissner plate theory and a mixed interpolation" // KJ Bathe, E Dvorkin double x1, x2, x3, x4; double y1, y2, y3, y4; double Ax, Bx, Cx, Ay, By, Cy; double r = localCoords[0]; double s = localCoords[1]; x1 = lnodes[0][0]; x2 = lnodes[1][0]; x3 = lnodes[2][0]; x4 = lnodes[3][0]; y1 = lnodes[0][1]; y2 = lnodes[1][1]; y3 = lnodes[2][1]; y4 = lnodes[3][1]; Ax = x1 - x2 - x3 + x4; Bx = x1 - x2 + x3 - x4; Cx = x1 + x2 - x3 - x4; Ay = y1 - y2 - y3 + y4; By = y1 - y2 + y3 - y4; Cy = y1 + y2 - y3 - y4; FloatMatrix jac; this->interp.giveJacobianMatrixAt(jac, localCoords, FEIVertexListGeometryWrapper(lnodes) ); double detJ = jac.giveDeterminant(); double rz = sqrt( sqr(Cx + r*Bx) + sqr(Cy + r*By)) / ( 16 * detJ ); double sz = sqrt( sqr(Ax + s*Bx) + sqr(Ay + s*By)) / ( 16 * detJ ); // TODO: Not sure about this part (the reference is not explicit about these angles. / Mikael // Not sure about the transpose either. OOFEM_WARNING("The MITC4 implementation isn't verified yet. Highly experimental"); FloatArray dxdr = {jac(0,0), jac(0,1)}; dxdr.normalize(); FloatArray dxds = {jac(1,0), jac(1,1)}; dxds.normalize(); double c_b = dxdr(0); //cos(beta); double s_b = dxdr(1); //sin(beta); double c_a = dxds(0); //cos(alpha); double s_a = dxds(1); //sin(alpha); // gamma_xz = "fi_y+dw/dx" in standard formulation answer(6, 2 + 5*0) = rz * s_b * ( (1+s)) - sz * s_a * ( (1+r)); answer(6, 2 + 5*1) = rz * s_b * (-(1+s)) - sz * s_a * ( (1-r)); answer(6, 2 + 5*2) = rz * s_b * (-(1-s)) - sz * s_a * (-(1-r)); answer(6, 2 + 5*3) = rz * s_b * ( (1-s)) - sz * s_a * (-(1+r)); answer(6, 3 + 5*0) = rz * s_b * (y2-y1) * 0.5 * (1+s) - sz * s_a * (y4-y1) * 0.5 * (1+r); // tx1 answer(6, 4 + 5*0) = rz * s_b * (x1-x2) * 0.5 * (1+s) - sz * s_a * (x1-x4) * 0.5 * (1+r); // ty1 answer(6, 3 + 5*1) = rz * s_b * (y2-y1) * 0.5 * (1+s) - sz * s_a * (y3-x2) * 0.5 * (1+r); // tx2 answer(6, 4 + 5*1) = rz * s_b * (x1-x2) * 0.5 * (1+s) - sz * s_a * (x2-x3) * 0.5 * (1+r); // ty2 answer(6, 3 + 5*2) = rz * s_b * (y3-y4) * 0.5 * (1-s) - sz * s_a * (y3-y2) * 0.5 * (1-r); // tx3 answer(6, 4 + 5*2) = rz * s_b * (x4-x3) * 0.5 * (1-s) - sz * s_a * (x2-x3) * 0.5 * (1-r); // ty3 answer(6, 3 + 5*3) = rz * s_b * (y3-y4) * 0.5 * (1-s) - sz * s_a * (y4-y1) * 0.5 * (1-r); // tx4 answer(6, 4 + 5*3) = rz * s_b * (x4-x3) * 0.5 * (1-s) - sz * s_a * (x1-x4) * 0.5 * (1-r); // ty4 // gamma_yz = -fi_x+dw/dy in standard formulation answer(7, 2 + 5*0) = - rz * c_b * ( (1+s)) + sz * c_a * ( (1+r)); answer(7, 2 + 5*1) = - rz * c_b * (-(1+s)) + sz * c_a * ( (1-r)); answer(7, 2 + 5*2) = - rz * c_b * (-(1-s)) + sz * c_a * (-(1-r)); answer(7, 2 + 5*3) = - rz * c_b * ( (1-s)) + sz * c_a * (-(1+r)); answer(7, 3 + 5*0) = - rz * c_b * (y2-y1) * 0.5 * (1+s) + sz * c_a * (y4-y1) * 0.5 * (1+r); // tx1 answer(7, 4 + 5*0) = - rz * c_b * (x1-x2) * 0.5 * (1+s) + sz * c_a * (x1-x4) * 0.5 * (1+r); // ty1 answer(7, 3 + 5*1) = - rz * c_b * (y2-y1) * 0.5 * (1+s) + sz * c_a * (y3-x2) * 0.5 * (1+r); // tx2 answer(7, 4 + 5*1) = - rz * c_b * (x1-x2) * 0.5 * (1+s) + sz * c_a * (x2-x3) * 0.5 * (1+r); // ty2 answer(7, 3 + 5*2) = - rz * c_b * (y3-y4) * 0.5 * (1-s) + sz * c_a * (y3-y2) * 0.5 * (1-r); // tx3 answer(7, 4 + 5*2) = - rz * c_b * (x4-x3) * 0.5 * (1-s) + sz * c_a * (x2-x3) * 0.5 * (1-r); // ty3 answer(7, 3 + 5*3) = - rz * c_b * (y3-y4) * 0.5 * (1-s) + sz * c_a * (y4-y1) * 0.5 * (1-r); // tx4 answer(7, 4 + 5*3) = - rz * c_b * (x4-x3) * 0.5 * (1-s) + sz * c_a * (x1-x4) * 0.5 * (1-r); // ty4 #endif }
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 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; }
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 SPRNodalRecoveryModel :: determinePatchAssemblyPoints(IntArray &pap, SPRPatchType regType, Set &elementSet) { int idofMan, ndofMan = domain->giveNumberOfDofManagers(); int ielem; int npap, ipap, count, neq, nip; IntArray dofManFlags(ndofMan), elemPap; SPRNodalRecoveryModelInterface *interface; Element *element; const IntArray *papDofManConnectivity; enum { papStatus_noPap, papStatus_regular, papStatus_boundary, papStatus_littleNIPs }; // init all dof man statuses for ( idofMan = 1; idofMan <= ndofMan; idofMan++ ) { dofManFlags.at(idofMan) = papStatus_noPap; } IntArray elements = elementSet.giveElementList(); // assign all possible paps with corresponding count for ( int i = 1; i <= elements.giveSize(); i++ ) { ielem = elements.at(i); element = domain->giveElement(ielem); if ( element->giveParallelMode() != Element_local ) { continue; } if ( ( interface = static_cast< SPRNodalRecoveryModelInterface * >( element->giveInterface(SPRNodalRecoveryModelInterfaceType) ) ) ) { interface->SPRNodalRecoveryMI_giveSPRAssemblyPoints(elemPap); npap = elemPap.giveSize(); for ( ipap = 1; ipap <= npap; ipap++ ) { dofManFlags.at( elemPap.at(ipap) ) = papStatus_regular; } } } // after loop all possible paps (patch assembly points) will have papStatus_regular flag // but we now have to skip those pap reported by elements, which have not enough integration points // to determine the least square fit of patch // and also we mark those dofManagers which are on boundary neq = this->giveNumberOfUnknownPolynomialCoefficients(regType); for ( idofMan = 1; idofMan <= ndofMan; idofMan++ ) { // mark boundary dofManagers if ( domain->giveDofManager(idofMan)->isBoundary() ) { dofManFlags.at(idofMan) = papStatus_boundary; } nip = 0; if ( dofManFlags.at(idofMan) != papStatus_noPap ) { papDofManConnectivity = domain->giveConnectivityTable()->giveDofManConnectivityArray(idofMan); for ( ielem = 1; ielem <= papDofManConnectivity->giveSize(); ielem++ ) { element = domain->giveElement( papDofManConnectivity->at(ielem) ); if ( element->giveParallelMode() != Element_local ) { continue; } if ( elementSet.hasElement( element->giveNumber() ) ) { if ( ( interface = static_cast< SPRNodalRecoveryModelInterface * >( element->giveInterface(SPRNodalRecoveryModelInterfaceType) ) ) ) { nip += interface->SPRNodalRecoveryMI_giveNumberOfIP(); } } } if ( nip < neq ) { // this pap has not enough integration points to determine patch polynomial // reset its count to zero dofManFlags.at(idofMan) = papStatus_littleNIPs; } } } // // generally boundary pap can be removed from pap list // if their value can be determined from other paps // and if they are not the last resort to determine other dofManagers values (for example those with little nips). // // // here only test if paps with papStatus_littleNIPs can be determined using regular paps (papStatus_regular) // or the boundary paps must be employed. In such case these boundary paps are marked as regular ones // to force paches to be assembled. // bool foundRegularPap, foundBoundaryPap, abort_flag = false; // loop over boundary candidates to remove and try to confirm whether they can be removed for ( idofMan = 1; idofMan <= ndofMan; idofMan++ ) { foundRegularPap = foundBoundaryPap = false; if ( dofManFlags.at(idofMan) == papStatus_littleNIPs ) { papDofManConnectivity = domain->giveConnectivityTable()->giveDofManConnectivityArray(idofMan); for ( ielem = 1; ielem <= papDofManConnectivity->giveSize(); ielem++ ) { // try to determine if they can be determined from surronuding elements paps element = domain->giveElement( papDofManConnectivity->at(ielem) ); if ( element->giveParallelMode() != Element_local ) { continue; } if ( !elementSet.hasElement( element->giveNumber() ) ) { continue; } if ( ( interface = static_cast< SPRNodalRecoveryModelInterface * >( element->giveInterface(SPRNodalRecoveryModelInterfaceType) ) ) ) { interface->SPRNodalRecoveryMI_giveSPRAssemblyPoints(elemPap); npap = elemPap.giveSize(); for ( ipap = 1; ipap <= npap; ipap++ ) { // skip other dofMans with littleNIPs if ( dofManFlags.at( elemPap.at(ipap) ) == papStatus_littleNIPs ) { continue; } if ( dofManFlags.at( elemPap.at(ipap) ) == papStatus_regular ) { foundRegularPap = true; } else if ( dofManFlags.at( elemPap.at(ipap) ) == papStatus_boundary ) { foundBoundaryPap = true; } } } } if ( foundRegularPap ) { continue; // can be determined from regular pap - ok } // boundary dof man can be removed <= can be determined if ( foundBoundaryPap ) { // try the last possibility-> determine its value from boundary patches // mark boundaryPap as regulars -> they can be used to assemble patch (they have enough nips) for ( ielem = 1; ielem <= papDofManConnectivity->giveSize(); ielem++ ) { element = domain->giveElement( papDofManConnectivity->at(ielem) ); if ( !elementSet.hasElement( element->giveNumber() ) ) { continue; } if ( ( interface = static_cast< SPRNodalRecoveryModelInterface * >( element->giveInterface(SPRNodalRecoveryModelInterfaceType) ) ) ) { interface->SPRNodalRecoveryMI_giveSPRAssemblyPoints(elemPap); npap = elemPap.giveSize(); for ( ipap = 1; ipap <= npap; ipap++ ) { if ( dofManFlags.at( elemPap.at(ipap) ) == papStatus_boundary ) { // change status to regular pap dofManFlags.at( elemPap.at(ipap) ) = papStatus_regular; } } } } } else { // if the pap with papStatus_littleNIPs status found, which values could not be determined using // regular pap or boundary pap then we are unable to determine such value if ( dofManFlags.at(idofMan) == papStatus_littleNIPs ) { OOFEM_WARNING("unable to determine dofMan %d\n", idofMan); //abort_flag = true; } } } } if ( abort_flag ) { abort(); } count = 0; // count regular paps - those for which patch will be assembled for ( idofMan = 1; idofMan <= ndofMan; idofMan++ ) { if ( dofManFlags.at(idofMan) == papStatus_regular ) { count++; } } pap.resize(count); count = 0; for ( idofMan = 1; idofMan <= ndofMan; idofMan++ ) { if ( dofManFlags.at(idofMan) == papStatus_regular ) { pap.at(++count) = idofMan; } } }
int EIPrimaryUnknownMapper :: evaluateAt(FloatArray &answer, IntArray &dofMask, ValueModeType mode, Domain *oldd, FloatArray &coords, IntArray ®List, TimeStep *tStep) { Element *oelem; EIPrimaryUnknownMapperInterface *interface; SpatialLocalizer *sl = oldd->giveSpatialLocalizer(); ///@todo Change to the other version after checking that it works properly. Will render "giveElementCloseToPoint" obsolete (superseeded by giveElementClosestToPoint). #if 1 if ( regList.isEmpty() ) { oelem = sl->giveElementContainingPoint(coords); } else { oelem = sl->giveElementContainingPoint(coords, & regList); } if ( !oelem ) { if ( regList.isEmpty() ) { oelem = oldd->giveSpatialLocalizer()->giveElementCloseToPoint(coords); } else { oelem = oldd->giveSpatialLocalizer()->giveElementCloseToPoint(coords, & regList); } if ( !oelem ) { OOFEM_WARNING("Couldn't find any element containing point."); return false; } } #else FloatArray lcoords, closest; if ( regList.isEmpty() ) { oelem = sl->giveElementClosestToPoint(lcoords, closest, coords, 0); } else { // Take the minimum of any region double mindist = 0.0, distance; oelem = NULL; for ( int i = 1; i < regList.giveSize(); ++i ) { Element *tmpelem = sl->giveElementClosestToPoint( lcoords, closest, coords, regList.at(i) ); distance = closest.distance_square(coords); if ( tmpelem != NULL ) { distance = closest.distance_square(coords); if ( distance < mindist || i == 1 ) { mindist = distance; oelem = tmpelem; if ( distance == 0.0 ) { break; } } } } } if ( !oelem ) { OOFEM_WARNING("Couldn't find any element containing point."); return false; } #endif interface = static_cast< EIPrimaryUnknownMapperInterface * >( oelem->giveInterface(EIPrimaryUnknownMapperInterfaceType) ); if ( interface ) { oelem->giveElementDofIDMask(dofMask); #if 1 FloatArray lcoords; if ( oelem->computeLocalCoordinates(lcoords, coords) ) { interface->EIPrimaryUnknownMI_computePrimaryUnknownVectorAtLocal(mode, tStep, lcoords, answer); } else { answer.clear(); } #else interface->EIPrimaryUnknownMI_computePrimaryUnknownVectorAtLocal(mode, tStep, lcoords, answer); #endif } else { OOFEM_ERROR("Element does not support EIPrimaryUnknownMapperInterface"); } return true; }
void LargeStrainMasterMaterialGrad :: giveFirstPKStressVectorGrad(FloatArray &answer1, double &answer2, GaussPoint *gp, const FloatArray &vF, double nonlocalCumulatedStrain, TimeStep *tStep) { LargeStrainMasterMaterialStatus *status = static_cast< LargeStrainMasterMaterialStatus * >( this->giveStatus(gp) ); this->initTempStatus(gp); MaterialMode mode = gp->giveMaterialMode(); if ( mode == _3dMat ) { Material *mat; StructuralMaterial *sMat; mat = domain->giveMaterial(slaveMat); sMat = dynamic_cast< StructuralMaterial * >(mat); if ( sMat == NULL ) { OOFEM_WARNING("material %d has no Structural support", slaveMat); return; } GradDpMaterialExtensionInterface *dpmat = static_cast< GradDpMaterialExtensionInterface * >( sMat->giveInterface(GradDpMaterialExtensionInterfaceType) ); if ( !dpmat ) { OOFEM_ERROR("Material doesn't implement the required DpGrad interface!"); } double lambda1, lambda2, lambda3, E1, E2, E3; FloatArray eVals, SethHillStrainVector, stressVector, stressM; FloatMatrix F, C, eVecs, SethHillStrain; FloatMatrix L1, L2, T; //store of deformation gradient into 3x3 matrix F.beMatrixForm(vF); //compute right Cauchy-Green tensor(C), its eigenvalues and eigenvectors C.beTProductOf(F, F); // compute eigen values and eigen vectors of C C.jaco_(eVals, eVecs, 40); // compute Seth - Hill's strain measure, it depends on mParameter lambda1 = eVals.at(1); lambda2 = eVals.at(2); lambda3 = eVals.at(3); if ( m == 0 ) { E1 = 1. / 2. * log(lambda1); E2 = 1. / 2. * log(lambda2); E3 = 1. / 2. * log(lambda3); } else { E1 = 1. / ( 2. * m ) * ( pow(lambda1, m) - 1. ); E2 = 1. / ( 2. * m ) * ( pow(lambda2, m) - 1. ); E3 = 1. / ( 2. * m ) * ( pow(lambda3, m) - 1. ); } SethHillStrain.resize(3, 3); for ( int i = 1; i < 4; i++ ) { for ( int j = 1; j < 4; j++ ) { SethHillStrain.at(i, j) = E1 * eVecs.at(i, 1) * eVecs.at(j, 1) + E2 *eVecs.at(i, 2) * eVecs.at(j, 2) + E3 *eVecs.at(i, 3) * eVecs.at(j, 3); } } SethHillStrainVector.beSymVectorFormOfStrain(SethHillStrain); dpmat->giveRealStressVectorGrad(stressVector, answer2, gp, SethHillStrainVector, nonlocalCumulatedStrain, tStep); this->constructTransformationMatrix(T, eVecs); stressVector.at(4) = 2 * stressVector.at(4); stressVector.at(5) = 2 * stressVector.at(5); stressVector.at(6) = 2 * stressVector.at(6); stressM.beProductOf(T, stressVector); stressM.at(4) = 1. / 2. * stressM.at(4); stressM.at(5) = 1. / 2. * stressM.at(5); stressM.at(6) = 1. / 2. * stressM.at(6); this->constructL1L2TransformationMatrices(L1, L2, eVals, stressM, E1, E2, E3); FloatMatrix junk, P, TL; FloatArray secondPK; junk.beProductOf(L1, T); P.beTProductOf(T, junk); //transformation of the stress to the 2PK stress and then to 1PK stressVector.at(4) = 0.5 * stressVector.at(4); stressVector.at(5) = 0.5 * stressVector.at(5); stressVector.at(6) = 0.5 * stressVector.at(6); secondPK.beProductOf(P, stressVector); answer1.beProductOf(F, secondPK); // P = F*S junk.zero(); junk.beProductOf(L2, T); TL.beTProductOf(T, junk); status->setPmatrix(P); status->setTLmatrix(TL); status->letTempStressVectorBe(answer1); } else { OOFEM_ERROR("Unknown material mode."); } }
void SolutionbasedShapeFunction :: loadProblem() { for ( int i = 0; i < this->domain->giveNumberOfSpatialDimensions(); i++ ) { OOFEM_LOG_INFO("************************** Instanciating microproblem from file %s for dimension %u\n", filename.c_str(), i); // Set up and solve problem OOFEMTXTDataReader drMicro( filename.c_str() ); EngngModel *myEngngModel = InstanciateProblem(& drMicro, _processor, 0, NULL, false); drMicro.finish(); myEngngModel->checkProblemConsistency(); myEngngModel->initMetaStepAttributes( myEngngModel->giveMetaStep(1) ); thisTimestep = myEngngModel->giveNextStep(); myEngngModel->init(); this->setLoads(myEngngModel, i + 1); // Check for ( int j = 1; j <= myEngngModel->giveDomain(1)->giveNumberOfElements(); j++ ) { Element *e = myEngngModel->giveDomain(1)->giveElement(j); FloatArray centerCoord; int vlockCount = 0; centerCoord.resize(3); centerCoord.zero(); for ( int k = 1; k <= e->giveNumberOfDofManagers(); k++ ) { DofManager *dman = e->giveDofManager(k); centerCoord.add( * dman->giveCoordinates() ); for ( Dof *dof: *dman ) { if ( dof->giveBcId() != 0 ) { vlockCount++; } } } if ( vlockCount == 30 ) { OOFEM_WARNING("Element over-constrained (%u)! Center coordinate: %f, %f, %f\n", e->giveNumber(), centerCoord.at(1) / 10, centerCoord.at(2) / 10, centerCoord.at(3) / 10); } } myEngngModel->solveYourselfAt(thisTimestep); isLoaded = true; // Set correct export filename std :: string originalFilename; originalFilename = myEngngModel->giveOutputBaseFileName(); if ( i == 0 ) { originalFilename = originalFilename + "_X"; } if ( i == 1 ) { originalFilename = originalFilename + "_Y"; } if ( i == 2 ) { originalFilename = originalFilename + "_Z"; } myEngngModel->letOutputBaseFileNameBe(originalFilename + "_1_Base"); myEngngModel->doStepOutput(thisTimestep); modeStruct *mode = new(modeStruct); mode->myEngngModel = myEngngModel; // Check elements // Set unknowns to the mean value of opposite sides of the domain. // Loop thru all nodes and compute phi for all degrees of freedom on the boundary. Save phi in a list for later use. initializeSurfaceData(mode); // Update with factor double am = 1.0, ap = 1.0; computeCorrectionFactors(* mode, & dofs, & am, & ap); OOFEM_LOG_INFO("Correction factors: am=%f, ap=%f\n", am, ap); mode->ap = ap; mode->am = am; updateModelWithFactors(mode); // myEngngModel->letOutputBaseFileNameBe(originalFilename + "_2_Updated"); modes.push_back(mode); OOFEM_LOG_INFO("************************** Microproblem at %p instanciated \n", myEngngModel); } }
void MPSDamMaterial :: computeDamageForCohesiveCrack(double &omega, double kappa, GaussPoint *gp) { MPSDamMaterialStatus *status = NULL; omega = 0.0; double e0 = this->givee0(gp); double ef = 0.; if ( kappa > e0 ) { double gf = this->givegf(gp); double Le; double wf = 0.; if ( softType == ST_Exponential_Cohesive_Crack ) { // exponential softening wf = gf / this->E / e0; // wf is the crack opening } else if ( softType == ST_Linear_Cohesive_Crack ) { // linear softening law wf = 2. * gf / this->E / e0; // wf is the crack opening } else { OOFEM_ERROR("Gf unsupported for softening type softType = %d", softType); } // MPSDamMaterialStatus *status = static_cast< MPSDamMaterialStatus * >( this->giveStatus(gp) ); status = static_cast< MPSDamMaterialStatus * >( this->giveStatus(gp) ); Le = status->giveCharLength(); ef = wf / Le; //ef is the fracturing strain if ( ef < e0 ) { //check that no snapback occurs double minGf = 0.; OOFEM_WARNING("ef %e < e0 %e, this leads to material snapback in element %d, characteristic length %f", ef, e0, gp->giveElement()->giveNumber(), Le); if ( softType == ST_Exponential_Cohesive_Crack ) { //exponential softening minGf = this->E * e0 * e0 * Le; } else if ( softType == ST_Linear_Cohesive_Crack ) { //linear softening law minGf = this->E * e0 * e0 * Le / 2.; } else { OOFEM_WARNING("Gf unsupported for softening type softType = %d", softType); } OOFEM_WARNING("Material number %d, decrease e0, or increase Gf from %f to Gf=%f", this->giveNumber(), gf, minGf); if ( checkSnapBack ) { OOFEM_ERROR(""); } } if ( this->softType == ST_Linear_Cohesive_Crack ) { if ( kappa < ef ) { omega = ( ef / kappa ) * ( kappa - e0 ) / ( ef - e0 ); } else { omega = 1.0; //maximum omega (maxOmega) is adjusted just for stiffness matrix in isodamagemodel.C } } else if ( this->softType == ST_Exponential_Cohesive_Crack ) { // exponential cohesive crack - iteration needed double R, Lhs, help; int nite = 0; // iteration to achieve objectivity // we are looking for a state in which the elastic stress is equal to // the stress from crack-opening relation // ef has now the meaning of strain do { nite++; help = omega * kappa / ef; R = ( 1. - omega ) * kappa - e0 *exp(-help); //residuum Lhs = kappa - e0 *exp(-help) * kappa / ef; //- dR / (d omega) omega += R / Lhs; if ( nite > 40 ) { OOFEM_ERROR("algorithm not converging"); } } while ( fabs(R) >= e0 * MPSDAMMAT_ITERATION_LIMIT ); } else { OOFEM_ERROR("Unknown softening type for cohesive crack model."); } if ( omega > 1.0 ) { OOFEM_ERROR("damage parameter is %f, which is greater than 1, snap-back problems", omega); } if ( omega < 0.0 ) { OOFEM_WARNING("damage parameter is %f, which is smaller than 0, snap-back problems", omega); omega = 1.; if ( checkSnapBack ) { OOFEM_ERROR(""); } } } #ifdef supplementary_info double residualStrength = 0.; if ( omega == 0. ) { residualStrength = E * e0; // undamaged material status = static_cast< MPSDamMaterialStatus * >( this->giveStatus(gp) ); } else { if ( this->softType == ST_Linear_Cohesive_Crack ) { residualStrength = E * e0 * ( ef - kappa ) / ( ef - e0 ); } else if ( this->softType == ST_Exponential_Cohesive_Crack ) { residualStrength = E * e0 * exp(-1. * ( kappa - e0 ) / ef); } else { OOFEM_ERROR("Unknown softening type for cohesive crack model."); } } if ( status ) { status->setResidualTensileStrength(residualStrength); } #endif }
int NodalAveragingRecoveryModel :: recoverValues(Set elementSet, InternalStateType type, TimeStep *tStep) { int nnodes = domain->giveNumberOfDofManagers(); IntArray regionNodalNumbers(nnodes); IntArray regionDofMansConnectivity; FloatArray lhs, val; if ( ( this->valType == type ) && ( this->stateCounter == tStep->giveSolutionStateCounter() ) ) { return 1; } #ifdef __PARALLEL_MODE bool parallel = this->domain->giveEngngModel()->isParallel(); if ( parallel ) { this->initCommMaps(); } #endif // clear nodal table this->clear(); int regionValSize = 0; int regionDofMans; // loop over elements and determine local region node numbering and determine and check nodal values size if ( this->initRegionNodeNumbering(regionNodalNumbers, regionDofMans, elementSet) == 0 ) { return 0; } regionDofMansConnectivity.resize(regionDofMans); regionDofMansConnectivity.zero(); IntArray elements = elementSet.giveElementList(); // assemble element contributions for ( int i = 1; i <= elements.giveSize(); i++ ) { int ielem = elements.at(i); NodalAveragingRecoveryModelInterface *interface; Element *element = domain->giveElement(ielem); if ( element->giveParallelMode() != Element_local ) { continue; } // If an element doesn't implement the interface, it is ignored. if ( ( interface = static_cast< NodalAveragingRecoveryModelInterface * > ( element->giveInterface(NodalAveragingRecoveryModelInterfaceType) ) ) == NULL ) { //abort(); continue; } int elemNodes = element->giveNumberOfDofManagers(); // ask element contributions for ( int elementNode = 1; elementNode <= elemNodes; elementNode++ ) { int node = element->giveDofManager(elementNode)->giveNumber(); interface->NodalAveragingRecoveryMI_computeNodalValue(val, elementNode, type, tStep); // if the element cannot evaluate this variable, it is ignored if ( val.giveSize() == 0 ) { continue; } else if ( regionValSize == 0 ) { regionValSize = val.giveSize(); lhs.resize(regionDofMans * regionValSize); lhs.zero(); } else if ( val.giveSize() != regionValSize ) { OOFEM_LOG_RELEVANT("NodalAveragingRecoveryModel :: size mismatch for InternalStateType %s, ignoring all elements that doesn't use the size %d\n", __InternalStateTypeToString(type), regionValSize); continue; } int eq = ( regionNodalNumbers.at(node) - 1 ) * regionValSize; for ( int j = 1; j <= regionValSize; j++ ) { lhs.at(eq + j) += val.at(j); } regionDofMansConnectivity.at( regionNodalNumbers.at(node) )++; } } // end assemble element contributions #ifdef __PARALLEL_MODE if ( parallel ) { this->exchangeDofManValues(lhs, regionDofMansConnectivity, regionNodalNumbers, regionValSize); } #endif // solve for recovered values of active region for ( int inode = 1; inode <= nnodes; inode++ ) { if ( regionNodalNumbers.at(inode) ) { int eq = ( regionNodalNumbers.at(inode) - 1 ) * regionValSize; for ( int i = 1; i <= regionValSize; i++ ) { if ( regionDofMansConnectivity.at( regionNodalNumbers.at(inode) ) > 0 ) { lhs.at(eq + i) /= regionDofMansConnectivity.at( regionNodalNumbers.at(inode) ); } else { OOFEM_WARNING("values of dofmanager %d undetermined", inode); lhs.at(eq + i) = 0.0; } } } } // update recovered values this->updateRegionRecoveredValues(regionNodalNumbers, regionValSize, lhs); this->valType = type; this->stateCounter = tStep->giveSolutionStateCounter(); return 1; }
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; }
int SPRNodalRecoveryModel :: recoverValues(Set elementSet, InternalStateType type, TimeStep *tStep) { int nnodes = domain->giveNumberOfDofManagers(); IntArray regionNodalNumbers(nnodes); IntArray patchElems, dofManToDetermine, pap; FloatMatrix a; FloatArray dofManValues; IntArray dofManPatchCount; if ( ( this->valType == type ) && ( this->stateCounter == tStep->giveSolutionStateCounter() ) ) { return 1; } #ifdef __PARALLEL_MODE this->initCommMaps(); #endif // clear nodal table this->clear(); int regionValSize; int regionDofMans; regionValSize = 0; // loop over elements and determine local region node numbering and determine and check nodal values size if ( this->initRegionNodeNumbering(regionNodalNumbers, regionDofMans, elementSet) == 0 ) { return 0; } SPRPatchType regType = this->determinePatchType(elementSet); dofManPatchCount.resize(regionDofMans); dofManPatchCount.zero(); //pap = patch assembly points this->determinePatchAssemblyPoints(pap, regType, elementSet); int npap = pap.giveSize(); for ( int ipap = 1; ipap <= npap; ipap++ ) { int papNumber = pap.at(ipap); int oldSize = regionValSize; this->initPatch(patchElems, dofManToDetermine, pap, papNumber, elementSet); this->computePatch(a, patchElems, regionValSize, regType, type, tStep); if ( oldSize == 0 ) { dofManValues.resize(regionDofMans * regionValSize); dofManValues.zero(); } this->determineValuesFromPatch(dofManValues, dofManPatchCount, regionNodalNumbers, dofManToDetermine, a, regType); } #ifdef __PARALLEL_MODE this->exchangeDofManValues(dofManValues, dofManPatchCount, regionNodalNumbers, regionValSize); #endif // average recovered values of active region bool abortFlag = false; for ( int i = 1; i <= nnodes; i++ ) { if ( regionNodalNumbers.at(i) && ( ( domain->giveDofManager(i)->giveParallelMode() == DofManager_local ) || ( domain->giveDofManager(i)->giveParallelMode() == DofManager_shared ) ) ) { int eq = ( regionNodalNumbers.at(i) - 1 ) * regionValSize; if ( dofManPatchCount.at( regionNodalNumbers.at(i) ) ) { for ( int j = 1; j <= regionValSize; j++ ) { dofManValues.at(eq + j) /= dofManPatchCount.at( regionNodalNumbers.at(i) ); } } else { OOFEM_WARNING("values of %s in dofmanager %d undetermined", __InternalStateTypeToString(type), i); for ( int j = 1; j <= regionValSize; j++ ) { dofManValues.at(eq + j) = 0.0; } //abortFlag = true; } } if ( abortFlag ) { abort(); } // update recovered values this->updateRegionRecoveredValues(regionNodalNumbers, regionValSize, dofManValues); } this->valType = type; this->stateCounter = tStep->giveSolutionStateCounter(); return 1; }
IRResultType B3SolidMaterial :: initializeFrom(InputRecord *ir) { IRResultType result; // Required by IR_GIVE_FIELD macro // // NOTE // // this material model is unit-dependent! // units must be in MPa, m???, MN. // double fc = -1.0, c = -1.0, wc = -1.0, ac = -1.0, alpha1 = 1.0, alpha2 = 1.0; double initHum; //MPS shrinkage parameter - initial value of humidity (range 0.2-0.98) double finalHum; //MPS shrinkage parameter - final value of humidity (range 0.2-0.98) // EmoduliMode has to be set first because characteristic times are computed from RheoChM initialization this->EmoduliMode = 0; // retardation spectrum or least square method is used. Retardation spectrum is default (EmoduliMode==0) IR_GIVE_OPTIONAL_FIELD(ir, EmoduliMode, _IFT_B3SolidMaterial_emodulimode); // characteristic time, usually 1 for analysis running in days this->lambda0 = 1.; IR_GIVE_OPTIONAL_FIELD(ir, lambda0, _IFT_B3SolidMaterial_lambda0); KelvinChainMaterial :: initializeFrom(ir); int mode = 0; IR_GIVE_OPTIONAL_FIELD(ir, mode, _IFT_B3Material_mode); if ( mode == 0 ) { // default - estimate model parameters q1,..,q5 from composition IR_GIVE_FIELD(ir, fc, _IFT_B3Material_fc); // 28-day standard cylinder compression strength [MPa] IR_GIVE_FIELD(ir, c, _IFT_B3Material_cc); // cement content of concrete [kg/m^3] IR_GIVE_FIELD(ir, wc, _IFT_B3Material_wc); // ratio (by weight) of water to cementitious material IR_GIVE_FIELD(ir, ac, _IFT_B3Material_ac); // ratio (by weight) of aggregate to cement IR_GIVE_FIELD(ir, t0, _IFT_B3Material_t0); // age when drying begins [days] } else { // read model parameters for creep IR_GIVE_FIELD(ir, q1, _IFT_B3Material_q1); IR_GIVE_FIELD(ir, q2, _IFT_B3Material_q2); IR_GIVE_FIELD(ir, q3, _IFT_B3Material_q3); IR_GIVE_FIELD(ir, q4, _IFT_B3Material_q4); } // default value = 0; it can be used for basic creep without any external fields this->MicroPrestress = 0; //if = 1 computation exploiting Microprestress solidification theory is done; IR_GIVE_OPTIONAL_FIELD(ir, MicroPrestress, _IFT_B3SolidMaterial_microprestress); // is MPS theory used? if ( this->MicroPrestress == 1 ) { // microprestress-sol-theory: read data for microprestress evaluation // constant c0 [MPa^-1 * day^-1] IR_GIVE_FIELD(ir, c0, _IFT_B3SolidMaterial_c0); // constant c1 (=C1*R*T/M) IR_GIVE_FIELD(ir, c1, _IFT_B3SolidMaterial_c1); // t0- necessary for the initial value of microprestress = S0 (age when drying begins) IR_GIVE_FIELD(ir, t0, _IFT_B3Material_t0); // microprestress-sol-theory: read data for inverse desorption isotherm IR_GIVE_FIELD(ir, w_h, _IFT_B3Material_wh); IR_GIVE_FIELD(ir, n, _IFT_B3Material_ncoeff); IR_GIVE_FIELD(ir, a, _IFT_B3Material_a); } // read shrinkage mode int shm = 0; IR_GIVE_FIELD(ir, shm, _IFT_B3Material_shmode); this->shMode = ( b3ShModeType ) shm; if ( this->shMode == B3_PointShrinkage ) { // #2 in enumerator if ( this->MicroPrestress == 0 ) { OOFEM_WARNING("to use B3_PointShrinkageMPS - MicroPrestress must be = 1"); //or else no external fiels would be found return IRRT_BAD_FORMAT; } kSh = -1; initHum = -1; finalHum = -1; IR_GIVE_OPTIONAL_FIELD(ir, kSh, _IFT_B3SolidMaterial_ksh); IR_GIVE_OPTIONAL_FIELD(ir, initHum, _IFT_B3SolidMaterial_initialhumidity); IR_GIVE_OPTIONAL_FIELD(ir, finalHum, _IFT_B3SolidMaterial_finalhumidity); // either kSh or initHum and finalHum must be given in input record if ( !( ( this->kSh != -1 ) || ( ( initHum != -1 ) && ( finalHum != -1 ) ) ) ) { OOFEM_WARNING("either kSh or initHum and finalHum must be given in input record"); return IRRT_BAD_FORMAT; } if ( ( ( initHum < 0.2 ) || ( initHum > 0.98 ) || ( finalHum < 0.2 ) || ( finalHum > 0.98 ) ) && ( this->kSh == -1 ) ) { OOFEM_ERROR("initital humidity or final humidity out of range (0.2 - 0.98)"); } if ( this->kSh == -1 ) { // predict kSh from composition IR_GIVE_OPTIONAL_FIELD(ir, alpha1, _IFT_B3Material_alpha1); // influence of cement type IR_GIVE_OPTIONAL_FIELD(ir, alpha2, _IFT_B3Material_alpha2); // influence of curing type this->kSh = alpha1 * alpha2 * ( 1 - pow(finalHum, 3.) ) * ( 0.019 * pow(wc * c, 2.1) * pow(fc, -0.28) + 270 ) * 1.e-6 / fabs(initHum - finalHum); } } else if ( this->shMode == B3_AverageShrinkage ) { IR_GIVE_FIELD(ir, ks, _IFT_B3Material_ks); // cross-section shape factor /* * use ks = 1.0 for an infinite slab * = 1.15 for an infinite cylinder * = 1.25 for an infinite square prism * = 1.30 for a sphere * = 1.55 for a cube */ IR_GIVE_FIELD(ir, hum, _IFT_B3Material_hum); // relative humidity of the environment IR_GIVE_FIELD(ir, vs, _IFT_B3Material_vs); // volume-to-surface ratio (in m???) if ( mode == 0 ) { // default mode - estimate model parameters kt, EpsSinf, q5 from composition IR_GIVE_OPTIONAL_FIELD(ir, alpha1, _IFT_B3Material_alpha1); // influence of cement type IR_GIVE_OPTIONAL_FIELD(ir, alpha2, _IFT_B3Material_alpha2); // influence of curing type } else { // read model parameters IR_GIVE_FIELD(ir, t0, _IFT_B3Material_t0); // age when drying begins [days] IR_GIVE_FIELD(ir, kt, _IFT_B3Material_kt); IR_GIVE_FIELD(ir, EpsSinf, _IFT_B3Material_EpsSinf); IR_GIVE_FIELD(ir, q5, _IFT_B3Material_q5); } } IR_GIVE_FIELD(ir, talpha, _IFT_B3Material_talpha); // evaluate the total water content [kg/m^3] w = wc * c; // estimate the conventional modulus ??? what if fc is not given ??? E28 = 4733. * sqrt(fc); // estimate parameters from composition if ( mode == 0 ) { this->predictParametersFrom(fc, c, wc, ac, t0, alpha1, alpha2); } // ph!!! //return KelvinChainMaterial :: initializeFrom(ir); return IRRT_OK; }
void PlasticMaterial :: giveRealStressVector(FloatArray &answer, GaussPoint *gp, const FloatArray &totalStrain, TimeStep *tStep) // // returns real stress vector in 3d stress space of receiver according to // previous level of stress and current // strain increment, the only way, how to correctly update gp records // // completely formulated in Reduced stress-strain space { FloatArray strainSpaceHardeningVariables; FloatArray fullStressVector, *fullStressSpaceHardeningVars, *residualVectorR; FloatArray elasticStrainVectorR; FloatArray strainVectorR, plasticStrainVectorR, *gradientVectorR; FloatArray helpVec, helpVec2; double yieldValue, Gamma, dGamma, helpVal1, helpVal2; int strSize, totSize, nIterations = 0; FloatMatrix elasticModuli, hardeningModuli, consistentModuli; FloatMatrix elasticModuliInverse, hardeningModuliInverse; FloatMatrix helpMtrx, helpMtrx2; PlasticMaterialStatus *status = static_cast< PlasticMaterialStatus * >( this->giveStatus(gp) ); this->initTempStatus(gp); // subtract stress independent part // note: eigenStrains (temperature) is not contained in mechanical strain stored in gp // therefore it is necessary to subtract always the total eigen strain value this->giveStressDependentPartOfStrainVector(strainVectorR, gp, totalStrain, tStep, VM_Total); plasticStrainVectorR = status->givePlasticStrainVector(); strainSpaceHardeningVariables = status->giveStrainSpaceHardeningVars(); // tady konec debugovani - strainSpaceHardeningVariables ve statusu neinicializovany // to musi udelat material. Gamma = 0.; strSize = strainVectorR.giveSize(); // size of reducedStrain Vector totSize = strSize + strainSpaceHardeningVariables.giveSize(); // compute elastic moduli and its inverse this->computeReducedElasticModuli(elasticModuli, gp, tStep); elasticModuliInverse.beInverseOf(elasticModuli); do { elasticStrainVectorR.beDifferenceOf(strainVectorR, plasticStrainVectorR); // stress vector in full form due to computational convenience this->computeTrialStressIncrement(fullStressVector, gp, elasticStrainVectorR, tStep); fullStressSpaceHardeningVars = this->ComputeStressSpaceHardeningVars(gp, & strainSpaceHardeningVariables); yieldValue = this->computeYieldValueAt(gp, & fullStressVector, fullStressSpaceHardeningVars); gradientVectorR = this->ComputeGradientVector(gp, & fullStressVector, fullStressSpaceHardeningVars); residualVectorR = this->ComputeResidualVector(gp, Gamma, & plasticStrainVectorR, & strainSpaceHardeningVariables, gradientVectorR); // check for end of iteration if ( ( yieldValue < YIELD_TOL ) && ( residualVectorR->computeNorm() < RES_TOL ) ) { delete fullStressSpaceHardeningVars; delete gradientVectorR; delete residualVectorR; break; } // compute consistent tangent moduli this->computeHardeningReducedModuli(hardeningModuli, gp, & strainSpaceHardeningVariables, tStep); if ( hardeningModuli.giveNumberOfRows() ) { hardeningModuliInverse.beInverseOf(hardeningModuli); } else { hardeningModuliInverse.clear(); } this->computeConsistentModuli(consistentModuli, gp, elasticModuliInverse, hardeningModuliInverse, Gamma, fullStressVector, * fullStressSpaceHardeningVars); // obtain increment to consistency parameter helpMtrx.initFromVector(* gradientVectorR, 1); helpMtrx2.beProductOf(helpMtrx, consistentModuli); helpVec.beProductOf(helpMtrx2, * gradientVectorR); helpVal1 = helpVec.at(1); helpVec.beProductOf(helpMtrx2, * residualVectorR); helpVal2 = helpVec.at(1); dGamma = ( yieldValue - helpVal2 ) / helpVal1; // obtain incremental plastic strains and internal variables // we overwrite residualVectorR and gradientVectorR vectors // but they are computed once again when iteration continues gradientVectorR->times(dGamma); residualVectorR->add(* gradientVectorR); helpVec.beProductOf(consistentModuli, * residualVectorR); // note elasticModuli and hardeningModuli are yet inverted this->computeDiagModuli(helpMtrx, gp, elasticModuliInverse, hardeningModuliInverse); helpVec2.beProductOf(helpMtrx, helpVec); // Update state variables and consistency parameter for ( int i = 1; i <= strSize; i++ ) { plasticStrainVectorR.at(i) += helpVec2.at(i); } for ( int i = strSize + 1; i <= totSize; i++ ) { strainSpaceHardeningVariables.at(i - strSize) += helpVec2.at(i); } Gamma += dGamma; // increment iteration count nIterations++; // free allocated memory inside loop delete fullStressSpaceHardeningVars; delete gradientVectorR; delete residualVectorR; if ( nIterations > PLASTIC_MATERIAL_MAX_ITERATIONS ) { OOFEM_WARNING("local equlibrium not reached in %d iterations\nElement %d, gp %d, continuing", PLASTIC_MATERIAL_MAX_ITERATIONS, gp->giveElement()->giveNumber(), gp->giveNumber() ); break; } } while ( 1 ); // update temp state variables in gp and associted material status status->letTempStrainVectorBe(totalStrain); StructuralMaterial :: giveReducedSymVectorForm( helpVec, fullStressVector, gp->giveMaterialMode() ); status->letTempStressVectorBe(helpVec); status->letTempPlasticStrainVectorBe(plasticStrainVectorR); status->letTempStrainSpaceHardeningVarsVectorBe(strainSpaceHardeningVariables); // update plastic consistency parameter status->letTempPlasticConsistencyPrameterBe(Gamma); // update state flag int newState, state = status->giveStateFlag(); if ( Gamma > 0. ) { newState = PM_Yielding; // test if plastic loading occur } // no plastic loading - check for unloading else if ( ( state == PM_Yielding ) || ( state == PM_Unloading ) ) { newState = PM_Unloading; } else { newState = PM_Elastic; } status->letTempStateFlagBe(newState); answer = status->giveTempStressVector(); }
void StructuralInterfaceMaterial :: give3dStiffnessMatrix_dTdj(FloatMatrix &answer, MatResponseMode rMode, GaussPoint *gp, TimeStep *tStep) { this->give3dStiffnessMatrix_dTdj_Num(answer, gp, tStep); OOFEM_WARNING("Using numerical tangent"); }
void SurfaceTensionBoundaryCondition :: computeTangentFromElement(FloatMatrix &answer, Element *e, int side, TimeStep *tStep) { FEInterpolation *fei = e->giveInterpolation(); if ( !fei ) { OOFEM_ERROR("No interpolation available for element."); } std :: unique_ptr< IntegrationRule > iRule( fei->giveBoundaryIntegrationRule(fei->giveInterpolationOrder()-1, side) ); int nsd = e->giveDomain()->giveNumberOfSpatialDimensions(); int nodes = e->giveNumberOfNodes(); if ( side == -1 ) { side = 1; } answer.clear(); if ( nsd == 2 ) { FEInterpolation2d *fei2d = static_cast< FEInterpolation2d * >(fei); ///@todo More of this grunt work should be moved to the interpolation classes FloatMatrix xy(2, nodes); Node *node; for ( int i = 1; i <= nodes; i++ ) { node = e->giveNode(i); xy.at(1, i) = node->giveCoordinate(1); xy.at(2, i) = node->giveCoordinate(2); } FloatArray tmpA(2 *nodes); FloatArray es; // Tangent vector to curve FloatArray dNds; FloatMatrix B(2, 2 *nodes); B.zero(); if ( e->giveDomain()->isAxisymmetric() ) { FloatArray N; FloatArray gcoords; FloatArray tmpB(2 *nodes); for ( GaussPoint *gp: *iRule ) { fei2d->edgeEvaldNds( dNds, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); fei->boundaryEvalN( N, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); double J = fei->boundaryGiveTransformationJacobian( side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); fei->boundaryLocal2Global( gcoords, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); double r = gcoords(0); // First coordinate is the radial coord. es.beProductOf(xy, dNds); // Construct the different matrices in the integrand; for ( int i = 0; i < nodes; i++ ) { tmpA(i * 2 + 0) = dNds(i) * es(0); tmpA(i * 2 + 1) = dNds(i) * es(1); tmpB(i * 2 + 0) = N(i); tmpB(i * 2 + 1) = 0; B(i * 2, 0) = B(i * 2 + 1, 1) = dNds(i); } double dV = 2 *M_PI *gamma *J *gp->giveWeight(); answer.plusDyadUnsym(tmpA, tmpB, dV); answer.plusDyadUnsym(tmpB, tmpA, dV); answer.plusProductSymmUpper(B, B, r * dV); answer.plusDyadUnsym(tmpA, tmpA, -r * dV); } } else { for ( GaussPoint *gp: *iRule ) { double t = e->giveCrossSection()->give(CS_Thickness, gp); ///@todo The thickness is not often relevant or used in FM. fei2d->edgeEvaldNds( dNds, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); double J = fei->boundaryGiveTransformationJacobian( side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); es.beProductOf(xy, dNds); // Construct the different matrices in the integrand; for ( int i = 0; i < nodes; i++ ) { tmpA(i * 2 + 0) = dNds(i) * es(0); tmpA(i * 2 + 1) = dNds(i) * es(1); B(i * 2, 0) = B(i * 2 + 1, 1) = dNds(i); } double dV = t * gamma * J * gp->giveWeight(); answer.plusProductSymmUpper(B, B, dV); answer.plusDyadSymmUpper(tmpA, -dV); } } answer.symmetrized(); } else if ( nsd == 3 ) { FEInterpolation3d *fei3d = static_cast< FEInterpolation3d * >(fei); OOFEM_ERROR("3D tangents not implemented yet."); //FloatMatrix tmp(3 *nodes, 3 *nodes); FloatMatrix dNdx; FloatArray n; for ( GaussPoint *gp: *iRule ) { fei3d->surfaceEvaldNdx( dNdx, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); /*double J = */ fei->boundaryEvalNormal( n, side, gp->giveNaturalCoordinates(), FEIElementGeometryWrapper(e) ); //double dV = gamma * J * gp->giveWeight(); for ( int i = 0; i < nodes; i++ ) { //tmp(3*i+0) = dNdx(i,0) - (dNdx(i,0)*n(0)* + dNdx(i,1)*n(1) + dNdx(i,2)*n(2))*n(0); //tmp(3*i+1) = dNdx(i,1) - (dNdx(i,0)*n(0)* + dNdx(i,1)*n(1) + dNdx(i,2)*n(2))*n(1); //tmp(3*i+2) = dNdx(i,2) - (dNdx(i,0)*n(0)* + dNdx(i,1)*n(1) + dNdx(i,2)*n(2))*n(2); } //answer.plusProductSymmUpper(A,B, dV); ///@todo Derive expressions for this. } } else { OOFEM_WARNING("Only 2D or 3D is possible!"); } }
void IncrementalLinearStatic :: solveYourselfAt(TimeStep *tStep) { Domain *d = this->giveDomain(1); // Creates system of governing eq's and solves them at given time step // >>> beginning PH // The following piece of code updates assignment of boundary conditions to dofs // (this allows to have multiple boundary conditions assigned to one dof // which can be arbitrarily turned on and off in time) // Almost the entire section has been copied from domain.C std :: vector< std :: map< int, int > > dof_bc( d->giveNumberOfDofManagers() ); for ( int i = 1; i <= d->giveNumberOfBoundaryConditions(); ++i ) { GeneralBoundaryCondition *gbc = d->giveBc(i); if ( gbc->isImposed(tStep) ) { if ( gbc->giveSetNumber() > 0 ) { ///@todo This will eventually not be optional. // Loop over nodes in set and store the bc number in each dof. Set *set = d->giveSet( gbc->giveSetNumber() ); ActiveBoundaryCondition *active_bc = dynamic_cast< ActiveBoundaryCondition * >(gbc); BoundaryCondition *bc = dynamic_cast< BoundaryCondition * >(gbc); if ( bc || ( active_bc && active_bc->requiresActiveDofs() ) ) { const IntArray &appliedDofs = gbc->giveDofIDs(); const IntArray &nodes = set->giveNodeList(); for ( int inode = 1; inode <= nodes.giveSize(); ++inode ) { for ( int idof = 1; idof <= appliedDofs.giveSize(); ++idof ) { if ( dof_bc [ nodes.at(inode) - 1 ].find( appliedDofs.at(idof) ) == dof_bc [ nodes.at(inode) - 1 ].end() ) { // is empty dof_bc [ nodes.at(inode) - 1 ] [ appliedDofs.at(idof) ] = i; DofManager * dofman = d->giveDofManager( nodes.at(inode) ); Dof * dof = dofman->giveDofWithID( appliedDofs.at(idof) ); dof->setBcId(i); } else { // another bc has been already prescribed at this time step to this dof OOFEM_WARNING("More than one boundary condition assigned at time %f to node %d dof %d. Considering boundary condition %d", tStep->giveTargetTime(), nodes.at(inode), appliedDofs.at(idof), dof_bc [ nodes.at(inode) - 1 ] [appliedDofs.at(idof)] ); } } } } } } } // to get proper number of equations this->forceEquationNumbering(); // <<< end PH // Initiates the total displacement to zero. if ( tStep->isTheFirstStep() ) { for ( auto &dofman : d->giveDofManagers() ) { for ( Dof *dof: *dofman ) { dof->updateUnknownsDictionary(tStep->givePreviousStep(), VM_Total, 0.); dof->updateUnknownsDictionary(tStep, VM_Total, 0.); } } for ( auto &bc : d->giveBcs() ) { ActiveBoundaryCondition *abc; if ( ( abc = dynamic_cast< ActiveBoundaryCondition * >(bc.get()) ) ) { int ndman = abc->giveNumberOfInternalDofManagers(); for ( int i = 1; i <= ndman; i++ ) { DofManager *dofman = abc->giveInternalDofManager(i); for ( Dof *dof: *dofman ) { dof->updateUnknownsDictionary(tStep->givePreviousStep(), VM_Total, 0.); dof->updateUnknownsDictionary(tStep, VM_Total, 0.); } } } } } // Apply dirichlet b.c's on total values for ( auto &dofman : d->giveDofManagers() ) { for ( Dof *dof: *dofman ) { double tot = dof->giveUnknown( VM_Total, tStep->givePreviousStep() ); if ( dof->hasBc(tStep) ) { tot += dof->giveBcValue(VM_Incremental, tStep); } dof->updateUnknownsDictionary(tStep, VM_Total, tot); } } int neq = this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ); #ifdef VERBOSE OOFEM_LOG_RELEVANT("Solving [step number %8d, time %15e, equations %d]\n", tStep->giveNumber(), tStep->giveTargetTime(), neq); #endif if ( neq == 0 ) { // Allows for fully prescribed/empty problems. return; } incrementOfDisplacementVector.resize(neq); incrementOfDisplacementVector.zero(); #ifdef VERBOSE OOFEM_LOG_INFO("Assembling load\n"); #endif // Assembling the element part of load vector internalLoadVector.resize(neq); internalLoadVector.zero(); this->assembleVector( internalLoadVector, tStep, InternalForceAssembler(), VM_Total, EModelDefaultEquationNumbering(), this->giveDomain(1) ); loadVector.resize(neq); loadVector.zero(); this->assembleVector( loadVector, tStep, ExternalForceAssembler(), VM_Total, EModelDefaultEquationNumbering(), this->giveDomain(1) ); loadVector.subtract(internalLoadVector); this->updateSharedDofManagers(loadVector, EModelDefaultEquationNumbering(), ReactionExchangeTag); #ifdef VERBOSE OOFEM_LOG_INFO("Assembling stiffness matrix\n"); #endif stiffnessMatrix.reset( classFactory.createSparseMtrx(sparseMtrxType) ); if ( !stiffnessMatrix ) { OOFEM_ERROR("sparse matrix creation failed"); } stiffnessMatrix->buildInternalStructure( this, 1, EModelDefaultEquationNumbering() ); stiffnessMatrix->zero(); this->assemble( *stiffnessMatrix, tStep, TangentAssembler(TangentStiffness), EModelDefaultEquationNumbering(), this->giveDomain(1) ); #ifdef VERBOSE OOFEM_LOG_INFO("Solving ...\n"); #endif this->giveNumericalMethod( this->giveCurrentMetaStep() ); NM_Status s = nMethod->solve(*stiffnessMatrix, loadVector, incrementOfDisplacementVector); if ( !( s & NM_Success ) ) { OOFEM_ERROR("No success in solving system."); } }
NM_Status SubspaceIteration :: solve(SparseMtrx &a, SparseMtrx &b, FloatArray &_eigv, FloatMatrix &_r, double rtol, int nroot) // // this function solve the generalized eigenproblem using the Generalized // jacobi iteration // { if ( a.giveNumberOfColumns() != b.giveNumberOfColumns() ) { OOFEM_ERROR("matrices size mismatch"); } FloatArray temp, w, d, tt, f, rtolv, eigv; FloatMatrix r; int nn, nc1, ij = 0, is; double rt, art, brt, eigvt; FloatMatrix ar, br, vec; std :: unique_ptr< SparseLinearSystemNM > solver( GiveClassFactory().createSparseLinSolver(ST_Direct, domain, engngModel) ); GJacobi mtd(domain, engngModel); int nc = min(2 * nroot, nroot + 8); nn = a.giveNumberOfColumns(); if ( nc > nn ) { nc = nn; } ar.resize(nc, nc); ar.zero(); br.resize(nc, nc); br.zero(); // // creation of initial iteration vectors // nc1 = nc - 1; w.resize(nn); w.zero(); d.resize(nc); d.zero(); tt.resize(nn); tt.zero(); rtolv.resize(nc); rtolv.zero(); vec.resize(nc, nc); vec.zero(); // eigen vectors of reduced problem // // create work arrays // r.resize(nn, nc); r.zero(); eigv.resize(nc); eigv.zero(); FloatArray h(nn); for ( int i = 1; i <= nn; i++ ) { h.at(i) = 1.0; w.at(i) = b.at(i, i) / a.at(i, i); } b.times(h, tt); r.setColumn(tt, 1); for ( int j = 2; j <= nc; j++ ) { rt = 0.0; for ( int i = 1; i <= nn; i++ ) { if ( fabs( w.at(i) ) >= rt ) { rt = fabs( w.at(i) ); ij = i; } } tt.at(j) = ij; w.at(ij) = 0.; for ( int i = 1; i <= nn; i++ ) { if ( i == ij ) { h.at(i) = 1.0; } else { h.at(i) = 0.0; } } b.times(h, tt); r.setColumn(tt, j); } // (r = z) # ifdef DETAILED_REPORT OOFEM_LOG_INFO("SubspaceIteration :: solveYourselfAt: Degrees of freedom invoked by initial vectors :\n"); tt.printYourself(); OOFEM_LOG_INFO("SubspaceIteration :: solveYourselfAt: initial vectors for iteration:\n"); r.printYourself(); # endif //ish = 0; a.factorized(); // // start of iteration loop // for ( int nite = 0; ; ++nite ) { // label 100 # ifdef DETAILED_REPORT printf("SubspaceIteration :: solveYourselfAt: Iteration loop no. %d\n", nite); # endif // // compute projection ar and br of matrices a , b // for ( int j = 1; j <= nc; j++ ) { f.beColumnOf(r, j); solver->solve(a, f, tt); for ( int i = j; i <= nc; i++ ) { art = 0.; for ( int k = 1; k <= nn; k++ ) { art += r.at(k, i) * tt.at(k); } ar.at(j, i) = art; } r.setColumn(tt, j); // (r = xbar) } ar.symmetrized(); // label 110 #ifdef DETAILED_REPORT OOFEM_LOG_INFO("SubspaceIteration :: solveYourselfAt: Printing projection matrix ar\n"); ar.printYourself(); #endif // for ( int j = 1; j <= nc; j++ ) { tt.beColumnOf(r, j); b.times(tt, temp); for ( int i = j; i <= nc; i++ ) { brt = 0.; for ( int k = 1; k <= nn; k++ ) { brt += r.at(k, i) * temp.at(k); } br.at(j, i) = brt; } // label 180 r.setColumn(temp, j); // (r=zbar) } // label 160 br.symmetrized(); #ifdef DETAILED_REPORT OOFEM_LOG_INFO("SubspaceIteration :: solveYourselfAt: Printing projection matrix br\n"); br.printYourself(); #endif // // solution of reduced eigenvalue problem // mtd.solve(ar, br, eigv, vec); // START EXPERIMENTAL #if 0 // solve the reduced problem by Inverse iteration { FloatMatrix x(nc,nc), z(nc,nc), zz(nc,nc), arinv; FloatArray w(nc), ww(nc), tt(nc), t(nc); double c; // initial setting for ( int i = 1;i <= nc; i++ ) { ww.at(i)=1.0; } for ( int i = 1;i <= nc; i++ ) for ( int j = 1; j <= nc;j++ ) z.at(i,j)=1.0; arinv.beInverseOf (ar); for ( int i = 0;i < nitem; i++ ) { // copy zz=z zz = z; // solve matrix equation K.X = M.X x.beProductOf(arinv, z); // evaluation of Rayleigh quotients for ( int j = 1;j <= nc; j++ ) { w.at(j) = 0.0; for (k = 1; k<= nc; k++) w.at(j) += zz.at(k,j) * x.at(k,j); } z.beProductOf (br, x); for ( int j = 1;j <= nc; j++ ) { c = 0; for ( int k = 1; k<= nc; k++ ) c += z.at(k,j) * x.at(k,j); w.at(j) /= c; } // check convergence int ac = 0; for ( int j = 1;j <= nc; j++ ) { if (fabs((ww.at(j)-w.at(j))/w.at(j))< rtol) ac++; ww.at(j) = w.at(j); } //printf ("\n iterace cislo %d %d",i,ac); //w.printYourself(); // Gramm-Schmidt ortogonalization for ( int j = 1;j <= nc;j++ ) { for ( int k = 1; k<= nc; k++ ) tt.at(k) = x.at(k,j); t.beProductOf(br,tt) ; for ( int ii = 1;ii < j; ii++ ) { c = 0.0; for ( int k = 1; k<= nc; k++ ) c += x.at(k,ii) * t.at(k); for ( int k = 1; k<= nc; k++ ) x.at(k,j) -= x.at(k,ii) * c; } for ( int k = 1; k<= nc; k++) tt.at(k) = x.at(k,j); t.beProductOf(br, tt); c = 0.0; for ( int k = 1; k<= nc; k++) c += x.at(k,j)*t.at(k); for ( int k = 1; k<= nc; k++) x.at(k,j) /= sqrt(c); } if ( ac > nroot ) { break; } // compute new approximation of Z z.beProductOf(br,x); } eigv = w; vec = x; } #endif // // sorting eigenvalues according to their values // do { is = 0; // label 350 for ( int i = 1; i <= nc1; i++ ) { if ( fabs( eigv.at(i + 1) ) < fabs( eigv.at(i) ) ) { is++; eigvt = eigv.at(i + 1); eigv.at(i + 1) = eigv.at(i); eigv.at(i) = eigvt; for ( int k = 1; k <= nc; k++ ) { rt = vec.at(k, i + 1); vec.at(k, i + 1) = vec.at(k, i); vec.at(k, i) = rt; } } } // label 360 } while ( is != 0 ); # ifdef DETAILED_REPORT OOFEM_LOG_INFO("SubspaceIteration :: solveYourselfAt: current eigen values of reduced problem \n"); eigv.printYourself(); OOFEM_LOG_INFO("SubspaceIteration :: solveYourselfAt: current eigen vectors of reduced problem \n"); vec.printYourself(); # endif // // compute eigenvectors // for ( int i = 1; i <= nn; i++ ) { // label 375 for ( int j = 1; j <= nc; j++ ) { tt.at(j) = r.at(i, j); } for ( int k = 1; k <= nc; k++ ) { rt = 0.; for ( int j = 1; j <= nc; j++ ) { rt += tt.at(j) * vec.at(j, k); } r.at(i, k) = rt; } } // label 420 (r = z) // // convergency check // for ( int i = 1; i <= nc; i++ ) { double dif = ( eigv.at(i) - d.at(i) ); rtolv.at(i) = fabs( dif / eigv.at(i) ); } # ifdef DETAILED_REPORT OOFEM_LOG_INFO("SubspaceIteration :: solveYourselfAt: Reached precision of eigenvalues:\n"); rtolv.printYourself(); # endif for ( int i = 1; i <= nroot; i++ ) { if ( rtolv.at(i) > rtol ) { goto label400; } } OOFEM_LOG_INFO("SubspaceIteration :: solveYourselfAt: Convergence reached for RTOL=%20.15f\n", rtol); break; label400: if ( nite >= nitem ) { OOFEM_WARNING("SubspaceIteration :: solveYourselfAt: Convergence not reached in %d iteration - using current values", nitem); break; } d = eigv; // label 410 and 440 continue; } // compute eigenvectors for ( int j = 1; j <= nc; j++ ) { tt.beColumnOf(r, j); a.backSubstitutionWith(tt); r.setColumn(tt, j); // r = xbar } // one cad add a normalization of eigen-vectors here // initialize original index locations _r.resize(nn, nroot); _eigv.resize(nroot); for ( int i = 1; i <= nroot; i++ ) { _eigv.at(i) = eigv.at(i); for ( int j = 1; j <= nn; j++ ) { _r.at(j, i) = r.at(j, i); } } return NM_Success; }
void NlDEIDynamic :: computeMassMtrx(FloatArray &massMatrix, double &maxOm, TimeStep *tStep) { Domain *domain = this->giveDomain(1); int nelem = domain->giveNumberOfElements(); int neq = this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ); int i, j, jj, n; double maxOmi, maxOmEl; FloatMatrix charMtrx, charMtrx2, R; IntArray loc; Element *element; EModelDefaultEquationNumbering en; #ifndef LOCAL_ZERO_MASS_REPLACEMENT FloatArray diagonalStiffMtrx; #endif maxOm = 0.; massMatrix.resize(neq); massMatrix.zero(); for ( i = 1; i <= nelem; i++ ) { element = domain->giveElement(i); // skip remote elements (these are used as mirrors of remote elements on other domains // when nonlocal constitutive models are used. They introduction is necessary to // allow local averaging on domains without fine grain communication between domains). if ( element->giveParallelMode() == Element_remote ) { continue; } element->giveLocationArray(loc, en); element->giveCharacteristicMatrix(charMtrx, LumpedMassMatrix, tStep); if ( charMtrx.isNotEmpty() ) { ///@todo This rotation matrix is not flexible enough.. it can only work with full size matrices and doesn't allow for flexibility in the matrixassembler. if ( element->giveRotationMatrix(R) ) { charMtrx.rotatedWith(R); } } #ifdef LOCAL_ZERO_MASS_REPLACEMENT element->giveCharacteristicMatrix(charMtrx2, TangentStiffnessMatrix, tStep); if ( charMtrx2.isNotEmpty() ) { ///@todo This rotation matrix is not flexible enough.. it can only work with full size matrices and doesn't allow for flexibility in the matrixassembler. if ( R.isNotEmpty() ) { charMtrx2.rotatedWith(R); } } #endif #ifdef DEBUG if ( loc.giveSize() != charMtrx.giveNumberOfRows() ) { OOFEM_ERROR("dimension mismatch"); } #endif n = loc.giveSize(); #ifdef LOCAL_ZERO_MASS_REPLACEMENT maxOmEl = 0.; double maxElmass = -1.0; for ( j = 1; j <= n; j++ ) { maxElmass = max( maxElmass, charMtrx.at(j, j) ); } if ( maxElmass <= 0.0 ) { OOFEM_WARNING("Element (%d) with zero (or negative) lumped mass encountered\n", i); } else { if (charMtrx2.isNotEmpty() ) { // in case stifness matrix defined, we can generate artificial mass // in those DOFs without mass for ( j = 1; j <= n; j++ ) { if ( charMtrx.at(j, j) > maxElmass * ZERO_REL_MASS ) { maxOmi = charMtrx2.at(j, j) / charMtrx.at(j, j); maxOmEl = ( maxOmEl > maxOmi ) ? ( maxOmEl ) : ( maxOmi ); } } maxOm = ( maxOm > maxOmEl ) ? ( maxOm ) : ( maxOmEl ); for ( j = 1; j <= n; j++ ) { jj = loc.at(j); if ( ( jj ) && ( charMtrx.at(j, j) <= maxElmass * ZERO_REL_MASS ) ) { charMtrx.at(j, j) = charMtrx2.at(j, j) / maxOmEl; } } } } #endif for ( j = 1; j <= n; j++ ) { jj = loc.at(j); if ( jj ) { massMatrix.at(jj) += charMtrx.at(j, j); } } } #ifndef LOCAL_ZERO_MASS_REPLACEMENT // If init step - find minimun period of vibration in order to // determine maximal admisible time step // global variant for ( i = 1; i <= nelem; i++ ) { element = domain->giveElement(i); element->giveLocationArray(loc, en); element->giveCharacteristicMatrix(charMtrx, TangentStiffnessMatrix, tStep); if ( charMtrx.isNotEmpty() ) { ///@todo This rotation matrix is not flexible enough.. it can only work with full size matrices and doesn't allow for flexibility in the matrixassembler. if ( element->giveRotationMatrix(R) ) { charMtrx.rotatedWith(R); } } n = loc.giveSize(); for ( j = 1; j <= n; j++ ) { jj = loc.at(j); if ( jj ) { diagonalStiffMtrx.at(jj) += charMtrx.at(j, j); } } } // Find find global minimun period of vibration double maxElmass = -1.0; for ( j = 1; j <= n; j++ ) { maxElmass = max( maxElmass, charMtrx.at(j, j) ); } if ( maxElmass <= 0.0 ) { OOFEM_ERROR("Element with zero (or negative) lumped mass encountered"); } for ( j = 1; j <= neq; j++ ) { if ( massMatrix.at(j) > maxElmass * ZERO_REL_MASS ) { maxOmi = diagonalStiffMtrx.at(j) / massMatrix.at(j); maxOm = ( maxOm > maxOmi ) ? ( maxOm ) : ( maxOmi ); } } // Set ZERO MASS members in massMatrix to value which corresponds to global maxOm. for ( i = 1; i <= neq; i++ ) { if ( massMatrix.at(i) <= maxElmass * ZERO_REL_MASS ) { massMatrix.at(i) = diagonalStiffMtrx.at(i) / maxOm; } } #endif this->updateSharedDofManagers(massMatrix, EModelDefaultEquationNumbering(), MassExchangeTag); #ifdef __PARALLEL_MODE // Determine maxOm over all processes. #ifdef __USE_MPI double globalMaxOm; #ifdef __VERBOSE_PARALLEL VERBOSEPARALLEL_PRINT( "NlDEIDynamic :: computeMassMtrx", "Reduce of maxOm started", this->giveRank() ); #endif int result = MPI_Allreduce(& maxOm, & globalMaxOm, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); #ifdef __VERBOSE_PARALLEL VERBOSEPARALLEL_PRINT( "NlDEIDynamic :: computeMassMtrx", "Reduce of maxOm finished", this->giveRank() ); #endif if ( result != MPI_SUCCESS ) { OOFEM_ERROR("MPI_Allreduce failed"); } maxOm = globalMaxOm; #else WARNING: NOT SUPPORTED MESSAGE PARSING LIBRARY #endif #endif }