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; }
void CBS :: solveYourselfAt(TimeStep *tStep) { int momneq = this->giveNumberOfDomainEquations(1, vnum); int presneq = this->giveNumberOfDomainEquations(1, pnum); int presneq_prescribed = this->giveNumberOfDomainEquations(1, pnumPrescribed); double deltaT = tStep->giveTimeIncrement(); FloatArray rhs(momneq); if ( initFlag ) { deltaAuxVelocity.resize(momneq); nodalPrescribedTractionPressureConnectivity.resize(presneq_prescribed); nodalPrescribedTractionPressureConnectivity.zero(); this->assembleVectorFromElements( nodalPrescribedTractionPressureConnectivity, tStep, NumberOfNodalPrescribedTractionPressureAssembler(), VM_Total, pnumPrescribed, this->giveDomain(1) ); lhs.reset( classFactory.createSparseMtrx(sparseMtrxType) ); if ( !lhs ) { OOFEM_ERROR("sparse matrix creation failed"); } lhs->buildInternalStructure(this, 1, pnum); this->assemble( *lhs, stepWhenIcApply.get(), PressureLhsAssembler(), pnum, this->giveDomain(1) ); lhs->times(deltaT * theta1 * theta2); if ( consistentMassFlag ) { mss.reset( classFactory.createSparseMtrx(sparseMtrxType) ); if ( !mss ) { OOFEM_ERROR("sparse matrix creation failed"); } mss->buildInternalStructure(this, 1, vnum); this->assemble( *mss, stepWhenIcApply.get(), MassMatrixAssembler(), vnum, this->giveDomain(1) ); } else { mm.resize(momneq); mm.zero(); this->assembleVectorFromElements( mm, tStep, LumpedMassVectorAssembler(), VM_Total, vnum, this->giveDomain(1) ); } //<RESTRICTED_SECTION> // init material interface if ( materialInterface ) { materialInterface->initialize(); } //</RESTRICTED_SECTION> initFlag = 0; } //<RESTRICTED_SECTION> else if ( materialInterface ) { lhs->zero(); this->assemble( *lhs, stepWhenIcApply.get(), PressureLhsAssembler(), pnum, this->giveDomain(1) ); lhs->times(deltaT * theta1 * theta2); if ( consistentMassFlag ) { mss->zero(); this->assemble( *mss, stepWhenIcApply.get(), MassMatrixAssembler(), vnum, this->giveDomain(1) ); } else { mm.zero(); this->assembleVectorFromElements( mm, tStep, LumpedMassVectorAssembler(), VM_Total, vnum, this->giveDomain(1) ); } } //</RESTRICTED_SECTION> if ( tStep->isTheFirstStep() ) { TimeStep *stepWhenIcApply = tStep->givePreviousStep(); this->applyIC(stepWhenIcApply); } VelocityField.advanceSolution(tStep); PressureField.advanceSolution(tStep); FloatArray *velocityVector = VelocityField.giveSolutionVector(tStep); FloatArray *prevVelocityVector = VelocityField.giveSolutionVector( tStep->givePreviousStep() ); FloatArray *pressureVector = PressureField.giveSolutionVector(tStep); FloatArray *prevPressureVector = PressureField.giveSolutionVector( tStep->givePreviousStep() ); velocityVector->resize(momneq); pressureVector->resize(presneq); /* STEP 1 - calculates auxiliary velocities*/ rhs.zero(); // Depends on old v: this->assembleVectorFromElements( rhs, tStep, IntermediateConvectionDiffusionAssembler(), VM_Total, vnum, this->giveDomain(1) ); //this->assembleVectorFromElements(mm, tStep, LumpedMassVectorAssembler(), VM_Total, this->giveDomain(1)); if ( consistentMassFlag ) { rhs.times(deltaT); // Depends on prescribed v this->assembleVectorFromElements( rhs, tStep, PrescribedVelocityRhsAssembler(), VM_Total, vnum, this->giveDomain(1) ); nMethod->solve(*mss, rhs, deltaAuxVelocity); } else { for ( int i = 1; i <= momneq; i++ ) { deltaAuxVelocity.at(i) = deltaT * rhs.at(i) / mm.at(i); } } /* STEP 2 - calculates pressure (implicit solver) */ this->prescribedTractionPressure.resize(presneq_prescribed); this->prescribedTractionPressure.zero(); this->assembleVectorFromElements( prescribedTractionPressure, tStep, DensityPrescribedTractionPressureAssembler(), VM_Total, pnumPrescribed, this->giveDomain(1) ); for ( int i = 1; i <= presneq_prescribed; i++ ) { prescribedTractionPressure.at(i) /= nodalPrescribedTractionPressureConnectivity.at(i); } // DensityRhsVelocityTerms needs this: Current velocity without correction; * velocityVector = * prevVelocityVector; velocityVector->add(this->theta1, deltaAuxVelocity); // Depends on old V + deltaAuxV * theta1 and p: rhs.resize(presneq); rhs.zero(); this->assembleVectorFromElements( rhs, tStep, DensityRhsAssembler(), VM_Total, pnum, this->giveDomain(1) ); this->giveNumericalMethod( this->giveCurrentMetaStep() ); nMethod->solve(*lhs, rhs, *pressureVector); pressureVector->times(this->theta2); pressureVector->add(* prevPressureVector); /* STEP 3 - velocity correction step */ rhs.resize(momneq); rhs.zero(); // Depends on p: this->assembleVectorFromElements( rhs, tStep, CorrectionRhsAssembler(), VM_Total, vnum, this->giveDomain(1) ); if ( consistentMassFlag ) { rhs.times(deltaT); //this->assembleVectorFromElements(rhs, tStep, PrescribedRhsAssembler(), VM_Incremental, vnum, this->giveDomain(1)); nMethod->solve(*mss, rhs, *velocityVector); velocityVector->add(deltaAuxVelocity); velocityVector->add(* prevVelocityVector); } else { for ( int i = 1; i <= momneq; i++ ) { velocityVector->at(i) = prevVelocityVector->at(i) + deltaAuxVelocity.at(i) + deltaT *rhs.at(i) / mm.at(i); } } // update solution state counter tStep->incrementStateCounter(); //<RESTRICTED_SECTION> if ( materialInterface ) { #ifdef TIME_REPORT Timer timer; timer.startTimer(); #endif materialInterface->updatePosition( this->giveCurrentStep() ); #ifdef TIME_REPORT timer.stopTimer(); OOFEM_LOG_INFO( "CBS info: user time consumed by updating interfaces: %.2fs\n", timer.getUtime() ); #endif } //</RESTRICTED_SECTION> }
void TransientTransportProblem :: solveYourselfAt(TimeStep *tStep) { Domain *d = this->giveDomain(1); int neq = this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ); field->advanceSolution(tStep); field->applyBoundaryCondition(tStep); if ( tStep->isTheFirstStep() ) { this->applyIC(); } field->initialize(VM_Total, tStep, solution, EModelDefaultEquationNumbering()); if ( !effectiveMatrix ) { effectiveMatrix.reset( classFactory.createSparseMtrx(sparseMtrxType) ); effectiveMatrix->buildInternalStructure( this, 1, EModelDefaultEquationNumbering() ); if ( lumped ) { capacityDiag.resize(neq); this->assembleVector( capacityDiag, tStep, LumpedMassVectorAssembler(), VM_Total, EModelDefaultEquationNumbering(), d ); } else { capacityMatrix.reset( classFactory.createSparseMtrx(sparseMtrxType) ); capacityMatrix->buildInternalStructure( this, 1, EModelDefaultEquationNumbering() ); this->assemble( *capacityMatrix, tStep, MassMatrixAssembler(), EModelDefaultEquationNumbering(), d ); } if ( this->keepTangent ) { this->assemble( *effectiveMatrix, tStep, TangentAssembler(TangentStiffness), EModelDefaultEquationNumbering(), d ); effectiveMatrix->times(alpha); if ( lumped ) { effectiveMatrix->addDiagonal(1./tStep->giveTimeIncrement(), capacityDiag); } else { effectiveMatrix->add(1./tStep->giveTimeIncrement(), *capacityMatrix); } } } OOFEM_LOG_INFO("Assembling external forces\n"); FloatArray externalForces(neq); externalForces.zero(); this->assembleVector( externalForces, tStep, ExternalForceAssembler(), VM_Total, EModelDefaultEquationNumbering(), d ); this->updateSharedDofManagers(externalForces, EModelDefaultEquationNumbering(), LoadExchangeTag); // set-up numerical method this->giveNumericalMethod( this->giveCurrentMetaStep() ); OOFEM_LOG_INFO("Solving for %d unknowns...\n", neq); internalForces.resize(neq); FloatArray incrementOfSolution; double loadLevel; int currentIterations; this->nMethod->solve(*this->effectiveMatrix, externalForces, NULL, // ignore this->solution, incrementOfSolution, this->internalForces, this->eNorm, loadLevel, // ignore SparseNonLinearSystemNM :: rlm_total, // ignore currentIterations, // ignore tStep); }
void TransientTransportProblem :: solveYourselfAt(TimeStep *tStep) { Domain *d = this->giveDomain(1); int neq = this->giveNumberOfDomainEquations( 1, EModelDefaultEquationNumbering() ); if ( tStep->isTheFirstStep() ) { this->applyIC(); } field->advanceSolution(tStep); #if 1 // This is what advanceSolution should be doing, but it can't be there yet // (backwards compatibility issues due to inconsistencies in other solvers). TimeStep *prev = tStep->givePreviousStep(); for ( auto &dman : d->giveDofManagers() ) { static_cast< DofDistributedPrimaryField* >(field.get())->setInitialGuess(*dman, tStep, prev); } for ( auto &elem : d->giveElements() ) { int ndman = elem->giveNumberOfInternalDofManagers(); for ( int i = 1; i <= ndman; i++ ) { static_cast< DofDistributedPrimaryField* >(field.get())->setInitialGuess(*elem->giveInternalDofManager(i), tStep, prev); } } for ( auto &bc : d->giveBcs() ) { int ndman = bc->giveNumberOfInternalDofManagers(); for ( int i = 1; i <= ndman; i++ ) { static_cast< DofDistributedPrimaryField* >(field.get())->setInitialGuess(*bc->giveInternalDofManager(i), tStep, prev); } } #endif field->applyBoundaryCondition(tStep); field->initialize(VM_Total, tStep, solution, EModelDefaultEquationNumbering()); if ( !effectiveMatrix ) { effectiveMatrix.reset( classFactory.createSparseMtrx(sparseMtrxType) ); effectiveMatrix->buildInternalStructure( this, 1, EModelDefaultEquationNumbering() ); if ( lumped ) { capacityDiag.resize(neq); this->assembleVector( capacityDiag, tStep, LumpedMassVectorAssembler(), VM_Total, EModelDefaultEquationNumbering(), d ); } else { capacityMatrix.reset( classFactory.createSparseMtrx(sparseMtrxType) ); capacityMatrix->buildInternalStructure( this, 1, EModelDefaultEquationNumbering() ); this->assemble( *capacityMatrix, tStep, MassMatrixAssembler(), EModelDefaultEquationNumbering(), d ); } if ( this->keepTangent ) { this->assemble( *effectiveMatrix, tStep, TangentAssembler(TangentStiffness), EModelDefaultEquationNumbering(), d ); effectiveMatrix->times(alpha); if ( lumped ) { effectiveMatrix->addDiagonal(1./tStep->giveTimeIncrement(), capacityDiag); } else { effectiveMatrix->add(1./tStep->giveTimeIncrement(), *capacityMatrix); } } } OOFEM_LOG_INFO("Assembling external forces\n"); FloatArray externalForces(neq); externalForces.zero(); this->assembleVector( externalForces, tStep, ExternalForceAssembler(), VM_Total, EModelDefaultEquationNumbering(), d ); this->updateSharedDofManagers(externalForces, EModelDefaultEquationNumbering(), LoadExchangeTag); // set-up numerical method this->giveNumericalMethod( this->giveCurrentMetaStep() ); OOFEM_LOG_INFO("Solving for %d unknowns...\n", neq); internalForces.resize(neq); FloatArray incrementOfSolution; double loadLevel; int currentIterations; this->nMethod->solve(*this->effectiveMatrix, externalForces, NULL, // ignore NULL, this->solution, incrementOfSolution, this->internalForces, this->eNorm, loadLevel, // ignore SparseNonLinearSystemNM :: rlm_total, // ignore currentIterations, // ignore tStep); }