G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsDynamicImplicitEuler.hpp
Go to the documentation of this file.
1 
14 #pragma once
15 
16 #include <gsSolver/gsGMRes.h>
17 #include <gsSolver/gsMatrixOp.h>
18 #include <gsSolver/gsBlockOp.h>
19 
20 namespace gismo
21 {
22 
23 template <class T, bool _NL>
24 template <bool _nonlinear>
25 typename std::enable_if<(_nonlinear==false), gsStatus>::type
26 gsDynamicImplicitEuler<T,_NL>::_step_impl(const T t, const T dt, gsVector<T> & U, gsVector<T> & V, gsVector<T> & A) const
27 {
28  gsVector<T> Uold = U;
29  gsVector<T> Vold = V;
30  gsVector<T> Aold = A;
31 
32  index_t N = U.rows();
33  gsVector<T> sol(2*N);
34  sol.topRows(N) = U;
35  sol.bottomRows(N) = V;
36 
37  typename gsBlockOp<>::Ptr Amat;
38 
39  Amat=gsBlockOp<>::make(2,2);
40  gsGMRes<T> gmres(Amat);
41 
42  gsSparseMatrix<T> eye(N,N);
43  eye.setIdentity();
44 
45  gsVector<T> F;
46  gsSparseMatrix<T> M, C, K;
47  gsSparseMatrix<T> Minv;
48 
49  // Computed at t=t0+dt
50  this->_computeMass(t+dt,M);
51  this->_computeForce(t+dt,F);
52  this->_computeDamping(U,t+dt,C);
53  this->_computeJacobian(U,t,K);
54 
55  // top-left
56  Amat->addOperator(0,0,gsIdentityOp<T>::make(N) );
57  // top-right
58  Amat->addOperator(0,1,makeMatrixOp( -dt*eye ) );
59  // bottom-left
60  Amat->addOperator(1,0,makeMatrixOp( dt*K ) );
61  // bottom-right
62  Amat->addOperator(1,1,makeMatrixOp( M + dt*C ) );
63 
64  gsVector<T> rhs(2*N);
65  rhs.topRows(N) = U;
66  rhs.bottomRows(N) = dt*F + M*V;
67 
68  gsMatrix<T> tmpsol;
69  gmres.solve(rhs,tmpsol);
70 
71  U = tmpsol.topRows(N);
72  V = tmpsol.bottomRows(N);
73  this->_initOutput();
74  this->_stepOutput(0,sol.norm(),0.);
75 
76  return gsStatus::Success;
77 }
78 
79 
80 template <class T, bool _NL>
81 template <bool _nonlinear>
82 typename std::enable_if<(_nonlinear==true), gsStatus>::type
83 gsDynamicImplicitEuler<T,_NL>::_step_impl(const T t, const T dt, gsVector<T> & U, gsVector<T> & V, gsVector<T> & A) const
84 {
85  gsVector<T> Uold = U;
86  gsVector<T> Vold = V;
87  gsVector<T> Aold = A;
88 
89  index_t N = U.rows();
90  gsVector<T> sol(2*N);
91  sol.topRows(N) = U;
92  sol.bottomRows(N) = V;
93 
94  gsMatrix<T> dsol;
95 
96  typename gsBlockOp<>::Ptr Amat;
97 
98  Amat=gsBlockOp<>::make(2,2);
99  gsGMRes<T> gmres(Amat);
100 
101  gsSparseMatrix<T> eye(N,N);
102  eye.setIdentity();
103 
104  gsVector<T> R;
105  gsSparseMatrix<T> M, C, K;
106 
107  // Computed at t=t0+dt
108  this->_computeMass(t+dt,M);
109  this->_computeDamping(U,t+dt,C);
110  this->_computeResidual(U,t+dt,R);
111 
112  gsVector<T> rhs(2*N);
113  rhs.topRows(N) = - dt * V; // same as below, but U-Uold=0
114  rhs.bottomRows(N) = dt * C * V + dt*(-R); // same as below, but V-Vold=0
115 
116  T tolU = m_options.getReal("TolU");
117  T tolF = m_options.getReal("TolF");
118  T updateNorm = 10.0*tolU;
119  T residualNorm = rhs.norm();
120  T residualNorm0 = (residualNorm!=0) ? residualNorm : 1;
121  T solnorm, dsolnorm;
122  this->_initOutput();
123  for (index_t numIterations = 0; numIterations < m_options.getInt("MaxIter"); ++numIterations)
124  {
125  // TODO: Quasi newton
126  if ((!m_options.getSwitch("Quasi")) || ((numIterations==0) || (numIterations % m_options.getInt("QuasiIterations") == 0)))
127  {
128  // Computed at t=t0+dt
129  this->_computeDamping(U,t+dt,C);
130  this->_computeJacobian(U,t+dt,K);
131  }
132 
133  Amat->addOperator(0,0,gsIdentityOp<T>::make(N) );
134  Amat->addOperator(0,1,makeMatrixOp(-dt*eye) );
135  Amat->addOperator(1,0,makeMatrixOp(dt*K) );
136  Amat->addOperator(1,1,makeMatrixOp(M + dt*C) );
137 
138  rhs.topRows(N) = U - Uold - dt * V;
139  rhs.bottomRows(N) = M*(V - Vold) + dt * C * V + dt*(-R);
140 
141  gmres.solve(-rhs,dsol);
142  sol += dsol;
143 
144  solnorm = sol.norm();
145  dsolnorm = dsol.norm();
146  updateNorm = (solnorm != 0) ? dsolnorm / solnorm : dsolnorm;
147 
148  U = sol.topRows(N);
149  V = sol.bottomRows(N);
150 
151  this->_computeResidual(U,t,R);
152  residualNorm = rhs.norm() / residualNorm0;
153 
154  this->_stepOutput(numIterations,residualNorm,updateNorm);
155 
156  if ( (updateNorm<tolU && residualNorm<tolF) )
157  {
158  return gsStatus::Success;
159  }
160  }
161 
162  gsInfo<<"maximum iterations reached. Solution did not converge\n";
163  return gsStatus::NotConverged;
164 }
165 
166 template <class T, bool _NL>
168  gsVector<T> & U, gsVector<T> & V,
169  gsVector<T> & A) const
170 {
172  status = _step_impl<_NL>(t,dt,U,V,A);
173  return status;
174 }
175 
176 template <class T, bool _NL>
178 {
179  if (m_options.getSwitch("Verbose"))
180  {
181  gsInfo<<"\t";
182  gsInfo<<std::setw(4)<<std::left<<"It.";
183  gsInfo<<std::setw(17)<<std::left<<"|R|/|R0|";
184  gsInfo<<std::setw(17)<<std::left<<"|dU|/|U0|"<<"\n";
185  }
186 }
187 
188 template <class T, bool _NL>
189 void gsDynamicImplicitEuler<T,_NL>::_stepOutput(const index_t it, const T resnorm, const T updatenorm) const
190 {
191  if (m_options.getSwitch("Verbose"))
192  {
193  gsInfo<<"\t";
194  gsInfo<<std::setw(4)<<std::left<<it;
195  gsInfo<<std::setw(17)<<std::left<<resnorm;
196  gsInfo<<std::setw(17)<<std::left<<updatenorm<<"\n";
197  }
198 }
199 
200 } // namespace gismo
Step did not converge.
Simple class create a block preconditioner structure.
Preconditioned iterative solver using the generalized minimal residual method.
#define index_t
Definition: gsConfig.h:32
gsStatus
Definition: gsStructuralAnalysisTypes.h:20
gsStatus _step(const T t, const T dt, gsVector< T > &U, gsVector< T > &V, gsVector< T > &A) const override
Initialize the ALM.
Definition: gsDynamicImplicitEuler.hpp:167
#define gsInfo
Definition: gsDebug.h:43
ALM has not started yet.
Performs the arc length method to solve a nonlinear system of equations.
Definition: gsDynamicImplicitEuler.h:33
static uPtr make(index_t nRows, index_t nCols)
Make function returning a smart pointer.
Definition: gsBlockOp.h:60
Simple adapter classes to use matrices or linear solvers as gsLinearOperators.