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();
601 gsEigen::SelfAdjointEigenSolver<gsMatrix<T>> es2(m_jacMat);
602 m_stabilityVec = es2.eigenvalues();
605 else if (m_bifurcationMethod == bifmethod::Nothing)
610 gsInfo<<
"bifurcation method unknown!";
612 m_negatives = countNegatives(m_stabilityVec);
613 m_indicator = m_stabilityVec.colwise().minCoeff()[0];
614 m_stability = (m_indicator < 0) ? 1 : -1;
620 return (m_indicator < 0) ? 1 : -1;
626 return (m_stability*m_stabilityPrev < 0) ? true :
false;
635 gsInfo<<
"Extended iterations --- Starting with U.norm = "<<m_U.norm()<<
" and L = "<<m_L<<
"\n";
637 m_jacMat = this->computeJacobian(m_U,m_deltaU);
638 this->factorizeMatrix(m_jacMat);
639 m_basisResidualKTPhi = (m_jacMat*m_V).norm();
649 _initOutputExtended();
650 for (m_numIterations = 0; m_numIterations < m_maxIterations; ++m_numIterations)
652 _extendedSystemIteration();
653 m_DeltaU += m_deltaU;
654 m_DeltaL += m_deltaL;
655 m_DeltaV += m_deltaV;
661 m_jacMat = this->computeJacobian(m_U+m_DeltaU,m_deltaU);
662 this->factorizeMatrix(m_jacMat);
663 m_residueKTPhi = (m_jacMat*(m_V+m_DeltaV)).norm();
664 m_resVec = this->computeResidual(m_U+m_DeltaU,m_L+m_DeltaL);
665 computeResidualNorms();
667 _stepOutputExtended();
671 if ( m_residueKTPhi< tol )
675 gsInfo<<
"Iterations finished. U.norm() = "<<m_U.norm()<<
"\t L = "<<m_L<<
"\n";
678 if (m_numIterations == m_maxIterations-1)
680 gsInfo<<
"Warning: Extended iterations did not converge! \n";
685 gsInfo<<
"Iterations finished; continuing with last solution U.norm() = "<<m_U.norm()<<
"\t L = "<<m_L<<
"\n";
696 gsInfo<<
"Iterations finished. continuing with original solution U.norm() = "<<m_U.norm()<<
"\t L = "<<m_L<<
"\n";
708 m_resVec = this->computeResidual(m_U+m_DeltaU, m_L+m_DeltaL);
709 m_jacMat = this->computeJacobian(m_U+m_DeltaU,m_deltaU);
710 this->factorizeMatrix(m_jacMat);
714 m_deltaUt = this->solveSystem(m_forcing);
715 m_deltaUbar = this->solveSystem(-m_resVec);
718 gsSparseMatrix<T> jacMatEps = this->computeJacobian((m_U+m_DeltaU) + eps*(m_V+m_DeltaV));
720 gsVector<T> h1 = 1/eps * ( jacMatEps * m_deltaUt ) - 1/eps * m_forcing;
721 gsVector<T> h2 = m_jacMat * (m_V+m_DeltaV) + 1/eps * ( jacMatEps * m_deltaUbar + m_resVec );
723 this->factorizeMatrix(m_jacMat);
725 m_deltaVt = this->solveSystem(-h1);
726 m_deltaVbar = this->solveSystem(-h2);
728 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 );
730 m_deltaU = m_deltaL * m_deltaUt + m_deltaUbar;
733 m_deltaV = m_deltaL * m_deltaVt + m_deltaVbar;
740 this->_computeStability(x,jacobian);
741 m_note +=
"(" + std::to_string(m_negatives) +
")";
748 this->_computeStability(x,jacobian);
762 real_t dL = m_arcLength;
763 bool adaptiveBool = m_adaptiveLength;
764 m_adaptiveLength =
false;
765 bool converged =
false;
767 T referenceError = _bisectionTerminationFunction(m_U,
true);
769 gsInfo<<
"Bisection iterations --- Starting with U.norm = "<<m_U.norm()<<
" and L = "<<m_L<<
"; Reference error = "<<referenceError<<
"\n";
772 fa = _bisectionObjectiveFunction(m_U,
false);
778 for (
index_t k = 1; k < m_maxIterations; ++k)
780 if (m_verbose)
gsInfo<<
"\t bisection iteration "<<k<<
"\t arc length = "<<m_arcLength<<
"; ";
786 gsInfo<<
"From U.norm = "<<m_U.norm()<<
" and L = "<<m_L<<
"\n";
792 fb = _bisectionObjectiveFunction(m_U,
true);
802 m_arcLength = m_arcLength/2.0;
806 T term = _bisectionTerminationFunction(m_U,
false);
808 if (m_verbose)
gsInfo<<
"\t Finished. Relative error = "<< abs(term/referenceError)<<
"\t"<<
" obj.value = "<<term<<
"\n";
811 if ( abs(term/referenceError) < tol )
820 m_adaptiveLength = adaptiveBool;
828 this->factorizeMatrix(m_jacMat);
830 m_V = this->solveSystem(m_V);
832 if ( (m_V-Vold).norm() < m_tolerance )
846 real_t lenPhi = m_V.norm();
847 real_t xi = lenPhi/m_tau;
850 m_U = m_U + m_DeltaU;
853 m_DeltaUold.setZero();
866 gsInfo<<std::setw(4)<<std::left<<
"It.";
867 gsInfo<<std::setw(17)<<std::left<<
"Res. F";
868 gsInfo<<std::setw(17)<<std::left<<
"|dU|/|Du|";
869 gsInfo<<std::setw(17)<<std::left<<
"dL/DL";
870 gsInfo<<std::setw(17)<<std::left<<
"K_T * φ";
871 gsInfo<<std::setw(17)<<std::left<<
"|U|";
872 gsInfo<<std::setw(17)<<std::left<<
"|φ|";
873 gsInfo<<std::setw(17)<<std::left<<
"L";
874 gsInfo<<std::setw(17)<<std::left<<
"|DU|";
875 gsInfo<<std::setw(17)<<std::left<<
"|Dφ|";
876 gsInfo<<std::setw(17)<<std::left<<
"DL";
877 gsInfo<<std::setw(17)<<std::left<<
"|dU|";
878 gsInfo<<std::setw(17)<<std::left<<
"|dφ|";
879 gsInfo<<std::setw(17)<<std::left<<
"dL";
880 gsInfo<<std::setw(17)<<std::left<<
"Dmin";
881 gsInfo<<std::setw(17)<<std::left<<
"note";
891 gsInfo<<std::setw(4)<<std::left<<m_numIterations;
892 gsInfo<<std::setw(17)<<std::left<<m_residueF;
893 gsInfo<<std::setw(17)<<std::left<<m_residueU;
894 gsInfo<<std::setw(17)<<std::left<<m_residueL;
895 gsInfo<<std::setw(17)<<std::left<<m_residueKTPhi;
896 gsInfo<<std::setw(17)<<std::left<<(m_U).norm();
897 gsInfo<<std::setw(17)<<std::left<<(m_V).norm();
898 gsInfo<<std::setw(17)<<std::left<<(m_L);
899 gsInfo<<std::setw(17)<<std::left<<m_DeltaU.norm();
900 gsInfo<<std::setw(17)<<std::left<<m_DeltaV.norm();
901 gsInfo<<std::setw(17)<<std::left<<m_DeltaL;
902 gsInfo<<std::setw(17)<<std::left<<m_deltaU.norm();
903 gsInfo<<std::setw(17)<<std::left<<m_deltaV.norm();
904 gsInfo<<std::setw(17)<<std::left<<m_deltaL;
905 gsInfo<<std::setw(17)<<std::left<<_bisectionTerminationFunction(m_U,
false);
906 gsInfo<<std::setw(17)<<std::left<<m_note;
Performs the arc length method to solve a nonlinear system of equations.
Definition gsALMBase.h:38
virtual void computeLength()
Compute the adaptive arc-length.
Definition gsALMBase.hpp:106
virtual gsVector< T > solveSystem(const gsVector< T > &F)
Solve the system with right-hand side F.
Definition gsALMBase.hpp:201
virtual void _computeStability(const gsVector< T > &x, bool jacobian=true, T shift=-1e2)
See computeStability.
Definition gsALMBase.hpp:547
virtual void _initOutputExtended()
Initialize the output for extended iterations.
Definition gsALMBase.hpp:863
virtual void defaultOptions()
Set default options.
Definition gsALMBase.hpp:23
virtual bool stabilityChange() const
Checks if the stability of the system changed since the previously known solution.
Definition gsALMBase.hpp:624
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
virtual void _extendedSystemIteration()
Perform an extended system iteration.
Definition gsALMBase.hpp:706
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:631
virtual void init(bool stability)
Initialize the solver.
Definition gsALMBase.hpp:96
virtual gsSparseMatrix< T > _computeJacobian(const gsVector< T > &U, const gsVector< T > &dU)
Compute the jacobian matrix.
Definition gsALMBase.hpp:214
virtual gsStatus step()
Perform one arc-length step.
Definition gsALMBase.hpp:328
virtual T _bisectionTerminationFunction(const gsVector< T > &x, bool jacobian=true)
Returns the termination function for the bisection method given solution x.
Definition gsALMBase.hpp:746
virtual void computeResidualNorms()
Compute the residual error norms.
Definition gsALMBase.hpp:151
virtual void computeUt()
Compute .
Definition gsALMBase.hpp:255
virtual bool _testSingularPoint(bool jacobian=false)
Tests if a point is a bifurcation point.
Definition gsALMBase.hpp:475
virtual T resetLength()
Reset the length.
Definition gsALMBase.hpp:127
virtual void _step()
Implementation of step.
Definition gsALMBase.hpp:354
virtual gsStatus computeStability(bool jacobian=true, T shift=-1e2)
Calculates the stability of the solution x.
Definition gsALMBase.hpp:521
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:738
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 T reduceLength(T fac=0.5)
Reduce the length by multiplication with a factor fac.
Definition gsALMBase.hpp:120
virtual void _stepOutputExtended()
Step output for extended iterations.
Definition gsALMBase.hpp:888
virtual void computeUbar()
Compute .
Definition gsALMBase.hpp:249
virtual void factorizeMatrix(const gsSparseMatrix< T > &M)
Factorize the matrix M.
Definition gsALMBase.hpp:186
virtual void switchBranch()
Switches branches.
Definition gsALMBase.hpp:843
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:754
virtual index_t stability() const
Computes the stability: -1 if unstable, +1 if stable.
Definition gsALMBase.hpp:618
virtual void getOptions()
Apply options.
Definition gsALMBase.hpp:57
virtual bool isBifurcation(bool jacobian=false)
Returns true if the point is a bifurcation.
Definition gsALMBase.hpp:514
Sparse matrix class, based on gsEigen::SparseMatrix.
Definition gsSparseMatrix.h:139
Abstract class for solvers. The solver interface is base on 3 methods: -compute set the system matrix...
Definition gsSparseSolver.h:67
Shifted Eigenvalue solver for real symmetric matrices.
Definition gsSpectra.h:362
A vector with arbitrary coefficient type and fixed or dynamic size.
Definition gsVector.h:37
#define index_t
Definition gsConfig.h:32
#define gsWarn
Definition gsDebug.h:50
#define GISMO_UNUSED(x)
Definition gsDebug.h:112
#define gsInfo
Definition gsDebug.h:43
#define GISMO_ASSERT(cond, message)
Definition gsDebug.h:89
The G+Smo namespace, containing all definitions for the library.
gsStatus
Definition gsStructuralAnalysisTypes.h:21
@ SolverError
Assembly problem in step.
@ AssemblyError
Assembly problem in step.
@ NotConverged
Step did not converge.