py::tuple compute_frequencies(Vector &ea, Vector &eix, Vector &eiy, Vector &gj, Vector &rhoJ, int &n) { int ndof; ndof = n*6; // int nnode; // nnode = BldR.size(); // ndof = 6 * nnode; // Vector freqs(ndof); // Matrix eig_vec(ndof, ndof); Vector freqs(ndof); Matrix eig_vec(0, 0); mycurve->frequencies(ea, eix, eiy, gj, rhoJ, freqs, eig_vec); return py::make_tuple(freqs, eig_vec); }
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; }