Directory: | ./ |
---|---|
File: | Solver/linearProblem_template.hpp |
Date: | 2024-04-14 07:32:34 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 47 | 128 | 36.7% |
Branches: | 36 | 160 | 22.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 | #ifndef LINEARPROBLEM_TPP | ||
16 | #define LINEARPROBLEM_TPP | ||
17 | |||
18 | #ifndef LINEARPROBLEM_HPP | ||
19 | #error Include linearProblem.hpp instead | ||
20 | #endif | ||
21 | |||
22 | namespace felisce | ||
23 | { | ||
24 | /*! | ||
25 | \brief This function is a GENERIC ASSEMBLY LOOP on the boundary elements on a certain list of labels | ||
26 | |||
27 | \param[in] functionOfTheLoop is the function that actually do the computation element-wise | ||
28 | \param[in] labels a std::vector containing a list of integer labels where we want to loop | ||
29 | \param[in] a function to initialize for each element-type (typically to initialize the FE) | ||
30 | \param[in] updatefunction it could be implemented into the functionOfTheLoop, but like this is more general when dealing with duplicated supportDof | ||
31 | |||
32 | |||
33 | For several examples on how to use this class check linearProblemNSSimplifiedFSI.hpp | ||
34 | |||
35 | |||
36 | The template parameter theClass is going to be the class where the different functions are implemented. | ||
37 | |||
38 | // Nerd alert! | ||
39 | | I think that it is possible to avoid using a template by using some new binding techniques of c++11 to wrap | ||
40 | | the function of the class into functions not belonging to any particular class. (i.e. by a creating a free-function from a class function) | ||
41 | | | ||
42 | | The problem is that I can not simply declare void (*functionOfTheLoop)( felInt ), because the class of a | ||
43 | | a member function is like the first argument of the function itself and it therefore alters the signature (I guess..) | ||
44 | | | ||
45 | | The main drawback of this implementation is that I am not sure you can call this function directly with | ||
46 | | methods of different class, maybe if they belong to the same hierarchy is going to work. | ||
47 | // | ||
48 | */ | ||
49 | template<class theClass> | ||
50 | 1056 | void LinearProblem::assemblyLoopBoundaryGeneral( void (theClass::*functionOfTheLoop)( felInt ), | |
51 | const std::vector<felInt> & labels, | ||
52 | void (theClass::*initPerElementType)(), | ||
53 | void (theClass::*updateFunction)(const std::vector<Point*>&,const std::vector<int>&)) { | ||
54 | |||
55 | // some useful vector | ||
56 | 1056 | std::vector<Point*> elemPoint; | |
57 | 1056 | std::vector<felInt> elemIdPoint; | |
58 | 1056 | std::vector<felInt> vectorIdSupport; | |
59 | |||
60 | //to improve readability | ||
61 | 1056 | const std::vector<ElementType>& bagElementTypeDomainBoundary = m_meshLocal[m_currentMesh]->bagElementTypeDomainBoundary(); | |
62 | |||
63 | //initialization of the counter numElement | ||
64 | felInt numElement[ GeometricMeshRegion::m_numTypesOfElement ]; //std::vector of size 23 number of the different type of elements | ||
65 |
2/2✓ Branch 0 taken 13200 times.
✓ Branch 1 taken 528 times.
|
27456 | for (int ityp=0; ityp < GeometricMeshRegion::m_numTypesOfElement; ityp++ ) { |
66 | 26400 | numElement[ityp]=0; | |
67 | } | ||
68 | |||
69 | //========loop on the element type of boundary (e.g. triangles..not a real loop) | ||
70 |
2/2✓ Branch 1 taken 528 times.
✓ Branch 2 taken 528 times.
|
2112 | for (std::size_t i = 0; i < bagElementTypeDomainBoundary.size(); ++i) { |
71 | |||
72 | 1056 | ElementType eltType = bagElementTypeDomainBoundary[i]; | |
73 |
1/2✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
|
1056 | defineCurvilinearFiniteElement(eltType); |
74 |
1/2✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
|
1056 | initElementArrayBD(); |
75 | |||
76 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 528 times.
✓ Branch 3 taken 528 times.
✗ Branch 4 not taken.
|
1056 | (static_cast<theClass*>(this)->*initPerElementType)(); |
77 | |||
78 | 1056 | int numPointPerElt = GeometricMeshRegion::m_numPointsPerElt[eltType]; | |
79 |
1/2✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
|
1056 | elemPoint.resize(numPointPerElt, nullptr); |
80 |
1/2✓ Branch 1 taken 528 times.
✗ Branch 2 not taken.
|
1056 | elemIdPoint.resize(numPointPerElt, 0); |
81 | |||
82 | //=======loop on subregion of the surface, with different labels. | ||
83 | 1056 | for(auto itRef = m_meshLocal[m_currentMesh]->intRefToBegEndMaps[eltType].begin(); | |
84 |
2/2✓ Branch 5 taken 1716 times.
✓ Branch 6 taken 528 times.
|
4488 | itRef != m_meshLocal[m_currentMesh]->intRefToBegEndMaps[eltType].end(); itRef++) { |
85 | 3432 | int currentLabel = itRef->first; | |
86 | 3432 | int numEltPerLabel = itRef->second.second; | |
87 | |||
88 |
3/4✓ Branch 4 taken 1716 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 1068 times.
✓ Branch 8 taken 648 times.
|
3432 | if ( std::find( labels.begin(), labels.end(), currentLabel) != labels.end() ) { |
89 |
2/2✓ Branch 0 taken 654528 times.
✓ Branch 1 taken 1068 times.
|
1311192 | for ( felInt iel = 0; iel < numEltPerLabel; iel++) { |
90 | // return each id of point of the element and coordinate in two arrays: | ||
91 | // elemPoint and elemIdPoint. | ||
92 |
1/2✓ Branch 1 taken 654528 times.
✗ Branch 2 not taken.
|
1309056 | setElemPoint(eltType, numElement[eltType], elemPoint, elemIdPoint, vectorIdSupport); |
93 | |||
94 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 654528 times.
✓ Branch 3 taken 654528 times.
✗ Branch 4 not taken.
|
1309056 | (static_cast<theClass*>(this)->*updateFunction)(elemPoint,elemIdPoint); |
95 | |||
96 | // loop over all the support elements | ||
97 |
2/2✓ Branch 1 taken 654528 times.
✓ Branch 2 taken 654528 times.
|
2618112 | for (std::size_t it = 0; it < vectorIdSupport.size(); it++) { |
98 | // get the id of the support | ||
99 | 1309056 | felInt ielSupportDof = vectorIdSupport[it]; | |
100 | |||
101 |
2/4✗ Branch 0 not taken.
✓ Branch 1 taken 654528 times.
✓ Branch 3 taken 654528 times.
✗ Branch 4 not taken.
|
1309056 | (static_cast<theClass*>(this)->*functionOfTheLoop)(ielSupportDof); |
102 | } | ||
103 | 1309056 | numElement[eltType]++; | |
104 | } | ||
105 | } else { | ||
106 | 1296 | numElement[eltType] += numEltPerLabel; | |
107 | } | ||
108 | } | ||
109 | } | ||
110 | } | ||
111 | |||
112 | |||
113 | /*! \brief this function assemble the mass matrix at the boundary. | ||
114 | * And the KSP | ||
115 | */ | ||
116 | #ifdef FELISCE_WITH_CVGRAPH | ||
117 | template<class theClass> | ||
118 | ✗ | void LinearProblem::assembleMassBoundaryAndInitKSP( void (theClass::*functionOfTheLoop)( felInt ), | |
119 | const std::vector<felInt> & labels, | ||
120 | void (theClass::*initPerElementType)(), | ||
121 | void (theClass::*updateFunction)(const std::vector<Point*>&,const std::vector<int>&), | ||
122 | std::size_t iConn ) | ||
123 | { | ||
124 | ✗ | this->m_dofBD[iConn].allocateMatrixOnBoundary( m_massBD[iConn] ); | |
125 | ✗ | m_auxiliaryMatrix=m_massBD[iConn]; | |
126 | ✗ | m_auxiliaryDofBD = &(this->dofBD(iConn)); | |
127 | ✗ | if ( m_auxiliaryDofBD->hasDofsOnBoundary() ) { | |
128 | ✗ | this->assemblyLoopBoundaryGeneral( functionOfTheLoop, | |
129 | labels, | ||
130 | initPerElementType, | ||
131 | updateFunction); | ||
132 | ✗ | m_globPosColumn.clear(); | |
133 | ✗ | m_globPosRow.clear(); | |
134 | ✗ | m_matrixValues.clear(); | |
135 | |||
136 | ✗ | m_massBD[iConn].assembly(MAT_FINAL_ASSEMBLY); | |
137 | ✗ | if ( FelisceParam::instance().exportMassMatrix ) { | |
138 | ✗ | m_massBD[iConn].saveInBinaryFormat( this->m_dofBD[iConn].comm(), "Mass", FelisceParam::instance().resultDir); | |
139 | } | ||
140 | } | ||
141 | // Better to put it since m_auxiliaryMatrix will stay alive as long as the linear problem, | ||
142 | // while we would like to deallocate this matrix when the mass matrix gets out of scope | ||
143 | ✗ | m_auxiliaryMatrix.destroy(); | |
144 | ✗ | if ( m_auxiliaryDofBD->hasDofsOnBoundary() ) { | |
145 | ✗ | m_kspMassBD[iConn].init(this->dofBD(iConn).comm()); | |
146 | |||
147 | // Setting the type, the GMRES restart, the PC type, tolerances,... | ||
148 | ✗ | const auto& r_instance = FelisceParam::instance(this->instanceIndex()); | |
149 | ✗ | const std::string solver = r_instance.solver[m_identifier_solver]; | |
150 | ✗ | const std::string preconditioner = r_instance.preconditioner[m_identifier_solver]; | |
151 | ✗ | const double relativeTolerance = r_instance.relativeTolerance[m_identifier_solver]; | |
152 | ✗ | const double absoluteTolerance = r_instance.absoluteTolerance[m_identifier_solver]; | |
153 | ✗ | const int maxIteration = r_instance.maxIteration[m_identifier_solver]; | |
154 | ✗ | const int gmresRestart = r_instance.gmresRestart[m_identifier_solver]; | |
155 | ✗ | const bool initPrevSolution = r_instance.initSolverWithPreviousSolution[m_identifier_solver]; | |
156 | ✗ | const std::string preconOptions = r_instance.setPreconditionerOption[m_identifier_solver]; | |
157 | ✗ | m_kspMassBD[iConn].setKSPandPCType(solver, preconditioner); | |
158 | ✗ | m_kspMassBD[iConn].setTolerances(relativeTolerance, absoluteTolerance, maxIteration, gmresRestart); | |
159 | ✗ | m_kspMassBD[iConn].setKSPOptions(solver, initPrevSolution); | |
160 | ✗ | m_kspMassBD[iConn].setKSPOperator(m_massBD[iConn], preconOptions); | |
161 | } | ||
162 | } | ||
163 | |||
164 | |||
165 | /*! \brief this function assemble the mass matrix at the boundary. | ||
166 | * | ||
167 | */ | ||
168 | template<class theClass> | ||
169 | ✗ | void LinearProblem::assembleMassBoundaryOnly( void (theClass::*functionOfTheLoop)( felInt ), | |
170 | const std::vector<felInt> & labels, | ||
171 | void (theClass::*initPerElementType)(), | ||
172 | void (theClass::*updateFunction)(const std::vector<Point*>&,const std::vector<int>&), | ||
173 | DofBoundary &dofBD, PetscMatrix& massMatrix ) { | ||
174 | ✗ | dofBD.allocateMatrixOnBoundary( massMatrix ); | |
175 | ✗ | m_auxiliaryMatrix = massMatrix; | |
176 | ✗ | m_auxiliaryDofBD = &dofBD; | |
177 | ✗ | if ( dofBD.hasDofsOnBoundary() ) { | |
178 | ✗ | this->assemblyLoopBoundaryGeneral( functionOfTheLoop, | |
179 | labels, | ||
180 | initPerElementType, | ||
181 | updateFunction); | ||
182 | ✗ | m_globPosColumn.clear(); | |
183 | ✗ | m_globPosRow.clear(); | |
184 | ✗ | m_matrixValues.clear(); | |
185 | |||
186 | ✗ | massMatrix.assembly(MAT_FINAL_ASSEMBLY); | |
187 | } | ||
188 | // Better to put it since m_auxiliaryMatrix will stay alive as long as the linear problem, | ||
189 | // while we would like to deallocate this matrix when the mass matrix gets out of scope | ||
190 | ✗ | m_auxiliaryMatrix.destroy(); | |
191 | } | ||
192 | #endif | ||
193 | |||
194 | |||
195 | template <class FunctorXYZ> | ||
196 | inline void LinearProblem::set_U_0(const FunctorXYZ& functorXYZ, int iUnknown, int iComponent) { | ||
197 | felInt dof = 0; | ||
198 | Point pt; | ||
199 | std::set<felInt> allDof; | ||
200 | std::vector<double> value; | ||
201 | felInt sizeDof = 0; | ||
202 | felInt sizeUpdate = 0; | ||
203 | felInt iPosGlob; | ||
204 | double val; | ||
205 | |||
206 | int idVar = m_listUnknown.idVariable(iUnknown); | ||
207 | |||
208 | for ( felInt iel = 0; iel < (felInt)supportDofUnknown(iUnknown).iEle().size() - 1; iel++) { | ||
209 | for ( int iSupport = 0; iSupport < supportDofUnknown(iUnknown).getNumSupportDof(iel); iSupport++) { | ||
210 | m_dof.loc2glob(iel, iSupport, idVar, iComponent, dof); | ||
211 | allDof.insert(dof); | ||
212 | sizeUpdate = allDof.size(); | ||
213 | if ( sizeUpdate > sizeDof ) { | ||
214 | pt = supportDofUnknown(iUnknown).listNode()[supportDofUnknown(iUnknown).iSupportDof()[supportDofUnknown(iUnknown).iEle()[iel] + iSupport ]]; | ||
215 | val = functorXYZ(pt.x(), pt.y(), pt.z()); | ||
216 | iPosGlob = dof; | ||
217 | AOApplicationToPetsc(m_ao, 1, &iPosGlob); | ||
218 | m_seqSol.setValues( 1, &iPosGlob, &val, INSERT_VALUES); | ||
219 | m_sol.setValues( 1, &iPosGlob, &val, INSERT_VALUES); | ||
220 | } | ||
221 | sizeDof = allDof.size(); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | m_seqSol.assembly(); | ||
226 | m_sol.assembly(); | ||
227 | } | ||
228 | |||
229 | template <class FunctorXYZ> | ||
230 | 8 | inline void LinearProblem::set_U_0_parallel(const FunctorXYZ& functorXYZ, int iUnknown, int iComponent) | |
231 | { | ||
232 | 8 | const int sizeLocal = m_numDofLocalUnknown[iUnknown]; | |
233 | 8 | const int idVar = m_listUnknown.idVariable(iUnknown); | |
234 | 8 | const int numCompOfVariable = m_listVariable[idVar].numComponent(); | |
235 | felInt indexGlobal; | ||
236 | Point pt; | ||
237 | |||
238 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | std::vector<double> valueForPETSC(sizeLocal); |
239 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | std::vector<felInt> idGlobalValue(sizeLocal,0); |
240 |
1/2✓ Branch 2 taken 8 times.
✗ Branch 3 not taken.
|
8 | std::vector<felInt> idLocalValue(sizeLocal); |
241 | 8 | std::iota(idLocalValue.begin(), idLocalValue.end(), 0); | |
242 | |||
243 |
1/2✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
|
8 | ISLocalToGlobalMappingApply(m_mappingIdLocalDofPerUnknownToIdGlobalDofPetsc[iUnknown], sizeLocal, idLocalValue.data(), idGlobalValue.data()); |
244 | |||
245 |
2/2✓ Branch 0 taken 8450 times.
✓ Branch 1 taken 8 times.
|
8458 | for (felInt i = iComponent; i < sizeLocal; i+=numCompOfVariable) { |
246 | 8450 | indexGlobal = idGlobalValue[i]; | |
247 |
1/2✓ Branch 1 taken 8450 times.
✗ Branch 2 not taken.
|
8450 | AOPetscToApplication(m_ao,1,&indexGlobal); |
248 |
1/2✓ Branch 1 taken 8450 times.
✗ Branch 2 not taken.
|
8450 | findCoordinateWithIdDof(indexGlobal,pt); |
249 | 8450 | valueForPETSC[i] = functorXYZ(pt.x(), pt.y(), pt.z()); | |
250 | } | ||
251 | |||
252 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | m_seqSol.setValues(sizeLocal, idGlobalValue.data(), valueForPETSC.data(), ADD_VALUES); |
253 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | m_seqSol.assembly(); |
254 |
1/2✓ Branch 3 taken 8 times.
✗ Branch 4 not taken.
|
8 | m_sol.setValues(sizeLocal, idGlobalValue.data(), valueForPETSC.data(), ADD_VALUES); |
255 |
1/2✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
|
8 | m_sol.assembly(); |
256 | 8 | } | |
257 | |||
258 | ✗ | template <class Templ_functor> void LinearProblem::evalFunctionOnDof(const Templ_functor& func, std::vector<double>& array) { | |
259 | Point pt; | ||
260 | ✗ | array.resize(m_numDof); | |
261 | felInt position; | ||
262 | ✗ | for( felInt i = 0; i < m_numDof; i++) { | |
263 | ✗ | findCoordinateWithIdDof(i,pt); | |
264 | ✗ | position = i; | |
265 | ✗ | AOApplicationToPetsc(m_ao,1,&position); | |
266 | ✗ | array[position] = func(pt.x(),pt.y(),pt.z()); | |
267 | } | ||
268 | } | ||
269 | |||
270 | // Warning: extraData size has to be numDof (not number of mesh points). | ||
271 | ✗ | template <class Templ_functor> void LinearProblem::evalFunctionOnDof(const Templ_functor& func, std::vector<double>& array, std::vector<double>& extraData) { | |
272 | Point pt; | ||
273 | ✗ | array.resize(m_numDof); | |
274 | felInt position; | ||
275 | ✗ | for( felInt i = 0; i < m_numDof; i++) { | |
276 | ✗ | findCoordinateWithIdDof(i,pt); | |
277 | ✗ | position = i; | |
278 | ✗ | AOApplicationToPetsc(m_ao,1,&position); | |
279 | ✗ | array[position] = func(pt.x(),pt.y(),pt.z(),extraData[i]); | |
280 | } | ||
281 | } | ||
282 | |||
283 | // Warning: extraData size has to be numDof (not number of mesh points). | ||
284 | ✗ | template <class Templ_functor> void LinearProblem::evalFunctionOnDof(const Templ_functor& func, std::vector<int>& array, std::vector<double>& extraData) { | |
285 | Point pt; | ||
286 | ✗ | array.resize(m_numDof); | |
287 | felInt position; | ||
288 | ✗ | for( felInt i = 0; i < m_numDof; i++) { | |
289 | ✗ | findCoordinateWithIdDof(i,pt); | |
290 | ✗ | position = i; | |
291 | ✗ | AOApplicationToPetsc(m_ao,1,&position); | |
292 | ✗ | array[position] = func(pt.x(),pt.y(),pt.z(),extraData[i]); | |
293 | } | ||
294 | } | ||
295 | |||
296 | ✗ | template <class Templ_functor> void LinearProblem::evalFunctionOnDof(const Templ_functor& func,double time, std::vector<double>& array) { | |
297 | Point pt; | ||
298 | ✗ | array.resize(m_numDof); | |
299 | felInt position; | ||
300 | ✗ | for( felInt i = 0; i < m_numDof; i++) { | |
301 | ✗ | findCoordinateWithIdDof(i,pt); | |
302 | ✗ | position = i; | |
303 | ✗ | AOApplicationToPetsc(m_ao,1,&position); | |
304 | ✗ | array[position] = func(pt.x(),pt.y(),pt.z(),time); | |
305 | } | ||
306 | } | ||
307 | |||
308 | // Warning: extraData size has to be numDof (not number of mesh points). | ||
309 | ✗ | template <class Templ_functor> void LinearProblem::evalFunctionOnDof(const Templ_functor& func, std::vector<double>& array, std::vector<double>& extraData,double time) { | |
310 | Point pt; | ||
311 | ✗ | array.resize(m_numDof); | |
312 | felInt position; | ||
313 | ✗ | for( felInt i = 0; i < m_numDof; i++) { | |
314 | ✗ | findCoordinateWithIdDof(i,pt); | |
315 | ✗ | position = i; | |
316 | ✗ | AOApplicationToPetsc(m_ao,1,&position); | |
317 | ✗ | array[position] = func(pt.x(),pt.y(),pt.z(),extraData[i],time); | |
318 | } | ||
319 | } | ||
320 | |||
321 | // Warning: extraData size has to be numDof (not number of mesh points). | ||
322 | ✗ | template <class Templ_functor> void LinearProblem::evalFunctionOnDof(const Templ_functor& func,double time, std::vector<double>& array, std::vector<double>& extraData) { | |
323 | Point pt; | ||
324 | ✗ | array.resize(m_numDof); | |
325 | felInt position; | ||
326 | ✗ | for( felInt i = 0; i < m_numDof; i++) { | |
327 | ✗ | findCoordinateWithIdDof(i,pt); | |
328 | ✗ | position = i; | |
329 | ✗ | AOApplicationToPetsc(m_ao,1,&position); | |
330 | ✗ | array[position] = func(pt.x(),pt.y(),pt.z(),time,extraData[i]); | |
331 | } | ||
332 | } | ||
333 | |||
334 | template <class Templ_functor> void LinearProblem::evalFunctionOnDof(const Templ_functor& func,int iComp, std::vector<double>& array) { | ||
335 | Point pt; | ||
336 | array.resize(m_numDof); | ||
337 | felInt position; | ||
338 | for( felInt i = 0; i < m_numDof; i++) { | ||
339 | findCoordinateWithIdDof(i,pt); | ||
340 | position = i; | ||
341 | AOApplicationToPetsc(m_ao,1,&position); | ||
342 | array[position] = func(iComp,pt.x(),pt.y(),pt.z()); | ||
343 | } | ||
344 | } | ||
345 | |||
346 | template <class Templ_functor> void LinearProblem::evalFunctionWithCompOnDof(const Templ_functor& func,std::vector<double>& array) { | ||
347 | Point pt; | ||
348 | for( felInt i = 0; i < m_numDof; i++) { | ||
349 | findCoordinateWithIdDof(i,pt); | ||
350 | for( int iComp = 0; iComp < 3; iComp++) { // change '3' to a m_numComp | ||
351 | array.push_back(func(iComp,pt.x(),pt.y(),pt.z())); | ||
352 | } | ||
353 | } | ||
354 | } | ||
355 | } | ||
356 | |||
357 | #endif // LINEAR_PROBLEM_TPP | ||
358 |