17 #include <gsStructuralAnalysis/src/gsALMSolvers/gsALMHelper.h>
25 m_options.addInt (
"MaxIter",
"Maximum iterations",100);
26 m_options.addReal(
"Tol",
"Tolerance",1e-6);
27 m_options.addReal(
"TolF",
"Tolerance",1e-3);
28 m_options.addReal(
"TolU",
"Tolerance",1e-6);
29 m_options.addReal(
"Perturbation",
"Set Perturbation factor Tau",1e3);
31 m_options.addReal(
"Length",
"Arclength",1e-2);
33 m_options.addSwitch(
"AdaptiveLength",
"Adaptive length",
false);
34 m_options.addInt (
"AdaptiveIterations",
"Desired iterations for adaptive length",10);
36 m_options.addSwitch(
"Quasi",
"Use Quasi Newton method",
false);
37 m_options.addInt (
"QuasiIterations",
"Number of iterations for quasi newton method",-1);
39 m_options.addInt (
"BifurcationMethod",
"Bifurcation Identification based on: -1: nothing, 0: Determinant; 1: Eigenvalue",bifmethod::Eigenvalue);
41 m_options.addInt (
"SingularPointFailure",
"What to do when a singular point determination fails?: 0 = Apply solution anyways; 1 = Proceed without singular point",SPfail::With);
42 m_options.addReal(
"SingularPointTestTol",
"Detection tolerance for singular points. Product of the mode shape and the forcing should be below this tolerance", 1e-6);
43 m_options.addInt (
"SingularPointTestIt" ,
"Number of iterations of the power method for the singular point test",5);
45 m_options.addReal(
"SingularPointComputeTolE",
"Tolerance for the extended iterations to compute a bifurcation point", 1e-10);
46 m_options.addReal(
"SingularPointComputeTolB",
"Tolerance for the bisection iterations to compute a bifurcation point. If tol = 0, no bi-section method is used.", 0);
48 m_options.addString(
"Solver",
"Sparse linear solver",
"SimplicialLDLT");
50 m_options.addSwitch (
"Verbose",
"Verbose output",
false);
52 m_options.addReal(
"Relaxation",
"Set Relaxation factor alpha",1.0);
59 m_maxIterations = m_options.getInt (
"MaxIter");
60 m_tolerance = m_options.getReal(
"Tol");
61 m_toleranceF = m_options.getReal(
"TolF");
62 m_toleranceU = m_options.getReal(
"TolU");
64 m_tau = m_options.getReal(
"Perturbation");
66 m_adaptiveLength = m_options.getSwitch(
"AdaptiveLength");
67 m_desiredIterations = m_options.getInt (
"AdaptiveIterations");
69 m_quasiNewton = m_options.getSwitch(
"Quasi");
70 m_quasiNewtonInterval = m_options.getInt (
"QuasiIterations");
72 m_bifurcationMethod = m_options.getInt (
"BifurcationMethod");
74 if (!
dynamic_cast<typename gsSparseSolver<T>::SimplicialLDLT*
>(m_solver.get()) && m_bifurcationMethod==bifmethod::Determinant)
76 gsWarn<<
"Determinant method cannot be used with solvers other than LDLT. Bifurcation method will be set to 'Eigenvalue'.\n";
77 m_bifurcationMethod = bifmethod::Eigenvalue;
80 m_verbose = m_options.getSwitch (
"Verbose");
81 m_relax = m_options.getReal(
"Relaxation");
83 m_arcLength = m_arcLength_prev = m_arcLength_ori = m_options.getReal(
"Length");
85 m_SPfail = m_options.getInt (
"SingularPointFailure");
86 m_SPTestTol = m_options.getReal(
"SingularPointTestTol");
87 m_SPTestIt = m_options.getInt (
"SingularPointTestIt");
89 m_SPCompTolE = m_options.getReal(
"SingularPointComputeTolE");
90 m_SPCompTolB = m_options.getReal(
"SingularPointComputeTolB");
100 this->_computeStability(m_U);
101 m_stability = this->stability();
109 T fac = m_desiredIterations / m_numIterations;
115 m_arcLength_prev = m_arcLength;
116 m_arcLength = m_arcLength*fac;
129 m_arcLength = m_arcLength_prev = m_arcLength_ori;
130 if (m_adaptiveLength)
139 if (!m_residualFun(U, L, resVec))
147 m_resVec = this->computeResidual(m_U + m_DeltaU, m_L + m_DeltaL);
153 if (m_numIterations ==0 )
156 m_basisResidualF = ((m_L+m_DeltaL) * m_forcing).norm();
157 m_basisResidualU = m_DeltaU.norm();
160 m_residueF = m_resVec.norm() / (((m_L+m_DeltaL) * m_forcing).norm());
161 m_residueU = m_deltaU.norm()/m_DeltaU.norm();
163 m_residueL = m_DeltaL;
168 m_residueF = m_resVec.norm() / m_basisResidualF;
169 m_residueU = m_deltaU.norm() / m_basisResidualU;
170 m_residueL = m_deltaL / m_DeltaL;
188 m_solver->compute(M);
189 if (m_solver->info()!=gsEigen::ComputationInfo::Success)
191 gsInfo<<
"Solver error with code "<<m_solver->info()<<
". See Eigen documentation on ComputationInfo \n"
192 <<gsEigen::ComputationInfo::Success<<
": Success"<<
"\n"
193 <<gsEigen::ComputationInfo::NumericalIssue<<
": NumericalIssue"<<
"\n"
194 <<gsEigen::ComputationInfo::NoConvergence<<
": NoConvergence"<<
"\n"
195 <<gsEigen::ComputationInfo::InvalidInput<<
": InvalidInput"<<
"\n";
205 return m_solver->solve(F);
219 if (!m_djacobian(U,deltaU,m))
221 this->factorizeMatrix(m);
228 return this->_computeJacobian(U,deltaU);
236 return this->computeJacobian(U,DeltaU);
243 if (m_deltaU.rows() == 0)
245 return this->computeJacobian(m_U + m_DeltaU, m_deltaU);
251 m_deltaUbar = this->solveSystem(-m_resVec);
257 m_deltaUt = this->solveSystem(m_forcing);
335 catch (
int errorCode)
339 else if (errorCode==2)
341 else if (errorCode==3)
356 GISMO_ASSERT(m_initialized,
"Arc-Length Method is not initialized! Call initialize()");
365 if (m_Uguess.rows()!=0 && m_Uguess.cols()!=0 && (m_Uguess-m_U).norm()!=0 && (m_Lguess-m_L)!=0)
371 computeResidualNorms();
378 quasiNewtonPredictor();
381 m_stabilityPrev = m_stability;
382 for (m_numIterations = 1; m_numIterations < m_maxIterations; ++m_numIterations)
384 if ( (!m_quasiNewton) || ( ( m_quasiNewtonInterval>0 ) && ( m_numIterations % m_quasiNewtonInterval) < 1e-10 ) )
386 quasiNewtonIteration();
390 computeStability(
false);
393 computeResidualNorms();
397 if ( m_residueF < m_toleranceF && m_residueU < m_toleranceU )
401 if (m_adaptiveLength)
404 m_arcLength_prev = m_arcLength;
408 else if (m_numIterations == m_maxIterations-1)
410 gsInfo<<
"maximum iterations reached. Solution did not converge\n";
425 bool test = (testPoint) ? this->_testSingularPoint(jacobian) :
true;
431 bool converged =
false;
433 if (m_SPCompTolB != 0)
434 this->_bisectionSolve(m_U,m_L,m_SPCompTolB);
436 converged = this->_extendedSystemSolve(m_U, m_L, m_SPCompTolE);
438 if (switchBranch && (converged || m_SPfail==1))
439 this->switchBranch();
444 m_stability = m_stabilityPrev;
454 this->_computeSingularPoint(U,L,switchBranch,jacobian, testPoint);
456 catch (
int errorCode)
460 else if (errorCode==2)
462 else if (errorCode==3)
482 m_jacMat = this->computeJacobian(m_U,m_deltaU);
483 this->factorizeMatrix(m_jacMat);
488 factorizeMatrix(m_jacMat);
490 for (
index_t k = 0; k<m_SPTestIt; k++)
492 m_V = this->solveSystem(m_V);
496 T dot = (
abs(m_V.dot(m_forcing)));
497 if ( (
abs(dot) / m_SPTestTol > 1e-1) && (
abs(dot) / m_SPTestTol < 10) )
499 gsInfo<<
"Warning: the singular point test is close to its tolerance. dot/tol = "<<
abs(dot)/m_SPTestTol<<
" dot = "<<dot<<
"\t tolerance = "<<m_SPTestTol<<
"\n";
501 if (dot < m_SPTestTol)
503 if (m_verbose) {
gsInfo<<
"\t Bifurcation point\n";}
508 if (m_verbose) {
gsInfo<<
"\t Limit point\n";}
517 return this->_testSingularPoint(jacobian);
525 _computeStability(m_U,jacobian,shift);
528 catch (
int errorCode)
532 else if (errorCode==2)
534 else if (errorCode==3)
552 m_jacMat = this->computeJacobian(x,dx);
553 this->factorizeMatrix(m_jacMat);
557 if (m_bifurcationMethod == bifmethod::Determinant)
559 if (
auto * s =
dynamic_cast<typename gsSparseSolver<T>::SimplicialLDLT*
>(m_solver.get()) )
561 factorizeMatrix(m_jacMat);
562 m_stabilityVec = s->vectorD();
566 gsWarn<<
"Determinant stability method only works with SimplicialLDLT solver, current solver is "<<m_options.getString(
"Solver")<<
"\n";
570 else if (m_bifurcationMethod == bifmethod::Eigenvalue)
572 #ifdef gsSpectra_ENABLED
573 index_t number = std::min(static_cast<index_t>(std::floor(m_jacMat.cols()/5.)),10);
587 es.compute(Spectra::SortRule::LargestAlge,1000,1e-6,Spectra::SortRule::SmallestAlge);
588 if (es.info()!=Spectra::CompInfo::Successful)
590 gsWarn<<
"Spectra did not converge!\n";
598 m_stabilityVec = es.eigenvalues();
600 gsEigen::SelfAdjointEigenSolver<gsMatrix<T>> es2(m_jacMat);
601 m_stabilityVec = es2.eigenvalues();
604 else if (m_bifurcationMethod == bifmethod::Nothing)
609 gsInfo<<
"bifurcation method unknown!";
611 m_negatives = countNegatives(m_stabilityVec);
612 m_indicator = m_stabilityVec.colwise().minCoeff()[0];
613 m_stability = (m_indicator < 0) ? 1 : -1;
619 return (m_indicator < 0) ? 1 : -1;
625 return (m_stability*m_stabilityPrev < 0) ?
true :
false;
634 gsInfo<<
"Extended iterations --- Starting with U.norm = "<<m_U.norm()<<
" and L = "<<m_L<<
"\n";
636 m_jacMat = this->computeJacobian(m_U,m_deltaU);
637 this->factorizeMatrix(m_jacMat);
638 m_basisResidualKTPhi = (m_jacMat*m_V).norm();
648 _initOutputExtended();
649 for (m_numIterations = 0; m_numIterations < m_maxIterations; ++m_numIterations)
651 _extendedSystemIteration();
652 m_DeltaU += m_deltaU;
653 m_DeltaL += m_deltaL;
654 m_DeltaV += m_deltaV;
660 m_jacMat = this->computeJacobian(m_U+m_DeltaU,m_deltaU);
661 this->factorizeMatrix(m_jacMat);
662 m_residueKTPhi = (m_jacMat*(m_V+m_DeltaV)).norm();
663 m_resVec = this->computeResidual(m_U+m_DeltaU,m_L+m_DeltaL);
664 computeResidualNorms();
666 _stepOutputExtended();
670 if ( m_residueKTPhi< tol )
674 gsInfo<<
"Iterations finished. U.norm() = "<<m_U.norm()<<
"\t L = "<<m_L<<
"\n";
677 if (m_numIterations == m_maxIterations-1)
679 gsInfo<<
"Warning: Extended iterations did not converge! \n";
684 gsInfo<<
"Iterations finished; continuing with last solution U.norm() = "<<m_U.norm()<<
"\t L = "<<m_L<<
"\n";
695 gsInfo<<
"Iterations finished. continuing with original solution U.norm() = "<<m_U.norm()<<
"\t L = "<<m_L<<
"\n";
707 m_resVec = this->computeResidual(m_U+m_DeltaU, m_L+m_DeltaL);
708 m_jacMat = this->computeJacobian(m_U+m_DeltaU,m_deltaU);
709 this->factorizeMatrix(m_jacMat);
713 m_deltaUt = this->solveSystem(m_forcing);
714 m_deltaUbar = this->solveSystem(-m_resVec);
717 gsSparseMatrix<T> jacMatEps = this->computeJacobian((m_U+m_DeltaU) + eps*(m_V+m_DeltaV));
719 gsVector<T> h1 = 1/eps * ( jacMatEps * m_deltaUt ) - 1/eps * m_forcing;
720 gsVector<T> h2 = m_jacMat * (m_V+m_DeltaV) + 1/eps * ( jacMatEps * m_deltaUbar + m_resVec );
722 this->factorizeMatrix(m_jacMat);
724 m_deltaVt = this->solveSystem(-h1);
725 m_deltaVbar = this->solveSystem(-h2);
727 m_deltaL = -( ( (m_V+m_DeltaV)/(m_V+m_DeltaV).norm() ).dot(m_deltaVbar) + (m_V+m_DeltaV).norm() - 1) / ( (m_V+m_DeltaV)/(m_V+m_DeltaV).norm() ).dot( m_deltaVt );
729 m_deltaU = m_deltaL * m_deltaUt + m_deltaUbar;
732 m_deltaV = m_deltaL * m_deltaVt + m_deltaVbar;
739 this->_computeStability(x,jacobian);
747 this->_computeStability(x,jacobian);
761 real_t dL = m_arcLength;
762 bool adaptiveBool = m_adaptiveLength;
763 m_adaptiveLength =
false;
764 bool converged =
false;
766 T referenceError = _bisectionTerminationFunction(m_U,
true);
768 gsInfo<<
"Bisection iterations --- Starting with U.norm = "<<m_U.norm()<<
" and L = "<<m_L<<
"; Reference error = "<<referenceError<<
"\n";
771 fa = _bisectionObjectiveFunction(m_U,
false);
777 for (
index_t k = 1; k < m_maxIterations; ++k)
779 if (m_verbose)
gsInfo<<
"\t bisection iteration "<<k<<
"\t arc length = "<<m_arcLength<<
"; ";
785 gsInfo<<
"From U.norm = "<<m_U.norm()<<
" and L = "<<m_L<<
"\n";
791 fb = _bisectionObjectiveFunction(m_U,
true);
801 m_arcLength = m_arcLength/2.0;
805 T term = _bisectionTerminationFunction(m_U,
false);
807 if (m_verbose)
gsInfo<<
"\t Finished. Relative error = "<<
abs(term/referenceError)<<
"\t"<<
" obj.value = "<<term<<
"\n";
810 if (
abs(term/referenceError) < tol )
819 m_adaptiveLength = adaptiveBool;
827 this->factorizeMatrix(m_jacMat);
829 m_V = this->solveSystem(m_V);
831 if ( (m_V-Vold).norm() < m_tolerance )
845 real_t lenPhi = m_V.norm();
846 real_t xi = lenPhi/m_tau;
849 m_U = m_U + m_DeltaU;
852 m_DeltaUold.setZero();
865 gsInfo<<std::setw(4)<<std::left<<
"It.";
866 gsInfo<<std::setw(17)<<std::left<<
"Res. F";
867 gsInfo<<std::setw(17)<<std::left<<
"|dU|/|Du|";
868 gsInfo<<std::setw(17)<<std::left<<
"dL/DL";
869 gsInfo<<std::setw(17)<<std::left<<
"K_T * φ";
870 gsInfo<<std::setw(17)<<std::left<<
"|U|";
871 gsInfo<<std::setw(17)<<std::left<<
"|φ|";
872 gsInfo<<std::setw(17)<<std::left<<
"L";
873 gsInfo<<std::setw(17)<<std::left<<
"|DU|";
874 gsInfo<<std::setw(17)<<std::left<<
"|Dφ|";
875 gsInfo<<std::setw(17)<<std::left<<
"DL";
876 gsInfo<<std::setw(17)<<std::left<<
"|dU|";
877 gsInfo<<std::setw(17)<<std::left<<
"|dφ|";
878 gsInfo<<std::setw(17)<<std::left<<
"dL";
879 gsInfo<<std::setw(17)<<std::left<<
"Dmin";
880 gsInfo<<std::setw(17)<<std::left<<
"note";
890 gsInfo<<std::setw(4)<<std::left<<m_numIterations;
891 gsInfo<<std::setw(17)<<std::left<<m_residueF;
892 gsInfo<<std::setw(17)<<std::left<<m_residueU;
893 gsInfo<<std::setw(17)<<std::left<<m_residueL;
894 gsInfo<<std::setw(17)<<std::left<<m_residueKTPhi;
895 gsInfo<<std::setw(17)<<std::left<<(m_U).norm();
896 gsInfo<<std::setw(17)<<std::left<<(m_V).norm();
897 gsInfo<<std::setw(17)<<std::left<<(m_L);
898 gsInfo<<std::setw(17)<<std::left<<m_DeltaU.norm();
899 gsInfo<<std::setw(17)<<std::left<<m_DeltaV.norm();
900 gsInfo<<std::setw(17)<<std::left<<m_DeltaL;
901 gsInfo<<std::setw(17)<<std::left<<m_deltaU.norm();
902 gsInfo<<std::setw(17)<<std::left<<m_deltaV.norm();
903 gsInfo<<std::setw(17)<<std::left<<m_deltaL;
904 gsInfo<<std::setw(17)<<std::left<<_bisectionTerminationFunction(m_U,
false);
905 gsInfo<<std::setw(17)<<std::left<<m_note;
virtual void defaultOptions()
Set default options.
Definition: gsALMBase.hpp:23
Shifted Eigenvalue solver for real symmetric matrices.
Definition: gsSpectra.h:359
virtual gsStatus computeStability(bool jacobian=true, T shift=-1e2)
Calculates the stability of the solution x.
Definition: gsALMBase.hpp:521
virtual void computeUbar()
Compute .
Definition: gsALMBase.hpp:249
virtual index_t _bisectionObjectiveFunction(const gsVector< T > &x, bool jacobian=true)
Returns the objective function for the bisection method given solution x.
Definition: gsALMBase.hpp:737
virtual gsStatus step()
Perform one arc-length step.
Definition: gsALMBase.hpp:328
virtual bool stabilityChange() const
Checks if the stability of the system changed since the previously known solution.
Definition: gsALMBase.hpp:623
virtual index_t stability() const
Computes the stability: -1 if unstable, +1 if stable.
Definition: gsALMBase.hpp:617
virtual gsStatus computeSingularPoint(const gsVector< T > &U, const T &L, bool switchBranch=false, bool jacobian=false, bool testPoint=true)
Calculates the singular point.
Definition: gsALMBase.hpp:450
virtual void computeUt()
Compute .
Definition: gsALMBase.hpp:255
virtual gsSparseMatrix< T > _computeJacobian(const gsVector< T > &U, const gsVector< T > &dU)
Compute the jacobian matrix.
Definition: gsALMBase.hpp:214
virtual T reduceLength(T fac=0.5)
Reduce the length by multiplication with a factor fac.
Definition: gsALMBase.hpp:120
virtual void _step()
Implementation of step.
Definition: gsALMBase.hpp:354
Assembly problem in step.
virtual void _extendedSystemIteration()
Perform an extended system iteration.
Definition: gsALMBase.hpp:705
Assembly failed due to an error in the expression (e.g. overflow)
#define index_t
Definition: gsConfig.h:32
gsStatus
Definition: gsStructuralAnalysisTypes.h:20
virtual void computeResidualNorms()
Compute the residual error norms.
Definition: gsALMBase.hpp:151
#define GISMO_ASSERT(cond, message)
Definition: gsDebug.h:89
virtual bool isBifurcation(bool jacobian=false)
Returns true if the point is a bifurcation.
Definition: gsALMBase.hpp:514
virtual void _computeStability(const gsVector< T > &x, bool jacobian=true, T shift=-1e2)
See computeStability.
Definition: gsALMBase.hpp:547
virtual void _computeSingularPoint(const gsVector< T > &U, const T &L, bool switchBranch=false, bool jacobian=false, bool testPoint=true)
See computeSingularPoint.
Definition: gsALMBase.hpp:422
std::string to_string(const unsigned &i)
Helper to convert small unsigned to string.
Definition: gsXml.cpp:74
#define gsWarn
Definition: gsDebug.h:50
#define gsInfo
Definition: gsDebug.h:43
virtual bool _extendedSystemSolve(const gsVector< T > &U, const T L, const T tol)
Perform an extended system solve to find a singular point.
Definition: gsALMBase.hpp:630
virtual bool _testSingularPoint(bool jacobian=false)
Tests if a point is a bifurcation point.
Definition: gsALMBase.hpp:475
virtual void _initOutputExtended()
Initialize the output for extended iterations.
Definition: gsALMBase.hpp:862
virtual void computeLength()
Compute the adaptive arc-length.
Definition: gsALMBase.hpp:106
virtual bool _bisectionSolve(const gsVector< T > &U, const T L, const T tol)
Perform a bisection system solve to find a singular point.
Definition: gsALMBase.hpp:753
virtual void switchBranch()
Switches branches.
Definition: gsALMBase.hpp:842
Abstract class for solvers. The solver interface is base on 3 methods: -compute set the system matrix...
Definition: gsSparseSolver.h:66
EIGEN_STRONG_INLINE abs_expr< E > abs(const E &u)
Absolute value.
Definition: gsExpressions.h:4488
virtual void init(bool stability)
Initialize the solver.
Definition: gsALMBase.hpp:96
virtual T resetLength()
Reset the length.
Definition: gsALMBase.hpp:127
virtual void factorizeMatrix(const gsSparseMatrix< T > &M)
Factorize the matrix M.
Definition: gsALMBase.hpp:186
Performs the arc length method to solve a nonlinear system of equations.
Definition: gsALMBase.h:37
virtual void _stepOutputExtended()
Step output for extended iterations.
Definition: gsALMBase.hpp:887
virtual gsVector< T > solveSystem(const gsVector< T > &F)
Solve the system with right-hand side F.
Definition: gsALMBase.hpp:201
virtual T _bisectionTerminationFunction(const gsVector< T > &x, bool jacobian=true)
Returns the termination function for the bisection method given solution x.
Definition: gsALMBase.hpp:745
virtual void getOptions()
Apply options.
Definition: gsALMBase.hpp:57