GCC Code Coverage Report


Directory: ./
File: Solver/linearProblemNS.cpp
Date: 2024-04-14 07:32:34
Exec Total Coverage
Lines: 359 1903 18.9%
Branches: 302 2867 10.5%

Line Branch Exec Source
1 // ______ ______ _ _ _____ ______
2 // | ____| ____| | (_)/ ____| | ____|
3 // | |__ | |__ | | _| (___ ___| |__
4 // | __| | __| | | | |\___ \ / __| __|
5 // | | | |____| |____| |____) | (__| |____
6 // |_| |______|______|_|_____/ \___|______|
7 // Finite Elements for Life Sciences and Engineering
8 //
9 // License: LGL2.1 License
10 // FELiScE default license: LICENSE in root folder
11 //
12 // Main authors: J. Foulon & J-F. Gerbeau & V. Martin
13 //
14
15 // System includes
16 #include <stack>
17 #include <functional>
18
19 // External includes
20
21 // Project includes
22 #include "DegreeOfFreedom/boundaryCondition.hpp"
23 #include "Core/felisceTools.hpp"
24 #include "FiniteElement/elementMatrix.hpp"
25 #include "FiniteElement/elementVector.hpp"
26 #include "InputOutput/io.hpp"
27 #include "Solver/linearProblemNS.hpp"
28
29 /*!
30 \file LinearProblemNS.cpp
31
32 \date 05/01/2011
33 \brief Monolithic algorithm for the Navier-Stokes equations
34 */
35
36 namespace felisce {
37
38 54 LinearProblemNS::LinearProblemNS():
39 108 LinearProblem("Navier-Stokes monolithic",FelisceParam::instance().nonLinearFluid == true ? 3 : 2), // TODO FelisceParam::instance(???) which one??
40 54 m_initializeMapPnt(true),
41 54 m_viscosity(0.),
42 54 m_density(0.),
43 54 m_theta(0.),
44 54 m_lumpedModelBC(nullptr),
45 54 m_forceConvAndStabComputation(false),
46 54 m_bdf(nullptr),
47 54 m_cardiacCycle(nullptr),
48 54 m_ris(nullptr),
49 54 allocateSeqVec(false),
50 54 allocateSeqVecExt(false),
51
24/46
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 46 times.
✓ Branch 5 taken 54 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 54 times.
✗ Branch 9 not taken.
✓ Branch 20 taken 54 times.
✗ Branch 21 not taken.
✓ Branch 23 taken 54 times.
✗ Branch 24 not taken.
✓ Branch 29 taken 54 times.
✗ Branch 30 not taken.
✓ Branch 32 taken 54 times.
✗ Branch 33 not taken.
✓ Branch 35 taken 54 times.
✗ Branch 36 not taken.
✓ Branch 38 taken 54 times.
✗ Branch 39 not taken.
✓ Branch 41 taken 54 times.
✗ Branch 42 not taken.
✓ Branch 44 taken 54 times.
✗ Branch 45 not taken.
✓ Branch 47 taken 54 times.
✗ Branch 48 not taken.
✓ Branch 50 taken 54 times.
✗ Branch 51 not taken.
✓ Branch 53 taken 54 times.
✗ Branch 54 not taken.
✓ Branch 56 taken 54 times.
✗ Branch 57 not taken.
✓ Branch 60 taken 54 times.
✗ Branch 61 not taken.
✓ Branch 63 taken 54 times.
✗ Branch 64 not taken.
✓ Branch 69 taken 54 times.
✗ Branch 70 not taken.
✓ Branch 73 taken 54 times.
✗ Branch 74 not taken.
✓ Branch 76 taken 54 times.
✗ Branch 77 not taken.
✓ Branch 79 taken 54 times.
✗ Branch 80 not taken.
✓ Branch 84 taken 54 times.
✗ Branch 85 not taken.
✓ Branch 87 taken 54 times.
✗ Branch 88 not taken.
54 m_isCsrNoInterfaceStored(false)
52 {
53 // When using cvgraph, the following vectors are needed.
54 // If we use a D2N or a N2D some of them may be unused
55
2/4
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 54 times.
54 if ( FelisceParam::instance().withCVG ) { // TODO FelisceParam::instance(???) which one??
56 #ifdef FELISCE_WITH_CVGRAPH
57 m_cvgDirichletVariable = "cvgraphVelocity";
58 #endif
59 m_seqVecs.Init("cvgraphSTRESS");
60 m_seqVecs.Init("externalDisplacementOld");
61 m_seqVecs.Init("externalDisplacement");
62 m_seqVecs.Init("cvgraphVelocity");
63 }
64 54 }
65
66 /***********************************************************************************/
67 /***********************************************************************************/
68
69 108 LinearProblemNS::~LinearProblemNS()
70 {
71 108 m_elemFieldLumpedModelBC.clear();
72 108 m_bdf = nullptr;
73
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
108 if (allocateSeqVec) {
74 108 m_seqBdfRHS.destroy();
75 }
76
1/2
✓ Branch 0 taken 54 times.
✗ Branch 1 not taken.
108 if (allocateSeqVecExt) {
77 108 m_solExtrapol.destroy();
78 }
79 }
80
81 /***********************************************************************************/
82 /***********************************************************************************/
83
84 1436 PetscErrorCode NSJacobian(SNES snes, Vec evaluationState, Mat jacobian , Mat preconditioner, void* context_as_void)
85 {
86 (void) snes;
87 (void) evaluationState;
88 (void) jacobian;
89 (void) preconditioner;
90 (void) context_as_void;
91 PetscFunctionBegin;
92
93 1436 SnesContext* context_ptr = static_cast<SnesContext*>(context_as_void);
94 1436 SnesContext& context = *context_ptr;
95 1436 LinearProblemNS& lpb = *static_cast<LinearProblemNS*>(context.linearProblem);
96
97 // Retrieve instance
98 1436 auto& r_instance = FelisceParam::instance(lpb.instanceIndex());
99
100 // add matrices linear and non linear terms
101 1436 lpb.addMatrixRHSNl(FlagMatrixRHS::only_matrix);
102
103 // remove rows of nl matrices that have prescribed velocities (Dirichlet)
104 2872 lpb.applyBC(r_instance.essentialBoundaryConditionsMethod,
105 1436 MpiInfo::rankProc(), FlagMatrixRHS::only_matrix, FlagMatrixRHS::only_matrix,
106 0, true, ApplyNaturalBoundaryConditions::no);
107
108 1436 PetscFunctionReturn(0);
109 }
110
111 /***********************************************************************************/
112 /***********************************************************************************/
113
114 2396 PetscErrorCode NSFunction(SNES snes, Vec evaluationState, Vec residual, void* context_as_void)
115 {
116 PetscFunctionBegin;
117 2396 SnesContext* context_ptr = static_cast<SnesContext*>(context_as_void);
118 2396 SnesContext& context = *context_ptr;
119 2396 LinearProblemNS& lpb = *static_cast<LinearProblemNS*>(context.linearProblem);
120
121 // Retrieve instance
122
2/4
✓ Branch 1 taken 2396 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2396 times.
✗ Branch 5 not taken.
2396 auto& r_instance = FelisceParam::instance(lpb.instanceIndex());
123
124 PetscInt nbEval;
125
1/2
✓ Branch 1 taken 2396 times.
✗ Branch 2 not taken.
2396 SNESGetNumberFunctionEvals(snes,&nbEval);
126
127 // transfer evaluation state U^(n, k-1) to computeElementArray
128
2/4
✓ Branch 2 taken 2396 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2396 times.
✗ Branch 6 not taken.
2396 VecCopy(evaluationState,lpb.evaluationState().toPetsc());
129
1/2
✓ Branch 3 taken 2396 times.
✗ Branch 4 not taken.
2396 lpb.gatherVector(lpb.evaluationState(), lpb.seqEvaluationState());
130
131 // add solution at previous time step
132
4/4
✓ Branch 0 taken 960 times.
✓ Branch 1 taken 1436 times.
✓ Branch 2 taken 160 times.
✓ Branch 3 taken 800 times.
2396 if (nbEval == 0 && r_instance.useALEformulation)
133
1/2
✓ Branch 1 taken 160 times.
✗ Branch 2 not taken.
160 lpb.addMatrixRHSNl(FlagMatrixRHS::only_rhs);
134
135 // clear non linear matrix
136
1/2
✓ Branch 2 taken 2396 times.
✗ Branch 3 not taken.
2396 lpb.matrix(2).zeroEntries();
137
138
2/2
✓ Branch 0 taken 1436 times.
✓ Branch 1 taken 960 times.
2396 if (nbEval > 0 ) {
139 // assembly after first inner iteration
140
1/2
✓ Branch 1 taken 1436 times.
✗ Branch 2 not taken.
1436 lpb.clearMatrixRHS(FlagMatrixRHS::matrix_and_rhs);
141
1/2
✓ Branch 1 taken 1436 times.
✗ Branch 2 not taken.
1436 lpb.assembleMatrixRHS(context.rankProc);
142
143 // add static and dynamic matrices
144
1/2
✓ Branch 1 taken 1436 times.
✗ Branch 2 not taken.
1436 lpb.addMatrixRHS();
145
146 // add solution at previous time step
147
2/2
✓ Branch 0 taken 316 times.
✓ Branch 1 taken 1120 times.
1436 if (r_instance.useALEformulation)
148
1/2
✓ Branch 1 taken 316 times.
✗ Branch 2 not taken.
316 lpb.addMatrixRHSNl(FlagMatrixRHS::only_rhs);
149
150 // apply boundary conditions.
151
1/2
✓ Branch 1 taken 1436 times.
✗ Branch 2 not taken.
1436 lpb.finalizeEssBCTransient();
152
1/2
✓ Branch 1 taken 1436 times.
✗ Branch 2 not taken.
1436 lpb.applyBC(r_instance.essentialBoundaryConditionsMethod,context.rankProc);
153 }
154
155 // compute residual
156
1/2
✓ Branch 1 taken 2396 times.
✗ Branch 2 not taken.
2396 lpb.evalDynamicResidual();
157
158 // send residual to petsc
159
2/4
✓ Branch 2 taken 2396 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2396 times.
✗ Branch 6 not taken.
2396 VecCopy(lpb.vector().toPetsc(),residual);
160
161 2396 PetscFunctionReturn(0);
162
163 }
164
165 2396 void LinearProblemNS::evalDynamicResidual()
166 {
167 // compute residual
168 2396 multAdd(matrix(0),evaluationState(),vector(),vector());
169 2396 }
170
171 54 void LinearProblemNS::InitializeDerivedAttributes()
172 {
173 // Retrieve instance
174 54 auto& r_instance = FelisceParam::instance(instanceIndex());
175
176
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 46 times.
54 if (r_instance.nonLinearFluid) {
177 8 m_snesContext.initialize(*this, MpiInfo::rankProc(), MpiInfo::numProc(), ApplyNaturalBoundaryConditions::no, FlagMatrixRHS::matrix_and_rhs);
178 8 snesInterface().setFunction(vector(), NSFunction, &m_snesContext);
179 8 snesInterface().setJacobian(matrix(0), matrix(0), NSJacobian, &m_snesContext);
180 }
181 54 }
182
183 /***********************************************************************************/
184 /***********************************************************************************/
185
186 54 void LinearProblemNS::initialize(std::vector<GeometricMeshRegion::Pointer>& mesh, FelisceTransient::Pointer fstransient, MPI_Comm& comm, bool doUseSNES)
187 {
188 // Retrieve instance
189
2/4
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 54 times.
✗ Branch 5 not taken.
54 auto& r_instance = FelisceParam::instance(instanceIndex());
190
191
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 LinearProblem::initialize(mesh, comm, doUseSNES);
192 54 m_fstransient = fstransient;
193 54 std::vector<PhysicalVariable> listVariable;
194 54 std::vector<std::size_t> listNumComp;
195
196
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 listVariable.push_back(velocity);
197
1/2
✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
54 listNumComp.push_back(dimension());
198
199
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 listVariable.push_back(pressure);
200
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 listNumComp.push_back(1);
201
202
2/2
✓ Branch 0 taken 18 times.
✓ Branch 1 taken 36 times.
54 if ( r_instance.useALEformulation ) {
203
1/2
✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
18 listVariable.push_back(displacement);
204
1/2
✓ Branch 2 taken 18 times.
✗ Branch 3 not taken.
18 listNumComp.push_back(dimension());
205 }
206
207 // define unknown of the linear system.
208
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 m_listUnknown.push_back(velocity);
209
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 m_listUnknown.push_back(pressure);
210
211
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if ( r_instance.useFDlagrangeMult ) {
212 listVariable.push_back(lagMultiplier);
213 listNumComp.push_back(dimension());
214 m_listUnknown.push_back(lagMultiplier);
215
216 if ( r_instance.massConstraint ) {
217 listVariable.push_back(temperature);
218 listNumComp.push_back(1);
219 m_listUnknown.push_back(temperature);
220 }
221 }
222
223
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 userAddOtherUnknowns(listVariable,listNumComp);
224
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 userAddOtherVariables(listVariable,listNumComp);
225
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 definePhysicalVariable(listVariable,listNumComp);
226
227
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 m_iVelocity = m_listVariable.getVariableIdList(velocity);
228
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 m_iPressure = m_listVariable.getVariableIdList(pressure);
229
230 54 m_velocity = &m_listVariable[m_iVelocity];
231 54 m_pressure = &m_listVariable[m_iPressure];
232
233
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 m_iUnknownVel = m_listUnknown.getUnknownIdList(velocity);
234
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 m_iUnknownPre = m_listUnknown.getUnknownIdList(pressure);
235
236
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 m_velBlock = m_listUnknown.getBlockPosition(m_iUnknownVel,0);
237
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 m_preBlock = m_listUnknown.getBlockPosition(m_iUnknownPre,0);
238
239
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (r_instance.useFDlagrangeMult) {
240
241 if ( r_instance.massConstraint ) {
242 if (r_instance.BHstab) {
243
244 if ( dimension() == 2 ) {
245 std::vector<int> mask{ 1, 1, /**/ 1, /**/ 1, 1, /**/ 1,
246 1, 1, /**/ 1, /**/ 1, 1, /**/ 1,
247 1, 1, /**/ 1, /**/ 0, 0, /**/ 0,
248 1, 1, /**/ 0, /**/ 1, 1, /**/ 1,
249 1, 1, /**/ 0, /**/ 1, 1, /**/ 1,
250 1, 1, /**/ 0, /**/ 1, 1, /**/ 1};
251 m_listUnknown.setMask(mask);
252 }
253 else if ( dimension() == 3 ) {
254 std::vector<int> mask{ 1, 1, 1, /**/ 1, /**/ 1, 1, 1, /**/ 1,
255 1, 1, 1, /**/ 1, /**/ 1, 1, 1, /**/ 1,
256 1, 1, 1, /**/ 1, /**/ 1, 1, 1, /**/ 1,
257 1, 1, 1, /**/ 1, /**/ 0, 0, 0, /**/ 0,
258 1, 1, 1, /**/ 0, /**/ 1, 1, 1, /**/ 1,
259 1, 1, 1, /**/ 0, /**/ 1, 1, 1, /**/ 1,
260 1, 1, 1, /**/ 0, /**/ 1, 1, 1, /**/ 1,
261 1, 1, 1, /**/ 0, /**/ 1, 1, 1, /**/ 1};
262 m_listUnknown.setMask(mask);
263 }
264 }
265 else if (r_instance.BPstab) {
266
267 if ( dimension() == 2 ) {
268 std::vector<int> mask{ 1, 1, /**/ 1, /**/ 1, 1, /**/ 1,
269 1, 1, /**/ 1, /**/ 1, 1, /**/ 1,
270 1, 1, /**/ 1, /**/ 0, 0, /**/ 0,
271 1, 1, /**/ 0, /**/ 1, 1, /**/ 0,
272 1, 1, /**/ 0, /**/ 1, 1, /**/ 0,
273 1, 1, /**/ 0, /**/ 0, 0, /**/ 1};
274 m_listUnknown.setMask(mask);
275 }
276 else if ( dimension() == 3 ) {
277 std::vector<int> mask{ 1, 1, 1, /**/ 1, /**/ 1, 1, 1, /**/ 1,
278 1, 1, 1, /**/ 1, /**/ 1, 1, 1, /**/ 1,
279 1, 1, 1, /**/ 1, /**/ 1, 1, 1, /**/ 1,
280 1, 1, 1, /**/ 1, /**/ 0, 0, 0, /**/ 0,
281 1, 1, 1, /**/ 0, /**/ 1, 1, 1, /**/ 0,
282 1, 1, 1, /**/ 0, /**/ 1, 1, 1, /**/ 0,
283 1, 1, 1, /**/ 0, /**/ 1, 1, 1, /**/ 0,
284 1, 1, 1, /**/ 0, /**/ 0, 0, 0, /**/ 1};
285 m_listUnknown.setMask(mask);
286 }
287 }
288 else {
289
290 if ( dimension() == 2 ) {
291 std::vector<int> mask{ 1, 1, /**/ 1, /**/ 1, 1, /**/ 1,
292 1, 1, /**/ 1, /**/ 1, 1, /**/ 1,
293 1, 1, /**/ 1, /**/ 0, 0, /**/ 0,
294 1, 1, /**/ 0, /**/ 0, 0, /**/ 0,
295 1, 1, /**/ 0, /**/ 0, 0, /**/ 0,
296 1, 1, /**/ 0, /**/ 0, 0, /**/ 0};
297 m_listUnknown.setMask(mask);
298 }
299 else if ( dimension() == 3 ) {
300 std::vector<int> mask{ 1, 1, 1, /**/ 1, /**/ 1, 1, 1, /**/ 1,
301 1, 1, 1, /**/ 1, /**/ 1, 1, 1, /**/ 1,
302 1, 1, 1, /**/ 1, /**/ 1, 1, 1, /**/ 1,
303 1, 1, 1, /**/ 1, /**/ 0, 0, 0, /**/ 0,
304 1, 1, 1, /**/ 0, /**/ 0, 0, 0, /**/ 0,
305 1, 1, 1, /**/ 0, /**/ 0, 0, 0, /**/ 0,
306 1, 1, 1, /**/ 0, /**/ 0, 0, 0, /**/ 0,
307 1, 1, 1, /**/ 0, /**/ 0, 0, 0, /**/ 0};
308 m_listUnknown.setMask(mask);
309 }
310 }
311 }
312 else {
313 if (r_instance.BHstab) {
314
315 if ( dimension() == 2 ) {
316 std::vector<int> mask{ 1, 1, /**/ 1, /**/ 1, 1,
317 1, 1, /**/ 1, /**/ 1, 1,
318 1, 1, /**/ 1, /**/ 0, 0,
319 1, 1, /**/ 0, /**/ 1, 1,
320 1, 1, /**/ 0, /**/ 1, 1};
321 m_listUnknown.setMask(mask);
322 }
323 else if ( dimension() == 3 ) {
324 std::vector<int> mask{ 1, 1, 1, /**/ 1, /**/ 1, 1, 1,
325 1, 1, 1, /**/ 1, /**/ 1, 1, 1,
326 1, 1, 1, /**/ 1, /**/ 1, 1, 1,
327 1, 1, 1, /**/ 1, /**/ 0, 0, 0,
328 1, 1, 1, /**/ 0, /**/ 1, 1, 1,
329 1, 1, 1, /**/ 0, /**/ 1, 1, 1,
330 1, 1, 1, /**/ 0, /**/ 1, 1, 1};
331 m_listUnknown.setMask(mask);
332 }
333 }
334 else if (r_instance.BPstab) {
335
336 if ( dimension() == 2 ) {
337 std::vector<int> mask{ 1, 1, /**/ 1, /**/ 1, 1,
338 1, 1, /**/ 1, /**/ 1, 1,
339 1, 1, /**/ 1, /**/ 0, 0,
340 1, 1, /**/ 0, /**/ 1, 1,
341 1, 1, /**/ 0, /**/ 1, 1};
342 m_listUnknown.setMask(mask);
343 }
344 else if ( dimension() == 3 ) {
345 std::vector<int> mask{ 1, 1, 1, /**/ 1, /**/ 1, 1, 1,
346 1, 1, 1, /**/ 1, /**/ 1, 1, 1,
347 1, 1, 1, /**/ 1, /**/ 1, 1, 1,
348 1, 1, 1, /**/ 1, /**/ 0, 0, 0,
349 1, 1, 1, /**/ 0, /**/ 1, 1, 1,
350 1, 1, 1, /**/ 0, /**/ 1, 1, 1,
351 1, 1, 1, /**/ 0, /**/ 1, 1, 1};
352 m_listUnknown.setMask(mask);
353 }
354 }
355 else {
356
357 if ( dimension() == 2 ) {
358 std::vector<int> mask{ 1, 1, /**/ 1, /**/ 1, 1,
359 1, 1, /**/ 1, /**/ 1, 1,
360 1, 1, /**/ 1, /**/ 0, 0,
361 1, 1, /**/ 0, /**/ 0, 0,
362 1, 1, /**/ 0, /**/ 0, 0};
363 m_listUnknown.setMask(mask);
364 }
365 else if ( dimension() == 3 ) {
366 std::vector<int> mask{ 1, 1, 1, /**/ 1, /**/ 1, 1, 1,
367 1, 1, 1, /**/ 1, /**/ 1, 1, 1,
368 1, 1, 1, /**/ 1, /**/ 1, 1, 1,
369 1, 1, 1, /**/ 1, /**/ 0, 0, 0,
370 1, 1, 1, /**/ 0, /**/ 0, 0, 0,
371 1, 1, 1, /**/ 0, /**/ 0, 0, 0,
372 1, 1, 1, /**/ 0, /**/ 0, 0, 0};
373 m_listUnknown.setMask(mask);
374 }
375 }
376 }
377
378 m_iLagrange = m_listVariable.getVariableIdList(lagMultiplier);
379 m_iUnknownLag = m_listUnknown.getUnknownIdList(lagMultiplier);
380 m_lagBlock = m_listUnknown.getBlockPosition(m_iUnknownLag,0);
381
382 if ( r_instance.massConstraint ) {
383 m_iJapanCon = m_listVariable.getVariableIdList(temperature);
384 m_iUnknownJap = m_listUnknown.getUnknownIdList(temperature);
385 m_japBlock = m_listUnknown.getBlockPosition(m_iUnknownJap,0);
386 }
387
388 m_listUnknown.setUnknownsRows(std::vector<int>{m_iUnknownVel,m_iUnknownPre});
389 m_listUnknown.setUnknownsCols(std::vector<int>{m_iUnknownVel,m_iUnknownPre});
390 }
391
392 54 m_viscosity = r_instance.viscosity;
393 54 m_density = r_instance.density;
394 54 m_theta = r_instance.theta;
395 54 m_useSymmetricStress = r_instance.useSymmetricStress;
396
397
1/2
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
54 const int verbose = FelisceParam::verbose();
398 54 const double tolrescaling = r_instance.Geo.tolrescaling;
399
400
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if ( r_instance.characteristicMethod )
401 m_pLocator = felisce::make_shared<Locator>(mesh[m_currentMesh].get(), false, tolrescaling, verbose);
402
403
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if ( r_instance.useFDlagrangeMult )
404 m_pLocator = felisce::make_shared<Locator>(mesh[m_currentMesh].get(), true, tolrescaling, verbose);
405 54 }
406
407 /***********************************************************************************/
408 /***********************************************************************************/
409
410 3940 void LinearProblemNS::initPerElementType(ElementType /* eltType */, FlagMatrixRHS /* flagMatrixRHS */)
411 {
412 // Retrieve instance
413 3940 auto& r_instance = FelisceParam::instance(instanceIndex());
414
415
1/2
✓ Branch 2 taken 3940 times.
✗ Branch 3 not taken.
3940 if ( m_currentMesh == m_listVariable[m_iVelocity].idMesh() ) {
416 3940 m_feVel = m_listCurrentFiniteElement[m_iVelocity];
417 3940 m_fePres = m_listCurrentFiniteElement[m_iPressure];
418
419 3940 m_elemFieldAdv.initialize(DOF_FIELD,*m_feVel,dimension());
420 3940 m_elemFieldRHS.initialize(DOF_FIELD,*m_feVel,dimension());
421 3940 m_elemFieldRHSbdf.initialize(DOF_FIELD,*m_feVel,dimension());
422 3940 m_elemFieldTotalPressureFormulation.initialize(QUAD_POINT_FIELD,*m_feVel,dimension());
423 3940 m_elemFieldCharact.initialize(QUAD_POINT_FIELD,*m_feVel,dimension());
424
425
2/2
✓ Branch 0 taken 2720 times.
✓ Branch 1 taken 1220 times.
3940 if (r_instance.nonLinearFluid) {
426 2720 m_elemFieldVelSeq.initialize(DOF_FIELD,*m_feVel,dimension());
427 2720 m_elemFieldPresSeq.initialize(DOF_FIELD, *m_fePres, 1);
428 }
429
430 // theta-method RHS
431
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3940 times.
3940 if ( m_theta < 1 ) {
432 m_elemFieldPres.initialize(DOF_FIELD,*m_fePres,1);
433 std::size_t SizeElMatRHSThetaMethod = 2;
434 if(r_instance.useALEformulation)
435 SizeElMatRHSThetaMethod = 1;
436
437 const std::vector<const CurBaseFiniteElement*> finiteElt({m_feVel, m_fePres});
438 std::vector<std::size_t> numberCmp({m_listVariable[m_iVelocity].numComponent(),m_listVariable[m_iPressure].numComponent()});
439 for (std::size_t i = 0; i < SizeElMatRHSThetaMethod; i++)
440 m_elMatRHSThetaMethod.push_back(new ElementMatrix(finiteElt,numberCmp, numberCmp));
441 }
442
443 //=========
444 // ALE
445 //=========
446
2/2
✓ Branch 0 taken 1396 times.
✓ Branch 1 taken 2544 times.
3940 if(r_instance.useALEformulation) {
447
448 1396 m_iDisplacement = m_listVariable.getVariableIdList(displacement);
449 1396 m_displacement = &m_listVariable[m_iDisplacement];
450
451 1396 m_elemFieldVelMesh.initialize(DOF_FIELD,*m_feVel,dimension());
452
453 1396 numDofExtensionProblem = m_externalDof[0]->numDof();
454
455 1396 m_petscToGlobal1.resize(numDofExtensionProblem);
456 1396 m_petscToGlobal2.resize(numDofExtensionProblem);
457 1396 m_auxvec.resize(numDofExtensionProblem);
458
459
2/2
✓ Branch 0 taken 24291396 times.
✓ Branch 1 taken 1396 times.
24292792 for (int i=0; i<numDofExtensionProblem; i++) {
460 24291396 m_petscToGlobal1[i]=i;
461 24291396 m_petscToGlobal2[i]=i;
462 }
463 1396 AOApplicationToPetsc(m_externalAO[0],numDofExtensionProblem,m_petscToGlobal1.data());
464 1396 AOApplicationToPetsc(m_ao,numDofExtensionProblem,m_petscToGlobal2.data());
465
466
1/2
✓ Branch 1 taken 1396 times.
✗ Branch 2 not taken.
1396 if ( m_fstransient->iteration > 0) {
467
2/2
✓ Branch 1 taken 58 times.
✓ Branch 2 taken 1338 times.
1396 if ( m_fstransient->iteration == 1) {
468 58 m_beta.duplicateFrom(m_solExtrapol);
469
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 42 times.
58 if (r_instance.nonLinearFluid)
470 16 m_betaSeq.duplicateFrom(seqEvaluationState());
471 }
472 //=========
473 // ALE
474 //=========
475 // Construction of m_beta = u^{n-1} - w^{n}
476 // Recall that externalVec(0) = - w^{n}
477 1396 m_beta.copyFrom(m_solExtrapol);
478 1396 externalVec(0).getValues(numDofExtensionProblem,m_petscToGlobal1.data(), m_auxvec.data());
479 1396 m_beta.setValues(numDofExtensionProblem, m_petscToGlobal2.data() ,m_auxvec.data(), ADD_VALUES);
480
2/2
✓ Branch 0 taken 796 times.
✓ Branch 1 taken 600 times.
1396 if (r_instance.nonLinearFluid){
481 796 m_auxvec.resize(numDofExtensionProblem);
482 796 externalVec(0).getValues(numDofExtensionProblem,m_petscToGlobal1.data(), m_auxvec.data());
483 796 m_betaSeq.copyFrom(seqEvaluationState());
484 796 m_betaSeq.setValues(numDofExtensionProblem, m_petscToGlobal2.data() ,m_auxvec.data(), ADD_VALUES);
485 }
486 }
487 }
488 }
489 3940 }
490
491 /***********************************************************************************/
492 /***********************************************************************************/
493
494 void LinearProblemNS::initializeRISModel(RISModel* risModel)
495 {
496 m_ris = risModel;
497 }
498
499 /***********************************************************************************/
500 /***********************************************************************************/
501
502 void LinearProblemNS::initializeCardiacCycle(CardiacCycle* cardiacCycle)
503 {
504 m_cardiacCycle = cardiacCycle;
505 }
506
507 /***********************************************************************************/
508 /***********************************************************************************/
509
510 8 void LinearProblemNS::initializeLumpedModelBC(LumpedModelBC* lumpedModelBC)
511 {
512 8 m_lumpedModelBC = lumpedModelBC;
513 8 m_elemFieldLumpedModelBC.clear();
514 8 m_elemFieldLumpedModelBC.resize(m_lumpedModelBC->size());
515 8 }
516
517 /***********************************************************************************/
518 /***********************************************************************************/
519
520 2508 void LinearProblemNS::initPerElementTypeBoundaryCondition(ElementType& /* eltType */, FlagMatrixRHS /* flagMatrixRHS */)
521 {
522 // Retrieve instance
523 2508 auto& r_instance = FelisceParam::instance(instanceIndex());
524
525
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2508 times.
2508 if (r_instance.CardiacCycle) {
526 m_curvFeVel = m_listCurvilinearFiniteElement[m_iVelocity];
527 m_elemFieldSistole.initialize(CONSTANT_FIELD, *m_curvFeVel, dimension());
528 m_elemFieldDiastole.initialize(CONSTANT_FIELD, *m_curvFeVel);
529 }
530
531
2/2
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 2424 times.
2508 if (m_lumpedModelBC) {
532 // allocate m_elemFieldLumpedModelBC
533
2/2
✓ Branch 1 taken 168 times.
✓ Branch 2 taken 84 times.
252 for (std::size_t iLumpedModelBC=0; iLumpedModelBC <m_lumpedModelBC->size() ; iLumpedModelBC++) {
534
2/8
✗ Branch 1 not taken.
✓ Branch 2 taken 168 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 168 times.
✗ Branch 10 not taken.
168 if(r_instance.lumpedModelBCAlgo[iLumpedModelBC] == 1 || (r_instance.lumpedModelBCAlgo[iLumpedModelBC] == 2 && r_instance.model == "NS"))
535 168 m_elemFieldLumpedModelBC[iLumpedModelBC].initialize(CONSTANT_FIELD,1);
536 }
537 }
538
539 #ifdef FELISCE_WITH_CVGRAPH
540
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2508 times.
2508 if (r_instance.withCVG ) {
541 m_curvFeVel = m_listCurvilinearFiniteElement[m_iVelocity];
542 if ( slave()->thereIsAtLeastOneRobinCondition() ){
543 m_robinAux.initialize( DOF_FIELD, *m_listCurvilinearFiniteElement[m_iVelocity], dimension() );
544 }
545 }
546 #endif
547 2508 }
548
549 /***********************************************************************************/
550 /***********************************************************************************/
551
552 7330 void LinearProblemNS::initPerDomainBoundaryCondition(std::vector<Point*>& elemPoint, const std::vector<felInt>& elemIdPoint,
553 int label, felInt numEltPerLabel,felInt* ielSupportDof,
554 ElementType& eltType, felInt numElement_eltType, FlagMatrixRHS flagMatrixRHS)
555 {
556 // Retrieve instance
557 7330 auto& r_instance = FelisceParam::instance(instanceIndex());
558
559 7330 m_currentLabel = label;
560
561 //================================
562 // Explicit/implicit lumpedModel boundary conditions with model NS
563 //================================
564
5/6
✓ Branch 0 taken 312 times.
✓ Branch 1 taken 7018 times.
✓ Branch 3 taken 312 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 312 times.
✓ Branch 6 taken 7018 times.
7330 if (m_lumpedModelBC && (r_instance.model == "NS") ) {
565
2/2
✓ Branch 1 taken 624 times.
✓ Branch 2 taken 312 times.
936 for (std::size_t iLumpedModelBC=0; iLumpedModelBC <m_lumpedModelBC->size() ; iLumpedModelBC++) {
566
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 624 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 624 times.
✗ Branch 7 not taken.
624 if(r_instance.lumpedModelBCAlgo[iLumpedModelBC] == 1 || r_instance.lumpedModelBCAlgo[iLumpedModelBC] == 2) {
567
2/2
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 582 times.
624 if (r_instance.lumpedModelBCLabel[iLumpedModelBC] == label) {
568 42 applyNaturalBoundaryConditionLumpedModelBC(elemPoint,elemIdPoint,label,numEltPerLabel, ielSupportDof,iLumpedModelBC,eltType, numElement_eltType, flagMatrixRHS);
569 }
570 }
571 }
572 }
573 7330 }
574
575 /***********************************************************************************/
576 /***********************************************************************************/
577
578 338616 void LinearProblemNS::computeElementArrayBoundaryCondition(const std::vector<Point*>& elemPoint, const std::vector<felInt>& /* elemIdPoint */, felInt& iel, FlagMatrixRHS /* flagMatrixRHS */)
579 {
580 // Retrieve instance
581 338616 auto& r_instance = FelisceParam::instance(instanceIndex());
582
583 // General updates
584
2/2
✓ Branch 1 taken 744224 times.
✓ Branch 2 taken 338616 times.
1082840 for (std::size_t iFe = 0; iFe < m_listCurvilinearFiniteElement.size(); iFe++) {
585 744224 m_listCurvilinearFiniteElement[iFe]->updateMeasNormal(0, elemPoint);
586 }
587
588 // Saving ptr to velocity curvilinear finite element
589 338616 CurvilinearFiniteElement* curvFeVel = m_listCurvilinearFiniteElement[m_iVelocity];
590 // Position of the velocity block
591 338616 int iblockVel = m_listUnknown.getBlockPosition(m_iUnknownVel,0);
592
593 // Windkessels model!
594
5/6
✓ Branch 0 taken 195812 times.
✓ Branch 1 taken 142804 times.
✓ Branch 3 taken 195812 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 195812 times.
✓ Branch 6 taken 142804 times.
338616 if (m_lumpedModelBC && r_instance.model == "NS") {
595
2/2
✓ Branch 1 taken 391624 times.
✓ Branch 2 taken 195812 times.
587436 for (std::size_t iLumpedModelBC=0; iLumpedModelBC <m_lumpedModelBC->size() ; iLumpedModelBC++) {
596
2/2
✓ Branch 1 taken 1120 times.
✓ Branch 2 taken 390504 times.
391624 if ( r_instance.lumpedModelBCLabel[iLumpedModelBC] == m_currentLabel) {
597
2/6
✗ Branch 1 not taken.
✓ Branch 2 taken 1120 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 1120 times.
✗ Branch 7 not taken.
1120 if(r_instance.lumpedModelBCAlgo[iLumpedModelBC] == 1 || r_instance.lumpedModelBCAlgo[iLumpedModelBC] == 2) {
598
599 1120 m_elementVectorBD[0]->f_phi_i_scalar_n(1.,*curvFeVel,m_elemFieldLumpedModelBC[iLumpedModelBC],iblockVel);
600 }
601 // to be continued // Justine 7/11/13
602 //if ( r_instance.lumpedModelBCAlgoImprovedExplicit == 1 ) {
603 // we add \int_Gamma (u^{n+1} \cdot n) (v \cdot n)
604 // and \int_Gamma (u^n \cdot n) (v \cdot n)
605 //}
606 }
607 }
608 }
609
610
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 338616 times.
338616 if(r_instance.CardiacCycleLabel == m_currentLabel) {
611 double penalisationParam = 0.;
612 penalisationParam = m_cardiacCycle->penalisationParam(); //= 0 if valve closed, = TGV if valve open
613 m_elemFieldSistole.setValue(m_cardiacCycle->inflow());
614 m_elemFieldDiastole.setValue(m_cardiacCycle->Pressure_in());
615
616 m_elementMatBD[0]->phi_i_phi_j(penalisationParam, *curvFeVel, iblockVel, iblockVel, dimension()); // epsilon * int_{Gamma_in} [ u^{n+1} * v ]
617 m_elementVectorBD[0]->source(penalisationParam, *curvFeVel, m_elemFieldSistole, iblockVel, dimension()); // epsilon * int_{Gamma_in} [ u_{in} * v ]
618 m_elementVectorBD[0]->f_phi_i_scalar_n(-1., *curvFeVel, m_elemFieldDiastole, iblockVel); // int_{Gamma_in} [-p * N* v ] curvFeVel referred to test function v
619 }
620
621
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 338616 times.
338616 if (r_instance.RISModels) {
622 if (r_instance.PenalizationMethod)
623 FEL_ERROR("RIS and penalization models are activated at the same time!");
624 double Res = 0.;
625 Res = m_ris->resistance(m_currentLabel);
626 if( Tools::notEqual(Res,0.) ) {
627 //LHS term of the penalisation
628 if ( std::find(r_instance.forbiddenLabelsForCorrection.begin(), r_instance.forbiddenLabelsForCorrection.end(), m_currentLabel) == r_instance.forbiddenLabelsForCorrection.end() ) {
629 m_elementMatBD[0]->phi_i_phi_j(Res,*curvFeVel, iblockVel, iblockVel, dimension());
630 }
631 //RHS term of the penalisation
632 //Correct the constraint with the velocity of the mesh (R*[u-w] = 0)
633 //This term is not added at the first iteration as the first iteration is not physical in our case (A.This, M. Fernandez, J-F. Gerbeau : Zygot case with full deformation).
634 if(m_fstransient->iteration>1){
635 if ( std::find(r_instance.forbiddenLabelsForCorrection.begin(), r_instance.forbiddenLabelsForCorrection.end(), m_currentLabel) == r_instance.forbiddenLabelsForCorrection.end() && r_instance.useALEformulation ) {
636 m_elementVectorBD[0]->source(-Res, *curvFeVel, m_elemFieldVelMesh, iblockVel, dimension());
637 }
638 }
639 }
640 }
641
642
2/2
✓ Branch 0 taken 46080 times.
✓ Branch 1 taken 292536 times.
338616 if (r_instance.PenalizationMethod) {
643
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 46080 times.
46080 if (r_instance.RISModels)
644 FEL_ERROR("RIS and penalization models are activated at the same time!");
645 46080 double Pen = r_instance.Gamma_penalization;
646
5/6
✓ Branch 1 taken 42240 times.
✓ Branch 2 taken 3840 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 42240 times.
✓ Branch 6 taken 3840 times.
✓ Branch 7 taken 42240 times.
46080 if ( r_instance.closed_penalization[0] == m_currentLabel || r_instance.closed_penalization[1] == m_currentLabel ){
647
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 3840 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 3840 times.
3840 if (r_instance.useALEformulation && m_fstransient->iteration>1 )
648 m_elemFieldVelSeq.setValue(m_betaSeq, *m_feVel, iel, m_iVelocity, m_ao, dof());
649 else
650 3840 m_elemFieldVelSeq.setValue(seqEvaluationState(), *m_feVel, iel, m_iVelocity, m_ao, dof());
651 //LHS term of penalization
652 3840 m_elementMatBD[2]->penalty_phi_i_scalar_n_phi_j_scalar_n(Pen, *curvFeVel, m_elemFieldVelSeq, iblockVel, iblockVel);
653 //RHS term of penalization
654 3840 m_elementVectorBD[0]->penalty_phi_i_scalar_n(-Pen, *curvFeVel, m_elemFieldVelSeq, iblockVel);
655 }
656 }
657
658 #ifdef FELISCE_WITH_CVGRAPH
659
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 338616 times.
338616 if (r_instance.withCVG )
660 cvgraphNaturalBC(iel);
661 #endif
662 338616 }
663
664 /***********************************************************************************/
665 /***********************************************************************************/
666
667 13890684 void LinearProblemNS::computeElementArray(const std::vector<Point*>& elemPoint, const std::vector<felInt>& /* elemIdPoint */, felInt& iel, FlagMatrixRHS flagMatrixRHS)
668 {
669 // Retrieve instance
670 13890684 auto& r_instance = FelisceParam::instance(instanceIndex());
671
672
1/2
✓ Branch 2 taken 13890684 times.
✗ Branch 3 not taken.
13890684 if ( m_currentMesh == m_listVariable[m_iVelocity].idMesh() ) {
673 13890684 m_feVel->updateFirstDeriv(0, elemPoint);
674 13890684 m_fePres->updateFirstDeriv(0, elemPoint);
675
676 13890684 PetscScalar coef = m_density/m_fstransient->timeStep;
677
678
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 13890684 times.
13890684 if ( m_feVel->measure() < 0. ) {
679 int iglo;
680 ISLocalToGlobalMappingApply(m_mappingElem[m_currentMesh],1,&iel,&iglo);
681 std::cout << " id global = " << iglo << std::endl;
682 FEL_ERROR("Error: Element of negative measure!");
683 }
684
685 std::size_t indexMatrix;
686
2/2
✓ Branch 0 taken 12276990 times.
✓ Branch 1 taken 1613694 times.
13890684 if( r_instance.useALEformulation )
687 12276990 indexMatrix = 0; // The matrix actually used in the solver, which is not constant (because of advection, ALE,...)
688 else
689 1613694 indexMatrix = 1; // The "static" part of the matrix, when there is no ALE it is basically everything, but the advection.
690
691
5/6
✓ Branch 1 taken 134158 times.
✓ Branch 2 taken 13756526 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 134158 times.
✓ Branch 5 taken 12411148 times.
✓ Branch 6 taken 1479536 times.
27647210 if ( ( (m_fstransient->iteration == 0) && (r_instance.useALEformulation != 1) ) ||
692
3/4
✓ Branch 1 taken 13756526 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 12276990 times.
✓ Branch 4 taken 1479536 times.
13756526 ( (m_fstransient->iteration > 0) && r_instance.useALEformulation ) ) {
693 /*! In this function we compute the term of the matrix that, without ALE does not change in time, so they should go to the matrix 1.
694 *
695 * We enter in the following cases:
696 *
697 * - Before the first iteration, when ALE is not 1 ( which means either no ALE or ALE = 2 )
698 * indexMatrix = 1 if ALE=0,
699 * indexMatrix = 0 if ALE>=2
700 *
701 * - For each iteration, but not before when ALE>0
702 * indexMatrix = 0
703 *
704 * When ALE=0
705 * you enter only before the first iteration.
706 * When ALE = 1
707 * you do not enter before the first iteration.
708 * When ALE = 2
709 * you enter the first iteration and the following
710 */
711
4/4
✓ Branch 0 taken 9243390 times.
✓ Branch 1 taken 3167758 times.
✓ Branch 2 taken 3081130 times.
✓ Branch 3 taken 6162260 times.
12411148 if( (flagMatrixRHS == FlagMatrixRHS::matrix_and_rhs) || (flagMatrixRHS == FlagMatrixRHS::only_matrix) ) {
712 // First part of system matrix.
713 //
714 // flagMatrixRHS :
715 // matrix_and_rhs = 0,
716 // only_matrix = 1,
717 // only_rhs = 2,
718 //
719 //================================
720 // matrix
721 //================================
722
2/2
✓ Branch 0 taken 6179816 times.
✓ Branch 1 taken 69072 times.
6248888 if (m_useSymmetricStress) {
723 // \eta \int \epsilon u^{n+1} : \epsilon v
724 6179816 m_elementMat[indexMatrix]->eps_phi_i_eps_phi_j(m_theta*2*m_viscosity, *m_feVel, 0, 0, dimension());
725 } else {
726 // \eta \int \nabla u^{n+1} \nabla v
727 69072 m_elementMat[indexMatrix]->grad_phi_i_grad_phi_j(m_theta*m_viscosity, *m_feVel, 0, 0, dimension());
728 }
729
730 // \int q \nabla \cdot u^{n+1} and \int p \nabla \cdot v
731 6248888 m_elementMat[indexMatrix]->psi_j_div_phi_i_and_psi_i_div_phi_j (*m_feVel, *m_fePres, 0, m_velocity->numComponent(), -1, -1);
732
733
1/2
✓ Branch 0 taken 6248888 times.
✗ Branch 1 not taken.
6248888 if ( ! r_instance.quasistatic ) { //normally you pass this if, you do not enter for instance when using stokesLinearElasticityCoupledModel
734 // \dfrac{\rho}{\dt} u^{n+1} v
735
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6248888 times.
6248888 if ( r_instance.useALEformulation == 2 ) {
736 m_elementMat[indexMatrix+1]->phi_i_phi_j(0.5*m_bdf->coeffDeriv0()*coef, *m_feVel, 0, 0, dimension()); // indexMatrix + 1 = 1
737 m_elementMat[indexMatrix ]->phi_i_phi_j(0.5*m_bdf->coeffDeriv0()*coef, *m_feVel, 0, 0, dimension()); // indexMatrix = 0
738 } else {
739 6248888 m_elementMat[indexMatrix]->phi_i_phi_j(m_bdf->coeffDeriv0()*coef, *m_feVel, 0, 0, dimension());
740 }
741 }
742 }
743 }
744
745
5/6
✓ Branch 1 taken 134158 times.
✓ Branch 2 taken 13756526 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 134158 times.
✓ Branch 5 taken 13756526 times.
✓ Branch 6 taken 134158 times.
13890684 if ( m_fstransient->iteration > 0 || m_forceConvAndStabComputation) {
746
4/4
✓ Branch 0 taken 9303520 times.
✓ Branch 1 taken 4453006 times.
✓ Branch 2 taken 3081130 times.
✓ Branch 3 taken 6222390 times.
13756526 if( (flagMatrixRHS == FlagMatrixRHS::matrix_and_rhs) || (flagMatrixRHS == FlagMatrixRHS::only_matrix)) {
747 //================================
748 // Convective Term
749 //================================
750
2/5
✓ Branch 0 taken 733696 times.
✓ Branch 1 taken 6800440 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
7534136 switch(r_instance.NSequationFlag) {
751 733696 case 0:
752 //nothing to do: Stokes' model
753 733696 break;
754
755 6800440 case 1:
756 // Method 1: \rho u \grad(u)
757 // Natural condition: \sigma(u,p) \cdot n = 0
758 // DEFAULT METHOD
759
760 // Temam's stabilization trick
761 6800440 m_elemFieldAdv.setValue(m_solExtrapol, *m_feVel, iel, m_iVelocity, m_ao, dof());
762 6800440 m_elementMat[0]->div_u_phi_j_phi_i(0.5*m_density,m_elemFieldAdv,*m_feVel,0,0,dimension());
763
764
2/2
✓ Branch 0 taken 6114730 times.
✓ Branch 1 taken 685710 times.
6800440 if(r_instance.useALEformulation) {
765 //=========
766 // ALE
767 //=========
768 // m_elemFieldAdv -> m_beta where m_beta = u^{n-1} - w^{n} is defined in userElementInit()
769 // m_elemFielVelMesh -> -w^{n}
770 6114730 m_elemFieldAdv.setValue(m_beta, *m_feVel, iel, m_iVelocity, m_ao, dof());
771 6114730 m_elemFieldVelMesh.setValue(externalVec(0), *m_feVel, iel, m_iDisplacement, m_externalAO[0], *m_externalDof[0]);
772
773
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 6114730 times.
6114730 if ( r_instance.useALEformulation == 2 )
774 m_elementMat[0]->div_u_phi_j_phi_i(0.5*m_density,m_elemFieldVelMesh,*m_feVel,0,0,dimension());
775 else
776 6114730 m_elementMat[0]->div_u_phi_j_phi_i(m_density,m_elemFieldVelMesh,*m_feVel,0,0,dimension());
777 }
778
779 6800440 m_elementMat[0]->u_grad_phi_j_phi_i(m_theta*m_density,m_elemFieldAdv,*m_feVel,0,0,dimension());
780 6800440 break;
781
782 case 2:
783 m_elemFieldAdv.setValue(m_solExtrapol, *m_feVel, iel, m_iVelocity, m_ao, dof());
784 // Method 2: rotational formulation
785 m_elemFieldTotalPressureFormulation.setValue(sequentialSolution(), *m_feVel, iel, m_iVelocity, m_ao, dof());
786
787 // Natural condition: \sigma(u,p) \cdot n + \rho * 0.5 * |u|^2 \cdot n = 0 (total pressure)
788 m_elementMat[0]->convective_rot(m_density,m_elemFieldTotalPressureFormulation,*m_feVel,0,0,dimension());
789 break;
790
791 case 3:
792 // Method 3: Total pressure skew-symmetric formulation
793 m_elemFieldAdv.setValue(m_solExtrapol, *m_feVel, iel, m_iVelocity, m_ao, dof());
794 // \int_{Sigma} u^{n+1} Grad u^{n} \dot v - v Grad u^{n} \dot u^{n+1}
795 m_elementMat[0]->phi_grad_u_minus_grad_u_phi(m_density, m_elemFieldAdv, *m_feVel, 0, 0, dimension());
796 break;
797
798 default:
799 FEL_ERROR("Error: No Convection Method found for Navier-Stokes equations");
800 }
801
802 //================================
803 // FE stabilization
804 //================================
805
1/2
✓ Branch 0 taken 7534136 times.
✗ Branch 1 not taken.
7534136 if(r_instance.NSStabType == 0) { // SUPG (1: face-oriented)
806
2/2
✓ Branch 2 taken 7480596 times.
✓ Branch 3 taken 53540 times.
7534136 if ( m_velocity->finiteElementType() == m_pressure->finiteElementType()) {
807 7480596 double stab1 = r_instance.stabSUPG;
808 7480596 double stab2 = r_instance.stabdiv;
809 7480596 int type = r_instance.typeSUPG;
810 double Rem_elem,tau;
811 double delta;
812
813
4/4
✓ Branch 0 taken 256000 times.
✓ Branch 1 taken 7224596 times.
✓ Branch 2 taken 51700 times.
✓ Branch 3 taken 204300 times.
7480596 if ( r_instance.hasImmersedData && r_instance.hasDivDivStab ) {
814
815 // Boilevin-Kayl 02/2018: for the moment, delta is the first external vector which has been pushed back in NSModel for the std::set of methods (hasImmersedData + hasDivDivStab + !useALEformulation)
816 // This should be updated when additional methods will be considered
817 // Boilevin-Kayl 11/2018: the following has been updated in order to handle the case where hasImmersedData and useALEformulation are used at the same time
818
819 // here iel is already relative to the global numbering, so no need to use an additional mapping or a global index like ielG
820
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 51700 times.
51700 if ( r_instance.useALEformulation ) {
821 externalVec(1).getValues(1, &iel, &delta);
822 }
823 else {
824
1/2
✓ Branch 2 taken 51700 times.
✗ Branch 3 not taken.
51700 externalVec(0).getValues(1, &iel, &delta);
825 }
826
827 51700 stab1 *= delta;
828 51700 stab2 *= 1.0/delta;
829 }
830
831 // Beware: if elemFieldRHS is modified in userNS, it wont be considered here (usually elemFieldRHS = 0 (no body force))...
832 // if the matrix and the rhs are not assembled together
833
834 //todo Jeremie 01 02 2012: assemble multiple matrix
835
1/2
✓ Branch 3 taken 7480596 times.
✗ Branch 4 not taken.
14961192 m_elementMat[0]->stab_supg(m_fstransient->timeStep, stab1, stab2, m_density, m_viscosity, *m_feVel,
836 7480596 m_elemFieldAdv, m_elemFieldRHS, *m_elementVector[0], Rem_elem, tau, type);
837 }
838 }
839 }
840
841
6/8
✓ Branch 0 taken 13756526 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 6222390 times.
✓ Branch 3 taken 7534136 times.
✓ Branch 4 taken 3141260 times.
✓ Branch 5 taken 3081130 times.
✓ Branch 6 taken 3141260 times.
✗ Branch 7 not taken.
13756526 if( (r_instance.NSStabType == 0) && (flagMatrixRHS==FlagMatrixRHS::only_rhs) && (m_meshUpdateState==FlagMeshUpdated::PreviousMesh) && !m_forceConvAndStabComputation) {
842
1/2
✓ Branch 2 taken 3141260 times.
✗ Branch 3 not taken.
3141260 if ( m_velocity->finiteElementType() == m_pressure->finiteElementType()) {
843
1/2
✓ Branch 2 taken 3141260 times.
✗ Branch 3 not taken.
3141260 m_elemFieldAdv.setValue(m_solExtrapol, *m_feVel, iel, m_iVelocity, m_ao, dof());
844 3141260 double stab1 = r_instance.stabSUPG;
845 3141260 int type = r_instance.typeSUPG;
846 double Rem_elem,tau;
847
848
1/2
✓ Branch 3 taken 3141260 times.
✗ Branch 4 not taken.
6282520 m_elementVector[0]->stab_supg(m_fstransient->timeStep, stab1, m_density, m_viscosity, *m_feVel,
849 3141260 m_elemFieldAdv, m_elemFieldRHS, Rem_elem, tau, type);
850 }
851 }
852
853
6/6
✓ Branch 0 taken 9303520 times.
✓ Branch 1 taken 4453006 times.
✓ Branch 2 taken 6222390 times.
✓ Branch 3 taken 3081130 times.
✓ Branch 4 taken 3141260 times.
✓ Branch 5 taken 3081130 times.
13756526 if( (flagMatrixRHS == FlagMatrixRHS::matrix_and_rhs) || ((flagMatrixRHS == FlagMatrixRHS::only_rhs) &&(m_meshUpdateState==FlagMeshUpdated::PreviousMesh))){
854 //================================
855 // RHS
856 //================================
857 // 1/ bdf (with order k from data)
858 // \frac{\rho}{\dt} \sum_{i=1}^k \alpha_i u_{n+1-i}
859
1/2
✓ Branch 0 taken 7594266 times.
✗ Branch 1 not taken.
7594266 if ( !r_instance.quasistatic ) {
860 7594266 m_elemFieldRHSbdf.setValue(m_seqBdfRHS, *m_feVel, iel, m_iVelocity, m_ao, dof());
861
2/2
✓ Branch 0 taken 4896000 times.
✓ Branch 1 taken 2698266 times.
7594266 if ( r_instance.nonLinearFluid ){
862
6/6
✓ Branch 0 taken 4569600 times.
✓ Branch 1 taken 326400 times.
✓ Branch 2 taken 3033600 times.
✓ Branch 3 taken 1536000 times.
✓ Branch 4 taken 326400 times.
✓ Branch 5 taken 3033600 times.
4896000 if ( (r_instance.useALEformulation && m_meshUpdateState==FlagMeshUpdated::PreviousMesh) || (!r_instance.useALEformulation) )
863 1862400 m_elementVector[0]->source(-1.*m_density,*m_feVel,m_elemFieldRHSbdf,0,dimension());
864 }
865 else {
866 2698266 m_elementVector[0]->source(m_density,*m_feVel,m_elemFieldRHSbdf,0,dimension());
867 }
868 }
869 // 'm_density' and not 'coef' because the time step is integrated into the bdf term
870
871 // 2/ no bdf method
872 // \dfrac{\rho}{\dt} u^{n} v
873 //m_elemFieldAdv.setValue(m_seqSol, *m_feVel, iel, m_iVelocity, m_ao, dof());
874 //m_elementVector[0]->source(coef,*m_feVel,m_elemFieldAdv,0,dimension());
875
876 // theta-method RHS
877
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 7594266 times.
7594266 if ( m_theta < 1 ) {
878 computeRHSThetaMethod(iel);
879 }
880 }
881 }
882 }
883 13890684 }
884
885 /***********************************************************************************/
886 /***********************************************************************************/
887
888 void LinearProblemNS::computeElementArrayCharact(const std::vector<Point*>& elemPoint, const std::vector<felInt>& /* elemIdPoint */, felInt& iel, ElementType& eltType, felInt& ielGeo, FlagMatrixRHS /* flagMatrixRHS */)
889 {
890
891 // Retrieve instance
892 auto& r_instance = FelisceParam::instance(instanceIndex());
893
894 m_feVel->updateFirstDeriv(0, elemPoint);
895 m_fePres->updateFirstDeriv(0, elemPoint);
896 PetscScalar coef = m_density/m_fstransient->timeStep;
897
898 if ( m_fstransient->iteration == 0) {
899 //================================
900 // matrix
901 //================================
902
903 if (m_useSymmetricStress) {
904 // \eta \int \epsilon u^{n+1} : \epsilon v
905 m_elementMat[1]->eps_phi_i_eps_phi_j(2*m_viscosity,*m_feVel, 0, 0, dimension());
906 } else {
907 // \eta \int \nabla u^{n+1} \nabla v
908 m_elementMat[1]->grad_phi_i_grad_phi_j(m_viscosity, *m_feVel, 0, 0, dimension());
909 }
910
911 // \int q \nabla \cdot u^{n+1} and \int p \nabla \cdot v
912 m_elementMat[1]->psi_j_div_phi_i_and_psi_i_div_phi_j (*m_feVel,*m_fePres,0,m_velocity->numComponent(), -1, -1);
913
914 // \dfrac{\rho}{\dt} u^{n+1} v
915 FEL_CHECK(r_instance.orderBdfNS == 1, "Error: Higher bdf order not yet implemented for method of characteristics");
916 if (r_instance.orderBdfNS == 1)
917 m_elementMat[1]->phi_i_phi_j(coef,*m_feVel,0,0,dimension());
918 } else {
919 //================================
920 // RHS
921 //================================
922
923 //method of characteristics: \dfrac{\rho}{\dt} u^n o X^n v
924 if (r_instance.orderBdfNS == 1) {
925 setValueCharact(sequentialSolution(),m_elemFieldCharact, *m_feVel, iel, m_iVelocity, eltType, ielGeo, m_fstransient->timeStep);
926 assert(!m_elementVector.empty()); // TODO D.C. FELASSERT?
927 m_elementVector[0]->source(coef, *m_feVel, m_elemFieldCharact, 0, dimension());
928 }
929
930 //================================
931 // FE stabilization
932 //================================
933
934 if ( m_velocity->finiteElementType() == m_pressure->finiteElementType()) {
935 double stab1 = r_instance.stabSUPG;
936 double stab2 = r_instance.stabdiv;
937 int type = r_instance.typeSUPG;
938 double Rem_elem,tau;
939
940 // Beware: if elemFieldRHS is modified in userNS, it wont be considered here...
941 // (usually elemFieldRHS = 0 (no body force))
942
943 //todo Jeremie 01 02 2012: assemble multiple matrix
944 m_elementMat[0]->stab_supg(m_fstransient->timeStep,
945 stab1,stab2, m_density, m_viscosity, *m_feVel,
946 m_elemFieldAdv, m_elemFieldRHS,
947 *m_elementVector[0], Rem_elem, tau, type);
948 }
949 }
950 }
951
952 /***********************************************************************************/
953 /***********************************************************************************/
954
955 void LinearProblemNS::setValueCharact(PetscVector& v, ElementField& elemFieldCharact, CurrentFiniteElement& fe, felInt iel,
956 int idVariable, const ElementType& eltType, felInt ielGeo, const double dt)
957 {
958 // Retrieve instance
959 auto& r_instance = FelisceParam::instance(instanceIndex());
960
961 Point pt, localCoord, vel;
962 ElementField elemFieldVelOnDep;
963 ElementType eltTypeArr;
964 felInt ielGeoArr;
965 double dtLeft, dtTol = r_instance.timeStepCharact;
966 int numComp = elemFieldCharact.numComp(), numStep = 1 + static_cast<int>(dt/dtTol), effStep;
967
968 switch (elemFieldCharact.type()) {
969 case QUAD_POINT_FIELD:
970 if ( !fe.hasQuadPtCoor() ) {
971 fe.computeCurrentQuadraturePoint();
972 }
973 //velocity field in the departure element, in the ordering of felisce
974 elemFieldVelOnDep.initialize(DOF_FIELD, fe, numComp);
975 elemFieldVelOnDep.setValue(v, fe, iel, idVariable, m_ao, dof());
976
977 //loop on quadrature points of the departure element
978 for(int ig=0; ig<fe.numQuadraturePoint(); ig++) {
979 //coordinates and local coordinates of each quadrature point pt
980 pt.setCoor( fe.currentQuadPoint[ig].coor() );
981 localCoord = fe.quadratureRule().quadraturePoint(ig);
982
983 //velocity at pt: v(pt) = \sum v(x_iDof) phi_iDof(localCoord)
984 vel.x() = vel.y() = vel.z() = 0.;
985 for(int iComp=0; iComp < numComp; iComp++) {
986 for (int iDof=0; iDof < fe.numDof(); iDof++) {
987 vel[iComp] += elemFieldVelOnDep.val(iComp, iDof) * fe.phi[ig](iDof);
988 }
989 }
990
991 //backtrack the characteristic line a length dt
992 eltTypeArr = eltType;
993 ielGeoArr = ielGeo;
994
995 if (r_instance.characteristicMethod == 1) {
996 //RK4 scheme
997 if ( !(charactLine(v, idVariable, numComp, dt, numStep, effStep, pt, localCoord, eltTypeArr, ielGeoArr, vel)) ) {
998 dtLeft = dt - effStep * (dt/numStep);
999 while ( charactLineElem(v, idVariable, numComp, dtTol, pt, localCoord, eltTypeArr, ielGeoArr, vel, dtLeft) );
1000 }
1001 } else {
1002 //Euler scheme
1003 dtLeft = dt;
1004 while ( charactLineElem(v, idVariable, numComp, dtTol, pt, localCoord, eltTypeArr, ielGeoArr, vel, dtLeft) );
1005 }
1006
1007 //compute elemFieldCharact
1008 for(int iComp=0; iComp < numComp; iComp++) {
1009 elemFieldCharact.val(iComp, ig) = vel[iComp];
1010 }
1011 }
1012 break;
1013 case CONSTANT_FIELD:
1014 case DOF_FIELD:
1015 FEL_ERROR("setValueCharact from Petsc std::vector is not yet implemented for this type of element field");
1016 break;
1017 }
1018 }
1019
1020 /***********************************************************************************/
1021 /***********************************************************************************/
1022
1023 int LinearProblemNS::charactLine(PetscVector& v, int idVariable, int numComp, const double dt, int numStep, int& effStep,
1024 Point& pt, Point& localCoord, ElementType& eltType, felInt& ielGeo, Point& vel)
1025 {
1026 //given a point pt, backtrack the characteristic line a length dt
1027 double step = - dt / numStep;
1028 for(int iStep=1; iStep <= numStep; iStep++) {
1029 if ( !nextPt(v, idVariable, numComp, step, pt, localCoord, eltType, ielGeo, vel) ) {
1030 /* This case occurs when for example the point pt got at iStep is outside the domain,
1031 then the number of effectively done steps before stopping is effStep = iStep-1 and
1032 the output pt, localCoord... are those at (iStep-1)-th step.
1033 */
1034 effStep = iStep-1;
1035 return(0);
1036 }
1037 }
1038 effStep = numStep;
1039
1040 return(1);
1041 }
1042
1043 /***********************************************************************************/
1044 /***********************************************************************************/
1045
1046 int LinearProblemNS::nextPt(PetscVector& v, int idVariable, int numComp, const double step,
1047 Point& pt, Point& localCoord, ElementType& eltType, felInt& ielGeo, Point& vel)
1048 {
1049 //given a point pt and initial velocity vel, backtrack the characteristic line a length step (<0) by a variant of RK4 scheme
1050 //input: point pt, its local coordinates, element containing pt, velocity at pt
1051 //output: next point pt with local coordinates localCoord, element containing pt, vel is velocity at pt
1052 Point ptTmp, localCoordTmp;
1053 ElementType eltTypeTmp;
1054 felInt ielGeoTmp;
1055 GeometricMeshRegion::seedElement seedElt, seedEltTmp;
1056 double s1 = step / 6.;
1057 int base;
1058
1059 std::array<Point, 4> veltmp;
1060 seedElt = std::make_pair(eltType, ielGeo);
1061
1062 // first, second and third integration point, element containing this point, velocity at this point
1063 veltmp[0] = vel;
1064 for (int intPnt = 0; intPnt < 3; ++intPnt) {
1065
1066 for(int iComp = 0; iComp < numComp; iComp++)
1067 ptTmp[iComp] = pt[iComp] + 0.5 * step * veltmp[intPnt][iComp];
1068
1069 base = ++m_pLocator->getMark();
1070
1071 seedEltTmp = m_pLocator->localizePoint(seedElt, ptTmp, localCoordTmp, base);
1072
1073 if ( seedEltTmp.first != GeometricMeshRegion::ELEMENT_TYPE_COUNTER && seedEltTmp.second >= 0 ) {
1074 eltTypeTmp = seedEltTmp.first;
1075 ielGeoTmp = seedEltTmp.second;
1076
1077 seedElt = seedEltTmp;
1078 } else {
1079
1080 return 0;
1081 }
1082
1083 veltmp[intPnt+1] = vecInterp(v, idVariable, numComp, localCoordTmp, eltTypeTmp, ielGeoTmp);
1084 }
1085
1086 // final point
1087 for(int iComp=0; iComp < numComp; iComp++)
1088 ptTmp[iComp] = pt[iComp] + s1 * ( veltmp[0][iComp] + 2*(veltmp[1][iComp] + veltmp[2][iComp]) + veltmp[3][iComp] );
1089
1090 base = ++m_pLocator->getMark();
1091
1092 seedEltTmp = m_pLocator->localizePoint(seedElt, ptTmp, localCoordTmp, base);
1093
1094 if ( seedEltTmp.first != GeometricMeshRegion::ELEMENT_TYPE_COUNTER && seedEltTmp.second >= 0 ) {
1095 eltTypeTmp = seedEltTmp.first;
1096 ielGeoTmp = seedEltTmp.second;
1097
1098 seedElt = seedEltTmp;
1099 } else {
1100
1101 return 0;
1102 }
1103
1104 // if succeed, update pt, localCoord, vel
1105 pt = ptTmp;
1106 localCoord = localCoordTmp;
1107
1108 vel = vecInterp(v, idVariable, numComp, localCoord, eltType, ielGeo);
1109
1110 return 1;
1111 }
1112
1113 /***********************************************************************************/
1114 /***********************************************************************************/
1115
1116 int LinearProblemNS::charactLineElem(PetscVector& v, int idVariable, int numComp, double dtTol, Point& pt, Point& localCoord, ElementType& eltType, felInt& ielGeo, Point& vel, double& dtLeft)
1117 {
1118 //given a point pt, backtrack the characteristic line in one element a length dtTol at most
1119 //update pt, localCoord, eltType, ielGeo, vel and the time remaining dtLeft
1120 //return 0 if dtLeft = 0 or reach to the boundary of the domain, else return 1
1121 const GeoElement *geoEle;
1122 geoEle = GeometricMeshRegion::eltEnumToFelNameGeoEle[eltType].second;
1123 TypeShape eltShape = (TypeShape)(geoEle->shape().typeShape());
1124
1125 Point pt1, localCoord1;
1126 double barCoord[4], vecBarCoord[4];
1127 double dtAdvec = 0.;
1128 ElementType eltTypeTmp = eltType;
1129 felInt ielGeoTmp = ielGeo;
1130 int i0;//, i1, i2;
1131
1132 if (vel[0]*vel[0] + vel[1]*vel[1] + vel[2]*vel[2] < 1e-20) //almost null velocity, no advection
1133 return(0);
1134
1135 switch (eltShape) {
1136
1137 case Triangle: {
1138 barCoord[2] = localCoord[0];
1139 barCoord[0] = localCoord[1];
1140 barCoord[1] = 1. - localCoord[0] - localCoord[1];
1141 //endpoint of velocity std::vector starting from pt
1142 for(int iComp=0; iComp < numComp; iComp++) {
1143 pt1[iComp] = pt[iComp] + vel[iComp];
1144 }
1145 //local coordinates of pt1, barycentric coordinates of vel
1146 m_mesh[m_currentMesh]->findLocalCoord(eltTypeTmp, ielGeoTmp, pt1, localCoord1);
1147 vecBarCoord[2] = localCoord1[0] - localCoord[0];
1148 vecBarCoord[0] = localCoord1[1] - localCoord[1];
1149 vecBarCoord[1] = - (vecBarCoord[0] + vecBarCoord[2]);
1150
1151 //dtAdvec = time length from pt to the first intersection of [pt pt1] with an edge
1152 // = min{barCoord[i]/vecBarCoord[i]} s.t. vecBarCoord[i]>0 and not too small
1153 dtAdvec = dtLeft * 1e+6;
1154 i0 = 0;
1155 for (int ind=0; ind < 3; ind++) {
1156 if (vecBarCoord[ind] > 1e-10) {
1157 if (dtAdvec > barCoord[ind]/vecBarCoord[ind]) {
1158 dtAdvec = barCoord[ind]/vecBarCoord[ind];
1159 i0 = ind;
1160 }
1161 }
1162 }
1163
1164 //case when advection stays in the current element, update only pt, localCoord, vel, dtLeft
1165 if ( (dtLeft <= dtAdvec) && (dtLeft <= dtTol) ) {
1166 for(int iComp=0; iComp < numComp; iComp++) {
1167 pt[iComp] = pt[iComp] - dtLeft * vel[iComp];
1168 localCoord[iComp] = localCoord[iComp] - dtLeft * vecBarCoord[(iComp+2)%3];
1169 }
1170 vel = vecInterp(v, idVariable, numComp, localCoord, eltType, ielGeo);
1171 dtLeft = 0.;
1172 return(0);
1173 }
1174
1175 //case when advection stays in the current element but dtLeft > dtTol
1176 if ( (dtLeft <= dtAdvec) && (dtLeft > dtTol) ) {
1177 for(int iComp=0; iComp < numComp; iComp++) {
1178 pt[iComp] = pt[iComp] - dtTol * vel[iComp];
1179 localCoord[iComp] = localCoord[iComp] - dtTol * vecBarCoord[(iComp+2)%3];
1180 }
1181 vel = vecInterp(v, idVariable, numComp, localCoord, eltType, ielGeo);
1182 dtLeft -= dtTol;
1183 return(1);
1184 }
1185
1186 //case when advection stays in the current element but dtAdvec > dtTol
1187 if ( (dtLeft > dtAdvec) && (dtAdvec >= dtTol) ) {
1188 for(int iComp=0; iComp < numComp; iComp++) {
1189 pt[iComp] = pt[iComp] - dtTol * vel[iComp];
1190 localCoord[iComp] = localCoord[iComp] - dtTol * vecBarCoord[(iComp+2)%3];
1191 }
1192 vel = vecInterp(v, idVariable, numComp, localCoord, eltType, ielGeo);
1193 dtLeft -= dtTol;
1194 return(1);
1195 }
1196
1197 //case when advection goes out of the current element through the edge i0
1198 if ( (dtLeft > dtAdvec) && (dtAdvec < dtTol) ) {
1199 //update pt, vel, dtLeft (not yet localCoord)
1200 for(int iComp=0; iComp < numComp; iComp++) {
1201 pt[iComp] = pt[iComp] - dtAdvec * vel[iComp]; //this point is on the edge i0 of the current element
1202 localCoord[iComp] = localCoord[iComp] - dtAdvec * vecBarCoord[(iComp+2)%3];
1203 }
1204 vel = vecInterp(v, idVariable, numComp, localCoord, eltType, ielGeo);
1205 dtLeft -= dtAdvec;
1206 //update element = edge i0 -> adjacency and localCoord in updated element
1207 if ( m_mesh[m_currentMesh]->getAdjElement(eltType, ielGeo, i0) ) { //element is already updated to the adjacent one
1208 eltTypeTmp = eltType;
1209 ielGeoTmp = ielGeo;
1210 m_mesh[m_currentMesh]->findLocalCoord(eltTypeTmp, ielGeoTmp, pt, localCoord);
1211 return(1);
1212 } else //reach to the boundary of the domain
1213 return(0);
1214 }
1215 break;
1216 }
1217
1218 case Tetrahedron: {
1219 barCoord[3] = localCoord[0];
1220 barCoord[1] = localCoord[1];
1221 barCoord[0] = localCoord[2];
1222 barCoord[2] = 1. - localCoord[0] - localCoord[1] - localCoord[2];
1223 //endpoint of velocity std::vector starting from pt
1224 for(int iComp=0; iComp < numComp; iComp++) {
1225 pt1[iComp] = pt[iComp] + vel[iComp];
1226 }
1227 //local coordinates of pt1, barycentric coordinates of vel
1228 m_mesh[m_currentMesh]->findLocalCoord(eltTypeTmp, ielGeoTmp, pt1, localCoord1);
1229 vecBarCoord[3] = localCoord1[0] - localCoord[0];
1230 vecBarCoord[1] = localCoord1[1] - localCoord[1];
1231 vecBarCoord[0] = localCoord1[2] - localCoord[2];
1232 vecBarCoord[2] = - (vecBarCoord[0] + vecBarCoord[1] + vecBarCoord[3]);
1233
1234 //dtAdvec = time length from pt to the first intersection of [pt pt1] with a face
1235 // = min{barCoord[i]/vecBarCoord[i]} s.t. vecBarCoord[i]>0 and not too small
1236 dtAdvec = dtLeft * 1e+6;
1237 i0 = 0;
1238 for (int ind=0; ind < 4; ind++) {
1239 if (vecBarCoord[ind] > 1e-10) {
1240 if (dtAdvec > barCoord[ind]/vecBarCoord[ind]) {
1241 dtAdvec = barCoord[ind]/vecBarCoord[ind];
1242 i0 = ind;
1243 }
1244 }
1245 }
1246
1247 //case when advection stays in the current element, update only pt, localCoord, vel, dtLeft
1248 if ( (dtLeft <= dtAdvec) && (dtLeft <= dtTol) ) {
1249 for(int iComp=0; iComp < numComp; iComp++) {
1250 pt[iComp] = pt[iComp] - dtLeft * vel[iComp];
1251 }
1252 localCoord[0] = localCoord[0] - dtLeft * vecBarCoord[3];
1253 localCoord[1] = localCoord[1] - dtLeft * vecBarCoord[1];
1254 localCoord[2] = localCoord[2] - dtLeft * vecBarCoord[0];
1255 vel = vecInterp(v, idVariable, numComp, localCoord, eltType, ielGeo);
1256 dtLeft = 0.;
1257 return(0);
1258 }
1259
1260 //case when advection stays in the current element but dtLeft > dtTol
1261 if ( (dtLeft <= dtAdvec) && (dtLeft > dtTol) ) {
1262 for(int iComp=0; iComp < numComp; iComp++) {
1263 pt[iComp] = pt[iComp] - dtTol * vel[iComp];
1264 }
1265 localCoord[0] = localCoord[0] - dtTol * vecBarCoord[3];
1266 localCoord[1] = localCoord[1] - dtTol * vecBarCoord[1];
1267 localCoord[2] = localCoord[2] - dtTol * vecBarCoord[0];
1268 vel = vecInterp(v, idVariable, numComp, localCoord, eltType, ielGeo);
1269 dtLeft -= dtTol;
1270 return(1);
1271 }
1272
1273 //case when advection stays in the current element but dtAdvec > dtTol
1274 if ( (dtLeft > dtAdvec) && (dtAdvec >= dtTol) ) {
1275 for(int iComp=0; iComp < numComp; iComp++) {
1276 pt[iComp] = pt[iComp] - dtTol * vel[iComp];
1277 }
1278 localCoord[0] = localCoord[0] - dtTol * vecBarCoord[3];
1279 localCoord[1] = localCoord[1] - dtTol * vecBarCoord[1];
1280 localCoord[2] = localCoord[2] - dtTol * vecBarCoord[0];
1281 vel = vecInterp(v, idVariable, numComp, localCoord, eltType, ielGeo);
1282 dtLeft -= dtTol;
1283 return(1);
1284 }
1285
1286 //case when advection goes out of the current element through the face i0
1287 if ( (dtLeft > dtAdvec) && (dtAdvec < dtTol) ) {
1288 //update pt, vel, dtLeft (not yet localCoord)
1289 for(int iComp=0; iComp < numComp; iComp++) {
1290 pt[iComp] = pt[iComp] - dtAdvec * vel[iComp]; //this point is on the face i0 of the current element
1291 }
1292 localCoord[0] = localCoord[0] - dtAdvec * vecBarCoord[3];
1293 localCoord[1] = localCoord[1] - dtAdvec * vecBarCoord[1];
1294 localCoord[2] = localCoord[2] - dtAdvec * vecBarCoord[0];
1295 vel = vecInterp(v, idVariable, numComp, localCoord, eltType, ielGeo);
1296 dtLeft -= dtAdvec;
1297 //update element = face i0 -> adjacency and localCoord in updated element
1298 if ( m_mesh[m_currentMesh]->getAdjElement(eltType, ielGeo, i0) ) { //element is already updated to the adjacent one
1299 eltTypeTmp = eltType;
1300 ielGeoTmp = ielGeo;
1301 m_mesh[m_currentMesh]->findLocalCoord(eltTypeTmp, ielGeoTmp, pt, localCoord);
1302 return(1);
1303 } else //reach to the boundary of the domain
1304 return(0);
1305 }
1306 break;
1307 }
1308
1309 case NullShape:
1310 case Node:
1311 case Segment:
1312 case Quadrilateral:
1313 case Hexahedron:
1314 case Prism:
1315 case Pyramid: {
1316 FEL_ERROR("Unknown (or not implemented) element Shape");
1317 break;
1318 }
1319 }
1320
1321 return(0);
1322 }
1323
1324
1325 /***********************************************************************************/
1326 /***********************************************************************************/
1327
1328 Point LinearProblemNS::vecInterp(PetscVector& v, int idVariable, int numComp,
1329 const Point& localCoord, ElementType& eltType, felInt ielGeo)
1330 {
1331 //given a point in an element with its local coordinates, compute the interpolated std::vector at this point
1332 Point vecInt(0.);
1333 ElementField elemField;
1334
1335 //define finite element
1336 const RefElement *refEle;
1337 const GeoElement *geoEle;
1338 int typeOfFiniteElement = 0;
1339 CurrentFiniteElement* fe;
1340 int numPointPerElt = 0;
1341 std::vector<Point*> elemPoint;
1342 std::vector<felInt> elemIdPoint;
1343 felInt ielSupportDof;
1344
1345 geoEle = GeometricMeshRegion::eltEnumToFelNameGeoEle[eltType].second;
1346 typeOfFiniteElement = m_listVariable[idVariable].finiteElementType();
1347 refEle = geoEle->defineFiniteEle(eltType,typeOfFiniteElement, *m_mesh[m_currentMesh]);
1348 fe = new CurrentFiniteElement(*refEle,*geoEle,m_listVariable[idVariable].degreeOfExactness());
1349
1350 //resize array
1351 numPointPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType];
1352 elemPoint.resize(numPointPerElt, nullptr);
1353 elemIdPoint.resize(numPointPerElt, 0);
1354 setElemPoint(eltType, ielGeo, elemPoint, elemIdPoint, &ielSupportDof);
1355
1356 //interpolation
1357 elemField.initialize(DOF_FIELD, *fe, numComp);
1358 elemField.setValue(v, *fe, ielSupportDof, idVariable, m_ao, dof());
1359 for(int iComp=0; iComp < numComp; iComp++) {
1360 for (int iDof=0; iDof < fe->numDof(); iDof++) {
1361 vecInt[iComp] += elemField.val(iComp, iDof) * refEle->basisFunction().phi(iDof, localCoord);
1362 }
1363 }
1364
1365 delete fe;
1366 elemPoint.clear();
1367 elemIdPoint.clear();
1368 return(vecInt);
1369 }
1370
1371 /***********************************************************************************/
1372 /***********************************************************************************/
1373
1374 2508 void LinearProblemNS::allocateElemFieldBoundaryConditionDerivedLinPb(const int idBCforLinCombMethod)
1375 {
1376 // Retrieve instance
1377 2508 auto& r_instance = FelisceParam::instance(instanceIndex());
1378
1379 // implicit lumpedModelBC but applied as Neumann Normal BC
1380
4/6
✓ Branch 0 taken 84 times.
✓ Branch 1 taken 2424 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 84 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2508 times.
2508 if(m_lumpedModelBC && r_instance.model == "NSlinComb") {
1381 bool isFullImplicit = true;
1382 bool isFullExplicit = true;
1383 for(std::size_t i=0; i<m_lumpedModelBC->size(); i++) {
1384 if(r_instance.lumpedModelBCAlgo[i] != 2)
1385 isFullImplicit = false;
1386 if(r_instance.lumpedModelBCAlgo[i] != 1)
1387 isFullImplicit = false;
1388 }
1389 if(!isFullImplicit && !isFullExplicit)
1390 FEL_WARNING("NSlinComb not implemented with mixed explicit and implicit algorithm for the windkessel");
1391
1392 if (isFullImplicit) {
1393 BoundaryCondition* BC;
1394 std::vector <double> valueOfBC(1);
1395 valueOfBC[0] = 0.;
1396 // 1st step: std::set std::vector m_elemFieldNeumannNormal = 0
1397 for (std::size_t i=0; i < m_boundaryConditionList.numNeumannNormalBoundaryCondition(); i++) {
1398 BC = m_boundaryConditionList.NeumannNormal(i);
1399 switch (BC->typeValueBC()) {
1400 case Constant:
1401 m_elemFieldNeumannNormal[i].setValue(valueOfBC);
1402 break;
1403 case FunctionT:
1404 m_elemFieldNeumannNormal[i].setValue(valueOfBC);
1405 break;
1406 case Vector:
1407 case FunctionS:
1408 case FunctionTS:
1409 case EnsightFile:
1410 FEL_ERROR("This kind of boundary conditions are not available.");
1411 break;
1412 }
1413 }
1414
1415 // 2nd step: std::set m_elemFieldNeumannNormal[idBCforLinCombMethod] = -1 alternatively while preProcessing
1416 if ( m_fstransient->iteration == 0 ) {
1417 valueOfBC[0] = -1.;
1418 BC = m_boundaryConditionList.NeumannNormal(idBCforLinCombMethod);
1419 switch (BC->typeValueBC()) {
1420 case Constant:
1421 m_elemFieldNeumannNormal[idBCforLinCombMethod].setValue(valueOfBC);
1422 break;
1423 case FunctionT:
1424 m_elemFieldNeumannNormal[idBCforLinCombMethod].setValue(valueOfBC);
1425 break;
1426 case FunctionS:
1427 case Vector:
1428 case FunctionTS:
1429 case EnsightFile:
1430 FEL_ERROR("This kind of boundary conditions are not available.");
1431 break;
1432 }
1433 }
1434 valueOfBC.clear();
1435 }
1436 }
1437 2508 }
1438
1439 96 void LinearProblemNS::initExtrapol(PetscVector& V_1)
1440 {
1441
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 42 times.
96 if (allocateSeqVecExt == false) {
1442 54 m_solExtrapol.create(PETSC_COMM_SELF);
1443 54 m_solExtrapol.setType(VECSEQ);
1444 54 m_solExtrapol.setSizes(PETSC_DECIDE,m_numDof);
1445 54 allocateSeqVecExt = true;
1446 }
1447 96 gatherVector(V_1, m_solExtrapol);
1448 96 }
1449
1450 1554 void LinearProblemNS::updateExtrapol(PetscVector& V_1)
1451 {
1452 1554 gatherVector(V_1, m_solExtrapol);
1453 1554 }
1454
1455 1608 void LinearProblemNS::gatherVectorBeforeAssembleMatrixRHS()
1456 {
1457
2/2
✓ Branch 0 taken 54 times.
✓ Branch 1 taken 1554 times.
1608 if (allocateSeqVec == false) {
1458 54 m_seqBdfRHS.create(PETSC_COMM_SELF);
1459 54 m_seqBdfRHS.setType(VECSEQ);
1460 54 m_seqBdfRHS.setSizes(PETSC_DECIDE,m_numDof);
1461 54 allocateSeqVec = true;
1462 }
1463 1608 gatherVector(m_bdf->vector(), m_seqBdfRHS);
1464 1608 }
1465
1466 /***********************************************************************************/
1467 /***********************************************************************************/
1468
1469 3044 void LinearProblemNS::addMatrixRHS()
1470 {
1471
1472 //! The not constant matrix (0) is summed with the constant matrix (1).
1473 //! The result is stored into the not constant matrix (0)
1474 //! When using ALE there is not a constant matrix (1) and therefore is useless to do it.
1475
1476 // Retrieve instance
1477 3044 auto& r_instance = FelisceParam::instance(instanceIndex());
1478
1479
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3044 times.
3044 if ( r_instance.useFDlagrangeMult )
1480 matrix(0).axpy(1,matrix(1),SUBSET_NONZERO_PATTERN);
1481
2/2
✓ Branch 0 taken 2368 times.
✓ Branch 1 taken 676 times.
3044 else if( r_instance.useALEformulation == 0 )
1482 2368 matrix(0).axpy(1,matrix(1),SAME_NONZERO_PATTERN);
1483 3044 }
1484
1485 /***********************************************************************************/
1486 /***********************************************************************************/
1487
1488 1912 void LinearProblemNS::addMatrixRHSNl(const FlagMatrixRHS flagMatrixRHS)
1489 {
1490 // Retrieve instance
1491 1912 auto& r_instance = FelisceParam::instance(instanceIndex());
1492
1493
2/3
✓ Branch 0 taken 1436 times.
✓ Branch 1 taken 476 times.
✗ Branch 2 not taken.
1912 switch (flagMatrixRHS) {
1494 1436 case FlagMatrixRHS::only_matrix:
1495 1436 matrix(0).axpy(1, matrix(2), SAME_NONZERO_PATTERN);
1496 1436 break;
1497 476 case FlagMatrixRHS::only_rhs:
1498
1/2
✓ Branch 0 taken 476 times.
✗ Branch 1 not taken.
476 if (r_instance.useALEformulation)
1499 476 vector().axpy(1, externalVec(1));
1500 476 break;
1501 default :
1502 break;
1503 }
1504 1912 }
1505
1506 /***********************************************************************************/
1507 /***********************************************************************************/
1508
1509 5330 void LinearProblemNS::applyEssentialBoundaryConditionDerivedProblem(int rank, FlagMatrixRHS flagMatrixRHS)
1510 {
1511 // Retrieve instance
1512 5330 auto& r_instance = FelisceParam::instance(instanceIndex());
1513
1514
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5330 times.
5330 if ( r_instance.zeroDisplacementAtBoarders ) {
1515 if (FelisceParam::verbose() > 2)
1516 std::cout<<"["<<rank<<"]--Applying zero-Dirichlet BCs on the velocity at the interface between inlet outlet and surface."<<std::endl;
1517 getRings();
1518 double bigValue=r_instance.penValueForEmbedFSI*1e10;
1519
1520 for(auto itDofBC = m_idDofRings.begin(); itDofBC != m_idDofRings.end(); ++itDofBC) {
1521 if( (flagMatrixRHS == FlagMatrixRHS::matrix_and_rhs) || (flagMatrixRHS == FlagMatrixRHS::only_matrix))
1522 matrix(0).setValue(*itDofBC, *itDofBC, bigValue, INSERT_VALUES);
1523 if((flagMatrixRHS == FlagMatrixRHS::matrix_and_rhs) ||( (flagMatrixRHS == FlagMatrixRHS::only_rhs)
1524 &&(m_meshUpdateState==FlagMeshUpdated::PreviousMesh) ) )
1525 vector().setValue(*itDofBC,0.0, INSERT_VALUES);
1526 }
1527 }
1528 5330 }
1529
1530 /***********************************************************************************/
1531 /***********************************************************************************/
1532
1533 42 void LinearProblemNS::applyNaturalBoundaryConditionLumpedModelBC(std::vector<Point*>& /* elemPoint */, const std::vector<felInt>& /* elemIdPoint */, int /* label */, felInt /* numEltPerLabel */, felInt* /* ielSupportDof */, std::size_t iLumpedModelBC, ElementType& /* eltType */, felInt /* numElement_eltType */, FlagMatrixRHS /* flagMatrixRHS */)
1534 {
1535 // Retrieve instance
1536 42 auto& r_instance = FelisceParam::instance(instanceIndex());
1537
1538 // to apply "NeumannNormal" BC with -p0
1539
1/2
✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
42 if (r_instance.lumpedModelBCAlgo[iLumpedModelBC] == 1)
1540
1/2
✓ Branch 2 taken 42 times.
✗ Branch 3 not taken.
42 PlumpedModelBC.push_back(-(m_lumpedModelBC->Pp(iLumpedModelBC)));
1541 else if (r_instance.lumpedModelBCAlgo[iLumpedModelBC] == 2) {
1542 // Add the explicit part on the RHS
1543 if(r_instance.lumpedModelBCType[iLumpedModelBC] == 1) {
1544 // RCR or R type
1545 double alpha = r_instance.lumpedModelBC_Rdist[iLumpedModelBC] * r_instance.lumpedModelBC_C[iLumpedModelBC];
1546 double beta = r_instance.timeStep;
1547 double Pv = r_instance.lumpedModelBC_Pvenous[iLumpedModelBC];
1548 double Pd = m_lumpedModelBC->Pd(iLumpedModelBC);
1549 PlumpedModelBC.push_back(-(alpha*Pd + beta*Pv)/(alpha + beta));
1550 } else if(r_instance.lumpedModelBCType[iLumpedModelBC] == 2) {
1551 // RC type
1552 PlumpedModelBC.push_back(-(m_lumpedModelBC->Pd(iLumpedModelBC)));
1553 }
1554 }
1555 42 m_elemFieldLumpedModelBC[iLumpedModelBC].setValue(PlumpedModelBC);
1556
1557
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
42 if (verbosity()>2) {
1558 std::cout << "LumpedModelBC on label " << m_currentLabel << std::endl;
1559 std::cout << "Applied PlumpedModelBC = " << -PlumpedModelBC[0] << std::endl;
1560 }
1561
1562 42 PlumpedModelBC.clear();
1563 42 }
1564
1565 /***********************************************************************************/
1566 /***********************************************************************************/
1567
1568 void LinearProblemNS::assembleMatrixImplLumpedModelBC(int rank, const std::size_t iLabel)
1569 {
1570 // Retrieve instance
1571 auto& r_instance = FelisceParam::instance(instanceIndex());
1572
1573 if (m_fstransient->iteration == 0) {
1574 int label = r_instance.lumpedModelBCLabel[iLabel];
1575 PetscScalar coef = 0.;
1576 if ( r_instance.lumpedModelBCType[iLabel] == 1 ) {
1577 // R lumpedModel bc, or RCR lumpedModel bc
1578 coef = r_instance.lumpedModelBC_Rdist[iLabel]/(1.0 + r_instance.lumpedModelBC_Rdist[iLabel] * r_instance.lumpedModelBC_C[iLabel]/r_instance.timeStep) + r_instance.lumpedModelBC_Rprox[iLabel];
1579 } else if ( r_instance.lumpedModelBCType[iLabel] == 2 ) {
1580 // RC lumpedModel bc
1581 coef = r_instance.lumpedModelBC_Rprox[iLabel] + r_instance.timeStep / r_instance.lumpedModelBC_C[iLabel];
1582 }
1583
1584 double *tmp_phi_i_dot_n = new double [m_numDof];
1585 double *phi_i_dot_n = new double [m_numDof]; // to store globally \int_Gamma phi_i n
1586 int *tmp_ind = new int [m_numDof];
1587 int *ind = new int [m_numDof]; // to mark the position of matrix assembling
1588 felInt node = 0;
1589 int idVar = m_listVariable.getVariableIdList(velocity);
1590 // int iUnknown = m_listVariable.listIdUnknownOfVariable(idVar);
1591 int numComp = m_listVariable[idVar].numComponent();
1592 ElementType eltType;
1593 felInt ielGeom;
1594 int numPointPerElt = 0;
1595 int currentLabel = 0;
1596 felInt numEltPerLabel = 0;
1597 std::vector<Point*> elemPoint;
1598 std::vector<felInt> elemIdPoint;
1599 felInt ielSupportDof;
1600
1601 // initialize tmp_phi_i_dot_n and phi_i_dot_n to 0
1602 for (int iDof = 0; iDof < m_numDof; iDof++) {
1603 tmp_phi_i_dot_n[iDof] = 0.;
1604 phi_i_dot_n[iDof] = 0.;
1605 tmp_ind[iDof] = 0;
1606 ind[iDof] = 0;
1607 }
1608 const std::vector<ElementType>& bagElementTypeDomainBoundary = m_meshLocal[m_currentMesh]->bagElementTypeDomainBoundary();
1609 for (std::size_t iTyp = 0; iTyp < bagElementTypeDomainBoundary.size(); ++iTyp) {
1610 eltType = bagElementTypeDomainBoundary[iTyp];
1611 ielGeom = 0;
1612 defineCurvilinearFiniteElement(eltType);
1613 initElementArrayBD();
1614 CurvilinearFiniteElement& fe = *m_listCurvilinearFiniteElement[idVar];
1615 numPointPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType];
1616 elemPoint.resize(numPointPerElt, nullptr);
1617 elemIdPoint.resize(numPointPerElt, 0);
1618
1619 for(auto itRef = m_meshLocal[m_currentMesh]->intRefToBegEndMaps[eltType].begin();
1620 itRef != m_meshLocal[m_currentMesh]->intRefToBegEndMaps[eltType].end(); itRef++) {
1621 currentLabel = itRef->first;
1622 numEltPerLabel = itRef->second.second;
1623 if (currentLabel == label) {
1624 // compute tmp_phi_i_dot_n = local \int_Gamma phi_i n = local \sum \int_{element of Gamma} phi_i n
1625 for (felInt iel1 = 0; iel1 < numEltPerLabel; iel1++) {
1626 setElemPoint(eltType, ielGeom, elemPoint, elemIdPoint, &ielSupportDof);
1627 fe.updateMeasNormal(0, elemPoint);
1628 for (int iDof = 0; iDof < fe.numDof(); iDof++) {
1629 for (int iComp = 0; iComp < numComp; iComp++) {
1630 dof().loc2glob(ielSupportDof,iDof,idVar,iComp,node);
1631 tmp_ind[node] = 1;
1632 for (int ig=0; ig < fe.numQuadraturePoint(); ig++) {
1633 tmp_phi_i_dot_n[node] += fe.phi[ig](iDof) * fe.normal[ig](iComp) * fe.weightMeas(ig);
1634 }
1635 }
1636 }
1637 ielGeom++;
1638 } // end of loop on iel1 of each label
1639 } // end of if currentLabel == label
1640 else
1641 ielGeom += numEltPerLabel;
1642 } //end of loop on itRef
1643 } // end of loop on iTyp
1644
1645 // synchronise value of tmp_phi_i_dot_n and tmp_ind
1646 MPI_Reduce(&tmp_phi_i_dot_n[0], &phi_i_dot_n[0], m_numDof, MPI_DOUBLE, MPI_SUM,0,MpiInfo::petscComm());
1647 MPI_Reduce(&tmp_ind[0], &ind[0], m_numDof, MPI_INT, MPI_SUM,0,MpiInfo::petscComm());
1648
1649 if (rank == 0) {
1650 felInt cptDof = 0;
1651 for (int iDof = 0; iDof < m_numDof; iDof++) {
1652 if (ind[iDof] > 0) {
1653 tmp_ind[cptDof] = iDof;
1654 tmp_phi_i_dot_n[cptDof] = phi_i_dot_n[iDof];
1655 cptDof++;
1656 }
1657 }
1658
1659 std::vector<double*> valueMat;
1660 for (unsigned int i = 0; i < numberOfMatrices(); i++) {
1661 valueMat.push_back(new double[cptDof*cptDof]);
1662 }
1663 for (int iRow = 0; iRow < cptDof; iRow++) {
1664 for (int iCol = 0; iCol < cptDof; iCol++) {
1665 valueMat[0][iCol + iRow*cptDof] = 0.;
1666 valueMat[1][iCol + iRow*cptDof] = coef * tmp_phi_i_dot_n[iRow] * tmp_phi_i_dot_n[iCol];
1667 }
1668 }
1669 AOApplicationToPetsc(m_ao,cptDof,tmp_ind);
1670 for (unsigned int i = 0; i < numberOfMatrices(); i++) {
1671 matrix(i).setValues(cptDof,tmp_ind,cptDof,tmp_ind,valueMat[i],ADD_VALUES);
1672 delete [] valueMat[i];
1673 }
1674 valueMat.clear();
1675 }
1676
1677 delete [] tmp_phi_i_dot_n;
1678 delete [] phi_i_dot_n;
1679 delete [] tmp_ind;
1680 delete [] ind;
1681 }
1682 }
1683
1684 /***********************************************************************************/
1685 /***********************************************************************************/
1686
1687 54 void LinearProblemNS::userChangePattern(int /* numProc */, int /* rankProc */)
1688 {
1689 // Retrieve instance
1690 54 auto& r_instance = FelisceParam::instance(instanceIndex());
1691
1692 54 bool isImplicitLumpedModelBCused = false;
1693
2/2
✓ Branch 1 taken 16 times.
✓ Branch 2 taken 54 times.
70 for(std::size_t i=0; i<r_instance.lumpedModelBCAlgo.size(); i++) {
1694
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 16 times.
16 if(r_instance.lumpedModelBCAlgo[i] == 2)
1695 isImplicitLumpedModelBCused = true;
1696 }
1697
1698 // ------------------------------------------- //
1699 // monolithic model and implicit LumpedModelBC //
1700 // ------------------------------------------- //
1701
4/8
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 8 times.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
✓ Branch 9 taken 54 times.
54 if (r_instance.lumpedModelBCLabel.size() > 0 && isImplicitLumpedModelBCused && r_instance.model == "NS") {
1702 // re-build random repartition of dof on processes
1703 felInt numDofByProc = m_numDof/MpiInfo::numProc();
1704 felInt *numDofPerProc = new felInt [MpiInfo::numProc()];
1705 for (int i = 0; i < MpiInfo::numProc(); i++) {
1706 if (i == MpiInfo::numProc() - 1)
1707 numDofPerProc[i] = m_numDof - i*numDofByProc;
1708 else
1709 numDofPerProc[i] = numDofByProc;
1710 }
1711 felInt scaleDof = 0;
1712 for (int i = 0; i < MpiInfo::rankProc(); i++) {
1713 scaleDof += numDofPerProc[i];
1714 }
1715 felInt *rankDof = new felInt[m_numDof];
1716 for (int i = 0; i < m_numDof; i++) {
1717 rankDof[i] = -1;
1718 }
1719 for (felInt i = 0; i < numDofPerProc[MpiInfo::rankProc()]; i++) {
1720 rankDof[i+scaleDof] = MpiInfo::rankProc();
1721 }
1722
1723 // loop to connect all added dof
1724 std::vector< std::set<felInt> > nodesNeighborhood(m_numDof);
1725 felInt node1 = 0;
1726 felInt node2 = 0;
1727 const int idVar = m_listVariable.getVariableIdList(velocity);
1728 const int iUnknown = m_listVariable.listIdUnknownOfVariable(idVar);
1729 const int numComp = m_listVariable[idVar].numComponent();
1730 const std::size_t iMesh = m_listVariable[idVar].idMesh();
1731 int searchLabel = -1;
1732 ElementType eltType;
1733 int currentLabel = 0;
1734 int numEltPerLabel = 0;
1735 felInt ielSupportDof1, ielSupportDof2;
1736 felInt ielGeom1, ielGeom2, ielGeomTmp;
1737
1738 for (std::size_t iLabel = 0; iLabel < r_instance.lumpedModelBCLabel.size(); iLabel++) {
1739 if(r_instance.lumpedModelBCAlgo[iLabel] == 2) {
1740 searchLabel = r_instance.lumpedModelBCLabel[iLabel];
1741 const std::vector<ElementType>& bagElementTypeDomainBoundary = m_mesh[iMesh]->bagElementTypeDomainBoundary();
1742 for (std::size_t iTyp = 0; iTyp < bagElementTypeDomainBoundary.size(); ++iTyp) {
1743 eltType = bagElementTypeDomainBoundary[iTyp];
1744 ielGeom1 = 0;
1745
1746 for(auto itRef = m_mesh[iMesh]->intRefToBegEndMaps[eltType].begin(); itRef != m_mesh[iMesh]->intRefToBegEndMaps[eltType].end(); itRef++) {
1747 currentLabel = itRef->first;
1748 numEltPerLabel = itRef->second.second;
1749
1750 if (searchLabel == currentLabel) {
1751 ielGeomTmp = ielGeom1;
1752 for (felInt iel1 = 0; iel1 < numEltPerLabel; iel1++) {
1753 // find ielSupportDof1
1754 supportDofUnknown(iUnknown).getIdElementSupport(eltType, ielGeom1, ielSupportDof1);
1755 for (int iSupport = 0; iSupport < supportDofUnknown(iUnknown).getNumSupportDof(ielSupportDof1); iSupport++) {
1756 for (int iComp = 0; iComp < numComp; iComp++) {
1757 dof().loc2glob(ielSupportDof1,iSupport,idVar,iComp,node1);
1758 if (rankDof[node1] == MpiInfo::rankProc()) {
1759 ielGeom2 = ielGeomTmp;
1760 for (felInt iel2 = 0; iel2 < numEltPerLabel; iel2++) {
1761 supportDofUnknown(iUnknown).getIdElementSupport(eltType, ielGeom2, ielSupportDof2);
1762 for (int jSupport = 0; jSupport < supportDofUnknown(iUnknown).getNumSupportDof(ielSupportDof2); jSupport++) {
1763 for (int jComp = 0; jComp < numComp; jComp++) {
1764 dof().loc2glob(ielSupportDof2,jSupport,idVar,jComp,node2);
1765 if ( node1 != node2)
1766 nodesNeighborhood[node1].insert(node2);
1767 }
1768 }
1769 ielGeom2++;
1770 } // end of loop on iel2 of each label
1771 } // end of if rankDof[node1] == MpiInfo::rankProc()
1772 } // end of loop on iComp
1773 } // end of loop on iSupport
1774 ielGeom1++;
1775 } // end of loop on iel1 of each label
1776 } // end of if searchLabel == currentLabel
1777 else
1778 ielGeom1 += numEltPerLabel;
1779 } //end of loop on itRef
1780 } //end of loop on bagElementTypeDomainBoundary
1781 } // end of if lumpedModelBCAlgo[iLabel] == 2
1782 } //end of loop on lumpedModelBCLabel
1783
1784 // Storage the added dof in CSR format
1785 felInt dofSize = 0;
1786 for (unsigned int iNode = 0; iNode < nodesNeighborhood.size(); iNode++) {
1787 dofSize += nodesNeighborhood[iNode].size();
1788 }
1789
1790 std::vector<felInt> m_iCSR1(dof().pattern().numRows()+1, 0);
1791 std::vector<felInt> m_jCSR1(dofSize, 0);
1792 felInt pos = 0;
1793 felInt cptDof = 0;
1794 for (unsigned int iNode = 0; iNode < nodesNeighborhood.size(); iNode++) {
1795 if (rankDof[iNode] == MpiInfo::rankProc()) {
1796 m_iCSR1[cptDof+1 ] = m_iCSR1[cptDof] + nodesNeighborhood[iNode].size();
1797 pos = 0;
1798 for(auto iCon = nodesNeighborhood[iNode].begin(); iCon != nodesNeighborhood[iNode].end(); iCon++) {
1799 m_jCSR1[m_iCSR1[cptDof] + pos] = *iCon;
1800 pos++;
1801 }
1802 cptDof++;
1803 }
1804 }
1805
1806 // merge pattern
1807 dof().mergeGlobalPattern(m_iCSR1, m_jCSR1);
1808
1809 delete [] numDofPerProc;
1810 delete [] rankDof;
1811 nodesNeighborhood.clear();
1812 m_iCSR1.clear();
1813 m_jCSR1.clear();
1814 }
1815
1816 // ---------------------------------------------- //
1817 // Modify pattern for face-oriented stabilization //
1818 // ---------------------------------------------- //
1819
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
54 if (r_instance.NSStabType == 1) {
1820 // If the face-oriented stabilization is used, the dofs of an element an all its neighbor
1821 // are linked together.
1822
1823 // compute initial (uniform) repartition of dof on processes
1824 felInt numDofByProc = m_numDof/MpiInfo::numProc();
1825 std::vector<felInt> numDofPerProc(MpiInfo::numProc());
1826 for(felInt i=0; i<MpiInfo::numProc(); ++i) {
1827 if(i == MpiInfo::numProc() - 1)
1828 numDofPerProc[i] = m_numDof - i*numDofByProc;
1829 else
1830 numDofPerProc[i] = numDofByProc;
1831 }
1832
1833 felInt shiftDof = 0;
1834 for(felInt i=0; i<MpiInfo::rankProc(); ++i)
1835 shiftDof += numDofPerProc[i];
1836
1837 std::vector<felInt> rankDof(m_numDof, -1);
1838 for(felInt i=0; i<numDofPerProc[MpiInfo::rankProc()]; ++i)
1839 rankDof[i + shiftDof] = MpiInfo::rankProc();
1840
1841 // variables
1842 GeometricMeshRegion::ElementType eltType, eltTypeOpp;
1843 const int idVar = m_listVariable.getVariableIdList(velocity);
1844 const std::size_t iMesh = m_listVariable[idVar].idMesh();
1845 felInt idVar1, idVar2;
1846 felInt node1, node2;
1847 felInt numFacesPerElement, numEltPerLabel;
1848 felInt ielSupport, jelSupport;
1849 felInt ielCurrentGeo, ielOppositeGeo;
1850 std::vector<felInt> vecSupport, vecSupportOpposite;
1851 std::vector<felInt> numElement(GeometricMeshRegion::m_numTypesOfElement, 0);
1852 std::vector< std::set<felInt> > nodesNeighborhood(m_numDof);
1853
1854 // zeroth loop on the unknown of the linear problem
1855 for (std::size_t iUnknown1 = 0; iUnknown1 < m_listUnknown.size(); ++iUnknown1) {
1856 idVar1 = m_listUnknown.idVariable(iUnknown1);
1857
1858 if ( iMesh != m_listVariable[idVar1].idMesh() )
1859 continue;
1860
1861 // build the edges or faces depending on the dimension (for the global mesh)
1862 // In this function, "faces" refers to either edges or faces.
1863 if(dimension() == 2)
1864 m_mesh[iMesh]->buildEdges();
1865 else
1866 m_mesh[iMesh]->buildFaces();
1867
1868 // first loop on element type
1869 ielCurrentGeo = 0;
1870 for (std::size_t i=0; i<m_mesh[iMesh]->bagElementTypeDomain().size(); ++i) {
1871 eltType = m_mesh[iMesh]->bagElementTypeDomain()[i];
1872 const GeoElement* geoEle = GeometricMeshRegion::eltEnumToFelNameGeoEle[eltType].second;
1873 numElement[eltType] = 0;
1874 numFacesPerElement = geoEle->numBdEle();
1875
1876 // second loop on region of the mesh.
1877 for(auto itRef = m_mesh[iMesh]->intRefToBegEndMaps[eltType].begin(); itRef != m_mesh[iMesh]->intRefToBegEndMaps[eltType].end(); itRef++) {
1878 numEltPerLabel = itRef->second.second;
1879
1880 // Third loop on element
1881 for (felInt iel = 0; iel < numEltPerLabel; iel++) {
1882 m_supportDofUnknown[iUnknown1].getIdElementSupport(eltType, numElement[eltType], vecSupport);
1883
1884 for(std::size_t ielSup=0; ielSup<vecSupport.size(); ++ielSup) {
1885 ielSupport = vecSupport[ielSup];
1886
1887 // for all support dof in this support element
1888 for (felInt iSup = 0; iSup < m_supportDofUnknown[iUnknown1].getNumSupportDof(ielSupport); ++iSup) {
1889 // for all component of the unknown
1890 for (std::size_t iComp = 0; iComp < m_listVariable[idVar1].numComponent(); iComp++) {
1891 // get the global id of the support dof
1892 dof().loc2glob(ielSupport, iSup, idVar1, iComp, node1);
1893
1894 // if this node is on this process
1895 if(rankDof[node1] == MpiInfo::rankProc()) {
1896 // loop over the boundaries of the element
1897 for(felInt iface=0; iface < numFacesPerElement; ++iface) {
1898 // check if this face is an inner face or a boundary
1899 ielOppositeGeo = ielCurrentGeo;
1900 eltTypeOpp = eltType;
1901 bool isAnInnerFace = m_mesh[iMesh]->getAdjElement(eltTypeOpp, ielOppositeGeo, iface);
1902
1903 if(isAnInnerFace) {
1904 // for all unknown
1905 for (std::size_t iUnknown2 = 0; iUnknown2 < m_listUnknown.size(); ++iUnknown2) {
1906 idVar2 = m_listUnknown.idVariable(iUnknown2);
1907
1908 if ( iMesh != m_listVariable[idVar2].idMesh() )
1909 continue;
1910
1911 // get the support element of the opposite element
1912 supportDofUnknown(iUnknown2).getIdElementSupport(ielOppositeGeo, vecSupportOpposite);
1913
1914 // for all support element
1915 for(std::size_t jelSup=0; jelSup<vecSupportOpposite.size(); ++jelSup) {
1916 jelSupport = vecSupportOpposite[jelSup];
1917
1918 // for all support dof in this support element
1919 for (felInt jSup = 0; jSup < supportDofUnknown(iUnknown2).getNumSupportDof(jelSupport); ++jSup) {
1920
1921 // for all component of the second unknown
1922 for (std::size_t jComp = 0; jComp < m_listVariable[idVar2].numComponent(); jComp++) {
1923
1924 // If the two current components are connected
1925 const felInt iConnect = dof().getNumGlobComp(iUnknown1, iComp);
1926 const felInt jConnect = dof().getNumGlobComp(iUnknown2, jComp);
1927 if (m_listUnknown.mask()(iConnect, jConnect) > 0) {
1928 // get the global id of the second support dof
1929 dof().loc2glob(jelSupport, jSup, idVar2, jComp, node2);
1930
1931 // remove diagonal term to define pattern and use it in Parmetis.
1932 // if the two global ids are different, they are neighboors
1933 if(node1 != node2)
1934 nodesNeighborhood[node1].insert(node2);
1935 }
1936 }
1937 }
1938 }
1939 }
1940 }
1941 }
1942 }
1943 }
1944 }
1945 }
1946 ++ielCurrentGeo;
1947 ++numElement[eltType];
1948 }
1949 }
1950 }
1951 }
1952
1953 // Store the pattern in CSR style
1954 std::vector<felInt> iCSR, jCSR;
1955 felInt dofSize = 0;
1956 felInt cptDof = 0;
1957 felInt pos;
1958
1959 iCSR.resize(dof().pattern().numRows() + 1, 0);
1960 for(std::size_t iNode=0; iNode<nodesNeighborhood.size(); ++iNode)
1961 dofSize += nodesNeighborhood[iNode].size();
1962
1963 jCSR.resize(dofSize, 0);
1964 for(std::size_t iNode=0; iNode<nodesNeighborhood.size(); ++iNode) {
1965 if(rankDof[iNode] == MpiInfo::rankProc()) {
1966 iCSR[cptDof + 1] = iCSR[cptDof] + nodesNeighborhood[iNode].size();
1967 pos = 0;
1968 for (auto it=nodesNeighborhood[iNode].begin(); it != nodesNeighborhood[iNode].end(); ++it) {
1969 jCSR[iCSR[cptDof] + pos] = *it;
1970 ++pos;
1971 }
1972 ++cptDof;
1973 }
1974 }
1975
1976 // Now, call merge pattern
1977 dof().mergeGlobalPattern(iCSR, jCSR);
1978 }
1979 54 }
1980
1981 /***********************************************************************************/
1982 /***********************************************************************************/
1983
1984 void LinearProblemNS::reviseSolution(PetscVector& alphai, std::vector<PetscVector>& stationnarySolutions)
1985 {
1986 // m_sol = u^n = \tilde{u}^n + \sum_i alpha_i^n u_i
1987
1988 // alpha_i^n = m_coefProblem->solution()[i]
1989 // u_i = m_stationnarySolutionsVec[i]
1990 // \tilde{u}^n = m_linearProblem[0]->solution() = m_sol already
1991
1992 PetscScalar coef ;
1993 for (PetscInt jj = 0 ; jj < (PetscInt) stationnarySolutions.size() ; jj++ ) {
1994 alphai.getValues(1, &jj, &coef);
1995 // m_sol = coef * statSol + m_sol
1996 solution().axpy(coef, stationnarySolutions[jj]);
1997 }
1998 }
1999
2000 /***********************************************************************************/
2001 /***********************************************************************************/
2002
2003 void LinearProblemNS::computeRHSThetaMethod(felInt& iel)
2004 {
2005 // Retrieve instance
2006 auto& r_instance = FelisceParam::instance(instanceIndex());
2007
2008 //==============================================
2009 // Provisional implementation
2010 //==============================================
2011
2012 m_elMatRHSThetaMethod[0]->mat().clear();
2013
2014 if ( ((m_fstransient->iteration == 1) && (r_instance.useALEformulation == 0))
2015 || ((m_fstransient->iteration > 0) && (r_instance.useALEformulation)) ) {
2016 std::size_t indexMatrix;
2017 if( r_instance.useALEformulation )
2018 indexMatrix = 0;
2019 else
2020 indexMatrix = 1;
2021 m_elMatRHSThetaMethod[indexMatrix]->mat().clear();
2022 if (m_useSymmetricStress) {
2023 m_elMatRHSThetaMethod[indexMatrix]->eps_phi_i_eps_phi_j((m_theta-1)*2*m_viscosity, *m_feVel, 0, 0, dimension());
2024 } else {
2025 m_elMatRHSThetaMethod[indexMatrix]->grad_phi_i_grad_phi_j((m_theta-1)*m_viscosity, *m_feVel, 0, 0, dimension());
2026 }
2027 }
2028
2029 if ( m_fstransient->iteration > 0) {
2030 //=======================
2031 // Convective Term
2032 //=======================
2033 switch(r_instance.NSequationFlag) {
2034 case 0:
2035 break;
2036 case 1:
2037 if(r_instance.useALEformulation) {
2038 m_elemFieldAdv.setValue(m_beta, *m_feVel, iel, m_iVelocity, m_ao, dof());
2039 } else {
2040 m_elemFieldAdv.setValue(m_solExtrapol, *m_feVel, iel, m_iVelocity, m_ao, dof());
2041 }
2042 m_elMatRHSThetaMethod[0]->u_grad_phi_j_phi_i((m_theta-1)*m_density,m_elemFieldAdv,*m_feVel,0,0,dimension());
2043 break;
2044 default:
2045 FEL_ERROR("Error: No theta-method for this kind of Convection Method ");
2046 }
2047 }
2048
2049 if( r_instance.useALEformulation == 0)
2050 m_elMatRHSThetaMethod[0]->mat() = m_elMatRHSThetaMethod[0]->mat() + m_elMatRHSThetaMethod[1]->mat();
2051
2052 m_elemFieldAdv.setValue(sequentialSolution(), *m_feVel, iel, m_iVelocity, m_ao, dof());
2053 m_elemFieldPres.setValue(sequentialSolution(), *m_fePres, iel, m_iPressure, m_ao, dof());
2054
2055 UBlasVector auxVec(m_elementVector[0]->vec().size());
2056 std::size_t entry=0;
2057
2058 for (std::size_t velComp=0; velComp <m_elemFieldAdv.get_val().size1() ; velComp++) {
2059 for (std::size_t velDof=0; velDof <m_elemFieldAdv.get_val().size2() ; velDof++) {
2060 auxVec(entry) = row(m_elemFieldAdv.get_val(),velComp)(velDof);
2061 entry++;
2062 }
2063 }
2064 for (std::size_t pressDof=0; pressDof <m_elemFieldPres.get_val().size2() ; pressDof++) {
2065 auxVec(entry) = row(m_elemFieldPres.get_val(),0)(pressDof);
2066 entry++;
2067 }
2068
2069 axpy_prod(m_elMatRHSThetaMethod[0]->mat(),auxVec,m_elementVector[0]->vec(), false);
2070
2071 }
2072
2073 /***********************************************************************************/
2074 /***********************************************************************************/
2075
2076 void LinearProblemNS::assembleFaceOrientedStabilization()
2077 {
2078 // Retrieve instance
2079 auto& r_instance = FelisceParam::instance(instanceIndex());
2080
2081 /*!
2082 * Assembly loop to compute the face-oriented stabilization
2083 * E. Burman, M. A. Fernandez and P. Hansbo, Continuous interior penalty finite element method
2084 * for Oseen's equations, SIAM J. Numer. Anal., 44(3), 1248-1274, 2006.
2085 *
2086 * This function works if the mesh has only one type of element !!!
2087 */
2088 // definition of variables
2089 std::pair<bool, GeometricMeshRegion::ElementType> adjElt;
2090 GeometricMeshRegion::ElementType eltType; // Type of element
2091
2092 felInt ielCurrentLocalGeo = 0; // local geometric id of the current element
2093 felInt ielCurrentGlobalGeo = 0; // global geometric id of the current element
2094 felInt ielOppositeGlobalGeo = 0; // global geometric id of the opposite element
2095 felInt numFacesPerType; // number of faces of an element of a given type
2096 felInt numPointPerElt; // number of vertices by element
2097 felInt ielCurrentGlobalSup; // global support element id of the current element
2098 felInt ielOppositeGlobalSup; // global support element id of the opposite element
2099
2100 std::vector<felInt> idOfFacesCurrent; // ids of the current element edges
2101 std::vector<felInt> idOfFacesOpposite; // ids of the opposite element edges
2102 std::vector<felInt> currentElemIdPoint; // ids of the vertices of the current element
2103 std::vector<felInt> oppositeElemIdPoint; // ids of the vertices of the opposite element
2104 std::vector<Point*> currentElemPoint; // point coordinates of the current element vertices
2105 std::vector<Point*> oppositeElemPoint; // point coordinates of the opposite element vertices
2106
2107 FlagMatrixRHS flag = FlagMatrixRHS::only_matrix; // flag to only assemble the matrix
2108 felInt idFaceToDo;
2109 bool allDone = false;
2110
2111 ElementField elemFieldAdvFace;
2112
2113 felInt rank;
2114 MPI_Comm_rank(PETSC_COMM_WORLD, &rank);
2115
2116 const int iVel = m_listVariable.getVariableIdList(velocity); // TODO D.C. ALREADY DEFINED IN CALSS???
2117 const int iPres = m_listVariable.getVariableIdList(pressure);
2118 m_velocity = &m_listVariable[iVel ];
2119 m_pressure = &m_listVariable[iPres];
2120
2121 if ( m_velocity->idMesh() != m_pressure->idMesh() && m_pressure->idMesh() != static_cast<std::size_t>(m_currentMesh) )
2122 FEL_ERROR("Velocity and pressure defined on different meshes, or not defined on m_currentMesh");
2123
2124 // bag element type vector
2125 const std::vector<ElementType>& bagElementTypeDomain = m_meshLocal[m_currentMesh]->bagElementTypeDomain();
2126 eltType = bagElementTypeDomain[0];
2127
2128 // Finite Element With Bd for the opposite element
2129 CurrentFiniteElementWithBd* ptmp;
2130 CurrentFiniteElementWithBd* oppositeFEWithBdVel;
2131 CurrentFiniteElementWithBd* oppositeFEWithBdPre;
2132
2133 const GeoElement *geoEle = GeometricMeshRegion::eltEnumToFelNameGeoEle[eltType].second;
2134
2135 felInt typeOfFEVel = m_velocity->finiteElementType();
2136 const RefElement *refEleVel = geoEle->defineFiniteEle(eltType, typeOfFEVel, *m_mesh[m_currentMesh]);
2137 oppositeFEWithBdVel = new CurrentFiniteElementWithBd(*refEleVel, *geoEle, m_velocity->degreeOfExactness(), m_velocity->degreeOfExactness());
2138
2139 felInt typeOfFEPre = m_pressure->finiteElementType();
2140 const RefElement *refElePre = geoEle->defineFiniteEle(eltType, typeOfFEPre, *m_mesh[m_currentMesh]);
2141 oppositeFEWithBdPre = new CurrentFiniteElementWithBd(*refElePre, *geoEle, m_pressure->degreeOfExactness(), m_pressure->degreeOfExactness());
2142
2143
2144 // initializing variables
2145 numPointPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType];
2146 numFacesPerType = GeometricMeshRegion::eltEnumToFelNameGeoEle[eltType].second->numBdEle();
2147
2148 // resize of vectors
2149 idOfFacesCurrent.resize(numFacesPerType, -1);
2150 idOfFacesOpposite.resize(numFacesPerType, -1);
2151 currentElemIdPoint.resize(numPointPerElt, -1);
2152 oppositeElemIdPoint.resize(numPointPerElt, -1);
2153 currentElemPoint.resize(numPointPerElt, nullptr);
2154 oppositeElemPoint.resize(numPointPerElt, nullptr);
2155
2156 // define finite element
2157 defineFiniteElement(eltType);
2158 initElementArray();
2159 defineCurrentFiniteElementWithBd(eltType);
2160
2161 // allocate arrays for assembling the matrix
2162 allocateArrayForAssembleMatrixRHS(flag);
2163
2164 // init variables
2165 initPerElementType(eltType, flag);
2166 m_feVelWithBd = m_listCurrentFiniteElementWithBd[m_iVelocity];
2167 m_fePreWithBd = m_listCurrentFiniteElementWithBd[m_iPressure];
2168
2169
2170 CurrentFiniteElementWithBd* firstCurrentVel = m_feVelWithBd;
2171 CurrentFiniteElementWithBd* firstCurrentPre = m_fePreWithBd;
2172 CurrentFiniteElementWithBd* firstOppositeVel = oppositeFEWithBdVel;
2173 CurrentFiniteElementWithBd* firstOppositePre = oppositeFEWithBdPre;
2174
2175 // get informations on the current element
2176 setElemPoint(eltType, 0, currentElemPoint, currentElemIdPoint, &ielCurrentGlobalSup);
2177
2178 // update the finite elements
2179 m_feVelWithBd->updateFirstDeriv(0, currentElemPoint);
2180 m_feVelWithBd->updateBdMeasNormal();
2181 m_fePreWithBd->updateFirstDeriv(0, currentElemPoint);
2182 m_fePreWithBd->updateBdMeasNormal();
2183
2184 // get the global id of the first geometric element
2185 ISLocalToGlobalMappingApply(m_mappingElem[m_currentMesh], 1, &ielCurrentLocalGeo, &ielCurrentGlobalGeo);
2186
2187 // the std::unordered_map to remember what contribution have already been computed
2188 std::map<felInt, std::vector<bool> > contribDone;
2189 addNewFaceOrientedContributor(numFacesPerType, ielCurrentGlobalGeo, contribDone[ielCurrentGlobalGeo]);
2190
2191 // build the stack to know what is the next element
2192 std::stack<felInt> nextInStack;
2193 nextInStack.push(ielCurrentGlobalGeo);
2194
2195 // get all the faces of the element
2196 if(dimension() == 2)
2197 m_mesh[m_currentMesh]->getAllEdgeOfElement(ielCurrentGlobalGeo, idOfFacesCurrent);
2198 else
2199 m_mesh[m_currentMesh]->getAllFaceOfElement(ielCurrentGlobalGeo, idOfFacesCurrent);
2200
2201 // loop over all the element (snake style)
2202 while(!nextInStack.empty()) {
2203 // check the faces and use the first one that is an inner face and that has not been done yet.
2204 idFaceToDo = -1;
2205 allDone = true;
2206 for(std::size_t iface=0; iface<contribDone[ielCurrentGlobalGeo].size(); ++iface) {
2207 if(!contribDone[ielCurrentGlobalGeo][iface]) {
2208 // This is an inner face, check if the contribution has already been computed or not
2209 if(idFaceToDo == -1) {
2210 idFaceToDo = iface;
2211 } else {
2212 allDone = false;
2213 }
2214 }
2215 }
2216
2217 // update the stack
2218 if(!allDone)
2219 nextInStack.push(ielCurrentGlobalGeo);
2220
2221 if(nextInStack.top() == ielCurrentGlobalGeo && allDone)
2222 nextInStack.pop();
2223
2224
2225 // assemble terms
2226 if(idFaceToDo != -1) {
2227 // get the opposite id of the element
2228 ielOppositeGlobalGeo = ielCurrentGlobalGeo;
2229 adjElt = m_mesh[m_currentMesh]->getAdjElement(ielOppositeGlobalGeo, idFaceToDo);
2230
2231 // get the type of the opposite element
2232 // eltTypeOpp = adjElt.second;
2233
2234 // update the opposite finite element and std::set ielOppositeGlobalSup
2235 updateFaceOrientedFEWithBd(oppositeFEWithBdVel, oppositeFEWithBdPre, idOfFacesOpposite, numPointPerElt, ielOppositeGlobalGeo, ielOppositeGlobalSup);
2236
2237 // find the local id of the edge in the opposite element
2238 felInt localIdFaceOpposite = -1;
2239 for(std::size_t jface=0; jface<idOfFacesOpposite.size(); ++jface) {
2240 if(idOfFacesCurrent[idFaceToDo] == idOfFacesOpposite[jface]) {
2241 localIdFaceOpposite = jface;
2242 }
2243 }
2244
2245
2246 // compute coefficients
2247 elemFieldAdvFace.initialize(DOF_FIELD, m_feVelWithBd->bdEle(idFaceToDo), dimension());
2248 elemFieldAdvFace.setValue(m_solExtrapol, *m_feVelWithBd, idFaceToDo, ielCurrentGlobalSup, m_iVelocity, m_ao, dof());
2249 UBlasVector tmpval = prod(trans(elemFieldAdvFace.val), m_feVelWithBd->bdEle(idFaceToDo).normal[0]);
2250 double normVelNormalBd = norm_inf(tmpval);
2251 double normVelBd = 0.;
2252 for(std::size_t jcol=0; jcol<elemFieldAdvFace.val.size2(); ++jcol)
2253 normVelBd = std::max(normVelBd, norm_2(column(elemFieldAdvFace.val, jcol)));
2254
2255 double hK = 0.5 * (m_feVelWithBd->diameter() + oppositeFEWithBdVel->diameter());
2256 double ReK = m_density * normVelBd * hK / m_viscosity;
2257
2258 double coeffVel = r_instance.stabFOVel * std::min(1., ReK) * hK * hK;
2259 double gammaU = coeffVel * normVelNormalBd;
2260 double gammaP = 0;
2261 if(r_instance.NSequationFlag == 0) {
2262 gammaP = r_instance.stabFOPre * hK * hK * hK / m_viscosity;
2263 } else {
2264 double xiPre = ReK < 1 ? m_density * hK * hK * hK / m_viscosity : hK * hK / normVelBd;
2265 gammaP = r_instance.stabFOPre * xiPre;
2266 }
2267
2268 // We can now compute all the integrals.
2269 // There is a minus sign for gammaP because there is one for q div(u).
2270 // current element for phi_i and phi_j
2271 m_elementMat[0]->zero();
2272 m_elementMat[0]->grad_phi_j_dot_n_grad_psi_i_dot_n(gammaU, *m_feVelWithBd, *m_feVelWithBd, idFaceToDo, idFaceToDo, 0, 0, dimension());
2273 m_elementMat[0]->grad_phi_j_dot_n_grad_psi_i_dot_n(-gammaP, *m_fePreWithBd, *m_fePreWithBd, idFaceToDo, idFaceToDo, dimension(), dimension(), 1);
2274 setValueMatrixRHS(ielCurrentGlobalSup, ielCurrentGlobalSup, flag);
2275
2276 // current element for phi_i and opposite element for phi_j
2277 m_elementMat[0]->zero();
2278 m_elementMat[0]->grad_phi_j_dot_n_grad_psi_i_dot_n(gammaU, *oppositeFEWithBdVel, *m_feVelWithBd, localIdFaceOpposite, idFaceToDo, 0, 0, dimension());
2279 m_elementMat[0]->grad_phi_j_dot_n_grad_psi_i_dot_n(-gammaP, *oppositeFEWithBdPre, *m_fePreWithBd, localIdFaceOpposite, idFaceToDo, dimension(), dimension(), 1);
2280 setValueMatrixRHS(ielCurrentGlobalSup, ielOppositeGlobalSup, flag);
2281
2282 // opposite element for phi_i and current element for phi_j
2283 m_elementMat[0]->mat() = trans(m_elementMat[0]->mat());
2284 setValueMatrixRHS(ielOppositeGlobalSup, ielCurrentGlobalSup, flag);
2285
2286 // opposite element for phi_i and phi_j
2287 m_elementMat[0]->zero();
2288 m_elementMat[0]->grad_phi_j_dot_n_grad_psi_i_dot_n(gammaU, *oppositeFEWithBdVel, *oppositeFEWithBdVel, localIdFaceOpposite, localIdFaceOpposite, 0, 0, dimension());
2289 m_elementMat[0]->grad_phi_j_dot_n_grad_psi_i_dot_n(-gammaP, *oppositeFEWithBdPre, *oppositeFEWithBdPre, localIdFaceOpposite, localIdFaceOpposite, dimension(), dimension(), 1);
2290 setValueMatrixRHS(ielOppositeGlobalSup, ielOppositeGlobalSup, flag);
2291
2292 // update the std::unordered_map to say that this face is done
2293 contribDone[ielCurrentGlobalGeo][idFaceToDo] = true;
2294
2295 // check if the opposite element is on this proc
2296 if(m_eltPart[m_currentMesh][ielOppositeGlobalGeo] == rank) {
2297 if(contribDone.find(ielOppositeGlobalGeo) == contribDone.end()) {
2298 // not found in the std::unordered_map, add it and initialize it.
2299 addNewFaceOrientedContributor(numFacesPerType, ielOppositeGlobalGeo, contribDone[ielOppositeGlobalGeo]);
2300 }
2301 contribDone[ielOppositeGlobalGeo][localIdFaceOpposite] = true;
2302
2303 // update the finite element as the opposite finite element.
2304 ptmp = m_feVelWithBd;
2305 m_feVelWithBd = oppositeFEWithBdVel;
2306 oppositeFEWithBdVel = ptmp;
2307
2308 ptmp = m_fePreWithBd;
2309 m_fePreWithBd = oppositeFEWithBdPre;
2310 oppositeFEWithBdPre = ptmp;
2311
2312 ielCurrentGlobalGeo = ielOppositeGlobalGeo;
2313 ielCurrentGlobalSup = ielOppositeGlobalSup;
2314 idOfFacesCurrent = idOfFacesOpposite;
2315 } else {
2316 // not on this rank, take the next one in the stack
2317 if(!nextInStack.empty()) {
2318 ielCurrentGlobalGeo = nextInStack.top();
2319 updateFaceOrientedFEWithBd(m_feVelWithBd, m_fePreWithBd, idOfFacesCurrent, numPointPerElt, ielCurrentGlobalGeo, ielCurrentGlobalSup);
2320 }
2321 }
2322 } else {
2323 // All contribution have been already computed on this element
2324 // take the next element in the stack
2325 if(!nextInStack.empty()) {
2326 ielCurrentGlobalGeo = nextInStack.top();
2327 updateFaceOrientedFEWithBd(m_feVelWithBd, m_fePreWithBd, idOfFacesCurrent, numPointPerElt, ielCurrentGlobalGeo, ielCurrentGlobalSup);
2328 }
2329 }
2330 }
2331
2332 // desallocate array use for assemble with petsc.
2333 desallocateArrayForAssembleMatrixRHS(flag);
2334
2335 // desallocate opposite finite elements
2336 m_feVelWithBd = firstCurrentVel;
2337 m_fePreWithBd = firstCurrentPre;
2338 delete firstOppositeVel;
2339 delete firstOppositePre;
2340 }
2341
2342 void LinearProblemNS::addNewFaceOrientedContributor(felInt size, felInt idElt, std::vector<bool>& vec)
2343 {
2344 felInt ielTmp;
2345 std::pair<bool, GeometricMeshRegion::ElementType> adjElt;
2346
2347 vec.resize(size, false);
2348 for(felInt iface=0; iface<size; ++iface) {
2349 // check if this face is an inner face or a boundary
2350 ielTmp = idElt;
2351 adjElt = m_mesh[m_currentMesh]->getAdjElement(ielTmp, iface);
2352
2353 if(!adjElt.first) {
2354 // not an inner face, set the contribution to done.
2355 vec[iface] = true;
2356 }
2357 }
2358 }
2359
2360 void LinearProblemNS::updateFaceOrientedFEWithBd(CurrentFiniteElementWithBd* fevel, CurrentFiniteElementWithBd* fepre, std::vector<felInt>& idOfFaces, felInt numPoints, felInt idElt, felInt& idSup)
2361 {
2362 std::vector<felInt> elemIdPoint(numPoints, -1);
2363 std::vector<Point*> elemPoint(numPoints, nullptr);
2364
2365 // get information on the opposite element
2366 // same as the function "setElemPoint" but here ielOppositeGlobalGeo is global
2367 // we assume that the supportDofMesh is the same for all unknown (like in setElemPoint)
2368 m_supportDofUnknown[0].getIdElementSupport(idElt, idSup);
2369 m_mesh[m_currentMesh]->getOneElement(idElt, elemIdPoint);
2370 for (felInt iPoint=0; iPoint<numPoints; ++iPoint)
2371 elemPoint[iPoint] = &(m_mesh[m_currentMesh]->listPoints()[elemIdPoint[iPoint]]);
2372
2373 // update the finite elements
2374 fevel->updateFirstDeriv(0, elemPoint);
2375 fevel->updateBdMeasNormal();
2376 fepre->updateFirstDeriv(0, elemPoint);
2377 fepre->updateBdMeasNormal();
2378
2379 // get all the faces of the element
2380 if(dimension() == 2)
2381 m_mesh[m_currentMesh]->getAllEdgeOfElement(idElt, idOfFaces);
2382 else
2383 m_mesh[m_currentMesh]->getAllFaceOfElement(idElt, idOfFaces);
2384 }
2385
2386 /***********************************************************************************/
2387 /***********************************************************************************/
2388
2389 12 void LinearProblemNS::computeNormalField(const std::vector<int> & labels, felInt idVecVariable)
2390 {
2391 12 m_auxiliaryInts.resize(1);
2392 12 m_auxiliaryInts[0]=idVecVariable;//for instance m_iVelocity;
2393 /*!
2394 For each dof d of the surface the sum: \f$\sum_{K} m(K)\vec n(K)\f$ is computed.
2395 - K are all the boundary elements that share the dof d.
2396 - m(K) is the measure of the element
2397 - n(K) is the P0 normal defined on the element
2398 */
2399 12 assemblyLoopBoundaryGeneral(&LinearProblemNS::normalFieldComputer,labels,&LinearProblemNS::initPerETNormVel,&LinearProblemNS::updateFeNormVel);
2400
2401
3/6
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
12 m_vecs.Get("normalField").assembly();
2402
3/6
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
12 m_vecs.Get("measStar").assembly();
2403
2404 /// Than the vector is divided by \f$\sum_{K} m(K)\f$ to obtain the P1 field.
2405
7/14
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
✓ Branch 16 taken 12 times.
✗ Branch 17 not taken.
✓ Branch 19 taken 12 times.
✗ Branch 20 not taken.
✓ Branch 22 taken 12 times.
✗ Branch 23 not taken.
12 pointwiseDivide(m_vecs.Get("normalField"), m_vecs.Get("normalField"), m_vecs.Get("measStar"));
2406
5/10
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 12 times.
✗ Branch 16 not taken.
12 gatherVector( m_vecs.Get("normalField"), m_seqVecs.Get("normalField") );
2407
2408 /// using normalizeComputer we normalize the result.
2409 12 assemblyLoopBoundaryGeneral(&LinearProblemNS::normalizeComputer,labels,&LinearProblemNS::initPerETNormVel,&LinearProblemNS::updateFeNormVel);
2410
2411
3/6
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 12 times.
✗ Branch 9 not taken.
12 m_vecs.Get("normalField").assembly();
2412
5/10
✓ Branch 2 taken 12 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 12 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 12 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 12 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 12 times.
✗ Branch 16 not taken.
12 gatherVector( m_vecs.Get("normalField"), m_seqVecs.Get("normalField") );
2413 12 }
2414
2415 /***********************************************************************************/
2416 /***********************************************************************************/
2417
2418 22499 void LinearProblemNS::normalFieldComputer(felInt ielSupportDof)
2419 {
2420 double value;
2421
2/2
✓ Branch 3 taken 67417 times.
✓ Branch 4 taken 22499 times.
89916 for ( std::size_t iSurfDof(0); iSurfDof < ( std::size_t ) m_listCurvilinearFiniteElement[m_auxiliaryInts[0]]->numDof(); iSurfDof++) {
2422 67417 double feMeas(m_listCurvilinearFiniteElement[m_auxiliaryInts[0]]->measure());
2423
2/2
✓ Branch 3 taken 202091 times.
✓ Branch 4 taken 67417 times.
269508 for ( std::size_t iCoor(0); iCoor < ( std::size_t ) m_listCurvilinearFiniteElement[m_auxiliaryInts[0]]->numCoor(); iCoor++) {
2424 felInt iDofGlob;
2425
1/2
✓ Branch 3 taken 202091 times.
✗ Branch 4 not taken.
202091 dof().loc2glob( ielSupportDof, iSurfDof, m_auxiliaryInts[0], iCoor, iDofGlob);
2426
1/2
✓ Branch 1 taken 202091 times.
✗ Branch 2 not taken.
202091 AOApplicationToPetsc(m_ao,1,&iDofGlob);
2427 202091 value=0.0;
2428
2/2
✓ Branch 3 taken 1211586 times.
✓ Branch 4 taken 202091 times.
1413677 for ( std::size_t iQuadBd(0.0) ; iQuadBd < ( std::size_t )m_listCurvilinearFiniteElement[m_auxiliaryInts[0]]->numQuadraturePoint(); iQuadBd++) {
2429
2/4
✓ Branch 3 taken 1211586 times.
✗ Branch 4 not taken.
✓ Branch 9 taken 1211586 times.
✗ Branch 10 not taken.
1211586 value += m_listCurvilinearFiniteElement[m_auxiliaryInts[0]]->weightMeas( iQuadBd ) * m_listCurvilinearFiniteElement[m_auxiliaryInts[0]]->normal[iQuadBd](iCoor);
2430 }
2431
3/6
✓ Branch 2 taken 202091 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 202091 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 202091 times.
✗ Branch 9 not taken.
202091 m_vecs.Get("normalField").setValue(iDofGlob, value, ADD_VALUES);
2432
3/6
✓ Branch 2 taken 202091 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 202091 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 202091 times.
✗ Branch 9 not taken.
202091 m_vecs.Get("measStar").setValue(iDofGlob, feMeas, ADD_VALUES);
2433 }
2434 }
2435 22499 }
2436
2437 /***********************************************************************************/
2438 /***********************************************************************************/
2439
2440 44998 void LinearProblemNS::updateFeNormVel(const std::vector<Point*>& elemPoint,const std::vector<int>& /*elemIdPoint*/)
2441 {
2442 44998 m_listCurvilinearFiniteElement[m_auxiliaryInts[0]]->updateMeasNormal(0,elemPoint);
2443 44998 }
2444
2445 /***********************************************************************************/
2446 /***********************************************************************************/
2447
2448 22499 void LinearProblemNS::normalizeComputer(felInt ielSupportDof)
2449 {
2450 22499 const int numComp = m_listCurvilinearFiniteElement[m_auxiliaryInts[0]]->numCoor( );
2451 22499 const int numDof = m_listCurvilinearFiniteElement[m_auxiliaryInts[0]]->numDof( );
2452
2453
1/2
✓ Branch 2 taken 22499 times.
✗ Branch 3 not taken.
22499 std::vector< double > norm(numDof,0.0);
2454
2/4
✓ Branch 3 taken 22499 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 22499 times.
✗ Branch 7 not taken.
44998 std::vector< std::vector< double > > NN(numDof, std::vector< double >(numComp, 0.0));
2455
2/2
✓ Branch 0 taken 67417 times.
✓ Branch 1 taken 22499 times.
89916 for ( int idof = 0; idof < numDof; idof++ ) {
2456
2/2
✓ Branch 0 taken 202091 times.
✓ Branch 1 taken 67417 times.
269508 for ( int icomp = 0; icomp < numComp; icomp++ ) {
2457 int iDofGlob;
2458 double value;
2459
1/2
✓ Branch 3 taken 202091 times.
✗ Branch 4 not taken.
202091 dof().loc2glob( ielSupportDof, idof, m_auxiliaryInts[0], icomp, iDofGlob);
2460
1/2
✓ Branch 1 taken 202091 times.
✗ Branch 2 not taken.
202091 AOApplicationToPetsc(m_ao, 1, &iDofGlob);
2461
3/6
✓ Branch 2 taken 202091 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 202091 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 202091 times.
✗ Branch 9 not taken.
202091 m_seqVecs.Get("normalField").getValues(1, &iDofGlob, &value);
2462 202091 norm[idof] += value*value;
2463 202091 NN[idof][icomp] = value;
2464 }
2465 67417 norm[idof] = std::sqrt( norm[idof] );
2466
2/2
✓ Branch 0 taken 202091 times.
✓ Branch 1 taken 67417 times.
269508 for ( int icomp = 0; icomp < numComp; icomp++ )
2467 202091 NN[idof][icomp] = NN[idof][icomp]/norm[idof];
2468 }
2469
2/2
✓ Branch 0 taken 67417 times.
✓ Branch 1 taken 22499 times.
89916 for ( int idof = 0; idof < numDof; idof++ ) {
2470
2/2
✓ Branch 0 taken 202091 times.
✓ Branch 1 taken 67417 times.
269508 for ( int icomp = 0; icomp < numComp; icomp++ ) {
2471 int iDofGlob;
2472
1/2
✓ Branch 3 taken 202091 times.
✗ Branch 4 not taken.
202091 dof().loc2glob( ielSupportDof, idof, m_auxiliaryInts[0], icomp, iDofGlob);
2473
1/2
✓ Branch 1 taken 202091 times.
✗ Branch 2 not taken.
202091 AOApplicationToPetsc(m_ao, 1, &iDofGlob);
2474
3/6
✓ Branch 2 taken 202091 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 202091 times.
✗ Branch 6 not taken.
✓ Branch 10 taken 202091 times.
✗ Branch 11 not taken.
202091 m_vecs.Get("normalField").setValue(iDofGlob, NN[idof][icomp], INSERT_VALUES);
2475 }
2476 }
2477 22499 }
2478
2479 /***********************************************************************************/
2480 /***********************************************************************************/
2481
2482 #ifdef FELISCE_WITH_CVGRAPH
2483 void LinearProblemNS::assembleMassBoundaryAndInitKSP( std::size_t iConn )
2484 {
2485 LinearProblem::assembleMassBoundaryAndInitKSP(&LinearProblemNS::massMatrixComputer,
2486 slave()->interfaceLabels(iConn),
2487 &LinearProblemNS::initPerETMass,
2488 &LinearProblemNS::updateFE,
2489 iConn);
2490 }
2491
2492 void LinearProblemNS::sendData()
2493 {
2494 gatherSolution();
2495 for ( std::size_t iConn(0); iConn<slave()->numConnections(); ++iConn ) {
2496 std::vector<PetscVector> vecs;
2497 for (std::size_t cVar(0); cVar<slave()->numVarToSend(iConn); ++cVar) {
2498 std::string varToSend=slave()->sendVariable(iConn,cVar);
2499 if ( varToSend== "STRESS" ) {
2500 prepareResidual(iConn);
2501 vecs.push_back(m_seqStressOut);
2502 } else if ( varToSend == "VELOCITY" ) {
2503 vecs.push_back(sequentialSolution());
2504 } else if ( varToSend == "DISPLACEMENT" ) {
2505 //TODO curDisp = oldDisp+dt*sequentialSolution();
2506 //vecs.push_back(curDisp);
2507 FEL_ERROR("TODO: implement it!");
2508 } else {
2509 std::cout<<"variable to send: "<<varToSend<<std::endl;
2510 FEL_ERROR("Error in variable to read");
2511 }
2512 }
2513 slave()->sendData(vecs,iConn);
2514 }
2515 }
2516
2517 void LinearProblemNS::readData()
2518 {
2519 bool usingDisp(false);
2520 bool usingVel(false);
2521 for ( std::size_t iConn(0); iConn<slave()->numConnections(); ++iConn ) {
2522 std::vector<PetscVector> vecs;
2523 for (std::size_t cVar(0); cVar<slave()->numVarToRead(iConn); ++cVar) {
2524 std::string varToRead=slave()->readVariable(iConn,cVar);
2525 if ( varToRead == "STRESS" ) {
2526 vecs.push_back(m_seqVecs.Get("cvgraphSTRESS"));
2527 } else if ( varToRead == "DISPLACEMENT" ) {
2528 usingDisp=true;
2529 vecs.push_back(m_seqVecs.Get("externalDisplacement"));
2530 } else if ( varToRead == "VELOCITY" ) {
2531 usingVel=true;
2532 vecs.push_back(m_seqVecs.Get("cvgraphVelocity"));
2533 } else {
2534 std::cout<<"Connection: "<<iConn<<"variable to read: "<<varToRead<<std::endl;
2535 FEL_ERROR("Error in variable to read");
2536 }
2537 }
2538 slave()->receiveData(vecs,iConn);
2539 }
2540 if ( usingDisp && usingVel ) {
2541 // It is not safe to mix velocity vars and displacement vars, even from different connections.
2542 // It is possible to do it of course, but the implementation should be checked carefully.
2543 FEL_ERROR("You can not mix velocity and displacement.");
2544 }
2545 if ( usingDisp ) {
2546 m_seqVecs.Get("cvgraphVelocity").axpbypcz(1./m_fstransient->timeStep, -1./m_fstransient->timeStep, 0, m_seqVecs.Get("externalDisplacement"), m_seqVecs.Get("externalDisplacementOld"));
2547 }
2548 }
2549
2550 /*! \brief Function to assemble the mass matrix
2551 * Function to be called in the assemblyLoopBoundaryGeneral
2552 */
2553 void LinearProblemNS::initPerETMass()
2554 {
2555 felInt numDofTotal = 0;
2556 //pay attention this numDofTotal is bigger than expected since it counts for all the VARIABLES
2557 for (std::size_t iFe = 0; iFe < m_listCurvilinearFiniteElement.size(); iFe++) {//this loop is on variables while it should be on unknown
2558 numDofTotal += m_listCurvilinearFiniteElement[iFe]->numDof()*m_listVariable[iFe].numComponent();
2559 }
2560 m_globPosColumn.resize(numDofTotal); m_globPosRow.resize(numDofTotal); m_matrixValues.resize(numDofTotal*numDofTotal);
2561 m_curvFeVel = m_listCurvilinearFiniteElement[ m_iVelocity ];
2562 }
2563
2564 void LinearProblemNS::massMatrixComputer(felInt ielSupportDof)
2565 {
2566 m_elementMatBD[0]->zero();
2567 m_elementMatBD[0]->phi_i_phi_j(/*coef*/1.,*m_curvFeVel,/*iblock*/0,/*iblock*/0,dimension());
2568 setValueMatrixBD(ielSupportDof);
2569 }
2570
2571 void LinearProblemNS::updateFE(const std::vector<Point*>& elemPoint, const std::vector<int>&)
2572 {
2573 m_curvFeVel->updateMeasNormal(0, elemPoint);
2574 }
2575
2576 void LinearProblemNS::computeBoundaryStress(PetscVector& vec)
2577 {
2578 // Retrieve instance
2579 auto& r_instance = FelisceParam::instance(instanceIndex());
2580
2581 // This function replaces computeBoundaryStress implemented in linearProblem.cpp
2582 // I think this function is safer and more general (should work in parallel as well)
2583
2584 ElementField velocityDofValuesVol;
2585 ElementField pressureDofValuesBD;
2586 ElementField tractionVel; // velocity part of \sigma \vect n
2587 ElementField tractionPre; // pressure part of \sigma \vect n: -p\vect n
2588
2589 /*===========================================*/
2590 // initializations for the loop
2591 ElementType eltType,volEltType,previousVolEltType=GeometricMeshRegion::Nod;
2592 int numPointPerElt = 0;
2593 int currentLabel = 0;
2594 felInt numEltPerLabel = 0;
2595 felInt numElement[ GeometricMeshRegion::m_numTypesOfElement ];
2596 for (int ityp=0; ityp<GeometricMeshRegion::m_numTypesOfElement; ityp++ ) {
2597 eltType = (ElementType)ityp;
2598 numElement[eltType] = 0;
2599 }
2600 if(m_mesh[m_currentMesh]->statusFaces() == false) {
2601 m_mesh[m_currentMesh]->buildFaces();
2602 }
2603 std::vector<Point*> elemPoint;
2604 std::vector<felInt> elemIdPoint;
2605 std::vector<felInt> vectorIdSupport;
2606 felInt ielSupportDof;
2607 allocateVectorBoundaryConditionDerivedLinPb();
2608 const std::vector<ElementType>& bagElementTypeDomainBoundary = m_meshLocal[m_currentMesh]->bagElementTypeDomainBoundary();
2609 /*===========================================*/
2610
2611 for (std::size_t i=0; i < bagElementTypeDomainBoundary.size(); ++i) {// loop over the boundary element type
2612 eltType = bagElementTypeDomainBoundary[i];
2613 numPointPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType];
2614 elemPoint.resize(numPointPerElt, nullptr);
2615 elemIdPoint.resize(numPointPerElt, 0);
2616 defineCurvilinearFiniteElement(eltType); // m_listCurvilinearFiniteElement update
2617 initElementArrayBD();
2618 allocateArrayForAssembleMatrixRHSBD(FlagMatrixRHS::only_rhs); // works in combo with setValueCustomVectorBD
2619
2620 m_curvFeVel = m_listCurvilinearFiniteElement[m_iVelocity];
2621 m_curvFePre = m_listCurvilinearFiniteElement[m_iPressure];
2622 // dof values
2623 pressureDofValuesBD.initialize(DOF_FIELD, *m_curvFePre,1/*numComp*/);
2624 // for the results
2625 tractionVel.initialize(DOF_FIELD, *m_curvFeVel, dimension());
2626 tractionPre.initialize(DOF_FIELD, *m_curvFePre, dimension());
2627
2628 for(auto itRef = m_meshLocal[m_currentMesh]->intRefToBegEndMaps[eltType].begin();
2629 itRef != m_meshLocal[m_currentMesh]->intRefToBegEndMaps[eltType].end(); itRef++) {// loop over the boundary labels that have this ref
2630 currentLabel = itRef->first;
2631 numEltPerLabel = itRef->second.second;
2632 initPerDomainBoundaryCondition(elemPoint, elemIdPoint, currentLabel, numEltPerLabel, &ielSupportDof, eltType, numElement[eltType], FlagMatrixRHS::only_rhs); //it updates label
2633 for ( felInt iel = 0; iel < numEltPerLabel; iel++) {// loop over the elements of this label
2634 // for each element:
2635 m_elementVectorBD[0]->zero();
2636 // - get the points and their ids and vectorIdSupport
2637 setElemPoint(eltType, numElement[eltType], elemPoint, elemIdPoint, vectorIdSupport);
2638 ielSupportDof=vectorIdSupport[0];// We assume we are not working with duplicated support dof: TODO
2639 // - get the volume points and their ids
2640 std::vector<Point*> elemPointVol; // Points of the current domain element.
2641 std::vector<felInt> elemIdPointVol; // Id of points of the domain element.
2642 std::vector<felInt> bd2vol;
2643 int idLocFace = -1; // Local identity of the face of a domain element
2644 felInt idElemVol = -1; // ID of the domain element associated to the face with identity idLocFace
2645 m_mesh[m_currentMesh]->getElementFromBdElem(elemIdPoint,elemIdPointVol,elemPointVol,idLocFace,idElemVol);
2646 int dummy;
2647 m_mesh[m_currentMesh]->getTypeElemFromIdElem(idElemVol, volEltType, dummy);
2648 if (volEltType != previousVolEltType ) {
2649 defineFiniteElement(volEltType);
2650 initElementArray();
2651 previousVolEltType=volEltType;
2652 m_feVel = m_listCurrentFiniteElement[m_iVelocity];
2653 velocityDofValuesVol.initialize(DOF_FIELD, *m_feVel,dimension());
2654 m_feVel->allocateOnDofsDataStructures();
2655 }
2656 m_feVel->updateFirstDerivOnDofs(0, elemPointVol);
2657 m_curvFeVel->updateMeasNormal(0,elemPoint);
2658 m_curvFePre->updateMeasNormal(0,elemPoint);
2659 m_feVel->identifyLocBDDof(*m_curvFeVel,bd2vol);
2660
2661 // Extract the corresponding values of both pressure and velocity from the sequentialSolution.
2662 velocityDofValuesVol.setValue(sequentialSolution(),*m_feVel,idElemVol,m_iVelocity,m_ao,dof());
2663 pressureDofValuesBD.setValue(sequentialSolution(),*m_curvFePre,ielSupportDof,m_iPressure,m_ao,dof());
2664
2665 // Create an element field (dof) to store the traction \vect t = \sigma \vect n
2666 // compute \vect t = -p \vect n
2667
2668 //Attention: we have assumed the normal is constant on the element, and we have taken it on the first quadrature node.
2669 // if we want to generalize this we have to transform tractionPres into an element field defined on quadrature nodes
2670 // and we have to evalu
2671 tractionPre.val = -outer_prod(m_curvFePre->normal[0],pressureDofValuesBD.valAsVec()); // t_{comp,dof) = - n_comp * p_dof
2672
2673
2674 // compute \vect t = \sigma \vect n (only vel part) (depending on the flag about symmetric stres?)
2675 UBlasVector tmp(dimension()),tmp2(m_feVel->numDof());
2676
2677 //\nu \nabla u^T \cdot n
2678 for (int hbdDof(0); hbdDof<m_curvFeVel->numDof(); hbdDof++) {
2679 tmp2 = prod(trans(velocityDofValuesVol.val),m_curvFePre->normal[0]);
2680 tmp = prod(m_feVel->dPhiOnDofs[bd2vol.at(hbdDof)], tmp2);
2681 for (int jcomp(0); jcomp<dimension(); jcomp++) {
2682 tractionVel.val(jcomp,hbdDof) = r_instance.viscosity*tmp(jcomp);
2683 }
2684 }
2685 //\nu \nabla u \cdot n
2686 for (int hbdDof(0); hbdDof<m_curvFeVel->numDof(); hbdDof++) {
2687 tmp2 = prod(trans(m_feVel->dPhiOnDofs[bd2vol.at(hbdDof)]),m_curvFePre->normal[0]);
2688 tmp = prod(velocityDofValuesVol.val,tmp2);
2689 for (int jcomp(0); jcomp<dimension(); jcomp++) {
2690 tractionVel.val(jcomp,hbdDof) += r_instance.viscosity*tmp(jcomp);
2691 }
2692 }
2693
2694 m_elementVectorBD[0]->source( /* coef*/-1.0, *m_curvFeVel, tractionVel, /*iBlock*/0, dimension());
2695 m_elementVectorBD[0]->source( /* coef*/-1.0, *m_curvFePre, tractionPre, /*iBlock*/0, dimension());
2696
2697 // Place m_elementVectorBD[0] in the correct PetscVector
2698 setValueCustomVectorBD( /* bd element id */ielSupportDof, ADD_VALUES, vec );
2699 numElement[eltType]++;
2700 }
2701 }
2702 desallocateArrayForAssembleMatrixRHS(FlagMatrixRHS::only_rhs);
2703 }
2704 vec.assembly();
2705 }
2706
2707 void LinearProblemNS::cvgraphNaturalBC(felInt iel)
2708 {
2709 // Retrieve instance
2710 auto& r_instance = FelisceParam::instance(instanceIndex());
2711
2712 BoundaryCondition* BC;
2713 // Loop over the cvgraph connections
2714 for ( std::size_t iConn(0); iConn<slave()->numConnections(); ++iConn ) {
2715 // Extract the labels of the current connection
2716 std::vector<int> labels = slave()->interfaceLabels(iConn);
2717 // Verify if the current label is part of the interface of this connection
2718 if ( std::find( labels.begin(), labels.end(), m_currentLabel ) != labels.end() ) {
2719 switch ( slave()->numVarToRead(iConn) ) {
2720
2721 case 1: // only one var to read: neumann interface BC
2722 // Verify that we have to apply the stress in its strong form.
2723 if ( slave()->readVariable(iConn,/*cVar*/0) == "STRESS" && slave()->residualInterpolationType(iConn) == 0 ) {
2724 // Look through the different neumann conditions to find the correct one.
2725 for (std::size_t iNeumann=0; iNeumann<m_boundaryConditionList.numNeumannBoundaryCondition(); iNeumann++ ) {
2726 BC = m_boundaryConditionList.Neumann(iNeumann);//get the the BC
2727 if ( std::find( BC->listLabel().begin(), BC->listLabel().end(),m_currentLabel) != BC->listLabel().end() ) {
2728 //compute the force term.
2729 m_elemFieldNeumann[iNeumann].setValue( m_seqVecs.Get("cvgraphSTRESS"), *m_curvFeVel , iel, m_iVelocity, m_ao, dof());
2730 }
2731 }
2732 }
2733 break;
2734 case 2: //two variables to read: robin interface BC
2735 // Look through the different robin conditions to find the correct one.
2736 for (std::size_t iRobin=0; iRobin<m_boundaryConditionList.numRobinBoundaryCondition(); iRobin++ ) {
2737 BC = m_boundaryConditionList.Robin(iRobin);
2738 if ( std::find( BC->listLabel().begin(), BC->listLabel().end(),m_currentLabel ) != BC->listLabel().end() ) {
2739 if ( slave()->residualInterpolationType(iConn) == 0 ) {
2740 m_elemFieldRobin[iRobin].setValue( m_seqVecs.Get("cvgraphSTRESS"), *m_curvFeVel , iel, m_iVelocity, m_ao, dof());
2741 } else {
2742 m_elemFieldRobin[iRobin].val *=0 ;
2743 }
2744 m_robinAux.setValue(m_seqVecs.Get("cvgraphVelocity"),*m_curvFeVel , iel, m_iVelocity, m_ao, dof());
2745 m_elemFieldRobin[iRobin].val += r_instance.alphaRobin[iRobin]*m_robinAux.val;
2746 }
2747 }
2748 break;
2749 default:
2750 FEL_ERROR("Three variables to read not yet implemented for this linear problem.")
2751 break;
2752 }
2753 }
2754 }
2755 }
2756 #endif
2757
2758 /***********************************************************************************/
2759 /***********************************************************************************/
2760
2761 void LinearProblemNS::localizeItfQpInBackMesh(std::size_t itfMsh, std::size_t /* bckMsh*/, felInt itfVar, std::vector<std::vector<felInt>>& mapItfQpInBackMesh)
2762 {
2763 const ElementType eltType = m_mesh[itfMsh]->bagElementTypeDomain()[0];
2764 const int numPointsPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType];
2765 std::vector<Point*> elemPoint(numPointsPerElt, nullptr);
2766 std::vector<felInt> elemIdPoint(numPointsPerElt, 0);
2767
2768 const GeoElement *geoEle = GeometricMeshRegion::eltEnumToFelNameGeoEle[eltType].second;
2769 int typeOfFiniteElement = m_listVariable[itfVar].finiteElementType();
2770 const RefElement *refEle = geoEle->defineFiniteEle(eltType, typeOfFiniteElement, *m_mesh[itfMsh]);
2771 CurvilinearFiniteElement feStruc(*refEle, *geoEle, m_listVariable[itfVar].degreeOfExactness());
2772
2773 const felInt nbrQuaPnt = feStruc.numQuadraturePoint();
2774 const felInt numEltPerType = m_mesh[itfMsh]->numElements(eltType);
2775
2776 if ( mapItfQpInBackMesh.size() != static_cast<std::size_t>(numEltPerType) )
2777 mapItfQpInBackMesh.resize(numEltPerType, std::vector<felInt>(nbrQuaPnt,-1));
2778
2779
2780 // Parallel localization ( i prefer this way since the local mesh is usually owned by only one proc)
2781 const felInt numEltByProc = numEltPerType/MpiInfo::numProc();
2782 const felInt beginIdEltLocal = MpiInfo::rankProc()*numEltByProc;
2783 const felInt numEltProc = ( MpiInfo::rankProc() == MpiInfo::numProc()-1 ) ? numEltPerType-beginIdEltLocal : numEltByProc;
2784
2785 std::vector<felInt> recvcn(MpiInfo::numProc(), nbrQuaPnt*numEltByProc);
2786 recvcn.back() = nbrQuaPnt * ( numEltPerType - numEltByProc * ( MpiInfo::numProc() - 1 ) );
2787
2788 std::vector<felInt> displs(MpiInfo::numProc(), 0);
2789 std::transform( recvcn.begin(), recvcn.end()-1, displs.begin(), displs.begin()+1, [](auto i, auto j ){ return i + j; } );
2790
2791 std::vector<Point> listQuadPoint(nbrQuaPnt*numEltProc);
2792
2793 // Loop on element in the region with the type: eltType
2794 for (felInt iel=0; iel<numEltProc; ++iel) {
2795
2796 // Get elemPoint and elemIdPoint.
2797 m_mesh[itfMsh]->getOneElement(eltType, beginIdEltLocal+iel, elemIdPoint, elemPoint, 0);
2798
2799 // Update structure finite element
2800 feStruc.updatePoint(elemPoint);
2801 feStruc.computeCurrentQuadraturePoint();
2802
2803 // Add quadrature point to list
2804 for (int ig=0; ig<nbrQuaPnt; ig++)
2805 listQuadPoint[iel*nbrQuaPnt+ig] = feStruc.currentQuadPoint[ig];
2806 }
2807
2808 std::vector<felInt> indElt(listQuadPoint.size());
2809 std::vector<ElementType> typElt(listQuadPoint.size());
2810
2811 // Retrieve instance
2812 auto& r_instance = FelisceParam::instance(instanceIndex());
2813
2814 // Get the timer
2815 auto& r_timer = r_instance.timer;
2816
2817 r_timer.Start("Locator" + std::to_string(identifierProblem()) + "::findListPointsInMesh", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
2818 m_pLocator->findListPointsInMesh(indElt, typElt, listQuadPoint);
2819 r_timer.Stop("Locator" + std::to_string(identifierProblem()) + "::findListPointsInMesh", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
2820
2821 // Now i need to build the global indElt vector
2822 std::vector<felInt> indEltGlb(nbrQuaPnt*numEltPerType);
2823 MPI_Allgatherv(indElt.data(), recvcn[MpiInfo::rankProc()], MPI_INT, indEltGlb.data(), recvcn.data(), displs.data(), MPI_INT, MpiInfo::petscComm() );
2824
2825 for (felInt iel=0; iel<numEltPerType; iel++){
2826 for (felInt ig=0; ig<nbrQuaPnt; ig++)
2827 mapItfQpInBackMesh[iel][ig] = indEltGlb[iel*nbrQuaPnt+ig];
2828 }
2829 }
2830
2831 void LinearProblemNS::computeSolidFluidMaps()
2832 {
2833 // Retrieve instance
2834 auto& r_instance = FelisceParam::instance(instanceIndex());
2835
2836 const std::size_t velMesh = m_listVariable[m_iVelocity].idMesh();
2837 const std::size_t lagMesh = m_listVariable[m_iLagrange].idMesh();
2838
2839 const ElementType eltType = m_mesh[lagMesh]->bagElementTypeDomain()[0];
2840
2841 // Save previous localization map
2842 std::vector<std::vector<felInt> > mapLagQpInVelMeshOld(m_mapLagQpInVelMesh.begin(), m_mapLagQpInVelMesh.end());
2843
2844 // Localize structure mesh in fluid mesh
2845 localizeItfQpInBackMesh(lagMesh, velMesh, m_iLagrange, m_mapLagQpInVelMeshSeq);
2846
2847 // Resize m_mapLagQpInVelMesh if needed
2848 m_mapLagQpInVelMesh.resize(m_meshLocal[lagMesh]->numElements(eltType));
2849
2850 // Initialize parallel map
2851 const auto rank = MpiInfo::rankProc();
2852 auto it = m_eltPart[lagMesh].begin();
2853 std::copy_if(m_mapLagQpInVelMeshSeq.begin(), m_mapLagQpInVelMeshSeq.end(), m_mapLagQpInVelMesh.begin(), [&](auto&) { return rank == *it++; } );
2854
2855 // Check if localization has changed
2856 m_hasLocalizationChanged = false;
2857 if ( m_mapLagQpInVelMesh != mapLagQpInVelMeshOld )
2858 m_hasLocalizationChanged = true;
2859
2860 MPI_Allreduce(MPI_IN_PLACE, &m_hasLocalizationChanged, 1, MPI_CXX_BOOL, MPI_LOR, MpiInfo::petscComm());
2861
2862 if ( r_instance.massConstraint && r_instance.useFicItf ) {
2863
2864 const std::size_t japMesh = 2; //m_listVariable[m_iLagrange].idMesh(); TODO D.C.
2865
2866 const ElementType eltType = m_mesh[japMesh]->bagElementTypeDomain()[0];
2867
2868 // Localize structure mesh in fluid mesh
2869 localizeItfQpInBackMesh(japMesh, velMesh, m_iLagrange, m_mapJapQpInVelMeshSeq);
2870
2871 // Resize m_mapJapQpInVelMesh if needed
2872 m_mapJapQpInVelMesh.resize(m_meshLocal[japMesh]->numElements(eltType));
2873
2874 // Initialize parallel map
2875 auto it = m_eltPart[japMesh].begin();
2876 std::copy_if(m_mapJapQpInVelMeshSeq.begin(), m_mapJapQpInVelMeshSeq.end(), m_mapJapQpInVelMesh.begin(), [&](auto&) { return rank == *it++; } );
2877 }
2878 }
2879
2880 void LinearProblemNS::evaluateFluidStructurePattern()
2881 {
2882 // Retrieve instance
2883 auto& r_instance = FelisceParam::instance(instanceIndex());
2884
2885 // Get the timer
2886 auto& r_timer = r_instance.timer;
2887 r_timer.Start("LinearProblem" + std::to_string(identifierProblem()) + "::evaluateFluidStructurePattern", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
2888
2889 if ( !m_isCsrNoInterfaceStored ){
2890 m_csrNoInterface.set(dof().pattern().rowPointer(),dof().pattern().columnIndices());
2891 m_isCsrNoInterfaceStored = true;
2892 }
2893
2894 if ( m_hasLocalizationChanged ) {
2895
2896 // Define variable
2897 std::vector< std::set<felInt> > nodesNeighborhood(m_numDof);
2898 felInt ielSupportDofVel, ielSupportDofLag;
2899 felInt node1, node2, idElt;
2900
2901 const std::size_t velMesh = m_listVariable[m_iVelocity].idMesh();
2902 const std::size_t lagMesh = m_listVariable[m_iLagrange].idMesh();
2903
2904 // Get element type
2905 const ElementType eltType = m_mesh[lagMesh]->bagElementTypeDomain()[0];
2906 const ElementType eltTypeFl = m_mesh[velMesh]->bagElementTypeDomain()[0];
2907
2908 // Set static pattern
2909 dof().pattern().set(m_csrNoInterface.rowPointer(),m_csrNoInterface.columnIndices());
2910
2911 // Loop on element in the region with the type: eltType
2912 const felInt numEltPerType = m_mesh[lagMesh]->numElements(eltType);
2913 for (felInt iel = 0; iel < numEltPerType; ++iel) {
2914 m_supportDofUnknown[m_iUnknownLag].getIdElementSupport(eltType, iel, ielSupportDofLag);
2915
2916 // For every LM component
2917 for (std::size_t iComp = 0; iComp < m_listVariable[m_iLagrange].numComponent(); ++iComp) {
2918 const int iConnect = dof().getNumGlobComp(m_iUnknownLag, iComp);
2919
2920 // For every dof in support element
2921 for (int iSup = 0; iSup < m_supportDofUnknown[m_iUnknownLag].getNumSupportDof(ielSupportDofLag); ++iSup) {
2922
2923 // get the global id of the support dof
2924 dof().loc2glob(ielSupportDofLag, iSup, m_iLagrange, iComp, node1);
2925
2926 // Loop over qpoint
2927 for (std::size_t iq = 0; iq < m_mapLagQpInVelMeshSeq[iel].size(); ++iq){
2928
2929 for (std::size_t iUnknown = 0; iUnknown < m_listUnknown.size(); ++iUnknown) {
2930 const int iVariable = m_listUnknown.idVariable(iUnknown);
2931 if ( m_listVariable[iVariable].idMesh() != velMesh )
2932 continue;
2933
2934 // get fluid element id
2935 idElt = m_mapLagQpInVelMeshSeq[iel][iq];
2936
2937 // get id support dof
2938 m_supportDofUnknown[iUnknown].getIdElementSupport(eltTypeFl, idElt, ielSupportDofVel);
2939
2940 // For every velocity component
2941 for (std::size_t jComp = 0; jComp < m_listVariable[iVariable].numComponent(); ++jComp) {
2942 const int jConnect = dof().getNumGlobComp(iUnknown, jComp);
2943
2944 // For every dof in support element
2945 for (int jSup = 0; jSup < m_supportDofUnknown[iUnknown].getNumSupportDof(ielSupportDofVel); ++jSup) {
2946
2947 // get the global id of the support dof
2948 dof().loc2glob(ielSupportDofVel, jSup, iVariable, jComp, node2);
2949
2950 // if this node is on this process
2951 if ( m_listUnknown.mask()(iConnect, jConnect) ) // TODO D.C. not smart put this check here
2952 nodesNeighborhood[node1].insert(node2);
2953
2954 if ( m_listUnknown.mask()(jConnect, iConnect) ) // TODO D.C. not smart put this check here
2955 nodesNeighborhood[node2].insert(node1);
2956 }
2957 }
2958 }
2959 }
2960 }
2961 }
2962 }
2963
2964 // Store the pattern in CSR style
2965 felInt dofSize = 0;
2966 felInt cptDof = 0;
2967 felInt pos;
2968
2969 for(std::size_t iNode=0; iNode<nodesNeighborhood.size(); ++iNode)
2970 dofSize += nodesNeighborhood[iNode].size();
2971
2972 CSRMatrixPattern csr(dof().pattern().numRows(), dofSize);
2973 for(std::size_t iNode = 0; iNode < nodesNeighborhood.size(); ++iNode) {
2974 if(m_dofPart[iNode] == MpiInfo::rankProc()) {
2975 csr.rowPointer(cptDof + 1) = csr.rowPointer(cptDof) + nodesNeighborhood[iNode].size();
2976 pos = 0;
2977 for (auto it = nodesNeighborhood[iNode].begin(); it != nodesNeighborhood[iNode].end(); ++it) {
2978 csr.columnIndex(csr.rowPointer(cptDof) + pos) = *it;
2979 ++pos;
2980 }
2981 ++cptDof;
2982 }
2983 }
2984
2985 dof().mergeGlobalPattern(csr.rowPointer(),csr.columnIndices());
2986
2987 ///////////////////////////////////////////////////////////////
2988 // Matrix 0 reconstruction with new pattern
2989 const std::size_t numRows = dof().pattern().numRows();
2990 std::vector<felInt> nnz(numRows);
2991 for (size_t idof = 0; idof < numRows; idof++)
2992 nnz[idof] = dof().pattern().numNonzerosInRow(idof);
2993
2994 if ( MpiInfo::numProc() > 1 ) {
2995 std::vector<felInt> jCSR = dof().pattern().columnIndices();
2996 AOApplicationToPetsc(ao(), dof().pattern().numNonzeros(), jCSR.data());
2997
2998 m_matrices[0].destroy();
2999 m_matrices[0].createAIJ(MpiInfo::petscComm(), m_numDofLocal, m_numDofLocal, dof().numDof(), dof().numDof(), 0, FELISCE_PETSC_NULLPTR, 0, FELISCE_PETSC_NULLPTR);
3000 m_matrices[0].mpiAIJSetPreallocationCSR(dof().pattern().rowPointer().data(), jCSR.data(), NULL);
3001 m_matrices[0].setOption(MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE);
3002 m_matrices[0].setFromOptions();
3003 } else {
3004 m_matrices[0].destroy();
3005 m_matrices[0].createSeqAIJ(MpiInfo::petscComm(), numRows, numRows, 0, nnz.data());
3006 m_matrices[0].setOption(MAT_KEEP_NONZERO_PATTERN, PETSC_TRUE);
3007 m_matrices[0].setFromOptions();
3008 }
3009 }
3010
3011 r_timer.Stop("LinearProblem" + std::to_string(identifierProblem()) + "::evaluateFluidStructurePattern", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
3012 }
3013
3014 void LinearProblemNS::computeLagrangeMultiplierOnInterface(FlagMatrixRHS flagMatrixRHS)
3015 {
3016 // Retrieve instance
3017 auto& r_instance = FelisceParam::instance(instanceIndex());
3018
3019 // Get the timer
3020 auto& r_timer = r_instance.timer;
3021 r_timer.Start("LinearProblem" + std::to_string(identifierProblem()) + "::computeLagrangeMultiplierOnInterface", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
3022
3023 // use to get element number in support dof mesh ordering.
3024 felInt ielSupportDofVel, ielSupportDofLag;
3025
3026 double val;
3027
3028 const felInt velMesh = m_listVariable[m_iVelocity].idMesh();
3029 const felInt lagMesh = m_listVariable[m_iLagrange].idMesh();
3030
3031 // Get element type
3032 std::vector<ElementType> eltTypeVec(m_listVariable.size());
3033 for (std::size_t iVar = 0; iVar < m_listVariable.size(); ++iVar)
3034 eltTypeVec[iVar] = m_mesh[m_listVariable[iVar].idMesh()]->bagElementTypeDomain()[0];
3035
3036 const ElementType eltType = m_mesh[lagMesh]->bagElementTypeDomain()[0];
3037 const ElementType eltTypeFl = m_mesh[velMesh]->bagElementTypeDomain()[0];
3038
3039 // Resize array.
3040 const int numPointsPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType];
3041 std::vector<Point*> elemPoint(numPointsPerElt, nullptr);
3042 std::vector<felInt> elemIdPoint(numPointsPerElt, 0);
3043
3044 const int numPointsPerEltFl = GeometricMeshRegion::m_numPointsPerElt[eltTypeFl];
3045 std::vector<Point*> elemPointFl(numPointsPerEltFl, nullptr);
3046 std::vector<felInt> elemIdPointFl(numPointsPerEltFl, 0);
3047
3048 // Define all current finite element use in the problem from data
3049 defineCurvilinearFiniteElement(eltTypeVec);
3050 m_curvFeVel = m_listCurvilinearFiniteElement[m_iVelocity];
3051 m_curvFeLag = m_listCurvilinearFiniteElement[m_iLagrange];
3052
3053 ///////////////////////////////////////////////////////////////
3054 // Normal constraint
3055 m_listUnknown.setUnknownsRows({m_iUnknownLag});
3056 m_listUnknown.setUnknownsCols({m_iUnknownVel});
3057
3058 m_velBlock = 0;
3059 m_lagBlock = 0;
3060
3061 // Element matrix and vector initialisation
3062 initElementArrayBD(true);
3063
3064 // Allocate array use for assemble with petsc.
3065 allocateArrayForAssembleMatrixRHSBD(flagMatrixRHS);
3066
3067 // Initialize element field
3068 m_structVelQuad.initialize(QUAD_POINT_FIELD, *m_curvFeLag, m_curvFeLag->numCoor());
3069 m_structNormalQuad.initialize(QUAD_POINT_FIELD, *m_curvFeLag, m_curvFeLag->numCoor());
3070
3071 // Loop on element in the region with the type: eltType
3072 const felInt numEltPerType = m_meshLocal[lagMesh]->numElements(eltType);
3073 for (felInt iel = 0; iel < numEltPerType; ++iel) {
3074
3075 m_supportDofUnknownLocal[m_iUnknownLag].getIdElementSupport(eltType, iel, ielSupportDofLag);
3076 ISLocalToGlobalMappingApply(*m_mappingElemSupportPerUnknown[m_iUnknownLag], 1, &ielSupportDofLag, &ielSupportDofLag);
3077
3078 // Get structure element points
3079 m_meshLocal[lagMesh]->getOneElement(eltType, iel, elemIdPoint, elemPoint, 0);
3080
3081 // Update structure finite element
3082 m_curvFeLag->updateMeasQuadPt(0, elemPoint);
3083
3084 // **** Matrix ****************
3085 if ( flagMatrixRHS != FlagMatrixRHS::only_rhs ) {
3086 // Sum over quadrature points
3087 for (int ig = 0; ig < m_curvFeLag->numQuadraturePoint(); ++ig) {
3088
3089 // Quadrature point localization in fluid mesh
3090 felInt idElt = m_mapLagQpInVelMesh[iel][ig];
3091
3092 // Get id support dof
3093 m_supportDofUnknown[m_iUnknownVel].getIdElementSupport(eltTypeFl, idElt, ielSupportDofVel);
3094
3095 // Get fluid element points
3096 m_mesh[velMesh]->getOneElement(eltTypeFl, idElt, elemIdPointFl, elemPointFl, 0);
3097
3098 // Map structure quadrature point in fluid reference element
3099 Point qRefPoint;
3100 m_curvFeVel->mapPointInReferenceElement(0, elemPointFl, m_curvFeLag->currentQuadPoint[ig], qRefPoint);
3101
3102 // Clean matrices
3103 m_elementMatBD[0]->zero();
3104 m_elementMatTBD[0]->zero();
3105
3106 // Sum over components
3107 for (std::size_t ic = 0; ic <m_listVariable[m_iLagrange].numComponent(); ++ic){
3108 UBlasMatrixRange matrix = m_elementMatBD[0]->matBlock(m_lagBlock+ic,m_velBlock+ic);
3109 UBlasMatrixRange matrixT = m_elementMatTBD[0]->matBlock(m_velBlock+ic,m_lagBlock+ic);
3110
3111 // Sum over structure element nodes
3112 for(int idof = 0; idof < m_curvFeLag->numDof(); ++idof) {
3113
3114 // Sum over fluid element nodes
3115 for(int jdof = 0; jdof < m_curvFeVel->numDof(); ++jdof) {
3116
3117 // Compute integral
3118 val = m_curvFeLag->weightMeas(ig) * m_curvFeLag->phi[ig](idof) * m_curvFeVel->refEle().basisFunction().phi(jdof,qRefPoint);
3119
3120 matrix(idof,jdof) -= val;
3121 matrixT(jdof,idof) -= val;
3122 }
3123 }
3124 }
3125
3126 // Add values of elemMat in the global matrix: m_matrices[0].
3127 setValueCustomMatrixBD(ielSupportDofLag, ielSupportDofVel, m_matrices[0], true);
3128 }
3129 }
3130 // ****************************
3131
3132 // **** Vector ****************
3133 if ( flagMatrixRHS != FlagMatrixRHS::only_matrix ) {
3134 // Update structure velocity
3135 updateStructureVel(*m_curvFeLag, elemIdPoint);
3136
3137 // Clean vector
3138 m_elementVectorBD[0]->zero();
3139
3140 // Compute
3141 m_elementVectorBD[0]->source(-1., *m_curvFeLag, m_structVelQuad, m_lagBlock, m_listVariable[m_iLagrange].numComponent());
3142
3143 // Add values of elemVec in the global vector: m_vectors[0].
3144 setValueCustomVectorBD(ielSupportDofLag, ADD_VALUES, m_vectors[0]);
3145 }
3146 // ****************************
3147 }
3148
3149 // Deallocate array use for assemble with petsc.
3150 desallocateArrayForAssembleMatrixRHS(flagMatrixRHS);
3151
3152 m_listUnknown.setUnknownsRows({m_iUnknownVel,m_iUnknownPre});
3153 m_listUnknown.setUnknownsCols({m_iUnknownVel,m_iUnknownPre});
3154
3155 m_velBlock = m_listUnknown.getBlockPosition(m_iUnknownVel,0);
3156 m_lagBlock = m_listUnknown.getBlockPosition(m_iUnknownLag,0);
3157
3158 if( flagMatrixRHS == FlagMatrixRHS::only_rhs ) {
3159 // Real assembling of the right hand side (RHS).
3160 // for (std::size_t i = 0; i < m_vectors.size(); i++)
3161 m_vectors[0].assembly();
3162 }
3163
3164 r_timer.Stop("LinearProblem" + std::to_string(identifierProblem()) + "::computeLagrangeMultiplierOnInterface", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
3165 }
3166
3167 void LinearProblemNS::computeBHStabLagLag(const double coeff, const int iq)
3168 {
3169 // \int_{\Sigma} \lambda \cdot \cxi
3170 UBlasMatrix tmpMat = coeff * m_curvFeLag->weightMeas(iq) * outer_prod(m_curvFeLag->phi[iq], m_curvFeLag->phi[iq]);
3171 for (std::size_t ic = 0; ic < m_listVariable[m_iLagrange].numComponent(); ++ic){
3172 UBlasMatrixRange matrix = m_elementMatBD[0]->matBlock(m_lagBlock+ic,m_lagBlock+ic);
3173 matrix -= tmpMat;
3174 }
3175 }
3176
3177 void LinearProblemNS::computeBHStabLagJap(const double coeff, const int iq)
3178 {
3179 double tmp;
3180
3181 // \int_{\Sigma} \lambda \cdot \cxi_j n and \int_{\Sigma} \lambda_j n \cdot \cxi
3182 for (std::size_t ic = 0; ic < m_listVariable[m_iLagrange].numComponent(); ++ic){
3183 UBlasMatrixRange matrix = m_elementMatBD[0]->matBlock(m_lagBlock+ic,m_japBlock);
3184 UBlasMatrixRange matrixT = m_elementMatBD[0]->matBlock(m_japBlock,m_lagBlock+ic);
3185
3186 for (int idof = 0; idof < m_curvFeLag->numDof(); ++idof){
3187 tmp = coeff * m_curvFeLag->weightMeas(iq) * m_curvFeLag->phi[iq](idof) * m_structNormalQuad.val(ic,iq);
3188 matrix(idof,0) -= tmp;
3189 matrixT(0,idof) -= tmp;
3190 }
3191 }
3192 }
3193
3194 void LinearProblemNS::computeBHStabJapJap(const double coeff, const int iq)
3195 {
3196 // \int_{\Sigma} \lambda_j n \cdot \cxi_j n
3197 UBlasMatrixRange matrix = m_elementMatBD[0]->matBlock(m_japBlock,m_japBlock);
3198 matrix(0,0) -= coeff * m_curvFeLag->weightMeas(iq);
3199 }
3200
3201 void LinearProblemNS::assembleBarbosaHughesStab()
3202 {
3203 // Retrieve instance
3204 auto& r_instance = FelisceParam::instance(instanceIndex());
3205
3206 // Get the timer
3207 auto& r_timer = r_instance.timer;
3208 r_timer.Start("LinearProblem" + std::to_string(identifierProblem()) + "::assembleBarbosaHughesStab", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
3209
3210 std::vector<felInt> ielSupportDof;
3211 double coeff;
3212 const felInt lagMesh = m_listVariable[m_iLagrange].idMesh();
3213
3214 // Get element type
3215 std::vector<ElementType> eltTypeVec(m_listVariable.size());
3216 for (std::size_t iVar = 0; iVar < m_listVariable.size(); ++iVar)
3217 eltTypeVec[iVar] = m_mesh[m_listVariable[iVar].idMesh()]->bagElementTypeDomain()[0];
3218
3219 const ElementType eltType = m_mesh[lagMesh]->bagElementTypeDomain()[0];
3220
3221 // Resize array.
3222 const int numPointsPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType];
3223 std::vector<Point*> elemPoint(numPointsPerElt, nullptr);
3224 std::vector<felInt> elemIdPoint(numPointsPerElt, 0);
3225
3226 // Define all current finite element use in the problem from data
3227 defineCurvilinearFiniteElement(eltTypeVec);
3228 m_curvFeLag = m_listCurvilinearFiniteElement[m_iLagrange];
3229
3230 const double inv_coeff = 1. / ( r_instance.stabCoeffLag * r_instance.viscosity );
3231
3232 felInt japMesh;
3233 ElementType eltTypeFl;
3234 if ( r_instance.massConstraint ){
3235 ielSupportDof.resize(2);
3236
3237 japMesh = m_listVariable[m_iJapanCon].idMesh();
3238 eltTypeFl = m_mesh[japMesh]->bagElementTypeDomain()[0];
3239
3240 m_listUnknown.setUnknownsRows({m_iUnknownLag, m_iUnknownJap});
3241 m_listUnknown.setUnknownsCols({m_iUnknownLag, m_iUnknownJap});
3242 m_lagBlock = 0;
3243 m_japBlock = m_listVariable[m_iLagrange].numComponent();
3244 }
3245 else {
3246 ielSupportDof.resize(1);
3247
3248 m_listUnknown.setUnknownsRows({m_iUnknownLag});
3249 m_listUnknown.setUnknownsCols({m_iUnknownLag});
3250 m_lagBlock = 0;
3251 }
3252
3253 // Initialize element field
3254 m_structNormalQuad.initialize(QUAD_POINT_FIELD, *m_curvFeLag, m_curvFeLag->numCoor());
3255
3256 // Element matrix and vector initialisation
3257 initElementArrayBD();
3258
3259 // Allocate array use for assemble with petsc.
3260 allocateArrayForAssembleMatrixRHSBD(FlagMatrixRHS::only_matrix);
3261
3262 // Loop on element in the region with the type: eltType
3263 const felInt numEltPerType = m_meshLocal[lagMesh]->numElements(eltType);
3264 for (felInt iel=0; iel<numEltPerType; iel++) {
3265
3266 m_supportDofUnknownLocal[m_iUnknownLag].getIdElementSupport(eltType, iel, ielSupportDof[0]);
3267 ISLocalToGlobalMappingApply(*m_mappingElemSupportPerUnknown[m_iUnknownLag], 1, &ielSupportDof[0], &ielSupportDof[0]);
3268
3269 // Get structure element points
3270 m_meshLocal[lagMesh]->getOneElement(eltType, iel, elemIdPoint, elemPoint, 0);
3271
3272 // Update structure finite element
3273 m_curvFeLag->updateMeas(0, elemPoint);
3274
3275 // Compute coefficiente
3276 coeff = m_curvFeLag->diameter() * inv_coeff;
3277
3278 // Update normals
3279 updateNormal(*m_curvFeLag, lagMesh, elemIdPoint);
3280
3281 // Sum over quadrature points
3282 for (int ig=0; ig<m_curvFeLag->numQuadraturePoint(); ig++) {
3283
3284 // Clear elementary matrix.
3285 m_elementMatBD[0]->zero();
3286
3287 // Assemble local matrix
3288 computeBHStabLagLag(coeff, ig);
3289
3290 if ( r_instance.massConstraint ){
3291 // Quadrature point localization in fluid mesh
3292 felInt idElt = m_mapLagQpInVelMesh[iel][ig];
3293
3294 // Get id support dof
3295 m_supportDofUnknown[m_iUnknownJap].getIdElementSupport(eltTypeFl, idElt, ielSupportDof[1]);
3296
3297 // Assemble local matrix
3298 computeBHStabLagJap(coeff, ig);
3299 computeBHStabJapJap(coeff, ig);
3300 }
3301
3302 // Add values of elemMat in the global matrix: m_matrices[0].
3303 setValueCustomMatrixBD(ielSupportDof, ielSupportDof, m_matrices[0]);
3304 }
3305 }
3306
3307 // Desallocate array use for assemble with petsc.
3308 desallocateArrayForAssembleMatrixRHS(FlagMatrixRHS::only_matrix);
3309
3310 // Reset
3311 m_listUnknown.setUnknownsRows({m_iUnknownVel,m_iUnknownPre}); // TODO write a method to reset to default
3312 m_listUnknown.setUnknownsCols({m_iUnknownVel,m_iUnknownPre});
3313
3314 m_lagBlock = m_listUnknown.getBlockPosition(m_iUnknownLag,0);
3315 if ( r_instance.massConstraint )
3316 m_japBlock = m_listUnknown.getBlockPosition(m_iUnknownJap,0);
3317
3318 r_timer.Stop("LinearProblem" + std::to_string(identifierProblem()) + "::assembleBarbosaHughesStab", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
3319 }
3320
3321 void LinearProblemNS::assembleBrezziPitkarantaStab()
3322 {
3323 // Retrieve instance
3324 auto& r_instance = FelisceParam::instance(instanceIndex());
3325
3326 ElementType eltType;
3327 int numPointPerElt;
3328 felInt ielSupportDofLag;
3329
3330 std::vector<Point*> elemPoint;
3331 std::vector<felInt> elemIdPoint;
3332 std::vector<felInt> vectorIdSupport;
3333
3334 // Lagrange multiplier mesh
3335 const felInt lagMesh = m_listVariable[m_iLagrange].idMesh();
3336
3337 const double inv_coeff = 1. / ( r_instance.stabCoeffLag * r_instance.viscosity );
3338
3339 m_listUnknown.setUnknownsRows({m_iUnknownLag});
3340 m_listUnknown.setUnknownsCols({m_iUnknownLag});
3341
3342 m_lagBlock = 0;
3343
3344 // Assembly loop.
3345 // First loop on geometric type.
3346 const std::vector<ElementType>& bagElementTypeDomain = m_meshLocal[lagMesh]->bagElementTypeDomain();
3347 for (std::size_t i = 0; i < bagElementTypeDomain.size(); ++i) {
3348 eltType = bagElementTypeDomain[i];
3349
3350 // Resize array.
3351 numPointPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType];
3352 elemPoint.resize(numPointPerElt, nullptr);
3353 elemIdPoint.resize(numPointPerElt, 0);
3354
3355 // define all current finite element use in the problem from data
3356 defineCurvilinearFiniteElement(eltType);
3357 m_curvFeLag = m_listCurvilinearFiniteElement[m_iLagrange];
3358
3359 // Element matrix and std::vector initialisation
3360 initElementArrayBD();
3361
3362 // Allocate array use for assemble with petsc.
3363 allocateArrayForAssembleMatrixRHSBD(FlagMatrixRHS::only_matrix);
3364
3365 // Loop on element in the region with the type: eltType
3366 const felInt numEltPerType = m_meshLocal[lagMesh]->numElements(eltType);
3367 for (felInt iel = 0; iel < numEltPerType; ++iel) {
3368
3369 // Get element info
3370 setElemPoint(eltType, iel, elemPoint, elemIdPoint, vectorIdSupport);
3371
3372 // Update structure finite element
3373 m_curvFeLag->updateMeasNormalContra(0, elemPoint);
3374
3375 // Set coefficient
3376 const double coeff = std::pow(m_curvFeLag->diameter(),3)*inv_coeff;
3377
3378 // Loop over all the support elements
3379 for (std::size_t it = 0; it < vectorIdSupport.size(); it++) {
3380
3381 // get the id of the support
3382 ielSupportDofLag = vectorIdSupport[it];
3383
3384 // clear elementary matrix.
3385 m_elementMatBD[0]->zero();
3386
3387 // Compute Brezzi-Pitkaranta stabilization
3388 m_elementMatBD[0]->grad_phi_i_grad_phi_j(-coeff, *m_curvFeLag, m_lagBlock, m_lagBlock, m_listVariable[m_iLagrange].numComponent());
3389
3390 // Add values of elemMat in the global matrix: m_matrices[0].
3391 setValueCustomMatrixBD(ielSupportDofLag, ielSupportDofLag, m_matrices[0]);
3392 }
3393 }
3394 // Deallocate array use for assemble with petsc.
3395 desallocateArrayForAssembleMatrixRHS(FlagMatrixRHS::only_matrix);
3396 }
3397
3398 // Reset
3399 m_listUnknown.setUnknownsRows({m_iUnknownVel,m_iUnknownPre}); // TODO write a method to reset to default
3400 m_listUnknown.setUnknownsCols({m_iUnknownVel,m_iUnknownPre});
3401
3402 m_lagBlock = m_listUnknown.getBlockPosition(m_iUnknownLag,0);
3403
3404 if ( r_instance.massConstraint ) {
3405 felInt numGlbDof;
3406 const double value = -1.e-7;
3407 m_dof.loc2glob(0, 0, m_iJapanCon, 0, numGlbDof);
3408 AOApplicationToPetsc(m_ao, 1, &numGlbDof);
3409 m_matrices[0].setValues(1, &numGlbDof, 1, &numGlbDof, &value, ADD_VALUES);
3410
3411 // m_elementMat[0]->phi_i_phi_j(-1.e-7, *m_feVel, m_lagBlock, m_lagBlock, m_listVariable[m_iLagrange].numComponent());
3412 }
3413 }
3414
3415 void LinearProblemNS::assembleJapanConstraintBoundary()
3416 {
3417 // Retrieve instance
3418 auto& r_instance = FelisceParam::instance(instanceIndex());
3419
3420 if ( r_instance.japanLabels.size() == 0 )
3421 return;
3422
3423 // Get the timer
3424 auto& r_timer = r_instance.timer;
3425 r_timer.Start("LinearProblem" + std::to_string(identifierProblem()) + "::assembleJapanConstraintBoundary", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
3426
3427 m_listUnknown.setUnknownsRows({m_iUnknownVel});
3428 m_listUnknown.setUnknownsCols({m_iUnknownJap});
3429
3430 m_velBlock = 0;
3431 m_japBlock = 0;
3432
3433 ElementType eltType; //geometric element type in the mesh.
3434 int numPointPerElt = 0; //number of points per geometric element.
3435 int currentLabel = 0; //number of label domain.
3436 felInt numEltPerLabel = 0; //number of element for one label and one eltType.
3437
3438 // use to define a "global" numbering of element in the mesh.
3439 felInt numElement[ GeometricMeshRegion::m_numTypesOfElement ];
3440 for (int ityp=0; ityp< GeometricMeshRegion::m_numTypesOfElement; ityp++) {
3441 eltType = (ElementType)ityp;
3442 numElement[eltType] = 0;
3443 }
3444
3445 // contains points of the current element.
3446 std::vector<Point*> elemPoint;
3447
3448 // contains ids of point of the current element.
3449 std::vector<felInt> elemIdPoint;
3450
3451 // contains ids of support elements of a mesh element
3452 std::vector<felInt> vectorIdSupport;
3453
3454 // use to get element number in support dof mesh ordering.
3455 felInt ielSupportDofCurv;
3456
3457 //Assembly loop curvilinear.
3458 const std::vector<ElementType>& bagElementTypeDomainBoundary = m_meshLocal[m_currentMesh]->bagElementTypeDomainBoundary();
3459 for (std::size_t i = 0; i < bagElementTypeDomainBoundary.size(); ++i) {
3460 eltType = bagElementTypeDomainBoundary[i];
3461
3462 //resize array.
3463 numPointPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType];
3464 elemPoint.resize(numPointPerElt, nullptr);
3465 elemIdPoint.resize(numPointPerElt, 0);
3466
3467 //define all current finite element use in the problem from data
3468 //file configuration and allocate elemMat and elemVec (question: virtual ?).
3469 defineCurvilinearFiniteElement(eltType);
3470
3471 // Element matrix and vector initialisation
3472 initElementArrayBD(true);
3473
3474 //allocate array use for assemble with petsc.
3475 allocateArrayForAssembleMatrixRHSBD(FlagMatrixRHS::only_matrix);
3476
3477 // get velocity curvilinear fe
3478 m_curvFeVel = m_listCurvilinearFiniteElement[m_iVelocity];
3479
3480 // Second loop on region of the mesh.
3481 for(auto itRef = m_meshLocal[m_currentMesh]->intRefToBegEndMaps[eltType].begin(); itRef != m_meshLocal[m_currentMesh]->intRefToBegEndMaps[eltType].end(); itRef++) {
3482 currentLabel = itRef->first;
3483 numEltPerLabel = itRef->second.second;
3484
3485 auto bndRefIt = find(r_instance.japanLabels.begin(), r_instance.japanLabels.end(), currentLabel);
3486 if(bndRefIt == r_instance.japanLabels.end()){
3487 numElement[eltType] += numEltPerLabel;
3488 continue;
3489 }
3490
3491 // Third loop on element in the region with the type: eltType. ("real" loop on elements).
3492 for ( felInt iel = 0; iel < numEltPerLabel; iel++) {
3493 // return each id of point of the element and coordinate in two arrays: elemPoint and elemIdPoint.
3494 setElemPoint(eltType, numElement[eltType], elemPoint, elemIdPoint, vectorIdSupport);
3495
3496 // update velcity fe
3497 m_curvFeVel->updateMeasNormal(0, elemPoint);
3498
3499 // loop over all the support elements
3500 for (std::size_t it = 0; it < vectorIdSupport.size(); it++) {
3501 // get the id of the support
3502 ielSupportDofCurv = vectorIdSupport[it];
3503
3504 // clear elementary matrix.
3505 m_elementMatBD[0]->zero();
3506 m_elementMatTBD[0]->zero();
3507
3508 m_elementMatBD[0]->const_phi_i_dot_n(-1., *m_curvFeVel, m_velBlock, m_japBlock);
3509 m_elementMatTBD[0]->const_phi_j_dot_n(-1., *m_curvFeVel, m_japBlock, m_velBlock);
3510
3511 setValueCustomMatrixBD(ielSupportDofCurv, ielSupportDofCurv, m_matrices[0], true);
3512 }
3513
3514 numElement[eltType]++;
3515 }
3516 }
3517
3518 //allocate array use for assemble with petsc.
3519 desallocateArrayForAssembleMatrixRHS(FlagMatrixRHS::only_matrix);
3520 }
3521
3522 m_listUnknown.setUnknownsRows({m_iUnknownVel,m_iUnknownPre});
3523 m_listUnknown.setUnknownsCols({m_iUnknownVel,m_iUnknownPre});
3524
3525 m_velBlock = m_listUnknown.getBlockPosition(m_iUnknownVel,0);
3526 m_japBlock = m_listUnknown.getBlockPosition(m_iUnknownJap,0);
3527
3528 r_timer.Stop("LinearProblem" + std::to_string(identifierProblem()) + "::assembleJapanConstraintBoundary", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
3529 }
3530
3531 void LinearProblemNS::assembleJapanConstraintInterface()
3532 {
3533 // Retrieve instance
3534 auto& r_instance = FelisceParam::instance(instanceIndex());
3535
3536 // Get the timer
3537 auto& r_timer = r_instance.timer;
3538 r_timer.Start("LinearProblem" + std::to_string(identifierProblem()) + "::assembleJapanConstraintInterface", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
3539
3540 felInt ielSupportDofVel;
3541
3542 double val;
3543
3544 const felInt lagMesh = m_listVariable[m_iLagrange].idMesh();
3545 const felInt velMesh = m_listVariable[m_iVelocity].idMesh();
3546
3547 std::vector<felInt> listMeshes;
3548 std::vector< std::vector<std::vector<felInt> >* > listMapQuadPt;
3549 if ( r_instance.useFicItf ){
3550
3551 if ( r_instance.M1G.enable ){
3552 listMeshes = {lagMesh, 2}; // TODO D.C.
3553 listMapQuadPt = {&m_mapLagQpInVelMesh, &m_mapJapQpInVelMesh};
3554 }
3555 else {
3556 listMeshes = {2}; // TODO D.C.
3557 listMapQuadPt = {&m_mapJapQpInVelMesh};
3558 }
3559 } else {
3560 listMeshes = {lagMesh};
3561 listMapQuadPt = {&m_mapLagQpInVelMesh};
3562 }
3563
3564 m_listUnknown.setUnknownsRows({m_iUnknownVel});
3565 m_listUnknown.setUnknownsCols({m_iUnknownJap});
3566
3567 m_velBlock = 0;
3568 m_japBlock = 0;
3569
3570 for (auto iMsh = 0u; iMsh < listMeshes.size(); ++iMsh) {
3571 const felInt id_mesh = listMeshes[iMsh];
3572 const std::vector<std::vector<felInt> >& mapQuadPt = *listMapQuadPt[iMsh];
3573
3574 // Get element type
3575 std::vector<ElementType> eltTypeVec(m_listVariable.size());
3576 for (std::size_t iVar = 0; iVar < m_listVariable.size(); ++iVar)
3577 eltTypeVec[iVar] = m_mesh[m_listVariable[iVar].idMesh()]->bagElementTypeDomain()[0];
3578
3579 // Get element type
3580 const ElementType eltType = m_mesh[id_mesh]->bagElementTypeDomain()[0];
3581 const ElementType eltTypeFl = m_mesh[velMesh]->bagElementTypeDomain()[0];
3582
3583 // Resize array.
3584 const int numPointsPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType];
3585 std::vector<Point*> elemPoint(numPointsPerElt, nullptr);
3586 std::vector<felInt> elemIdPoint(numPointsPerElt, 0);
3587
3588 const int numPointsPerEltFl = GeometricMeshRegion::m_numPointsPerElt[eltTypeFl];
3589 std::vector<Point*> elemPointFl(numPointsPerEltFl, nullptr);
3590 std::vector<felInt> elemIdPointFl(numPointsPerEltFl, 0);
3591
3592 // Define all current finite element use in the problem from data
3593 defineCurvilinearFiniteElement(eltTypeVec);
3594 m_curvFeLag = m_listCurvilinearFiniteElement[m_iLagrange];
3595 m_curvFeVel = m_listCurvilinearFiniteElement[m_iVelocity];
3596
3597 // Element matrix and vector initialisation
3598 initElementArrayBD(true);
3599
3600 // Allocate array use for assemble with petsc.
3601 allocateArrayForAssembleMatrixRHSBD(FlagMatrixRHS::only_matrix);
3602
3603 // Initialize element field
3604 m_structNormalQuad.initialize(QUAD_POINT_FIELD, *m_curvFeLag, m_curvFeLag->numCoor());
3605
3606 // Loop on element in the region with the type: eltType
3607 const felInt numEltPerType = m_meshLocal[id_mesh]->numElements(eltType);
3608 for (felInt iel = 0; iel < numEltPerType; ++iel) {
3609
3610 // return each id of point of the element and coordinate in two arrays: elemPoint and elemIdPoint.
3611 m_meshLocal[id_mesh]->getOneElement(eltType, iel, elemIdPoint, elemPoint, 0);
3612
3613 // Update structure finite element
3614 m_curvFeLag->updateMeasQuadPt(0, elemPoint);
3615
3616 // Update normals
3617 updateNormal(*m_curvFeLag, id_mesh, elemIdPoint);
3618
3619 // Sum over quadrature points
3620 for (int ig = 0; ig < m_curvFeLag->numQuadraturePoint(); ++ig) {
3621
3622 // Quadrature point localization in fluid mesh
3623 felInt idElt = mapQuadPt[iel][ig];
3624
3625 // Get id support dof
3626 m_supportDofUnknown[m_iUnknownVel].getIdElementSupport(eltTypeFl, idElt, ielSupportDofVel);
3627
3628 // Get fluid element points
3629 m_mesh[velMesh]->getOneElement(eltTypeFl, idElt, elemIdPointFl, elemPointFl, 0);
3630
3631 // Map structure quadrature point in fluid reference element
3632 Point qRefPoint;
3633 m_curvFeVel->mapPointInReferenceElement(0, elemPointFl, m_curvFeLag->currentQuadPoint[ig], qRefPoint);
3634
3635 // Clear elementary matrices
3636 m_elementMatBD[0]->zero();
3637 m_elementMatTBD[0]->zero();
3638
3639 // Sum over components
3640 for (std::size_t ic = 0; ic < m_listVariable[m_iVelocity].numComponent(); ++ic){
3641
3642 // Get matrix block
3643 UBlasMatrixRange matrix = m_elementMatBD[0]->matBlock(m_velBlock+ic,m_japBlock);
3644 UBlasMatrixRange matrixT = m_elementMatTBD[0]->matBlock(m_japBlock,m_velBlock+ic);
3645
3646 // Sum over element nodes
3647 for(int idof = 0; idof < m_curvFeVel->numDof(); ++idof) {
3648
3649 // Compute integral
3650 val = m_curvFeLag->weightMeas(ig) * m_structNormalQuad.val(ic, ig) * m_curvFeVel->refEle().basisFunction().phi(idof,qRefPoint);
3651
3652 // Fill matrix block
3653 matrix(idof,0) -= val;
3654 matrixT(0,idof) -= val;
3655 }
3656 }
3657
3658 // add values of elemMat in the global matrix: m_matrices[0].
3659 setValueCustomMatrixBD(ielSupportDofVel, ielSupportDofVel, m_matrices[0], true);
3660 }
3661 }
3662
3663 // Deallocate array use for assemble with petsc.
3664 desallocateArrayForAssembleMatrixRHS(FlagMatrixRHS::only_matrix);
3665 }
3666
3667 m_listUnknown.setUnknownsRows({m_iUnknownVel,m_iUnknownPre});
3668 m_listUnknown.setUnknownsCols({m_iUnknownVel,m_iUnknownPre});
3669
3670 m_velBlock = m_listUnknown.getBlockPosition(m_iUnknownVel,0);
3671 m_japBlock = m_listUnknown.getBlockPosition(m_iUnknownJap,0);
3672
3673 r_timer.Stop("LinearProblem" + std::to_string(identifierProblem()) + "::assembleJapanConstraintInterface", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
3674 }
3675
3676 void LinearProblemNS::updateStructureVel(CurBaseFiniteElement& fe, std::vector<felInt>& elemIdPoint)
3677 {
3678 // update on the structure dof the local structure velocity from the master at the struct element strucId
3679 // FEL_CHECK(m_structVel != 0, "Error: the pointer of the interface velocity has not been initialized yet.");
3680 // velocity comming from the FSI master ( The order is not the same! )
3681 // the local ordering is done by component while the global is by point
3682 for(int iq = 0; iq < fe.numQuadraturePoint(); ++iq) {
3683 for(int ic = 0; ic < fe.numCoor(); ++ic) {
3684 m_structVelQuad.val(ic, iq) = 0;
3685 for(int il = 0; il < fe.numDof(); ++il)
3686 m_structVelQuad.val(ic, iq) += (*m_structVel)[fe.numCoor()*elemIdPoint[il]+ic] * fe.phi[iq](il);
3687 }
3688 }
3689 }
3690
3691 void LinearProblemNS::computeItfDisp(std::vector<double>& itfDisp)
3692 {
3693 // Retrieve instance
3694 auto& r_instance = FelisceParam::instance(instanceIndex());
3695
3696 // Get number coor
3697 const int nbrCrd = dimension();
3698
3699 // Get id mesh
3700 const int idMshLag = m_listVariable[m_iLagrange].idMesh();
3701
3702 // Get number of real interface points
3703 const int nbrPntReal = m_mesh[idMshLag]->numPoints();
3704
3705 // Compute displacement real structure
3706 m_realDisp.assign( itfDisp.begin(), itfDisp.begin()+nbrCrd*nbrPntReal );
3707
3708 if ( r_instance.useFicItf ) {
3709
3710 // Get number of fictitious interface points
3711 const felInt nbrPntFict = m_mesh[2]->listPoints().size(); // TODO D.C.
3712
3713 // Resize fictitious displacement vector
3714 m_fictDisp.assign(nbrPntFict*nbrCrd,0.);
3715
3716 // User defined displacement for fictitious interface
3717 userComputeItfDisp();
3718 }
3719 }
3720
3721 void LinearProblemNS::moveItfMeshes()
3722 {
3723 // Retrieve instance
3724 auto& r_instance = FelisceParam::instance(instanceIndex());
3725
3726 const int idMshLag = listVariable()[m_iLagrange].idMesh();
3727
3728 mesh(idMshLag)->moveMesh(m_realDisp,1.0); // TODO D.C. mesh or meshLocal???
3729 meshLocal(idMshLag)->moveMesh(m_realDisp,1.0); // TODO D.C. mesh or meshLocal???
3730
3731 // Compute mesh normals
3732 mesh(idMshLag)->computeNormalTangent();
3733 auto& listNormals = mesh(idMshLag)->listNormals();
3734 if ( r_instance.flipItfNormal )
3735 std::for_each(listNormals.begin(), listNormals.end(), [](auto& p) { p *= -1.; } );
3736
3737 if ( r_instance.useFicItf ) {
3738
3739 // Move the fictitous mesh
3740 userMoveFictMesh();
3741
3742 // Compute mesh normals
3743 mesh(2)->computeNormalTangent();
3744 auto& listNormals = mesh(2)->listNormals();
3745 if ( r_instance.flipItfNormal )
3746 std::for_each(listNormals.begin(), listNormals.end(), [](auto& p) { p *= -1.; } );
3747 }
3748 }
3749
3750 void LinearProblemNS::updateNormal(CurvilinearFiniteElement& fe, int idMsh, std::vector<felInt>& elemIdPoint)
3751 {
3752 // Retrieve instance
3753 auto& r_instance = FelisceParam::instance(instanceIndex());
3754
3755 if ( r_instance.useAverageNormal ) {
3756 double norm;
3757 for(int iq=0; iq<fe.numQuadraturePoint(); ++iq) {
3758 for(int ic=0; ic<fe.numCoor(); ++ic) {
3759 m_structNormalQuad.val(ic, iq) = 0;
3760 for(int idof=0; idof<fe.numDof(); ++idof)
3761 m_structNormalQuad.val(ic, iq) += fe.phi[iq](idof) * m_mesh[idMsh]->listNormal(elemIdPoint[idof])[ic];
3762 }
3763
3764 norm = 0;
3765 for(int ic=0; ic<fe.numCoor(); ++ic)
3766 norm += m_structNormalQuad.val(ic, iq) * m_structNormalQuad.val(ic, iq);
3767
3768 norm = 1./std::sqrt(norm);
3769 for(int ic=0; ic<fe.numCoor(); ++ic)
3770 m_structNormalQuad.val(ic, iq) *= norm;
3771 }
3772 } else {
3773 fe.computeNormal();
3774
3775 const double coef = r_instance.flipItfNormal == true ? -1. : 1.;
3776
3777 for(int ic=0; ic<fe.numCoor(); ++ic)
3778 for(int iq=0; iq<fe.numQuadraturePoint(); ++iq)
3779 m_structNormalQuad.val(ic, iq) = coef * fe.normal[iq](ic);
3780 }
3781 }
3782
3783 void LinearProblemNS::setInterfaceExchangedData(std::vector<double>& itfVel, std::vector<double>& itfForc)
3784 {
3785 m_structVel = &itfVel;
3786 m_intfForc = &itfForc;
3787 }
3788
3789 void LinearProblemNS::computeInterfaceStress()
3790 {
3791 // Retrieve instance
3792 auto& r_instance = FelisceParam::instance(instanceIndex());
3793
3794 // Get the timer
3795 auto& r_timer = r_instance.timer;
3796 r_timer.Start("LinearProblem" + std::to_string(identifierProblem()) + "::computeInterfaceStress", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
3797
3798 FEL_CHECK(m_intfForc != nullptr, "Error: the pointer of the interface force has not been initialized yet.");
3799
3800 std::fill(m_intfForc->begin(), m_intfForc->end(), 0);
3801
3802 // const felInt velMesh = m_listVariable[m_iVelocity].idMesh();
3803 const felInt lagMesh = m_listVariable[m_iLagrange].idMesh();
3804
3805 // Get element type
3806 std::vector<ElementType> eltTypeVec(m_listVariable.size());
3807 for (std::size_t iVar = 0; iVar < m_listVariable.size(); ++iVar)
3808 eltTypeVec[iVar] = m_mesh[m_listVariable[iVar].idMesh()]->bagElementTypeDomain()[0];
3809
3810 const ElementType eltType = m_mesh[lagMesh]->bagElementTypeDomain()[0];
3811 // const ElementType eltTypeFl = m_mesh[velMesh]->bagElementTypeDomain()[0];
3812
3813 // Resize array
3814 const int numPointsPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType];
3815 std::vector<Point*> elemPoint(numPointsPerElt, nullptr);
3816 std::vector<felInt> elemIdPoint(numPointsPerElt, 0);
3817
3818 // Define structure finite element
3819 const GeoElement *geoEleStruc = m_mesh[lagMesh]->eltEnumToFelNameGeoEle[eltType].second;
3820 const RefElement *refEleStruc = geoEleStruc->defineFiniteEle(eltType, 0, *m_mesh[lagMesh]);
3821 m_curvFeStruc = new CurvilinearFiniteElement(*refEleStruc, *geoEleStruc, DegreeOfExactness_2); // TODO D.C.: Provide the value with the fluid or by data file
3822
3823 // Define all current finite element use in the problem from data
3824 defineCurvilinearFiniteElement(eltTypeVec);
3825 m_curvFeVel = m_listCurvilinearFiniteElement[m_iVelocity];
3826 m_curvFeLag = m_listCurvilinearFiniteElement[m_iLagrange];
3827
3828 // Initialize element fields
3829 m_structNormalQuad.initialize( QUAD_POINT_FIELD, *m_curvFeStruc, m_curvFeStruc->numCoor());
3830 m_structVelQuad.initialize(QUAD_POINT_FIELD, *m_curvFeStruc, m_curvFeStruc->numCoor());
3831 m_seqVelDofPts.initialize(DOF_FIELD, *m_curvFeVel, m_curvFeVel->numCoor());
3832 m_seqLagDofPts.initialize(DOF_FIELD, *m_curvFeLag, m_curvFeLag->numCoor());
3833
3834 ElementVector elemVec({m_curvFeStruc}, {static_cast<std::size_t>(m_curvFeStruc->numCoor())});
3835
3836 // Loop on element in the region with the type: eltType
3837 const felInt numEltPerType = m_meshLocal[lagMesh]->numElements(eltType);
3838 for (felInt iel = 0; iel < numEltPerType; ++iel) {
3839
3840 // return each id of point of the element and coordinate in two arrays: elemPoint and elemIdPoint.
3841 m_meshLocal[lagMesh]->getOneElement(eltType, iel, elemIdPoint, elemPoint, 0);
3842
3843 // clear elementary vector.
3844 elemVec.zero();
3845
3846 // compute stress on interface element
3847 computeElementaryInterfaceStress(elemPoint, elemIdPoint, iel, elemVec);
3848
3849 // assembly m_intForc
3850 for (int ic = 0; ic < m_curvFeStruc->numCoor(); ++ic) {
3851 for (int ip = 0; ip < m_curvFeStruc->numPoint(); ++ip) {
3852 int gdof = elemIdPoint[ip]; // <- // TODO D.C.: don't like this, works only for P1
3853 (*m_intfForc)[m_curvFeStruc->numCoor()*gdof+ic] -= elemVec[ip+ic*m_curvFeStruc->numDof()];
3854 }
3855 }
3856 }
3857
3858 MPI_Allreduce(MPI_IN_PLACE, m_intfForc->data(), m_intfForc->size(), MPI_DOUBLE, MPI_SUM, MpiInfo::petscComm());
3859
3860 // if ( MpiInfo::rankProc() == 0 ){
3861 // std::cout << "Stress: ";
3862 // for (auto it = m_intfForc->begin(); it != m_intfForc->end(); ++it)
3863 // std::cout << *it << " ";
3864 // std::cout << std::endl;
3865 // }
3866
3867 delete m_curvFeStruc;
3868
3869 r_timer.Stop("LinearProblem" + std::to_string(identifierProblem()) + "::computeInterfaceStress", m_fstransient ? (m_fstransient->total_number_iterations > 0 ? m_fstransient->total_number_iterations : m_fstransient->iteration ) : 0);
3870 }
3871
3872 void LinearProblemNS::computeElementaryInterfaceStress(const std::vector<Point*>& elemPoint, std::vector<felInt>& /*elemIdPoint*/, felInt iel, ElementVector& elemVec)
3873 {
3874 double lag_ic;
3875 felInt ielGlb;
3876 const felInt lagMesh = m_listVariable[m_iLagrange].idMesh();
3877
3878 // update structure finite element
3879 m_curvFeStruc->updateMeasQuadPt(0, elemPoint);
3880
3881
3882 //--- Constraint on velocity
3883 ISLocalToGlobalMappingApply(mappingElem(lagMesh), 1, &iel, &ielGlb);
3884 m_seqLagDofPts.setValue(sequentialSolution(), *m_curvFeLag, ielGlb, m_iLagrange, m_ao, dof());
3885
3886 // for every component of the struct test function
3887 for (int ic = 0; ic < m_curvFeStruc->numCoor(); ++ic) {
3888 UBlasVectorRange vec = elemVec.vecBlock(ic);
3889
3890 // for every quadrature point
3891 for (int ig = 0; ig < m_curvFeStruc->numQuadraturePoint(); ig++) {
3892
3893 const Point& qRefPoint = m_curvFeStruc->quadratureRule().quadraturePoint(ig);
3894
3895 // evaluate \lambda_{ic}(x_{iq})
3896 lag_ic = 0;
3897 for(int idof = 0; idof < m_curvFeLag->numDof(); idof++)
3898 lag_ic += m_curvFeLag->refEle().basisFunction().phi(idof,qRefPoint) * m_seqLagDofPts.val(ic,idof);
3899
3900 // for every node
3901 for(int idof = 0; idof < m_curvFeStruc->numDof(); idof++)
3902 vec(idof) += m_curvFeStruc->weightMeas(ig) * lag_ic * m_curvFeStruc->phi[ig](idof);
3903 }
3904 }
3905 }
3906
3907 }
3908