GCC Code Coverage Report


Directory: ./
File: Model/NitscheXFEMModel.cpp
Date: 2024-04-14 07:32:34
Exec Total Coverage
Lines: 0 229 0.0%
Branches: 0 318 0.0%

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: M. A. Fernandez & F.M. Gerosa
13 //
14
15 /*!
16 \file linearProblemNitscheXFEM.cpp
17 \authors M. Fernandez & F.M. Gerosa
18 \date 04/2018
19 \brief Model class for Navier-Stokes with Nitsche XFEM formulation
20 */
21
22 // System includes
23
24 // External includes
25
26 // Project includes
27 #include "FiniteElement/elementVector.hpp"
28 #include "Model/NitscheXFEMModel.hpp"
29
30 namespace felisce
31 {
32
33 NitscheXFEMModel::NitscheXFEMModel():Model()
34 {
35 m_name = "Nitsche XFEM Navier-Stokes Model";
36 m_isParFluidVelAllocated = false;
37 m_pLinFluid = nullptr;
38 m_feStruc = nullptr;
39 m_indexTime = 0;
40 m_countToInitOldObjects = 0;
41 m_reinitializeFluidBdf = false;
42 m_intfDisp = nullptr;
43 }
44
45 /***********************************************************************************/
46 /***********************************************************************************/
47
48 NitscheXFEMModel::~NitscheXFEMModel()
49 {
50
51 if( m_isParFluidVelAllocated ) {
52 for(std::size_t i = 0; i < m_parFluidVel.size(); ++i)
53 m_parFluidVel[i].destroy();
54 m_parFluidVel.clear();
55 }
56
57 if( m_feStruc != NULL )
58 delete m_feStruc;
59 }
60
61 /***********************************************************************************/
62 /***********************************************************************************/
63
64 void NitscheXFEMModel::initializeDerivedLinearProblem()
65 {
66 // type conversion of the linear problems
67 m_pLinFluid = dynamic_cast<LinearProblemNitscheXFEM*>(m_linearProblem[0]);
68
69 std::cout << " Reading interface mesh... " ;
70 std::string inputDirectory1 = "./";
71 std::string inputFile1 = "";
72 std::string inputMesh1 = FelisceParam::instance().meshFileImmersedStruct;
73 std::string outputMesh1 = "toto.geo";
74 std::string meshDir1 = FelisceParam::instance().meshDirImmersedStruct;
75 std::string resultDir1 = "";
76 std::string prefixName1 = "";
77
78 IO io(inputDirectory1, inputFile1, inputMesh1, outputMesh1, meshDir1, resultDir1, prefixName1);
79
80 io.readMesh(m_interfMesh, 1.0);
81 std::cout << " done. " << std::endl; // TODO D.C. the model can already have more than one mesh...
82
83 m_pLinFluid->setInterfaceMesh(&m_interfMesh);
84
85 if( !FelisceParam::instance().duplicateSupportDof )
86 FEL_ERROR("NXFEM model requires duplicateSupportDof = true");
87
88 // build the edges or faces of the fluid mesh
89 if( m_mesh[0]->domainDim() == 2 )
90 m_mesh[0]->buildEdges();
91 else
92 m_mesh[0]->buildFaces();
93
94 // We intersect the two meshes here (because this function is called before computeDof)
95 // The meshes can be found in the linear problem
96 m_intersectMeshes.setMeshesName("fluidMesh", "strucMesh");
97 m_intersectMeshes.setVerbose(FelisceParam::verbose());
98 m_intersectMeshes.initAndIntersectMeshes(*m_mesh[0], m_interfMesh);
99
100 // give access to the intersection to each linear problems
101 m_pLinFluid->setDuplicateSupportObject(&m_intersectMeshes);
102
103 // compute normals
104 m_interfMesh.computeElementNormal(m_interfMesh.listElementNormals());
105 }
106
107 /***********************************************************************************/
108 /***********************************************************************************/
109
110 void NitscheXFEMModel::initializeDerivedModel()
111 {
112
113 if (FelisceParam::instance().orderBdfNS > 2)
114 FEL_ERROR("BDF not yet implemented for order greater than 2 with Nitsche-XFEM.");
115
116 // Definition and initialization of bdf schemes
117 m_bdfFluid.defineOrder(FelisceParam::instance().orderBdfNS);
118 m_pLinFluid->initializeTimeScheme(&m_bdfFluid);
119
120 // Finite element for the linear problems
121 // We assume that there is only one type of volume element for the structure
122 const std::vector<GeometricMeshRegion::ElementType>& bagElementTypeDomainStruc = m_interfMesh.bagElementTypeDomain();
123 FEL_ASSERT(bagElementTypeDomainStruc.size() == 1);
124
125 const int typeOfFiniteElement = 0;
126 const GeoElement *geoEleStruc = GeometricMeshRegion::eltEnumToFelNameGeoEle[bagElementTypeDomainStruc[0]].second;
127 const RefElement *refEleStruc = geoEleStruc->defineFiniteEle(bagElementTypeDomainStruc[0], typeOfFiniteElement, m_interfMesh);
128 m_feStruc = new CurvilinearFiniteElement(*refEleStruc, *geoEleStruc, DegreeOfExactness_2); // WARNING: Provide the value with the fluid or by data file
129
130 FEL_ASSERT(m_feStruc);
131 m_pLinFluid->setStrucFiniteElement(m_feStruc); // TODO D.C. remove this part once merged multimesh in master
132
133 // We assume that there is only one type of volume element for the fluid
134 FEL_ASSERT(m_pLinFluid->meshLocal()->bagElementTypeDomain().size() == 1);
135 }
136
137 /***********************************************************************************/
138 /***********************************************************************************/
139
140 void NitscheXFEMModel::preAssemblingMatrixRHS(std::size_t /*iProblem*/)
141 {
142
143 // Allocate the extrapolation of the velocity if necessary
144 if( !m_isParFluidVelAllocated ) {
145 // There are orderBdfNS term in the velocity extrapolation
146 m_parFluidVel.resize(FelisceParam::instance().orderBdfNS);
147
148 // If we use a projection of the old solution, all the terms have the same size
149 if( FelisceParam::instance().useProjectionForNitscheXFEM || m_fstransient->iteration == 0 ) {
150 for(std::size_t i = 0; i < m_parFluidVel.size(); ++i)
151 m_parFluidVel[i].duplicateFrom(m_pLinFluid->vector());
152 } else {
153 for(std::size_t i = 0; i < m_parFluidVel.size(); ++i)
154 m_parFluidVel[i].duplicateFrom(m_pLinFluid->solutionOld(i));
155 }
156
157 // set the extrapolation term to zero
158 for(std::size_t i = 0; i < m_parFluidVel.size(); ++i)
159 m_parFluidVel[i].set( 0.);
160
161 m_isParFluidVelAllocated = true;
162 }
163 }
164
165 /***********************************************************************************/
166 /***********************************************************************************/
167
168 void NitscheXFEMModel::forward()
169 {
170 prepareForward();
171 solve();
172 }
173
174 /***********************************************************************************/
175 /***********************************************************************************/
176
177 void NitscheXFEMModel::prepareForward()
178 {
179
180 // Write solution for postprocessing (if required)
181 if ( m_fstransient->iteration > 0 ){
182 writeSolutionAndMeshes();
183 if( FelisceParam::verbose() > 4 )
184 m_pLinFluid->printStructStress(m_fstransient->iteration, m_fstransient->timeStep);
185 }
186
187 // update the position of the interface and recompute the intersection
188 if ( ( FelisceParam::instance().useDynamicStructure ) and (m_fstransient->iteration > 0) ) {
189 FEL_CHECK(m_intfDisp != 0, "Error: the pointer of the interface force has not been initialized yet.");
190
191 m_intersectMeshes.updateInterfacePosition( *m_intfDisp );
192
193 m_interfMesh.moveMesh( *m_intfDisp, 1.0);
194 m_interfMesh.computeElementNormal(m_interfMesh.listElementNormals());
195
196 m_intersectMeshes.setIteration(m_fstransient->iteration);
197 m_intersectMeshes.intersectMeshes(*m_mesh[0], m_interfMesh);
198 }
199
200 // save the solution with the original support Dof and delete the matrices, vectors and mapping of the fluid
201 if ( m_fstransient->iteration > 0 ) {
202
203 if( m_intersectMeshes.hasIntersectionChange() ) {
204
205 // delete dynamic parts
206 m_pLinFluid->updateOldSolution(1);
207 m_pLinFluid->deleteDynamicData();
208
209 if(m_isParFluidVelAllocated) {
210 for(std::size_t i=0; i<m_parFluidVel.size(); ++i)
211 m_parFluidVel[i].destroy();
212
213 m_isParFluidVelAllocated = false;
214 }
215
216 // set to true only to remember that the intersection has changed after this time step
217 // If the intersection is not changing at the next time step, we need to reinitialize the old objects
218 m_countToInitOldObjects = FelisceParam::instance().orderBdfNS;
219 } else {
220
221 m_pLinFluid->updateOldSolution(m_countToInitOldObjects);
222
223 if(m_countToInitOldObjects > 0) {
224
225 if(m_isParFluidVelAllocated) {
226 for(std::size_t i=0; i<m_parFluidVel.size(); ++i)
227 m_parFluidVel[i].destroy();
228
229 m_isParFluidVelAllocated = false;
230 }
231
232 // pre assembling to reallocate the extrapolations
233 for (std::size_t ipb = 0; ipb < m_linearProblem.size(); ipb++) {
234 preAssemblingMatrixRHS(ipb);
235 }
236
237 m_countToInitOldObjects -= 1;
238 m_reinitializeFluidBdf = true;
239 }
240 }
241 }
242
243 // Note that hasIntersectionChange() is true only if the duplicated elements or the signs of the original fluid vertices (for instance, when the structure intersects a new edge or face) are different
244 if( m_intersectMeshes.hasIntersectionChange() ) {
245 // reallocate everything for the fluid
246 // supportDofMeshes, duplication, and dofs
247 m_pLinFluid->computeDof(MpiInfo::numProc(), MpiInfo::rankProc());
248
249 // new pattern
250 m_pLinFluid->userChangePattern(MpiInfo::numProc(), MpiInfo::rankProc());
251
252 // cut the mesh
253 m_pLinFluid->cutMesh();
254
255 // allocate matrices and vectors
256 m_pLinFluid->allocateMatrix();
257
258 // determine dof for the boundary conditions
259 m_pLinFluid->determineDofAssociateToLabel();
260
261 m_pLinFluid->finalizeEssBCConstantInT();
262
263 // pre assembling to reallocate the extrapolations
264 for (std::size_t ipb = 0; ipb < m_linearProblem.size(); ipb++)
265 preAssemblingMatrixRHS(ipb);
266
267 // re build the solver (not possible to change the matrix size in the ksp without destroying it ?)
268 m_pLinFluid->buildSolver();
269 }
270
271 if( m_fstransient->iteration == 0 ) {
272 // initialize the old objects
273 m_pLinFluid->initOldObjects();
274
275 writeSolutionAndMeshes();
276 if( FelisceParam::verbose() > 4)
277 m_pLinFluid->printStructStress(m_fstransient->iteration, m_fstransient->timeStep);
278 }
279
280 // if ( MpiInfo::rankProc() == 0 ){
281 // // m_ios[ipb]->writeMesh(m_mesh[0]);
282 // m_ios[0]->ensight().writerGeoGold(m_mesh[0], FelisceParam::instance().resultDir+"fluid.geo");
283 // m_pLinFluid->printMeshPartition(m_fstransient->iteration, m_fstransient->timeStep);
284 // }
285
286 // Advance time step.
287 updateTime();
288
289 // Print time information
290 printNewTimeIterationBanner();
291
292 ///////////////////////
293 // Update Bdf scheme //
294 ///////////////////////
295 if( m_intersectMeshes.hasIntersectionChange() || m_reinitializeFluidBdf || m_fstransient->iteration == 1 ) {
296 // initialize the bdf for the fluid
297 PetscVector zero = PetscVector::null();
298 felInt order = FelisceParam::instance().orderBdfNS;
299 if( order == 1 )
300 m_bdfFluid.reinitialize(FelisceParam::instance().orderBdfNS, m_pLinFluid->solutionOld(0), zero, zero);
301 else if( order == 2 )
302 m_bdfFluid.reinitialize(FelisceParam::instance().orderBdfNS, m_pLinFluid->solutionOld(1), m_pLinFluid->solutionOld(0), zero);
303 else
304 FEL_ERROR("This bdf order is not implemented for this problem");
305
306 // Compute the extrapolation of the velocity and initialize the one in the solver
307 m_bdfFluid.extrapolateByPart(m_parFluidVel);
308 m_pLinFluid->gatherSeqVelExtrapol(m_parFluidVel);
309
310 // Compute the rhs coming from the time scheme and initialize the one in the solver
311 m_bdfFluid.computeRHSTimeByPart(m_fstransient->timeStep, m_parFluidVel);
312 m_pLinFluid->gatherSeqBdfRHS(m_parFluidVel);
313
314 // set flag to false
315 m_reinitializeFluidBdf = false;
316 } else {
317 m_bdfFluid.update(m_pLinFluid->solution());
318
319 m_bdfFluid.extrapolateByPart(m_parFluidVel);
320 m_pLinFluid->gatherSeqVelExtrapol(m_parFluidVel);
321
322 m_bdfFluid.computeRHSTimeByPart(m_fstransient->timeStep, m_parFluidVel);
323 m_pLinFluid->gatherSeqBdfRHS(m_parFluidVel);
324 }
325
326 // clear the matrices at each sub iteration and computation of the matrix and rhs
327 m_pLinFluid->clearMatrixRHS(FlagMatrixRHS::matrix_and_rhs);
328 m_pLinFluid->vector(1).zeroEntries();
329
330 if( FelisceParam::instance().confIntersection ){
331
332 m_pLinFluid->assembleMatrixFrontPoints();
333 } else {
334 m_pLinFluid->assembleMatrixTip();
335 m_pLinFluid->assembleMatrixTipFaces();
336 }
337
338 if(FelisceParam::instance().useGhostPenalty)
339 m_pLinFluid->assembleMatrixGhostPenalty();
340
341 if(FelisceParam::instance().NSStabType == 1)
342 m_pLinFluid->assembleMatrixFaceOriented();
343
344 if( FelisceParam::instance().contactDarcy > 0 )
345 m_pLinFluid->assembleMatrixBCDarcy();
346
347 // Main assembly loop and assembly of the matrix
348 // The pattern is reduced to where values have been set till here, that is why this loop is called in last
349 m_pLinFluid->assembleMatrixRHS(MpiInfo::rankProc());
350
351 m_pLinFluid->addMatrixRHS();
352 }
353
354 /***********************************************************************************/
355 /***********************************************************************************/
356
357 void NitscheXFEMModel::solve()
358 {
359
360 // Apply boundary conditions.
361 m_pLinFluid->finalizeEssBCTransient();
362 m_pLinFluid->applyBC(FelisceParam::instance().essentialBoundaryConditionsMethod, MpiInfo::rankProc());
363
364 // Solve the linear system.
365 PetscPrintf(PETSC_COMM_WORLD, "*** Fluid solver ***\n");
366 m_pLinFluid->solve(MpiInfo::rankProc(), MpiInfo::numProc());
367
368 // Gather the solution to use it in the solid problem
369 m_pLinFluid->gatherSolution();
370
371 // evaluation stresses
372 if ( FelisceParam::verbose() )
373 PetscPrintf(MpiInfo::petscComm(),"Evaluating stress \n");
374
375 m_pLinFluid->computeInterfaceStress();
376 }
377
378 /***********************************************************************************/
379 /***********************************************************************************/
380
381 void NitscheXFEMModel::solveLinearized(bool linearFlag)
382 {
383
384 m_pLinFluid->printSkipVolume(false);
385
386 m_linearProblem[0]->linearizedFlag() = linearFlag;
387
388 m_linearProblem[0]->vector().zeroEntries();
389 m_pLinFluid->vector(1).zeroEntries();
390
391 m_linearProblem[0]->assembleMatrixRHS(MpiInfo::rankProc(),FlagMatrixRHS::only_rhs);
392
393 if ( !linearFlag )
394 m_linearProblem[0]->addMatrixRHS();
395
396 if ( linearFlag && FelisceParam::verbose() )
397 PetscPrintf(MpiInfo::petscComm(),"NS linearized solver \n");
398 else if ( FelisceParam::verbose() )
399 PetscPrintf(MpiInfo::petscComm(),"NS solver \n");
400
401 if ( FelisceParam::verbose() )
402 PetscPrintf(MpiInfo::petscComm(),"Applying BC \n");
403
404 //Apply essential transient boundary conditions.
405 m_linearProblem[0]->finalizeEssBCTransient();
406
407 if ( linearFlag ) // only Dirichlet BC is applied (RHS)
408 m_linearProblem[0]->applyBC(FelisceParam::instance().essentialBoundaryConditionsMethod,
409 MpiInfo::rankProc(), FlagMatrixRHS::only_rhs, FlagMatrixRHS::only_rhs,
410 0, true, ApplyNaturalBoundaryConditions::no);
411 else // all BC applied (RHS):
412 m_linearProblem[0]->applyBC(FelisceParam::instance().essentialBoundaryConditionsMethod,
413 MpiInfo::rankProc(), FlagMatrixRHS::only_rhs, FlagMatrixRHS::only_rhs,
414 0, true, ApplyNaturalBoundaryConditions::yes);
415
416 if ( linearFlag && FelisceParam::verbose() )
417 PetscPrintf(MpiInfo::petscComm(),"Solving linearized NS system (same matrix) \n");
418 else if ( FelisceParam::verbose() )
419 PetscPrintf(MpiInfo::petscComm(),"Solving NS system (same matrix) \n");
420
421 m_linearProblem[0]->solveWithSameMatrix();
422
423 m_linearProblem[0]->gatherSolution();
424
425 if ( FelisceParam::verbose() )
426 PetscPrintf(MpiInfo::petscComm(),"Evaluating stress \n");
427
428 m_pLinFluid->computeInterfaceStress();
429
430 m_pLinFluid->printSkipVolume(true);
431 }
432
433 /***********************************************************************************/
434 /***********************************************************************************/
435
436 void NitscheXFEMModel::writeSolutionAndMeshes()
437 {
438
439 if( (m_fstransient->iteration % FelisceParam::instance().frequencyWriteSolution == 0) ) {
440
441 // write the mesh
442 if(FelisceParam::verbose()>1)
443 PetscPrintf(MpiInfo::petscComm(),"Write meshes\n");
444
445 std::map<felInt, std::vector<felInt> > refToListOfIds;
446 std::string fileName;
447 std::string indexFile;
448
449 std::size_t ipb=0;
450 for(std::size_t iUnknown=0; iUnknown<m_linearProblem[ipb]->listUnknown().size(); ++iUnknown) {
451 std::stringstream oss;
452 oss << m_indexTime;
453 if(m_indexTime < 10)
454 indexFile = "0000" + oss.str();
455 else if(m_indexTime < 100)
456 indexFile = "000" + oss.str();
457 else if(m_indexTime < 1000)
458 indexFile = "00" + oss.str();
459 else if(m_indexTime < 10000)
460 indexFile = "0" + oss.str();
461 else
462 indexFile = oss.str();
463
464 fileName = FelisceParam::instance().resultDir+FelisceParam::instance().outputMesh[0]+"."+indexFile+".geo";
465
466 // fluid, write mesh from the support dof to see the duplication
467 if(iUnknown == 0) {
468 // write the mesh only once (with the velocity, the pressure mesh is the same)
469 if(FelisceParam::instance().outputFileFormat == 0){
470 m_linearProblem[ipb]->writeGeoForUnknown(iUnknown, fileName);
471 }
472 else if(FelisceParam::instance().outputFileFormat == 1) {
473 m_linearProblem[ipb]->writeGeoForUnknownEnsightGold(iUnknown, refToListOfIds, fileName);
474 m_ios[0]->ensight().setRefToListOfIds(refToListOfIds);
475 }
476 else
477 FEL_ERROR("Unknown output file format");
478 }
479 }
480 m_meshIsWritten = true;
481 ++m_indexTime;
482
483 // write the solutions
484 if(FelisceParam::verbose() > 1)
485 PetscPrintf(MpiInfo::petscComm(),"Write solutions\n");
486
487 m_linearProblem[ipb]->writeSolution(MpiInfo::rankProc(), m_ios, m_fstransient->time, m_fstransient->iteration);
488
489 if (MpiInfo::rankProc() == 0)
490 m_pLinFluid->writeDuplication(MpiInfo::rankProc(), *m_ios[0], m_fstransient->time, m_fstransient->iteration);
491
492 if (MpiInfo::rankProc() == 0) {
493 for(std::size_t iio=0; iio<m_ios.size(); ++iio) {
494 if(m_ios[iio]->typeOutput == 1 ) // 1 : ensight
495 m_ios[iio]->postProcess(m_fstransient->time, 2);
496 }
497 }
498 }
499
500 if(FelisceParam::verbose()>1)
501 PetscPrintf(MpiInfo::petscComm(),"End Write meshes\n");
502 }
503
504 }
505