Directory: | ./ |
---|---|
File: | Solver/linearProblemReducedSteklov.hxx |
Date: | 2024-04-14 07:32:34 |
Exec | Total | Coverage | |
---|---|---|---|
Lines: | 111 | 304 | 36.5% |
Branches: | 105 | 659 | 15.9% |
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: | ||
13 | // | ||
14 | |||
15 | // System includes | ||
16 | |||
17 | // External includes | ||
18 | |||
19 | // Project includes | ||
20 | #include "FiniteElement/elementMatrix.hpp" | ||
21 | #include "Core/felisceTransient.hpp" | ||
22 | #include "Geometry/curvatures.hpp" | ||
23 | #include "Solver/steklovBanner.hpp" | ||
24 | |||
25 | namespace felisce { | ||
26 | |||
27 | // ====================================================================== | ||
28 | // the public methods | ||
29 | // ====================================================================== | ||
30 | /* \brief Constructor | ||
31 | */ | ||
32 | template <class volumeProblem> | ||
33 | 4 | LinearProblemReducedSteklov<volumeProblem>::LinearProblemReducedSteklov(): | |
34 | volumeProblem(), | ||
35 | 4 | m_reducedSteklov(nullptr), | |
36 |
4/8✓ Branch 6 taken 4 times.
✗ Branch 7 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
✓ Branch 17 taken 4 times.
✗ Branch 18 not taken.
✓ Branch 20 taken 4 times.
✗ Branch 21 not taken.
|
4 | m_chronoRS(nullptr) |
37 | { | ||
38 | 4 | m_imgType=dirichlet; // Default value is Dirichlet, but it can be changed in derived classes. | |
39 | 4 | } | |
40 | |||
41 | /*! \brief Destructor | ||
42 | * | ||
43 | * We destroy the reducedSteklov class | ||
44 | */ | ||
45 | template <class volumeProblem> | ||
46 | 8 | LinearProblemReducedSteklov<volumeProblem>::~LinearProblemReducedSteklov(){ | |
47 | 8 | if ( m_reducedSteklov ) | |
48 | ✗ | delete m_reducedSteklov; | |
49 | } | ||
50 | |||
51 | /* \brief Function to assemble the system of the volume problem | ||
52 | * Matrix and Boundary Conditions | ||
53 | */ | ||
54 | template <class volumeProblem> | ||
55 | void | ||
56 | 656 | LinearProblemReducedSteklov<volumeProblem>::assembleVolumeSystem( FlagMatrixRHS flag ) { | |
57 | 656 | this->assembleMatrixRHS(MpiInfo::rankProc(), flag ); | |
58 | 656 | this->derivedProblemAssemble(flag); | |
59 |
1/4✗ Branch 0 not taken.
✓ Branch 1 taken 328 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
|
656 | if ( m_imgType == neumann && !( flag == FlagMatrixRHS::only_rhs ) ) { |
60 | ✗ | this->createAndCopyMatrixRHSWithoutBC(); | |
61 | } | ||
62 | 656 | this->finalizeEssBCTransient(); | |
63 | 656 | this->applyBC( FelisceParam::instance().essentialBoundaryConditionsMethod, MpiInfo::rankProc(), flag, flag ); | |
64 | } | ||
65 | /*! \brief Computation/Loading of the real (Full rank) Steklov operator | ||
66 | * | ||
67 | * this function compute the Steklov-Poincare operator | ||
68 | * the idea is to solve N times the volume problem | ||
69 | * where N is the dimension of the interface | ||
70 | * each time the data is computed via dirac delta in a different dof | ||
71 | */ | ||
72 | template <class volumeProblem> | ||
73 | void | ||
74 | 4 | LinearProblemReducedSteklov<volumeProblem>::assembleFullRankSteklov() { | |
75 | 4 | this->initChronoRS(); | |
76 | //! We allocate the (dense) matrix for the Steklov operator | ||
77 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { |
78 | 4 | m_fullSteklov.createDense(this->m_dofBD[0/*iBD*/].comm(), | |
79 | 4 | /*local row size*/ this->m_dofBD[0/*iBD*/].numLocalDofInterface(), | |
80 | 4 | /*local col size*/ this->m_dofBD[0/*iBD*/].numLocalDofInterface(), | |
81 | 4 | /*global row size*/ this->m_dofBD[0/*iBD*/].numGlobalDofInterface(), | |
82 | 4 | /*global col size*/ this->m_dofBD[0/*iBD*/].numGlobalDofInterface(), | |
83 | /*where to allocate the matrix*/FELISCE_PETSC_NULLPTR); | ||
84 | 4 | m_fullSteklov.setFromOptions(); | |
85 | } | ||
86 | |||
87 | //! The operator is computed via the solution of the volume problem. | ||
88 | //! this operator is obviously skipped when the operator is loaded from file. | ||
89 |
1/3✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | switch ( FelisceParam::instance().optionForSteklov ) { |
90 | ✗ | case LOAD_IT: | |
91 | ✗ | break; | |
92 | 4 | case COMPUTE_IT: | |
93 | case COMPUTE_AND_SAVE_IT: | ||
94 | { | ||
95 | // we raise this flag to use correctly the boundary conditions | ||
96 | // function | ||
97 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | this->useSteklovDataBegin(); |
98 | |||
99 | //! We use a banner object to handle the comunications on the screen of this function | ||
100 | //! and to improve readibility | ||
101 |
2/4✓ Branch 3 taken 4 times.
✗ Branch 4 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
|
4 | steklovBanner banner(this->m_dofBD[0/*iBD*/].numLocalDofInterface(), MpiInfo::rankProc(), this->m_dofBD[0/*iBD*/].comm()); |
102 | |||
103 | |||
104 | // We switch off the verbosity of the KSP | ||
105 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | FelisceParam::linearSolverVerboseOFF(); |
106 | |||
107 | // We assemble the matrix of the linearProblem ( the volume matrix ) | ||
108 | // including the informations needed for the BC | ||
109 | // the flag is std::set to only_matrix since we want to build just the matrix | ||
110 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | this->clearMatrixRHS( FlagMatrixRHS::only_matrix ); |
111 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | this->assembleVolumeSystem( FlagMatrixRHS::only_matrix ); |
112 | |||
113 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | banner.initComputation(); |
114 | std::size_t idDofGlobalApplication, idDofGlobalVolumePetsc; | ||
115 |
3/4✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 324 times.
✓ Branch 6 taken 4 times.
|
328 | for ( idDofGlobalApplication=0; idDofGlobalApplication < this->m_dofBD[0/*iBD*/].numGlobalDofInterface(); ++idDofGlobalApplication, ++banner) { |
116 |
1/2✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
|
324 | this->clearMatrixRHS( FlagMatrixRHS::only_rhs ); |
117 | // retrieving the correct volume indeces | ||
118 | 324 | idDofGlobalVolumePetsc=this->m_dofBD[0/*iBD*/].globBD2PetscVol(idDofGlobalApplication); | |
119 | 324 | felInt idDofGlobalVolumeApplication = idDofGlobalVolumePetsc; | |
120 | 324 | felInt idDofGlobalPetsc = idDofGlobalApplication; | |
121 |
1/2✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
|
324 | AOPetscToApplication(this->m_ao,1,&idDofGlobalVolumeApplication); |
122 |
1/2✓ Branch 3 taken 324 times.
✗ Branch 4 not taken.
|
324 | AOApplicationToPetsc(this->m_dofBD[0/*iBD*/].ao(), 1, &idDofGlobalPetsc); |
123 | |||
124 | // creating the correct data steklov | ||
125 |
3/6✓ Branch 2 taken 324 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 324 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 324 times.
✗ Branch 9 not taken.
|
324 | this->m_vecs.Get("dataSteklov").set(0.0); |
126 |
3/4✓ Branch 2 taken 324 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 81 times.
✓ Branch 5 taken 243 times.
|
324 | if ( this->m_dofPart[idDofGlobalVolumeApplication] == MpiInfo::rankProc() ) { |
127 |
3/6✓ Branch 2 taken 81 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 81 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 81 times.
✗ Branch 9 not taken.
|
81 | this->m_vecs.Get("dataSteklov").setValue(idDofGlobalVolumePetsc, /* value */ 1., INSERT_VALUES); |
128 | } | ||
129 |
3/6✓ Branch 2 taken 324 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 324 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 324 times.
✗ Branch 9 not taken.
|
324 | this->m_vecs.Get("dataSteklov").assembly(); |
130 |
5/10✓ Branch 2 taken 324 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 324 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 324 times.
✗ Branch 10 not taken.
✓ Branch 12 taken 324 times.
✗ Branch 13 not taken.
✓ Branch 15 taken 324 times.
✗ Branch 16 not taken.
|
324 | this->gatherVector(this->m_vecs.Get("dataSteklov"),this->m_seqVecs.Get("dataSteklov")); |
131 | |||
132 | //Problem solution | ||
133 |
1/2✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
|
324 | this->assembleVolumeSystem( FlagMatrixRHS::only_rhs ); |
134 | |||
135 | 324 | m_chronoRS->start(); | |
136 |
3/6✓ Branch 1 taken 324 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 324 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 324 times.
✗ Branch 8 not taken.
|
324 | this->solve( MpiInfo::rankProc(), MpiInfo::numProc() ); |
137 |
1/2✓ Branch 2 taken 324 times.
✗ Branch 3 not taken.
|
324 | m_chronoRS->stop(); |
138 | |||
139 |
1/2✓ Branch 2 taken 324 times.
✗ Branch 3 not taken.
|
324 | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { |
140 |
1/2✓ Branch 7 taken 324 times.
✗ Branch 8 not taken.
|
324 | this->solution().getValues(this->m_dofBD[0/*iBD*/].numLocalDofInterface(), this->m_dofBD[0/*iBD*/].loc2PetscVolPtr(), m_tmpValues.data()); |
141 |
1/2✓ Branch 6 taken 324 times.
✗ Branch 7 not taken.
|
324 | m_fullSteklov.setValues(/*nb rows*/this->m_dofBD[0/*iBD*/].numLocalDofInterface(),/*id rows*/this->m_dofBD[0/*iBD*/].loc2PetscBDPtr(), /*nb cols*/ 1,/*id cols*/ &idDofGlobalPetsc , m_tmpValues.data(), INSERT_VALUES); |
142 | } | ||
143 | } | ||
144 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { |
145 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | m_fullSteklov.assembly(MAT_FINAL_ASSEMBLY); |
146 | } | ||
147 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | banner.finalizeComputation(); |
148 | |||
149 | // restoring the normal state | ||
150 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | FelisceParam::linearSolverVerboseON(); |
151 |
1/2✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
|
4 | this->useSteklovDataEnd(); |
152 | } | ||
153 | 4 | break; | |
154 | ✗ | default: | |
155 | ✗ | FEL_ERROR("unrecognized option for Steklov operator"); | |
156 | } | ||
157 | |||
158 |
1/2✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
|
4 | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { |
159 |
1/4✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
4 | switch ( FelisceParam::instance().optionForSteklov ) { |
160 | ✗ | case LOAD_IT: | |
161 | { | ||
162 | ✗ | std::stringstream filename; | |
163 | ✗ | if ( FelisceParam::instance().steklovMatrixName.size() == 0 ) | |
164 | ✗ | filename << "steklov_" << MpiInfo::numProc(); | |
165 | else | ||
166 | ✗ | filename << FelisceParam::instance().steklovMatrixName << "_" << MpiInfo::numProc(); | |
167 | ✗ | m_fullSteklov.loadFromBinaryFormat(this->m_dofBD[0/*iBD*/].comm(),filename.str(),FelisceParam::instance().steklovDataDir); | |
168 | } | ||
169 | ✗ | break; | |
170 | 4 | case COMPUTE_IT: | |
171 | 4 | break; | |
172 | ✗ | case COMPUTE_AND_SAVE_IT: | |
173 | { | ||
174 | ✗ | std::stringstream filename; | |
175 | ✗ | filename << "steklov_" << MpiInfo::numProc(); | |
176 | ✗ | m_fullSteklov.saveInBinaryFormat(this->m_dofBD[0/*iBD*/].comm(),filename.str(),FelisceParam::instance().steklovDataDir); | |
177 | } | ||
178 | ✗ | break; | |
179 | } | ||
180 | } | ||
181 |
2/6✗ Branch 1 not taken.
✓ Branch 2 taken 4 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
✓ Branch 8 taken 4 times.
|
4 | if ( FelisceParam::instance().exportSteklovMatrix && this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { |
182 | ✗ | m_fullSteklov.saveInBinaryFormat(this->m_dofBD[0/*iBD*/].comm(),"Steklov",FelisceParam::instance().resultDir); | |
183 | } | ||
184 | 4 | } | |
185 | /*! \brief Computation of the Reduced Order (Ro) Steklov operator. | ||
186 | * | ||
187 | * The function provides an approximation of the Steklov operator. The matrix rapresentation of the operator | ||
188 | * is never computated. The action of the operator on a new input std::vector is approximated via a low rank expansion. | ||
189 | */ | ||
190 | template <class volumeProblem> | ||
191 | void | ||
192 | ✗ | LinearProblemReducedSteklov<volumeProblem>::assembleLowRankSteklov(felInt imesh){ | |
193 | ✗ | this->initChronoRS(); | |
194 | //! First the mass and the laplacian matrix on the boundary are computed. | ||
195 | ✗ | PetscMatrix mass = assembleMassBoundary(); | |
196 | ✗ | PetscMatrix laplacian = assembleLaplacianBoundary(); | |
197 | //! Then the object handling the steklov reduction techniques is created. | ||
198 | ✗ | m_reducedSteklov = new ReducedSteklov<volumeProblem>(mass, laplacian, this->m_dofBD[0/*iBD*/].comm(), this, m_imgType,m_chronoRS); | |
199 | |||
200 | ✗ | this->computeTheConstantResponse(); | |
201 | ✗ | m_reducedSteklov->addConstantResponse(this->getSteklovImg()); | |
202 | |||
203 | ✗ | if ( m_reducedSteklov->loadedFromFile() ) { | |
204 | ✗ | std::stringstream msg; | |
205 | ✗ | msg<<"Off-line basis correctly loaded."<<std::endl; | |
206 | ✗ | PetscPrintf(MpiInfo::petscComm(),"%s",msg.str().c_str()); | |
207 | ✗ | } else { | |
208 | ✗ | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { | |
209 | //! The laplacian eigen-problem on the surface is solved. | ||
210 | ✗ | m_reducedSteklov->solveLaplacianEP(); | |
211 | } | ||
212 | //! The image through the steklov operator of the laplacian eigen-std::vector is computed. | ||
213 | ✗ | m_reducedSteklov->applySteklovOperatorOnLEV(imesh); | |
214 | ✗ | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { | |
215 | //! The steklov eigenValues and eigenVectors are approximated. | ||
216 | ✗ | m_reducedSteklov->steklovEVecEstimate(); | |
217 | } | ||
218 | } | ||
219 | } | ||
220 | template <class volumeProblem> | ||
221 | void | ||
222 | ✗ | LinearProblemReducedSteklov<volumeProblem>::setSteklovData( PetscVector& bdInput ) { | |
223 | ✗ | this->m_vecs.Get("dataSteklov").set(0.0); | |
224 | ✗ | this->dofBD(/*iBD*/0).extendOnVolume( this->m_vecs.Get("dataSteklov"), bdInput ); | |
225 | ✗ | this->gatherVector( this->m_vecs.Get("dataSteklov"), this->m_seqVecs.Get("dataSteklov")); | |
226 | } | ||
227 | |||
228 | template <class volumeProblem> | ||
229 | ✗ | PetscVector LinearProblemReducedSteklov<volumeProblem>::getSteklovImg() { | |
230 | |||
231 | //! Initialization | ||
232 | ✗ | PetscVector bdOutput; | |
233 | ✗ | if ( m_tmpValues.size() != this->m_dofBD[0/*iBD*/].numLocalDofInterface() ) { | |
234 | ✗ | m_tmpValues.resize( this->m_dofBD[0/*iBD*/].numLocalDofInterface() ); | |
235 | } | ||
236 | |||
237 | ✗ | if ( m_imgType == dirichlet ) { | |
238 | //! Just read the data | ||
239 | ✗ | this->solution().getValues( this->m_dofBD[0/*iBD*/].numLocalDofInterface(), this->m_dofBD[0/*iBD*/].loc2PetscVolPtr(), m_tmpValues.data()); | |
240 | ✗ | } else if (m_imgType == neumann) { | |
241 | //! Compute the residual | ||
242 | ✗ | this->computeResidual(); | |
243 | //! And read the data inside | ||
244 | ✗ | this->m_residual.scale(-1); //We change the sign to be consistent with the reduce steklov class | |
245 | ✗ | this->m_residual.getValues( this->m_dofBD[0/*iBD*/].numLocalDofInterface(), this->m_dofBD[0/*iBD*/].loc2PetscVolPtr(), m_tmpValues.data()); | |
246 | ✗ | this->m_residual.scale(-1); | |
247 | } | ||
248 | ✗ | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { | |
249 | //allocation | ||
250 | ✗ | bdOutput = this->dofBD(/*iBD*/0).allocateBoundaryVector(DofBoundary::parallel); | |
251 | //std::set to zero | ||
252 | ✗ | bdOutput.set(0.0); | |
253 | //std::set of the real values | ||
254 | ✗ | bdOutput.setValues( this->m_dofBD[0/*iBD*/].numLocalDofInterface(), this->m_dofBD[0/*iBD*/].loc2PetscBDPtr(), m_tmpValues.data(), INSERT_VALUES); | |
255 | //assembly | ||
256 | ✗ | bdOutput.assembly(); | |
257 | } | ||
258 | ✗ | return bdOutput; | |
259 | } | ||
260 | |||
261 | // ====================================================================== | ||
262 | // now the privates methods | ||
263 | // ====================================================================== | ||
264 | // reader of vectors coming from different linearProblems | ||
265 | // the std::vector are stored in sequential std::vector "whereToSave" | ||
266 | // For scalar | ||
267 | template <class volumeProblem> | ||
268 | void | ||
269 | 312 | LinearProblemReducedSteklov<volumeProblem>::readerInterface( const std::map<int,std::map<int,int> > & externalMap, | |
270 | PetscVector& seqExternalVec, | ||
271 | const std::map<int,int> &mapBetweenLabels, | ||
272 | std::string whereToSave, | ||
273 | felInt iUnkWTW, // std::set to zero by default | ||
274 | felInt iCompWTW // std::set to zero by default | ||
275 | ) { | ||
276 |
1/2✓ Branch 2 taken 312 times.
✗ Branch 3 not taken.
|
312 | this->readerInterfaceComponentWise(externalMap,seqExternalVec,mapBetweenLabels,whereToSave,iUnkWTW,iCompWTW); |
277 | 312 | this->m_vecs[whereToSave].assembly(); | |
278 | 312 | this->gatherVector(this->m_vecs[whereToSave],this->m_seqVecs[whereToSave]); | |
279 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 312 times.
|
312 | if ( FelisceParam::verbose() > 0 ) { |
280 | ✗ | PetscPrintf(MpiInfo::petscComm(), "done\n"); | |
281 | } | ||
282 | 312 | } | |
283 | // For std::vector | ||
284 | template <class volumeProblem> | ||
285 | void | ||
286 | ✗ | LinearProblemReducedSteklov<volumeProblem>::readerInterface( const std::map<int, std::map<int,std::map<int,int> > > & externalMap, | |
287 | PetscVector& seqExternalVec, | ||
288 | const std::map<int,int> &mapBetweenLabels, | ||
289 | std::string whereToSave, | ||
290 | felInt iUnkWTW, | ||
291 | felInt iUCR | ||
292 | ) { | ||
293 | ✗ | for ( std::size_t iComp(0); iComp < (std::size_t) this->dimension(); ++iComp,++iUCR) { | |
294 | ✗ | this->readerInterfaceComponentWise( externalMap.at(iUCR),seqExternalVec, mapBetweenLabels, whereToSave, iUnkWTW, iComp); | |
295 | } | ||
296 | ✗ | this->m_vecs[whereToSave].assembly(); | |
297 | ✗ | this->gatherVector(this->m_vecs[whereToSave],this->m_seqVecs[whereToSave]); | |
298 | ✗ | if ( FelisceParam::verbose() > 0 ) { | |
299 | ✗ | PetscPrintf(MpiInfo::petscComm(), "done\n"); | |
300 | } | ||
301 | } | ||
302 | // Reader of vectors coming from different linearProblems | ||
303 | // the std::vector are stored in sequential std::vector "whereToSave" | ||
304 | // TODO: This function fill a volume std::vector, can this be avoided? | ||
305 | template <class volumeProblem> | ||
306 | void | ||
307 | 312 | LinearProblemReducedSteklov<volumeProblem>::readerInterfaceComponentWise( const std::map<int,std::map<int,int> > & externalMap, | |
308 | PetscVector& seqExternalVec, | ||
309 | const std::map<int,int> &mapBetweenLabels, | ||
310 | std::string whereToSave, | ||
311 | felInt iUnkWTW, | ||
312 | felInt iCompWTW) { | ||
313 | // some couts to help debugging | ||
314 |
2/4✓ Branch 1 taken 312 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 312 times.
|
312 | if ( FelisceParam::verbose() > 2 ) |
315 | ✗ | PetscPrintf(MpiInfo::petscComm(),"%s", std::string("[linearProblem--Reduced Steklov] Reading "+ whereToSave +"...").c_str() ); | |
316 | |||
317 | felInt iDofGlobThisLPB; // petsc index of the current dof in this linear problem | ||
318 | felInt iDofGlobThisLPBApp; // application index of the current dof in this linear problem | ||
319 | felInt iDofGlobOtherLPB; // petsc index of the current dof in the other linear problem | ||
320 | |||
321 |
1/2✓ Branch 2 taken 312 times.
✗ Branch 3 not taken.
|
312 | int iUnknComp = this->dof().getNumGlobComp(iUnkWTW, iCompWTW); |
322 | double tmpValue; | ||
323 | |||
324 | // for each label of the interface in the mesh of this problem | ||
325 |
2/2✓ Branch 4 taken 312 times.
✓ Branch 5 taken 312 times.
|
624 | for(auto currentLabel = m_interfaceLabels.begin(); currentLabel != m_interfaceLabels.end(); currentLabel++) { |
326 | // we get the corresponding label in the other mesh | ||
327 |
1/2✓ Branch 2 taken 312 times.
✗ Branch 3 not taken.
|
312 | felInt labelOtherLPBMesh=mapBetweenLabels.find(*currentLabel)->second; |
328 | // some couts to help debugging | ||
329 |
2/4✓ Branch 1 taken 312 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 312 times.
|
312 | if ( FelisceParam::verbose() > 2 ) { |
330 | ✗ | std::cout << std::endl; | |
331 | ✗ | std::cout << "Interface label from reduced steklov mesh: "<<*currentLabel<<" , label from the other mesh: "<<labelOtherLPBMesh<<std::endl; | |
332 | } | ||
333 | // for each dof on this portion of the interface | ||
334 |
1/2✓ Branch 1 taken 312 times.
✗ Branch 2 not taken.
|
312 | for(auto currentPetscOtherLPBDOF = externalMap.find(labelOtherLPBMesh)->second.begin(); //begin of the std::unordered_map |
335 |
3/4✓ Branch 1 taken 25584 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 25272 times.
✓ Branch 7 taken 312 times.
|
25584 | currentPetscOtherLPBDOF != externalMap.find(labelOtherLPBMesh)->second.end(); //end of the std::unordered_map |
336 | 25272 | ++currentPetscOtherLPBDOF) { | |
337 | 25272 | iDofGlobOtherLPB = currentPetscOtherLPBDOF->second; //global dof | |
338 |
1/2✓ Branch 4 taken 25272 times.
✗ Branch 5 not taken.
|
25272 | iDofGlobThisLPB = this->m_dofBD[0/*iBD*/].getPetscDofs(/*iUnknown,iComp where to write*/iUnknComp, *currentLabel, currentPetscOtherLPBDOF->first) ; |
339 | |||
340 | 25272 | iDofGlobThisLPBApp = iDofGlobThisLPB; | |
341 |
1/2✓ Branch 1 taken 25272 times.
✗ Branch 2 not taken.
|
25272 | AOPetscToApplication(this->m_ao,1,&iDofGlobThisLPBApp); |
342 | // we check if the dof belongs to this proc | ||
343 |
3/4✓ Branch 2 taken 25272 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 6318 times.
✓ Branch 5 taken 18954 times.
|
25272 | if ( this->m_dofPart[iDofGlobThisLPBApp] == MpiInfo::rankProc() ) { |
344 | //we get the value | ||
345 |
1/2✓ Branch 1 taken 6318 times.
✗ Branch 2 not taken.
|
6318 | seqExternalVec.getValues(1,&iDofGlobOtherLPB, &tmpValue); |
346 | // and we std::set it | ||
347 |
3/6✓ Branch 1 taken 6318 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6318 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 6318 times.
✗ Branch 8 not taken.
|
6318 | this->m_vecs.Get(whereToSave).setValue(iDofGlobThisLPB, tmpValue, INSERT_VALUES); |
348 | } | ||
349 | } | ||
350 | } | ||
351 | 312 | } | |
352 | |||
353 | |||
354 | |||
355 | |||
356 | template <class volumeProblem> | ||
357 | void | ||
358 | ✗ | LinearProblemReducedSteklov<volumeProblem>::setValueMatrixBD(felInt ielSupportDof) { | |
359 | // Elementary matrices are placed into the bigger one defined on the boundary. | ||
360 | ✗ | felInt numDofTotal = this->m_elementMatBD[0]->mat().size1(); | |
361 | |||
362 | ✗ | felInt node1 = 0; | |
363 | ✗ | felInt node2 = 0; | |
364 | ✗ | felInt cptGposLine = 0; | |
365 | ✗ | felInt cptGposLine2 = 0; | |
366 | ✗ | felInt sizeSupport = 0; | |
367 | ✗ | felInt sizeSupport2 = 0; | |
368 | ✗ | felInt cptBlock = 0; | |
369 | ✗ | int idVar = -1; | |
370 | ✗ | int idVar2 = -1; | |
371 | //! for all the unknowns of the problems | ||
372 | ✗ | for ( std::size_t iUnknown = 0; iUnknown < this->m_listUnknown.size(); iUnknown++) { | |
373 | ✗ | idVar = this->m_listUnknown.idVariable(iUnknown); | |
374 | ✗ | sizeSupport = this->m_listCurvilinearFiniteElement[idVar]->numDof(); | |
375 | //! for all its components | ||
376 | ✗ | for (std::size_t iComp = 0; iComp < this->m_listVariable[idVar].numComponent(); iComp++) { | |
377 | ✗ | cptBlock++; | |
378 | //! for all the dof on the element | ||
379 | ✗ | for ( int iSupport = 0; iSupport < sizeSupport; iSupport++) { | |
380 | |||
381 | //! get the volume application index | ||
382 | ✗ | this->dof().loc2glob(ielSupportDof, iSupport, idVar, iComp, node1); | |
383 | //! save it | ||
384 | ✗ | m_globPosRow[cptGposLine]= node1; | |
385 | ✗ | cptGposLine2 = 0; | |
386 | //! then we do the same with the columns: | ||
387 | //! for each unknown | ||
388 | ✗ | for ( std::size_t iUnknown2 = 0; iUnknown2 <this->m_listUnknown.size(); iUnknown2++) { | |
389 | ✗ | idVar2 = this->m_listUnknown.idVariable(iUnknown2); | |
390 | ✗ | sizeSupport2 = this->m_listCurvilinearFiniteElement[idVar2]->numDof(); | |
391 | //! for all its components | ||
392 | ✗ | for (std::size_t jComp = 0; jComp <this->m_listVariable[idVar2].numComponent(); jComp++) { | |
393 | //! for all the dofs on the element | ||
394 | ✗ | for ( int jSupport = 0; jSupport < sizeSupport2; jSupport++) { | |
395 | ✗ | int iConnect = this->dof().getNumGlobComp( iUnknown, iComp); | |
396 | ✗ | int jConnect = this->dof().getNumGlobComp( iUnknown2, jComp); | |
397 | ✗ | if ( this->m_listUnknown.mask()(iConnect, jConnect) > 0) { | |
398 | //! the global index | ||
399 | ✗ | this->dof().loc2glob(ielSupportDof,jSupport,idVar2,jComp,node2); | |
400 | //! save it | ||
401 | ✗ | m_globPosColumn[cptGposLine2] = node2; | |
402 | //! store in this small matrix the values just computed | ||
403 | ✗ | m_matrixValues[cptGposLine2 + cptGposLine*numDofTotal] = this->m_elementMatBD[0]->mat()(cptGposLine, cptGposLine2); | |
404 | ✗ | cptGposLine2++; | |
405 | } | ||
406 | } | ||
407 | } | ||
408 | } | ||
409 | ✗ | cptGposLine++; | |
410 | } | ||
411 | } | ||
412 | } | ||
413 | //! Now we have to compute where this numbers have to be put into the boundary matrix | ||
414 | //! volume application -> petsc volume | ||
415 | ✗ | AOApplicationToPetsc(this->m_ao,cptGposLine,m_globPosRow.data()); | |
416 | ✗ | AOApplicationToPetsc(this->m_ao,cptGposLine2,m_globPosColumn.data()); | |
417 | |||
418 | ✗ | std::vector<felInt> row; | |
419 | ✗ | std::vector<felInt> col; | |
420 | ✗ | std::vector<felInt> tmpCol; | |
421 | ✗ | std::vector<double> val; | |
422 | //! petsc volume -> boundary application | ||
423 | ✗ | for ( int k(0); k < cptGposLine; ++k) { | |
424 | ✗ | tmpCol.clear(); | |
425 | try { | ||
426 | // petscVol2ApplicationBD can throw an out_of_range while m_globPosRow[k] can not | ||
427 | // The idea is that if this fails it means that this particular dof is not in the mapping | ||
428 | // and that it can be discarded (e.g. pressure nodes when dealing with Stokes problem) | ||
429 | ✗ | row.push_back(this->m_dofBD[0/*iBD*/].petscVol2ApplicationBD(m_globPosRow[k])); | |
430 | ✗ | for ( int k2(0); k2 < cptGposLine2; ++k2) { | |
431 | try { | ||
432 | ✗ | tmpCol.push_back(this->m_dofBD[0/*iBD*/].petscVol2ApplicationBD(m_globPosColumn[k2])); | |
433 | ✗ | val.push_back(m_matrixValues[k2+k*numDofTotal]); | |
434 | ✗ | } catch ( const std::out_of_range& oor ){} | |
435 | } | ||
436 | ✗ | } catch ( const std::out_of_range& oor ){} | |
437 | ✗ | if (tmpCol.size()>0) { | |
438 | ✗ | col=tmpCol; | |
439 | } | ||
440 | } | ||
441 | //! boundary application -> petsc application | ||
442 | ✗ | AOApplicationToPetsc(this->m_dofBD[0/*iBD*/].ao(),row.size(),row.data()); | |
443 | ✗ | AOApplicationToPetsc(this->m_dofBD[0/*iBD*/].ao(),col.size(),col.data()); | |
444 | // std::set value | ||
445 | ✗ | m_aux.setValues(row.size(),row.data(),col.size(),col.data(),val.data(),ADD_VALUES); | |
446 | } | ||
447 | |||
448 | |||
449 | //! \brief It assembles the laplacian matrix on the boundary. | ||
450 | template <class volumeProblem> | ||
451 | PetscMatrix | ||
452 | ✗ | LinearProblemReducedSteklov<volumeProblem>::assembleLaplacianBoundary() { | |
453 | ✗ | PetscMatrix laplacian; | |
454 | ✗ | if ( this->dimension() == 3 ) { | |
455 | ✗ | this->m_dofBD[0/*iBD*/].allocateMatrixOnBoundary( laplacian ); | |
456 | ✗ | m_aux=laplacian; | |
457 | ✗ | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { | |
458 | ✗ | this->assemblyLoopBoundaryGeneral( &LinearProblemReducedSteklov<volumeProblem>::laplacianMatrixComputer, | |
459 | ✗ | m_interfaceLabels, | |
460 | &LinearProblemReducedSteklov<volumeProblem>::initPerETLAP, | ||
461 | &LinearProblemReducedSteklov<volumeProblem>::updateFE);// we do not need the derivatives for surface laplacian: they are computed in m_curv | ||
462 | ✗ | m_globPosColumn.clear();m_globPosRow.clear();m_matrixValues.clear(); | |
463 | ✗ | laplacian.assembly(MAT_FINAL_ASSEMBLY); | |
464 | } | ||
465 | ✗ | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { | |
466 | ✗ | if ( FelisceParam::instance().exportLaplacianMatrix ) { | |
467 | ✗ | laplacian.saveInBinaryFormat( this->m_dofBD[0/*iBD*/].comm(), "Laplacian" , FelisceParam::instance().resultDir); | |
468 | } | ||
469 | } | ||
470 | // Better to put it since m_aux will stay alive as long as the linear problem, | ||
471 | // while we would like to deallocate this matrix when the laplacian matrix gets out of scope | ||
472 | ✗ | m_aux.destroy(); | |
473 | } else { | ||
474 | ✗ | FEL_ERROR("We can not yet assemble the laplacian operator on the boundary of a 2D-domain."); | |
475 | } | ||
476 | ✗ | return laplacian; | |
477 | } | ||
478 | /* ! \brief this function assemble the mass matrix at the boundary. | ||
479 | * It saves such matrix in binary format and then it destroies the matrix. | ||
480 | */ | ||
481 | template <class volumeProblem> | ||
482 | PetscMatrix | ||
483 | ✗ | LinearProblemReducedSteklov<volumeProblem>::assembleMassBoundary( ) { | |
484 | ✗ | PetscMatrix mass; | |
485 | ✗ | this->m_dofBD[0/*iBD*/].allocateMatrixOnBoundary( mass ); | |
486 | ✗ | m_aux=mass; | |
487 | ✗ | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { | |
488 | ✗ | this->assemblyLoopBoundaryGeneral( &LinearProblemReducedSteklov<volumeProblem>::massMatrixComputer, | |
489 | ✗ | m_interfaceLabels, | |
490 | &LinearProblemReducedSteklov<volumeProblem>::initPerETMASS, | ||
491 | &LinearProblemReducedSteklov<volumeProblem>::updateFE); | ||
492 | ✗ | m_globPosColumn.clear();m_globPosRow.clear();m_matrixValues.clear(); | |
493 | |||
494 | ✗ | mass.assembly(MAT_FINAL_ASSEMBLY); | |
495 | ✗ | if ( FelisceParam::instance().exportMassMatrix ) { | |
496 | ✗ | mass.saveInBinaryFormat( this->m_dofBD[0/*iBD*/].comm(), "Mass", FelisceParam::instance().resultDir); | |
497 | } | ||
498 | } | ||
499 | // Better to put it since m_aux will stay alive as long as the linear problem, | ||
500 | // while we would like to deallocate this matrix when the mass matrix gets out of scope | ||
501 | ✗ | m_aux.destroy(); | |
502 | ✗ | return mass; | |
503 | } | ||
504 | template <class volumeProblem> | ||
505 | void | ||
506 | ✗ | LinearProblemReducedSteklov<volumeProblem>::exportOutputSteklov(FelisceTransient::Pointer fstransient,int iFixedPointIteration) { | |
507 | ✗ | PetscVector restrictedSolution = this->dofBD(/*iBD*/0).allocateBoundaryVector(DofBoundary::parallel); | |
508 | ✗ | this->dofBD(/*iBD*/0).restrictOnBoundary(this->solution(),restrictedSolution); | |
509 | ✗ | std::stringstream iFixedPointIterationString; | |
510 | ✗ | if ( iFixedPointIteration < 10 ) iFixedPointIterationString<<"00"<<iFixedPointIteration; | |
511 | ✗ | else if (iFixedPointIteration < 100) iFixedPointIterationString<<"0" <<iFixedPointIteration; | |
512 | ✗ | else iFixedPointIterationString <<iFixedPointIteration; | |
513 | ✗ | if( FelisceParam::instance().exportOutputOfSteklov ) { | |
514 | // binary export | ||
515 | ✗ | if ( FelisceParam::instance().exportOnlyLastOutput ) { | |
516 | ✗ | iFixedPointIterationString.str("last"); | |
517 | } | ||
518 | ✗ | std::stringstream filename2; | |
519 | ✗ | filename2<<"outputSteklov_"<<fstransient->itStr()<<"_"<<iFixedPointIterationString.str().c_str(); | |
520 | ✗ | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { | |
521 | ✗ | restrictedSolution.saveInBinaryFormat(this->m_dofBD[0/*iBD*/].comm(), filename2.str(), FelisceParam::instance().resultDir); | |
522 | } | ||
523 | } | ||
524 | } | ||
525 | |||
526 | // the data is given as a volume std::vector: first you restrict this volume std::vector on | ||
527 | // the surface you apply the Steklov operator and you save the result in a volume | ||
528 | // std::vector | ||
529 | template <class volumeProblem> | ||
530 | void | ||
531 | 304 | LinearProblemReducedSteklov<volumeProblem>::applySteklov( PetscVector& volumeInput, PetscVector& volumeOutput, FelisceTransient::Pointer fstransient, int iFixedPointIteration) { | |
532 | // reset this to zero | ||
533 |
1/2✓ Branch 1 taken 152 times.
✗ Branch 2 not taken.
|
304 | volumeOutput.set(0.0); |
534 |
1/2✓ Branch 2 taken 152 times.
✗ Branch 3 not taken.
|
304 | PetscVector Input = this->dofBD(/*iBD*/0).allocateBoundaryVector(DofBoundary::parallel); |
535 |
1/2✓ Branch 2 taken 152 times.
✗ Branch 3 not taken.
|
304 | PetscVector Output = this->dofBD(/*iBD*/0).allocateBoundaryVector(DofBoundary::parallel); |
536 |
1/2✓ Branch 2 taken 152 times.
✗ Branch 3 not taken.
|
304 | this->dofBD(/*iBD*/0).restrictOnBoundary( volumeInput, Input); |
537 | |||
538 |
1/2✓ Branch 2 taken 152 times.
✗ Branch 3 not taken.
|
304 | if ( this->dofBD(/*iBD*/0).hasDofsOnBoundary() ) { |
539 |
2/4✓ Branch 1 taken 152 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 152 times.
|
304 | if ( FelisceParam::instance().useRoSteklov ) { |
540 | ✗ | m_reducedSteklov->applyLowRankSteklov(Input,Output); | |
541 | } else { | ||
542 |
1/2✓ Branch 1 taken 152 times.
✗ Branch 2 not taken.
|
304 | mult(m_fullSteklov, Input, Output); |
543 | } | ||
544 |
1/2✓ Branch 2 taken 152 times.
✗ Branch 3 not taken.
|
304 | this->exportSteklovInputOutput(Input,Output,fstransient,iFixedPointIteration); |
545 | } | ||
546 |
1/2✓ Branch 2 taken 152 times.
✗ Branch 3 not taken.
|
304 | this->dofBD(/*iBD*/0).extendOnVolume(volumeOutput,Output); |
547 | } | ||
548 | template <class volumeProblem> | ||
549 | 304 | void LinearProblemReducedSteklov<volumeProblem>::exportSteklovInputOutput( PetscVector& Input, PetscVector& Output, FelisceTransient::Pointer fstransient, int iFixedPointIteration) { | |
550 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 152 times.
|
304 | if ( FelisceParam::instance().exportSteklovData ) { |
551 | ✗ | std::stringstream iFixedPointIterationString; | |
552 | ✗ | if ( iFixedPointIteration < 10 ) iFixedPointIterationString<<"00"<<iFixedPointIteration; | |
553 | ✗ | else if (iFixedPointIteration < 100) iFixedPointIterationString<<"0" <<iFixedPointIteration; | |
554 | ✗ | else iFixedPointIterationString <<iFixedPointIteration; | |
555 | ✗ | if( FelisceParam::instance().exportInputOfSteklov ) { | |
556 | ✗ | if ( FelisceParam::instance().exportOnlyLastInput ) { iFixedPointIterationString.str("last"); } | |
557 | ✗ | std::stringstream filename; | |
558 | ✗ | filename<<"inputSteklov_"<<fstransient->itStr()<<"_"<<iFixedPointIterationString.str().c_str(); | |
559 | ✗ | Input.saveInBinaryFormat(this->m_dofBD[0/*iBD*/].comm(), filename.str(), FelisceParam::instance().resultDir); | |
560 | } | ||
561 | ✗ | if( FelisceParam::instance().exportOutputOfSteklov ) { | |
562 | ✗ | if ( FelisceParam::instance().exportOnlyLastOutput ) { iFixedPointIterationString.str("last"); } | |
563 | ✗ | std::stringstream filename2; | |
564 | ✗ | filename2<<"outputSteklov_"<<fstransient->itStr()<<"_"<<iFixedPointIterationString.str().c_str(); | |
565 | ✗ | Output.saveInBinaryFormat(this->m_dofBD[0/*iBD*/].comm(), filename2.str(), FelisceParam::instance().resultDir); | |
566 | } | ||
567 | } | ||
568 | } | ||
569 | template <class volumeProblem> | ||
570 | ✗ | void LinearProblemReducedSteklov<volumeProblem>::userSetNullSpace(PetscVector& v, int k) { | |
571 | //TODO move this in a user file or do something better | ||
572 | ✗ | if ( FelisceParam::instance().notConnectedCylinders ) { | |
573 | ✗ | v.set(0.0); | |
574 | ✗ | std::size_t labelCount = 0; | |
575 | ✗ | double aus(1.0); | |
576 | ✗ | for(auto itLabel = this->m_dofBD[0/*iBD*/].listOfBoundaryPetscDofs(/*iUnkown*/0,/*iComp*/0).begin(); itLabel != this->m_dofBD[0/*iBD*/].listOfBoundaryPetscDofs(/*iUnkown*/0,/*iComp*/0).end(); ++itLabel, ++labelCount ) { | |
577 | ✗ | if ( labelCount == std::size_t(k) ) { | |
578 | ✗ | for(auto itDof = itLabel->second.begin(); itDof != itLabel->second.end(); ++itDof) { | |
579 | ✗ | felInt dof=this->m_dofBD[0/*iBD*/].petscVol2ApplicationBD(itDof->second); | |
580 | ✗ | AOApplicationToPetsc(this->m_dofBD[0/*iBD*/].ao(),1,&dof); | |
581 | ✗ | v.setValues(1,&dof,&aus, INSERT_VALUES); | |
582 | } | ||
583 | } | ||
584 | } | ||
585 | ✗ | v.assembly(); | |
586 | } else { | ||
587 | ✗ | if ( k > 0 ) { | |
588 | ✗ | FEL_ERROR("There are too many zero eigenvalues: implement your own userSetNullSpace function"); | |
589 | } else { | ||
590 | ✗ | v.set(1.0); | |
591 | } | ||
592 | } | ||
593 | } | ||
594 | //! \brief it modifies the state of the class | ||
595 | //! In particular it raises the flag m_useSteklovData, and it allocates the dataSteklov vectors | ||
596 | template <class volumeProblem> | ||
597 | 4 | void LinearProblemReducedSteklov<volumeProblem>::useSteklovDataBegin() { | |
598 | 4 | this->m_useSteklovData = true; | |
599 |
3/6✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
|
4 | this->m_vecs["dataSteklov"].duplicateFrom( this->solution() ); |
600 |
3/6✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
|
4 | this->m_vecs.Get("dataSteklov").set(0.0); |
601 |
3/6✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 4 times.
✗ Branch 10 not taken.
|
4 | this->m_seqVecs["dataSteklov"].duplicateFrom( this->sequentialSolution() ); |
602 |
3/6✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 4 times.
✗ Branch 9 not taken.
|
4 | this->m_seqVecs.Get("dataSteklov").set(0.0); |
603 | 4 | m_tmpValues.resize( this->m_dofBD[0/*iBD*/].numLocalDofInterface() ); | |
604 | 4 | this->m_boundaryConditionList.temporarySetBCValuesToZero(); | |
605 | 4 | } | |
606 | |||
607 | //! \brief it restores the previous state of the class | ||
608 | //! Call this function only after having used useSteklovBegin. | ||
609 | //! The flag: m_useSteklovData is reset to false and the dataSteklov vectors are destroyed | ||
610 | template <class volumeProblem> | ||
611 | void | ||
612 | 4 | LinearProblemReducedSteklov<volumeProblem>::useSteklovDataEnd() { | |
613 | 4 | this->m_useSteklovData = false; | |
614 |
2/4✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
4 | this->m_vecs.erase("dataSteklov"); |
615 |
2/4✓ Branch 2 taken 4 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
|
4 | this->m_seqVecs.erase("dataSteklov"); |
616 | 4 | this->m_boundaryConditionList.restoreBCValues(); | |
617 | 4 | } | |
618 | } | ||
619 |