G+Smo  24.08.0
Geometry + Simulation Modules
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
gsPartitionedFSI.hpp
Go to the documentation of this file.
1 
15 #pragma once
16 
18 
21 #include <gsElasticity/gsALE.h>
22 #include <gsUtils/gsStopwatch.h>
24 
25 namespace gismo
26 {
27 
28 template <class T>
29 gsPartitionedFSI<T>::gsPartitionedFSI(gsNsTimeIntegrator<T> & nsSolver,
30  gsMultiPatch<T> & velocity, gsMultiPatch<T> & pressure,
31  gsElTimeIntegrator<T> & elSolver,
32  gsMultiPatch<T> & displacement,
33  gsALE<T> & aleSolver,
34  gsMultiPatch<T> & aleDisplacement, gsMultiPatch<T> & aleVelocity) :
35  m_nsSolver(nsSolver),
36  m_velocity(velocity),
37  m_pressure(pressure),
38  m_elSolver(elSolver),
39  m_displacement(displacement),
40  m_aleSolver(aleSolver),
41  m_ALEdisplacment(aleDisplacement),
42  m_ALEvelocity(aleVelocity),
43  m_options(defaultOptions())
44 {
45 
46 }
47 
48 template <class T>
49 gsOptionList gsPartitionedFSI<T>::defaultOptions()
50 {
51  gsOptionList opt;
52  opt.addInt("MaxIter","Maximum number of coupling iterations per time step",10);
53  opt.addReal("AbsTol","Absolute tolerance for the convergence creterion",1e-10);
54  opt.addReal("RelTol","Absolute tolerance for the convergence creterion",1e-6);
55  opt.addInt("Verbosity","Amount of information printed to the terminal: none, some, all",solver_verbosity::none);
56  return opt;
57 }
58 
59 template <class T>
60 bool gsPartitionedFSI<T>::makeTimeStep(T timeStep)
61 {
62  // save states of the component solvers at the beginning of the time step
63  m_nsSolver.saveState();
64  m_elSolver.saveState();
65  m_aleSolver.saveState();
66 
67  // reset the solver
68  numIter = 0;
69  converged = false;
70  omega = 1.;
71 
72  // reset time profiling info
73  gsStopwatch clock;
74  nsTime = elTime = aleTime = 0.;
75 
76  gsMultiPatch<> dispOldOld, dispOld, dispOldGuess;
77 
78  while (numIter < m_options.getInt("MaxIter") && !converged)
79  {
80  // ================== Structure section ================ //
81  clock.restart();
82  if (numIter > 0) // recover the solver state from the time step beginning
83  m_elSolver.recoverState();
84 
85  m_elSolver.makeTimeStep(timeStep);
86 
87  if (numIter == 0) // save displacement i-2, no correction
88  {
89  m_elSolver.constructSolution(dispOldOld);
90  m_elSolver.constructSolution(m_displacement);
91  }
92  else if (numIter == 1) // save displacement i-1 as a guess and a corrected solution
93  {
94  m_elSolver.constructSolution(dispOld);
95  m_elSolver.constructSolution(dispOldGuess);
96  m_elSolver.constructSolution(m_displacement);
97  gsMatrix<> vecA, vecB;
98  formVector(dispOldOld,vecA);
99  formVector(m_displacement,vecB);
100  absResNorm = initResNorm = (vecB-vecA).norm()/sqrt(vecB.rows());
101  }
102  else // save displacement as a current guess i and apply Aitken relaxation
103  {
104  m_elSolver.constructSolution(m_displacement);
105  aitken(dispOldOld,dispOldGuess,dispOld,m_displacement);
106  }
107 
108  if (numIter > 0 && m_options.getInt("Verbosity") == solver_verbosity::all)
109  gsInfo << numIter << ": absRes " << absResNorm << ", relRes " << absResNorm/initResNorm << std::endl;
110 
111 
112  elTime += clock.stop();
113  // =================================================================== //
114 
115 
116  // ============= Flow mesh/ALE section ===================== //
117  clock.restart();
118  // recover ALE at the start of timestep
119  if (numIter > 0)
120  m_aleSolver.recoverState();
121 
122  // undo last ALE deformation of the flow domain
123  for (size_t p = 0; p < m_nsSolver.aleInterface().patches.size(); ++p)
124  {
125  index_t pFlow = m_nsSolver.aleInterface().patches[p].second;
126  index_t pALE = m_nsSolver.aleInterface().patches[p].first;
127  m_nsSolver.assembler().patches().patch(pFlow).coefs() -= m_ALEdisplacment.patch(pALE).coefs();
128  m_nsSolver.mAssembler().patches().patch(pFlow).coefs() -= m_ALEdisplacment.patch(pALE).coefs();
129  }
130 
131  // save ALE displacement at the beginning of the time step for ALE velocity computation
132  m_aleSolver.constructSolution(m_ALEvelocity);
133  // update ALE
134  if (m_aleSolver.updateMesh() != -1)
135  return false; // if the new ALE deformation is not bijective, stop the simulation
136  // construct new ALE displacement
137  m_aleSolver.constructSolution(m_ALEdisplacment);
138  for (size_t p = 0; p < m_ALEvelocity.nPatches(); ++p)
139  m_ALEvelocity.patch(p).coefs() = (m_ALEdisplacment.patch(p).coefs() - m_ALEvelocity.patch(p).coefs()) / timeStep;
140 
141  // apply new ALE deformation to the flow domain
142  for (size_t p = 0; p < m_nsSolver.aleInterface().patches.size(); ++p)
143  {
144  index_t pFlow = m_nsSolver.aleInterface().patches[p].second;
145  index_t pALE = m_nsSolver.aleInterface().patches[p].first;
146  m_nsSolver.assembler().patches().patch(pFlow).coefs() += m_ALEdisplacment.patch(pALE).coefs();
147  m_nsSolver.mAssembler().patches().patch(pFlow).coefs() += m_ALEdisplacment.patch(pALE).coefs();
148  }
149 
150  aleTime += clock.stop();
151  // =================================================================== //
152 
153 
154  // ======================= Flow section ============================== //
155  clock.restart();
156  if (numIter > 0) // recover the solver state from the time step beginning
157  m_nsSolver.recoverState();
158 
159  // set velocity boundary condition on the FSI interface; velocity comes from the ALE velocity;
160  // FSI inteface info is contained in the Navier-Stokes solver
161  for (size_t p = 0; p < m_nsSolver.aleInterface().sidesA.size(); ++p)
162  {
163  index_t pFlow = m_nsSolver.aleInterface().sidesB[p].patch;
164  boxSide sFlow = m_nsSolver.aleInterface().sidesB[p].side();
165  index_t pALE = m_nsSolver.aleInterface().sidesA[p].patch;
166  boxSide sALE = m_nsSolver.aleInterface().sidesA[p].side();
167  m_nsSolver.assembler().setFixedDofs(pFlow,sFlow,m_ALEvelocity.patch(pALE).boundary(sALE)->coefs());
168  }
169 
170  m_nsSolver.makeTimeStep(timeStep);
171  m_nsSolver.constructSolution(m_velocity,m_pressure);
172 
173  nsTime += clock.stop();
174  // =================================================================== //
175 
176 
177  ++numIter;
178  }
179 
180  if (m_options.getInt("Verbosity") != solver_verbosity::none && numIter > 1)
181  {
182  if (converged)
183  gsInfo << "Converged after " << numIter << " iters, absRes "
184  << absResNorm << ", relRes " << absResNorm/initResNorm << std::endl;
185  else
186  gsInfo << "Terminated after " << numIter << " iters, absRes "
187  << absResNorm << ", relRes " << absResNorm/initResNorm << std::endl;
188  }
189 
190  return true;
191 }
192 
193 template <class T>
194 void gsPartitionedFSI<T>::formVector(const gsMultiPatch<T> & disp, gsMatrix<T> & vector)
195 {
196  index_t dim = disp.patch(0).parDim();
197 
198  index_t totalSize = 0;
199  for (size_t i = 0; i < m_aleSolver.interface().sidesA.size(); ++i)
200  {
201  index_t patch = m_aleSolver.interface().sidesA[i].patch;
202  boxSide side = m_aleSolver.interface().sidesA[i].side();
203  totalSize += disp.patch(patch).boundary(side)->coefs().rows();
204  }
205 
206  vector.setZero(totalSize*dim,1);
207  index_t filledSize = 0;
208  for (size_t i = 0; i < m_aleSolver.interface().sidesA.size(); ++i)
209  {
210  index_t patch = m_aleSolver.interface().sidesA[i].patch;
211  boxSide side = m_aleSolver.interface().sidesA[i].side();
212  index_t size = disp.patch(patch).boundary(side)->coefs().rows();
213  for (index_t d = 0; d < dim;++d)
214  {
215  vector.middleRows(filledSize,size) = disp.patch(patch).boundary(side)->coefs().col(d);
216  filledSize += size;
217  }
218  }
219 }
220 
221 template <class T>
222 void gsPartitionedFSI<T>::aitken(gsMultiPatch<T> & dispOO, gsMultiPatch<T> & dispOG,
223  gsMultiPatch<T> & dispO, gsMultiPatch<T> & dispN)
224 {
225  gsMatrix<> vecOO,vecOG,vecO,vecN;
226  formVector(dispOO,vecOO);
227  formVector(dispOG,vecOG);
228  formVector(dispO,vecO);
229  formVector(dispN,vecN);
230 
231  gsMatrix<> vecTemp = vecN - vecO - vecOG + vecOO;
232  omega = -1*omega * ((vecOG - vecOO).transpose()*vecTemp)(0,0) /
233  (vecTemp.transpose()*vecTemp)(0,0);
234 
235  for (size_t p = 0; p < dispOO.nPatches(); ++p)
236  {
237  dispOO.patch(p).coefs() = dispO.patch(p).coefs();
238  dispOG.patch(p).coefs() = dispN.patch(p).coefs();
239  dispN.patch(p).coefs() = omega * dispN.patch(p).coefs() + (1-omega) * dispO.patch(p).coefs();
240  dispO.patch(p).coefs() = dispN.patch(p).coefs();
241  }
242 
243  formVector(dispN,vecN);
244  absResNorm = ((vecN-vecO)*omega).norm()/sqrt(vecN.rows());
245  if (absResNorm < m_options.getReal("AbsTol") || absResNorm/initResNorm < m_options.getReal("RelTol"))
246  converged = true;
247 }
248 
249 } // namespace ends
#define index_t
Definition: gsConfig.h:32
Timing functions.
Provides isogeometric meshing and modelling routines.
Implementation of mesh deformation method for partitioned FSI solver.
Provides time integration for dynamical elasticity.
only essential output
Definition: gsBaseUtils.h:84
Partitioned FSI solver.
#define gsInfo
Definition: gsDebug.h:43
gsGenericStopwatch< WallClock > gsStopwatch
A stop-watch measuring real (wall) time.
Definition: gsStopwatch.h:160
Provides time integration for incompressible Navier-Stokes equations.