Beispiel #1
0
  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);
  }
Beispiel #2
0
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;
}