G+Smo  25.01.0
Geometry + Simulation Modules
 
Loading...
Searching...
No Matches
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
25namespace gismo
26{
27
28template <class T>
29gsPartitionedFSI<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
48template <class T>
49gsOptionList 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
59template <class T>
60bool 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
193template <class T>
194void 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
221template <class T>
222void 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
Implementation of mesh deformation method for partitioned FSI solver.
#define index_t
Definition gsConfig.h:32
#define gsInfo
Definition gsDebug.h:43
Provides time integration for dynamical elasticity.
Provides isogeometric meshing and modelling routines.
Provides time integration for incompressible Navier-Stokes equations.
Partitioned FSI solver.
Timing functions.
The G+Smo namespace, containing all definitions for the library.
gsGenericStopwatch< WallClock > gsStopwatch
A stop-watch measuring real (wall) time.
Definition gsStopwatch.h:160