void StaticStructural :: solveYourselfAt(TimeStep *tStep) { int neq; int di = 1; this->field->advanceSolution(tStep); this->field->applyBoundaryCondition(tStep); ///@todo Temporary hack, advanceSolution should apply the boundary conditions directly. neq = this->giveNumberOfDomainEquations( di, EModelDefaultEquationNumbering() ); if (tStep->giveNumber()==1) { this->field->initialize(VM_Total, tStep, this->solution, EModelDefaultEquationNumbering() ); } else { this->field->initialize(VM_Total, tStep->givePreviousStep(), this->solution, EModelDefaultEquationNumbering() ); this->field->update(VM_Total, tStep, this->solution, EModelDefaultEquationNumbering() ); } this->field->applyBoundaryCondition(tStep); ///@todo Temporary hack to override the incorrect values that is set by "update" above. Remove this when that is fixed. FloatArray incrementOfSolution(neq), externalForces(neq); // Create "stiffness matrix" if ( !this->stiffnessMatrix ) { this->stiffnessMatrix.reset( classFactory.createSparseMtrx(sparseMtrxType) ); if ( !this->stiffnessMatrix ) { OOFEM_ERROR("Couldn't create requested sparse matrix of type %d", sparseMtrxType); } this->stiffnessMatrix->buildInternalStructure( this, di, EModelDefaultEquationNumbering() ); } this->internalForces.resize(neq); this->giveNumericalMethod( this->giveCurrentMetaStep() ); this->initMetaStepAttributes( this->giveCurrentMetaStep() ); if ( this->initialGuessType == IG_Tangent ) { OOFEM_LOG_RELEVANT("Computing initial guess\n"); FloatArray extrapolatedForces(neq); this->assembleExtrapolatedForces( extrapolatedForces, tStep, TangentStiffnessMatrix, this->giveDomain(di) ); extrapolatedForces.negated(); ///@todo Need to find a general way to support this before enabling it by default. //this->assembleVector(extrapolatedForces, tStep, LinearizedDilationForceAssembler(), VM_Incremental, EModelDefaultEquationNumbering(), this->giveDomain(di) ); #if 0 // Some debug stuff: extrapolatedForces.printYourself("extrapolatedForces"); this->internalForces.zero(); this->assembleVectorFromElements(this->internalForces, tStep, InternalForceAssembler(), VM_Total, EModelDefaultEquationNumbering(), this->giveDomain(di)); this->internalForces.printYourself("internal forces"); #endif OOFEM_LOG_RELEVANT("Computing old tangent\n"); this->updateComponent( tStep, NonLinearLhs, this->giveDomain(di) ); SparseLinearSystemNM *linSolver = nMethod->giveLinearSolver(); OOFEM_LOG_RELEVANT("Solving for increment\n"); linSolver->solve(*stiffnessMatrix, extrapolatedForces, incrementOfSolution); OOFEM_LOG_RELEVANT("Initial guess found\n"); this->solution.add(incrementOfSolution); this->field->update(VM_Total, tStep, this->solution, EModelDefaultEquationNumbering()); this->field->applyBoundaryCondition(tStep); ///@todo Temporary hack to override the incorrect values that is set by "update" above. Remove this when that is fixed. } else if ( this->initialGuessType != IG_None ) { OOFEM_ERROR("Initial guess type: %d not supported", initialGuessType); } else { incrementOfSolution.zero(); } // Build initial/external load externalForces.zero(); this->assembleVector( externalForces, tStep, ExternalForceAssembler(), VM_Total, EModelDefaultEquationNumbering(), this->giveDomain(1) ); this->updateSharedDofManagers(externalForces, EModelDefaultEquationNumbering(), LoadExchangeTag); if ( this->giveProblemScale() == macroScale ) { OOFEM_LOG_INFO("\nStaticStructural :: solveYourselfAt - Solving step %d, metastep %d, (neq = %d)\n", tStep->giveNumber(), tStep->giveMetaStepNumber(), neq); } double loadLevel; int currentIterations; NM_Status status = this->nMethod->solve(*this->stiffnessMatrix, externalForces, NULL, this->solution, incrementOfSolution, this->internalForces, this->eNorm, loadLevel, // Only relevant for incrementalBCLoadVector? SparseNonLinearSystemNM :: rlm_total, currentIterations, tStep); if ( !( status & NM_Success ) ) { OOFEM_ERROR("No success in solving problem"); } }
NM_Status InverseIteration :: solve(SparseMtrx &a, SparseMtrx &b, FloatArray &_eigv, FloatMatrix &_r, double rtol, int nroot) { FILE *outStream; if ( a.giveNumberOfColumns() != b.giveNumberOfColumns() ) { OOFEM_ERROR("matrices size mismatch"); } SparseLinearSystemNM *solver = GiveClassFactory().createSparseLinSolver(ST_Direct, domain, engngModel); int nn = a.giveNumberOfColumns(); int nc = min(2 * nroot, nroot + 8); nc = min(nc, nn); //// control of diagonal zeroes in mass matrix, to be avoided //int i; //for (i = 1; i <= nn; i++) { // if (b.at(i, i) == 0) { // b.at(i, i) = 1.0e-12; // } //} FloatArray w(nc), ww(nc), t; std :: vector< FloatArray > z(nc, nn), zz(nc, nn), x(nc, nn); outStream = domain->giveEngngModel()->giveOutputStream(); /* initial setting */ #if 0 ww.add(1.0); for ( int j = 0; j < nc; j++ ) { z[j].add(1.0); } #else { FloatArray ad(nn), bd(nn); for (int i = 1; i <= nn; i++) { ad.at(i) = fabs(a.at(i, i)); bd.at(i) = fabs(b.at(i, i)); } IntArray order; order.enumerate(nn); std::sort(order.begin(), order.end(), [&ad, &bd](int a, int b) { return bd.at(a) * ad.at(b) > bd.at(b) * ad.at(a); }); for (int i = 0; i < nc; i++) { x[i].at(order[i]) = 1.0; b.times(x[i], z[i]); ww.at(i + 1) = z[i].dotProduct(x[i]); } } #endif int it; for ( it = 0; it < nitem; it++ ) { /* copy zz=z */ for ( int j = 0; j < nc; j++ ) { zz[j] = z[j]; } /* solve matrix equation K.X = M.X */ for ( int j = 0; j < nc; j++ ) { solver->solve(a, z[j], x[j]); } /* evaluation of Rayleigh quotients */ for ( int j = 0; j < nc; j++ ) { w.at(j + 1) = zz[j].dotProduct(x[j]); } for ( int j = 0; j < nc; j++ ) { b.times(x[j], z[j]); } for ( int j = 0; j < nc; j++ ) { w.at(j + 1) /= z[j].dotProduct(x[j]); } /* check convergence */ int ac = 0; for ( int j = 1; j <= nc; j++ ) { if ( fabs( ww.at(j) - w.at(j) ) <= fabs( w.at(j) * rtol ) ) { ac++; } ww.at(j) = w.at(j); } //printf ("\n iteration %d %d",it,ac); //w.printYourself(); /* Gramm-Schmidt ortogonalization */ for ( int j = 0; j < nc; j++ ) { if ( j != 0 ) { b.times(x[j], t); } for ( int ii = 0; ii < j; ii++ ) { x[j].add( -x[ii].dotProduct(t), x[ii] ); } b.times(x[j], t); x[j].times( 1.0 / sqrt( x[j].dotProduct(t) ) ); } if ( ac > nroot ) { break; } /* compute new approximation of Z */ for ( int j = 0; j < nc; j++ ) { b.times(x[j], z[j]); } } // copy results IntArray order; order.enumerate(w.giveSize()); std :: sort(order.begin(), order.end(), [&w](int a, int b) { return w.at(a) < w.at(b); }); _eigv.resize(nroot); _r.resize(nn, nroot); for ( int i = 1; i <= nroot; i++ ) { _eigv.at(i) = w.at(order.at(i)); _r.setColumn(x[order.at(i) - 1], i); } if ( it < nitem ) { fprintf(outStream, "InverseIteration :: convergence reached in %d iterations\n", it); } else { fprintf(outStream, "InverseIteration :: convergence not reached after %d iterations\n", it); } return NM_Success; }
void NonLinearStatic :: proceedStep(int di, TimeStep *tStep) { // // creates system of governing eq's and solves them at given time step // // first assemble problem at current time step // if ( initFlag ) { // // first step create space for stiffness Matrix // if ( !stiffnessMatrix ) { stiffnessMatrix.reset( classFactory.createSparseMtrx(sparseMtrxType) ); } if ( !stiffnessMatrix ) { OOFEM_ERROR("sparse matrix creation failed"); } if ( nonlocalStiffnessFlag ) { if ( !stiffnessMatrix->isAsymmetric() ) { OOFEM_ERROR("stiffnessMatrix does not support asymmetric storage"); } } stiffnessMatrix->buildInternalStructure( this, di, EModelDefaultEquationNumbering() ); } #if 0 if ( ( mstep->giveFirstStepNumber() == tStep->giveNumber() ) ) { #ifdef VERBOSE OOFEM_LOG_INFO("Resetting load level\n"); #endif if ( mstepCumulateLoadLevelFlag ) { cumulatedLoadLevel += loadLevel; } else { cumulatedLoadLevel = 0.0; } this->loadLevel = 0.0; } #endif if ( loadInitFlag || controlMode == nls_directControl ) { #ifdef VERBOSE OOFEM_LOG_DEBUG("Assembling reference load\n"); #endif // // assemble the incremental reference load vector // this->assembleIncrementalReferenceLoadVectors(incrementalLoadVector, incrementalLoadVectorOfPrescribed, refLoadInputMode, this->giveDomain(di), tStep); loadInitFlag = 0; } if ( tStep->giveNumber() == 1 ) { int neq = this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ); totalDisplacement.resize(neq); totalDisplacement.zero(); incrementOfDisplacement.resize(neq); incrementOfDisplacement.zero(); } // // -> BEGINNING OF LOAD (OR DISPLACEMENT) STEP <- // // // set-up numerical model // this->giveNumericalMethod( this->giveMetaStep( tStep->giveMetaStepNumber() ) ); // // call numerical model to solve arise problem // #ifdef VERBOSE OOFEM_LOG_RELEVANT( "\n\nSolving [step number %5d.%d, time = %e]\n\n", tStep->giveNumber(), tStep->giveVersion(), tStep->giveIntrinsicTime() ); #endif if ( this->initialGuessType == IG_Tangent ) { #ifdef VERBOSE OOFEM_LOG_RELEVANT("Computing initial guess\n"); #endif FloatArray extrapolatedForces; this->assembleExtrapolatedForces( extrapolatedForces, tStep, TangentStiffnessMatrix, this->giveDomain(di) ); extrapolatedForces.negated(); this->updateComponent( tStep, NonLinearLhs, this->giveDomain(di) ); SparseLinearSystemNM *linSolver = nMethod->giveLinearSolver(); OOFEM_LOG_RELEVANT("solving for increment\n"); linSolver->solve(*stiffnessMatrix, extrapolatedForces, incrementOfDisplacement); OOFEM_LOG_RELEVANT("initial guess found\n"); totalDisplacement.add(incrementOfDisplacement); } else if ( this->initialGuessType != IG_None ) { OOFEM_ERROR("Initial guess type: %d not supported", initialGuessType); } else { incrementOfDisplacement.zero(); } //totalDisplacement.printYourself(); if ( initialLoadVector.isNotEmpty() ) { numMetStatus = nMethod->solve(*stiffnessMatrix, incrementalLoadVector, & initialLoadVector, totalDisplacement, incrementOfDisplacement, internalForces, internalForcesEBENorm, loadLevel, refLoadInputMode, currentIterations, tStep); } else { numMetStatus = nMethod->solve(*stiffnessMatrix, incrementalLoadVector, NULL, totalDisplacement, incrementOfDisplacement, internalForces, internalForcesEBENorm, loadLevel, refLoadInputMode, currentIterations, tStep); } ///@todo Martin: ta bort!!! //this->updateComponent(tStep, NonLinearLhs, this->giveDomain(di)); ///@todo Use temporary variables. updateYourself() should set the final values, while proceedStep should be callable multiple times for each step (if necessary). / Mikael OOFEM_LOG_RELEVANT("Equilibrium reached at load level = %f in %d iterations\n", cumulatedLoadLevel + loadLevel, currentIterations); prevStepLength = currentStepLength; }