Loading...
Searching...
No Matches
PODTemplate.C
1
2#include "PODTemplate.H"
3
4namespace ITHACAPOD
5{
6
7template<typename T>
8PODTemplate<T>::PODTemplate(Parameters* myParameters,
9 const word& myfield_name, const word& mySnapshots_path) :
10 m_parameters(static_cast<StoredParameters*>(myParameters)),
11 field_name(myfield_name),
12 casenameData(m_parameters->get_casenameData()),
13 l_nSnapshot(m_parameters->get_nSnapshots()),
14 snapshotsPath(mySnapshots_path),
15 l_nBlocks(m_parameters->get_nBlocks()),
16 l_nmodes(m_parameters->get_nModes()[field_name]),
17 l_hilbertSp(m_parameters->get_hilbertSpacePOD()[field_name]),
18 weightH1(m_parameters->get_weightH1()),
19 weightBC(m_parameters->get_weightPOD()),
20 patchBC(m_parameters->get_patchBC()),
21 l_startTime(m_parameters->get_startTime()),
22 l_endTime(m_parameters->get_endTime()),
23 l_nSnapshotSimulation(m_parameters->get_nSnapshotsSimulation()),
24 l_endTimeSimulation(m_parameters->get_endTimeSimulation()),
25 b_centeredOrNot(m_parameters->get_centeredOrNot()),
26 lambda(Eigen::VectorXd::Zero(l_nmodes)),
27 w_eigensolver(m_parameters->get_eigensolver()),
28 i_precision(m_parameters->get_precision()),
29 ios_outytpe(m_parameters->get_outytpe()),
30 runTime2(Foam::Time::controlDictName, ".",
31 m_parameters->get_casenameData())
32{
33 if (snapshotsPath == "default_path")
34 {
35 snapshotsPath = casenameData;
36 }
37
38 word pathProcessor("");
39 if (Pstream::parRun())
40 {
41 pathProcessor = "processor" + name(Pstream::myProcNo()) + "/";
42 }
43 timeFolders = runTime2.findTimes(snapshotsPath + pathProcessor);
44
45 l_startTime = Time::findClosestTimeIndex(timeFolders,std::stoi(runTime2.times()[l_startTime].name()));
46 l_endTime = l_startTime + l_nSnapshot - 1;
47
48 f_field = new T(
49 IOobject
50 (
51 field_name,
52 snapshotsPath + timeFolders[1].name(),
53 m_parameters->get_mesh(),
54 IOobject::MUST_READ
55 ),
56 m_parameters->get_mesh()
57 );
58 f_meanField = new T(f_field->name(), *f_field);
59 // // Set the inlet boundaries where we have non homogeneous boundary conditions
60 // inletIndex.resize(1, 2);
61 // inletIndex(0, 0) = 3;
62 // inletIndex(0, 1) = 2;
63 // if (field_name=="U")
64 // {
65 // lifting = true;
66 // }
67 // else
68 // {
69 // lifting = false;
70 // }
71 // b_centeredOrNot = false;
72 lifting = false;
73 define_paths();
74}
75
76template<typename T>
77PODTemplate<T>::~PODTemplate()
78{
79 delete f_field;
80 delete f_meanField;
81}
82
83
84template<typename T>
85void PODTemplate<T>::define_paths()
86{
87 word pathCentered("");
88
89 if (b_centeredOrNot && !(field_name == "U"))
90 {
91 pathCentered = "_centered";
92 }
93
94 if (lifting)
95 {
96 pathCentered += "Lifted";
97 }
98
99 word pathProcessor("");
100 if (Pstream::parRun())
101 {
102 pathProcessor = "processor" + name(Pstream::myProcNo()) + "/";
103 }
104
105 word pathHilbertSpace(m_parameters->get_pathHilbertSpace_fromHS(
106 l_hilbertSp));
107 // name and folder of the covariance
108 // check if the matrix was already computed
109 name_covMatrix = "covMatrix" + f_field->name();
110 folder_covMatrix = "./ITHACAoutput/CovMatrices" + pathHilbertSpace
111 + pathCentered + "/";
112 exist_covMatrix = ITHACAutilities::check_file(folder_covMatrix + name_covMatrix
113 + ".npy");
114 // name and folder of the eigen decomposition
115 name_eigenValues = "Eigenvalues_" + f_field->name();
116 name_eigenValuesNormalized = "EigenvaluesNormalized_" + f_field->name();
117 name_cumEigenValues = "/CumEigenvalues_" + f_field->name();
118 name_eigenVector = "/Eigenvector_" + f_field->name() ;
119 folder_eigen = "./ITHACAoutput/EigenValuesandVector"
120 + pathCentered + "_" + std::to_string(l_nmodes) + "modes/";
121 exist_eigenDecomposition = ITHACAutilities::check_file(folder_eigen +
122 name_eigenValues + ".npy")
123 && ITHACAutilities::check_file(folder_eigen + name_eigenVector + ".npy");
124 // folder of the spatial modes and check if every modes were already computed
125 folder_spatialModes = "./ITHACAoutput/spatialModes"
126 + pathCentered + "_" + std::to_string(l_nmodes) + "modes/";
127 exist_spatialModes = ITHACAutilities::check_file(folder_spatialModes + pathProcessor + "1/" +
128 f_field->name());
129 // folder of the temporal modes and check if modes were already computed
130 folder_temporalModes = "./ITHACAoutput/temporalModes"
131 + pathCentered + "_" + std::to_string(l_nmodes) + "modes/";
132 exist_temporalModes = ITHACAutilities::check_file(folder_temporalModes +
133 f_field->name() + ".npy");
134 // folder of the temporal modes and check if modes were already computed
135 folder_temporalModesSimulation = "./ITHACAoutput/temporalModesSimulation"
136 + pathCentered + "_" + std::to_string(l_nmodes) + "modes/";
137 exist_temporalModesSimulation = ITHACAutilities::check_file(
138 folder_temporalModesSimulation + f_field->name() + ".npy");
139 // folder of mean field and check if mean was already computed
140 folder_mean = "./ITHACAoutput/mean/";
141 exist_noMean = !ITHACAutilities::check_file(folder_mean + "/" + pathProcessor +
142 std::to_string(1) + "/" + f_field->name());
143}
144
145
146template<typename T>
147void PODTemplate<T>::computeMeanField()
148{
149 if (lifting)
150 {
151 Info << "Loading lifting functions" << endl;
152 liftfield.resize(inletIndex.rows());
153
154 for (label k = 0; k < inletIndex.rows(); k++)
155 {
156 T* f_lift = new T
157 (
158 IOobject
159 (
160 f_field->name() + "lift" + std::to_string(k),
161 snapshotsPath + timeFolders[1].name(),
162 m_parameters->get_mesh(),
163 IOobject::MUST_READ
164 ),
165 m_parameters->get_mesh()
166 );
167 liftfield.set(k, f_lift );
168 }
169 }
170
171 if (b_centeredOrNot)
172 {
173 if (exist_noMean)
174 {
175 ITHACAutilities::setToZero(*f_meanField);
176 Info << "Computing the mean of " << f_field->name() << " field" << endl;
177 T snapshotj = *f_field;
178 b_centeredOrNot = false;
179
180 for (label j = 0; j < l_nSnapshot; j++)
181 {
182 // Read the j-th field
183 ITHACAstream::read_snapshot(snapshotj, timeFolders[l_startTime+j].name(), snapshotsPath);
184 lift(snapshotj);
185 // add j-th field to meanfield
186 ITHACAutilities::addFields(*f_meanField, snapshotj);
187 }
188
189 b_centeredOrNot = true;
190 ITHACAutilities::multField(*f_meanField, 1 / double(l_nSnapshot));
191 PtrList<T> meanExport(1);
192 meanExport.set(0, new T(f_meanField->name(), *f_meanField));
193 ITHACAstream::exportFields(meanExport, folder_mean, f_field->name());
194 }
195 else
196 {
197 PtrList<T> meanRead;
198 Info << "Reading the mean of " << f_field->name() << " field" << endl;
199 ITHACAstream::read_fields(meanRead, (*f_field), folder_mean);
200 *f_meanField = meanRead[0];
201 }
202
203 double energyMean = ITHACAutilities::dot_product_L2(*f_meanField, *f_meanField);
204 double energyHilbertMean = ITHACAutilities::dot_product_POD(*f_meanField,
205 *f_meanField, l_hilbertSp);
206 m_parameters->set_meanEnergy( f_meanField->name(), energyMean);
207 m_parameters->set_meanEnergy( f_meanField->name() + "_" + l_hilbertSp,
208 energyHilbertMean);
209 }
210 else
211 {
212 ITHACAutilities::setToZero(*f_meanField);
213 }
214
215 Info << endl;
216}
217
218
219template<typename T>
220void PODTemplate<T>::appendMeanfieldtoSpatialModes(PtrList<T>& spatialModes)
221{
222 if (b_centeredOrNot)
223 {
224 spatialModes.set(l_nmodes, f_meanField);
225 }
226}
227
228template<typename T>
229void PODTemplate<T>::findTempFile(Eigen::MatrixXd* covMat, int* index1,
230 int* index2)
231{
232 word pathTemp = name_covMatrix + "_temp_";
233 DIR* dir;
234 struct dirent* entry;
235 dir = opendir(folder_covMatrix.c_str());
236 word extTemp = ".npy";
237 Info << "looking for " << pathTemp.c_str() << "*" << extTemp.c_str() << " in "
238 << folder_covMatrix.c_str() << endl;
239 // INDEX : index1 and index2 of oldest and most recent *_temp_*.npy file
240 // INDEX[O][*] : index min (for example with *_temp_0_1.npy and *_temp_3_2.npy => INDEX[0][0]=0 and INDEX[0][1]=1 )
241 // INDEX[1][*] : index max (for example with *_temp_0_1.npy and *_temp_3_2.npy => INDEX[1][0]=3 and INDEX[1][1]=2 )
242 int INDEX[2][2], N_INDEX = 0;
243
244 for (int i = 0; i < 2; i++)
245 {
246 for (int j = 0; j < 2; j++)
247 {
248 INDEX[i][j] = -1;
249 }
250 }
251
252 if (dir != NULL)
253 {
254 while ((entry = readdir(dir)) != NULL)
255 {
256 char ext_name[4];
257 strncpy(ext_name, " ", 4);
258
259 if ( strlen(entry->d_name) >= 4 )
260 {
261 for (int i = 0; i < 4; i++)
262 {
263 ext_name[i] = entry->d_name[strlen(entry->d_name) - (4 - i)];
264 }
265 }
266
267 if ((strncmp(entry->d_name, pathTemp.c_str(), pathTemp.size()) == 0)
268 && (strncmp(ext_name, extTemp.c_str(), 4) == 0))
269 {
270 int num1, num2;
271 char endFileName[12];
272 strncpy(endFileName, entry->d_name+strlen(entry->d_name)-12, 12);
273 sscanf(endFileName, "%*[^0-9]%d_%d", &num1, &num2);
274 *index1 = num1;
275 *index2 = num2;
276
277 if ( N_INDEX == 0 )
278 {
279 INDEX[0][0] = *index1;
280 INDEX[0][1] = *index2;
281 INDEX[1][0] = *index1;
282 INDEX[1][1] = *index2;
283 }
284 else
285 {
286 // updating INDEX from oldest *_temp_*.npy file ( -> INDEX[0][*])
287 if ( *index1 < INDEX[0][0] )
288 {
289 INDEX[0][0] = *index1;
290 INDEX[0][1] = *index2;
291 }
292 else
293 {
294 if (( *index1 == INDEX[0][0] ) && ( *index2 < INDEX[0][1] ))
295 {
296 INDEX[0][1] = *index2;
297 }
298 }
299
300 // updating INDEX from most recent *_temp_*.npy file ( -> INDEX[1][*])
301 if ( *index1 > INDEX[1][0] )
302 {
303 INDEX[1][0] = *index1;
304 INDEX[1][1] = *index2;
305 }
306 else
307 {
308 if (( *index1 == INDEX[1][0] ) && ( *index2 > INDEX[1][1] ))
309 {
310 INDEX[1][1] = *index2;
311 }
312 }
313 }
314
315 N_INDEX = N_INDEX + 1;
316 Info << " " << entry->d_name << " FOUND => covMat can be updated" << endl;
317 }
318 }
319
320 closedir(dir);
321 }
322
323 // restart from oldest *_temp_*.npy file or most recent *_temp_*.npy file
324 if ( N_INDEX > 0 )
325 {
326 // updating matrix from oldest *_temp_*.npy file ( -> INDEX[0][*])
327 *index1 = INDEX[0][0];
328 *index2 = INDEX[0][1];
329 Info << " -> RESTART from INDEX : " << *index1 << " " << *index2 <<
330 " (oldest *_temp_*.npy file)" << endl;
331 char str1[10];
332 sprintf(str1, "%d", *index1);
333 char str2[10];
334 sprintf(str2, "%d", *index2);
335 word suffix = static_cast<word>(str1) + "_" + static_cast<word>(str2);
336 cnpy::load(*covMat, folder_covMatrix + pathTemp + suffix + extTemp);
337 Info << " with covMat size=(" << covMat->rows() << ", " << covMat->cols()
338 << ")" << endl;
339 }
340}
341
342template<typename T>
343word PODTemplate<T>::nameTempCovMatrix( int i, int j)
344{
345 char str1[10];
346 sprintf(str1, "%d", i);
347 char str2[10];
348 sprintf(str2, "%d", j);
349 word suffix = "_temp_" + static_cast<word>(str1) + "_" + static_cast<word>
350 (str2);
351 word filename = folder_covMatrix + name_covMatrix + suffix + ".npy";
352 return filename;
353}
354
355template<typename T>
356void PODTemplate<T>::saveTempCovMatrix(Eigen::MatrixXd& covMatrix, int i, int j)
357{
358 word filename = nameTempCovMatrix(i, j);
359 if (Pstream::master())
360 {
361 cnpy::save(covMatrix, filename);
362 }
363}
364
365template<typename T>
366void PODTemplate<T>::deleteTempCovMatrix(int i, int j)
367{
368 word filename = nameTempCovMatrix(i, j);
369 std::ifstream fileStr(filename.c_str());
370
371 if (fileStr)
372 {
373 remove(filename.c_str());
374 }
375}
376
377template<typename T>
378void PODTemplate<T>::deletePreviousTempCovMatrix_N(int* valI, int* valJ, int i,
379 int j, int N)
380{
381 // NUM = (sum_{n=1}^{n=i} n) = ( (m+(m+i))+(m+1+(m+i)-1)+...+((m+i)+m))/2 = (2*m*i+i+i*i)/2
382 // => NUM(m=0) = (i+i*i)/2
383 // NUM(m=0)+j+1 = (sum_{n=1}^{n=i} n) +j+1 = (1+i)*i/2 +j
384 int NUM = (1 + i) * i / 2 + j;
385 int dNUM = NUM - N;
386 *valI = 0;
387 int S = 0;
388
389 while ( dNUM >= S )
390 {
391 *valI = *valI + 1;
392 S = (1 + *valI)** valI / 2;
393 }
394
395 *valI = *valI - 1;
396 S = (1 + *valI)** valI / 2;
397 *valJ = dNUM - S;
398
399 if ( *valI != i )
400 {
401 *valJ = *valJ - 1;
402 }
403
404 if ( *valJ == -1 )
405 {
406 *valI = *valI - 1;
407 *valJ = *valJ + 1;
408 }
409
410 if ((*valI >= 0) && (*valJ >= 0))
411 {
412 deleteTempCovMatrix(*valI, *valJ);
413 }
414
415 *valJ = j;
416}
417
418template<typename T>
419Eigen::MatrixXd PODTemplate<T>::buildCovMatrix()
420{
421 // the covariance matrix is initialized to a unreal value
422 double CovUnrealValue = 999999.999999;
423 Eigen::MatrixXd covMatrix;
424 covMatrix.setConstant(l_nSnapshot, l_nSnapshot, CovUnrealValue);
425 bool exist_covMatrix_bin = ITHACAutilities::check_file(folder_covMatrix +
426 name_covMatrix);
427 int valI, valJ;
428 //initializing value of etapeI and etapeJ : no temp file found
429 int etapeI, etapeJ;
430 etapeI = -1;
431 etapeJ = -1;
432 // create folder
433 mkDir(folder_covMatrix);
434
435 // in case the cov matrix was not computed
436 if (!exist_covMatrix && !exist_covMatrix_bin)
437 {
438 // updating covMatrix from previous step (when a *_temp_* file exist)
439 findTempFile(&covMatrix, &etapeI, &etapeJ);
440 Info << "Computing the covariance matrix of the " << f_field->name() << " field"
441 << endl;
442 // the size is cov matrix l_nSnapshot, it has been subdivised in l_nBlocks
443 label q = l_nSnapshot / l_nBlocks;
444 label r = l_nSnapshot % l_nBlocks;
445 Info << "q = " << q << endl;
446 Info << "r = " << r << endl;
447 Info << "nSnapshot = " << l_nSnapshot << endl;
448 Info << "nBlocks = " << l_nBlocks << endl;
449 Info << endl;
450 PtrList<T> snapshots;
451
452 // If a temp file is found load it and go to the next step
453 if (etapeI != -1)
454 {
455 if (etapeJ == etapeI - 1)
456 {
457 etapeJ = 0;
458 etapeI += 1;
459 }
460 else
461 {
462 etapeJ += 1;
463 }
464 }
465 else
466 {
467 etapeI = 0;
468 etapeJ = 0;
469 }
470
471 // Number of previous tempory CovMatrix to keep in directory
472 // (parameter used by [deletePreviousTempCovMatrix_N])
473 int N_previous_temp_Mat = 3;
474
475 for (label i = etapeI; i < l_nBlocks; i++)
476 {
477 ITHACAstream::read_fields(snapshots, (*f_field), snapshotsPath,
478 l_startTime - 2 + i * q, q);
479 lift(snapshots);
480 indexTri indTri;
481 indTri.index_start = i * q;
482 indTri.index_end = (i + 1) * q;
483 addCovMatrixTriCoeff(covMatrix, snapshots, indTri);
484 PtrList<T> snapshots2;
485 int valI = etapeI, valJ = etapeJ;
486
487 for (label j = etapeJ; j < i; j++)
488 {
489 ITHACAstream::read_fields(snapshots2, (*f_field), snapshotsPath,
490 l_startTime - 2 + j * q, q);
491 lift(snapshots2);
492 indexSquare indSquare;
493 indSquare.index1_start = i * q;
494 indSquare.index1_end = (i + 1) * q;
495 indSquare.index2_start = j * q;
496 indSquare.index2_end = (j + 1) * q;
497 addCovMatrixSquareCoeff(covMatrix, snapshots, snapshots2, indSquare);
498 // Clear the pointer to snapshots2
499 snapshots2.clear();
500 // Save cove matrix temp file
501 saveTempCovMatrix(covMatrix, i, j);
502 // Delete previous covMatrix temp file after saving the current one
503 deletePreviousTempCovMatrix_N(&valI, &valJ, i, j, N_previous_temp_Mat);
504 }
505
506 // Clear the pointer to snapshots
507 snapshots.clear();
508 valI = i;
509 etapeJ = 0;
510 }
511
512 if (r != 0)
513 {
514 PtrList<T> snapshotsEnd;
515 ITHACAstream::read_fields(snapshotsEnd, (*f_field), snapshotsPath,
516 l_startTime - 2 + l_nBlocks * q, r);
517 lift(snapshotsEnd);
518 indexTri indTri;
519 indTri.index_start = l_nBlocks * q;
520 indTri.index_end = l_nSnapshot;
521 addCovMatrixTriCoeff(covMatrix, snapshotsEnd, indTri);
522 PtrList<T> snapshotsEnd2;
523
524 for (label j = 0; j < l_nBlocks; j++)
525 {
526 ITHACAstream::read_fields(snapshotsEnd2, (*f_field), snapshotsPath,
527 l_startTime - 2 + j * q, q);
528 lift(snapshotsEnd2);
529 indexSquare indSquare;
530 indSquare.index1_start = l_nBlocks * q;
531 indSquare.index1_end = l_nSnapshot;
532 indSquare.index2_start = j * q;
533 indSquare.index2_end = (j + 1) * q;
534 addCovMatrixSquareCoeff(covMatrix, snapshotsEnd, snapshotsEnd2, indSquare);
535 snapshotsEnd2.clear();
536 // Save cove matrix temp file
537 saveTempCovMatrix(covMatrix, l_nBlocks, j);
538 // Delete previous covMatrix temp file after saving the current one
539 deletePreviousTempCovMatrix_N(&valI, &valJ, l_nBlocks, j, N_previous_temp_Mat);
540 }
541
542 snapshotsEnd.clear();
543 }
544 // covMatrix is symetric, the lower part is used to build the upper part
545 covMatrix = covMatrix.selfadjointView<Eigen::Lower>();
546 if (Pstream::master())
547 {
548 cnpy::save(covMatrix, folder_covMatrix + name_covMatrix + ".npy");
549
550 }
551 // Delete previous covMatrix temp file after saving the current one
552 if (r == 0)
553 {
554 deletePreviousTempCovMatrix_N(&valI, &valJ, l_nBlocks - 1, l_nBlocks - 1, 1);
555 }
556
557 if (r != 0)
558 {
559 deletePreviousTempCovMatrix_N(&valI, &valJ, l_nBlocks, l_nBlocks, 1);
560 }
561 }
562 // in case the cov matrix was already computed, it reads in the hard disk
563 else if (exist_covMatrix)
564 {
565 Info << "Reading the covariance matrix of the " << f_field->name() << " field"
566 << endl;
567 cnpy::load(covMatrix, folder_covMatrix + name_covMatrix + ".npy");
568 }
569 // in case the cov matrix was already computed, it reads in the hard disk
570 else
571 {
572 Info << "Reading (binary) the covariance matrix of the " << f_field->name() <<
573 " field" << endl;
574 ITHACAstream::ReadDenseMatrix(covMatrix, folder_covMatrix, name_covMatrix);
575 if (Pstream::master())
576 {
577 cnpy::save(covMatrix, folder_covMatrix + name_covMatrix + ".npy");
578 }
579 }
580
581 // looking for CovUnrealValue
582 int covMatrixOK = 1;
583 int NbCovUnrealValue = 0;
584
585 for (int i = 0; i < l_nSnapshot; i++)
586 {
587 for (int j = i; j < l_nSnapshot; j++)
588 {
589 if (covMatrix(i, j) == CovUnrealValue)
590 {
591 covMatrixOK = 0;
592 NbCovUnrealValue += 1;
593 }
594 }
595 }
596
597 if (covMatrixOK == 0)
598 {
599 Info << "\n!!! OUPS !!! Unreal value [" << CovUnrealValue << "] found " <<
600 NbCovUnrealValue << " times in triangular up part of " << name_covMatrix <<
601 " !!!\n" << endl;
602 abort();
603 }
604
605 double varyingEnergy = covMatrix.trace() / l_nSnapshot;
606
607 if (l_hilbertSp == "L2" || l_hilbertSp == "dL2")
608 {
609 m_parameters->set_varyingEnergy( f_field->name(), varyingEnergy);
610 }
611
612 Info << "Total varying " << l_hilbertSp << " energy for " << field_name << " : "
613 << varyingEnergy << endl;
614 Info << endl;
615 return covMatrix;
616}
617
618
619template<typename T>
620void PODTemplate<T>::addCovMatrixTriCoeff(Eigen::MatrixXd& covMatrix,
621 PtrList<T>& snapshots, indexTri& indTri)
622{
623 Info << "Adding the triangular block [" << indTri.index_start << ":" <<
624 indTri.index_end - 1 << "]x["
625 << indTri.index_start << ":" << indTri.index_end - 1 <<
626 "] to the covariance matrix" << endl;
627 Eigen::MatrixXd covMatrixTemp(ITHACAutilities::dot_product_POD(snapshots,
628 snapshots, l_hilbertSp, weightBC, patchBC));
629
630 for (label i = 0; i < indTri.index_end - indTri.index_start; i++)
631 {
632 for (label j = 0; j <= i; j++)
633 {
634 covMatrix(i + indTri.index_start, j + indTri.index_start) =
635 covMatrixTemp(i, j);
636 }
637 }
638
639 Info << endl;
640}
641
642
643template<typename T>
644void PODTemplate<T>::addCovMatrixSquareCoeff(Eigen::MatrixXd& covMatrix,
645 PtrList<T>& snapshots1,
646 PtrList<T>& snapshots2,
647 indexSquare& indSquare)
648{
649 Info << "Adding the square block [" << indSquare.index1_start << ":" <<
650 indSquare.index1_end - 1 << "]x["
651 << indSquare.index2_start << ":" << indSquare.index2_end - 1 <<
652 "] to the covariance matrix" << endl;
653 Eigen::MatrixXd covMatrixTemp(ITHACAutilities::dot_product_POD(snapshots1,
654 snapshots2, l_hilbertSp, weightBC, patchBC));
655
656 for (label i = 0; i < indSquare.index1_end - indSquare.index1_start; i++)
657 {
658 for (label j = 0; j < indSquare.index2_end - indSquare.index2_start; j++)
659 {
660 covMatrix(i + indSquare.index1_start, j + indSquare.index2_start) =
661 covMatrixTemp(i, j);
662 }
663 }
664
665 Info << endl;
666}
667
668
669template<typename T>
670void PODTemplate<T>::diagonalisation(Eigen::MatrixXd& covMatrix,
671 Eigen::VectorXd& eigenValueseig, Eigen::MatrixXd& eigenVectoreig)
672{
673 if (!exist_eigenDecomposition)
674 {
675 mkDir(folder_eigen);
676 Info << "Performing the eigen decomposition" << endl;
677
678 if (w_eigensolver == "spectra")
679 {
680 Spectra::DenseSymMatProd<double> op(covMatrix);
681 Spectra::SymEigsSolver<Spectra::DenseSymMatProd<double>> es(op, l_nmodes, l_nSnapshot);
682 std::cout << "Using Spectra EigenSolver " << std::endl;
683 es.init();
684 es.compute(Spectra::SortRule::LargestAlge);
685 M_Assert(es.info() == Spectra::CompInfo::Successful,
686 "The Eigenvalue Decomposition did not succeed");
687 eigenVectoreig = es.eigenvectors().real();
688 eigenValueseig = es.eigenvalues().real();
689 }
690 else if (w_eigensolver == "eigen")
691 {
692 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> esEg;
693 std::cout << "Using Eigen EigenSolver " << std::endl;
694 esEg.compute(covMatrix);
695 M_Assert(esEg.info() == Eigen::Success,
696 "The Eigenvalue Decomposition did not succeed");
697 eigenVectoreig = esEg.eigenvectors().real().rowwise().reverse().leftCols(
698 l_nmodes);
699 eigenValueseig = esEg.eigenvalues().real().reverse().head(l_nmodes);
700 }
701 else
702 {
703 }
704
705 // Compute the norm of each Modes
706 eigenValueseigLam = eigenValueseig.real().array().abs().sqrt();
707 // save the eigen values
708
709 if (Pstream::master())
710 {
711 cnpy::save(eigenValueseig, folder_eigen + name_eigenValues + ".npy");
712 // save the eigen vectors
713 cnpy::save(eigenVectoreig,
714 folder_eigen + "/Eigenvector_" + f_field->name() + ".npy");
715 // save the norm of each Modes
716 cnpy::save(eigenValueseigLam,
717 folder_eigen + "/EigenvectorLambda_" + f_field->name() + ".npy");
718 Eigen::VectorXd eigenValueseigNormalized = eigenValueseig /
719 eigenValueseig.sum();
720 Eigen::VectorXd cumEigenValues(eigenValueseigNormalized);
721
722 for (int j = 1; j < cumEigenValues.size(); ++j)
723 {
724 cumEigenValues(j) += cumEigenValues(j - 1);
725 }
726
727 // save eigen values normalized
728 cnpy::save(eigenValueseigNormalized,
729 folder_eigen + name_eigenValuesNormalized + ".npy");
730 // save the cumulated eigen values
731 cnpy::save(cumEigenValues, folder_eigen + name_cumEigenValues + ".npy");
732 }
733 }
734 else
735 {
736 // in case the eigen decomposition was already performed
737 // load eigen values
738 cnpy::load(eigenValueseig, folder_eigen + name_eigenValues + ".npy");
739 // load eigen vectors
740 cnpy::load(eigenVectoreig,
741 folder_eigen + "/Eigenvector_" + f_field->name() + ".npy");
742 // load the norm of each Modes
743 cnpy::load(eigenValueseigLam,
744 folder_eigen + "/EigenvectorLambda_" + f_field->name() + ".npy");
745 }
746
747 double resolvedVaryingEnergy = eigenValueseig.sum() / l_nSnapshot;
748
749 if (l_hilbertSp == "L2")
750 {
751 m_parameters->set_resolvedVaryingEnergy( f_field->name(),
752 resolvedVaryingEnergy);
753 }
754 else
755 {
756 m_parameters->set_resolvedVaryingEnergy( f_field->name() + "_" +
757 l_hilbertSp, resolvedVaryingEnergy);
758 }
759
760 Info << "% of varying " << l_hilbertSp << " energy captures by the modes for "
761 << field_name
762 << " : " << 100.0 * eigenValueseig.sum() / covMatrix.trace() << "%" << endl;
763 Info << endl;
764}
765
766
767template<typename T>
768PtrList<T> PODTemplate<T>::computeSpatialModes(Eigen::VectorXd& eigenValueseig,
769 Eigen::MatrixXd& eigenVectoreig)
770{
771 PtrList<T> spatialModes;
772
773 // In case the modes were not computed
774 if (!exist_spatialModes)
775 {
776 Info << "Computing the spatial modes of the " << f_field->name() << " field" <<
777 endl;
778 spatialModes.resize(l_nmodes);
779
780 for (int k = 0; k < l_nmodes; k++)
781 {
782 spatialModes.set(k, new T(f_field->name(), *f_field) );
783 ITHACAutilities::setToZero(spatialModes[k]);
784 }
785
786 for (label j = 0; j < l_nSnapshot; j++)
787 {
788 T snapshotj = *f_field;
789 ITHACAstream::read_snapshot(snapshotj, timeFolders[l_startTime+j].name(), snapshotsPath);
790
791 if ((m_parameters->get_DEIMInterpolatedField() == "nut"
792 || ITHACAutilities::containsSubstring(m_parameters->get_DEIMInterpolatedField(), "reducedNut"))
793 && l_hilbertSp == "dL2")
794 {
795 ITHACAutilities::multField(snapshotj, m_parameters->get_deltaWeight());
796 }
797
798 lift(snapshotj);
799
800 for (label k = 0; k < l_nmodes; k++)
801 {
802 ITHACAutilities::addFields(spatialModes[k], snapshotj, eigenVectoreig(j, k));
803 }
804 }
805
806 for (int k = 0; k < l_nmodes; k++)
807 {
808 ITHACAutilities::multField(spatialModes[k], 1 / eigenValueseigLam(k));
809 }
810
811 mkDir(folder_spatialModes);
812 ITHACAstream::exportFields(spatialModes, folder_spatialModes, f_field->name());
813 }
814 // in the case the spatial modes was already computed, it reads in the hard disk
815 else
816 {
817 Info << "Reading the spatial modes of the " << f_field->name() << " field" <<
818 endl;
819 ITHACAstream::read_fields(spatialModes, (*f_field), folder_spatialModes);
820 }
821
822 Info << endl;
823 return spatialModes;
824}
825
826
827template<typename T>
828Eigen::MatrixXd PODTemplate<T>::computeTemporalModes(Eigen::VectorXd&
829 eigenValueseig, Eigen::MatrixXd& eigenVectoreig)
830{
831 Eigen::MatrixXd temporalModes(l_nSnapshot, l_nmodes);
832
833 if (!exist_temporalModes)
834 {
835 Info << "Computing the temporal modes of the " << f_field->name() << " field" <<
836 endl;
837 mkDir( folder_temporalModes );
838
839 for (int i = 0; i < l_nmodes; i++)
840 {
841 temporalModes.col(i) = eigenVectoreig.col(i) * eigenValueseigLam(i);
842 }
843
844 if (Pstream::master())
845 {
846 cnpy::save(temporalModes, folder_temporalModes + f_field->name() + ".npy");
847 }
848 }
849 else
850 {
851 Info << "Reading the temporal modes of the " << f_field->name() << " field" <<
852 endl;
853 cnpy::load(temporalModes, folder_temporalModes + f_field->name() + ".npy");
854 }
855
856 Info << endl;
857 return temporalModes;
858}
859
860template<typename T>
861void PODTemplate<T>::getModes(PtrList<T>& spatialModes,
862 Eigen::MatrixXd& temporalModes, Eigen::MatrixXd& temporalModesSimulation,
863 Eigen::MatrixXd& covMatrix)
864{
865 Info << "-------------------------------------------------------------------------------------------"
866 << endl;
867 Info << "The POD is performing with the following parameters :" << endl;
868 Info << "Field : " << f_field->name() << endl;
869 Info << "Number of modes : " << l_nmodes << endl;
870 Info << "POD Hilbert space : " << l_hilbertSp << endl;
871 Info << "Weight for the boundary conditions (0 for L2 POD Hilbert space) : " <<
872 weightBC << endl;
873 Info << "Patch for the boundary conditions(inlet by default) used in L2wBC : "
874 << patchBC << endl;
875 Info << "start time : " << l_startTime << endl;
876 Info << "End time : " << l_endTime << endl;
877 Info << "Number of snapshots : " << l_nSnapshot << endl;
878 Info << "Number of test snapshots : " << l_nSnapshotSimulation << endl;
879 Info << "Number of blocks : " << l_nBlocks << endl;
880 Info << "Centered datas or not : " << b_centeredOrNot <<
881 " (1 centered, 0 not centered)" << endl;
882 Info << "Name of eigensolver used : " << w_eigensolver << endl;
883 Info << "Results folder : " << "ITHACAoutput" << endl;
884 computeMeanField();
885 covMatrix = this->buildCovMatrix();
886 // Reduction (parallelization)
887 Eigen::VectorXd eigenValueseig = Eigen::VectorXd::Zero(l_nmodes);
888 Eigen::MatrixXd eigenVectoreig = Eigen::MatrixXd::Zero(l_nSnapshot, l_nmodes);
889 diagonalisation(covMatrix, eigenValueseig, eigenVectoreig);
890 spatialModes = computeSpatialModes(eigenValueseig, eigenVectoreig);
891 temporalModes = computeTemporalModes(eigenValueseig, eigenVectoreig);
892 compute_lambda(temporalModes);
893 temporalModesSimulation = computeSimulationTemporalModes(spatialModes);
894 // Reduction (parallelization)
895
896 if (field_name == "U")
897 {
898 m_parameters->set_eigenValues_U(eigenValueseig);
899 m_parameters->set_lambda(lambda);
900 }
901
902 Info << "-------------------------------------------------------------------------------------------"
903 << endl;
904}
905
906template<typename T>
907Eigen::MatrixXd PODTemplate<T>::computeSimulationTemporalModes(
908 PtrList<T>& f_spatialModes)
909{
910 Eigen::MatrixXd temporalModesSimulation(l_nSnapshotSimulation, l_nmodes);
911
912 if (!exist_temporalModesSimulation)
913 {
914 Info << "Computing the Simulation temporal modes of the " << f_field->name() <<
915 " field" << endl;
916 mkDir( folder_temporalModesSimulation );
917 label l_startTimeSimulation(l_endTime);
918
919 for (label j = 0; j < l_nSnapshotSimulation; j++)
920 {
921 T snapshotj = *f_field;
922 ITHACAstream::read_snapshot(snapshotj, timeFolders[l_startTimeSimulation+j].name(), snapshotsPath);
923
924 if ((m_parameters->get_DEIMInterpolatedField() == "nut"
925 || ITHACAutilities::containsSubstring(m_parameters->get_DEIMInterpolatedField(), "reducedNut"))
926 && l_hilbertSp == "dL2")
927 {
928 ITHACAutilities::multField(snapshotj, m_parameters->get_deltaWeight());
929 }
930
931 lift(snapshotj);
932
933 for (label i = 0; i < l_nmodes; i++)
934 {
935 temporalModesSimulation(j, i) = ITHACAutilities::dot_product_POD(snapshotj,
936 f_spatialModes[i], l_hilbertSp, weightBC, patchBC, weightH1);
937 }
938 }
939
940 if (Pstream::master())
941 {
942 cnpy::save(temporalModesSimulation,
943 folder_temporalModesSimulation + f_field->name() + ".npy");
944 }
945 }
946 else
947 {
948 Info << "Reading the Simulation temporal modes of the " << f_field->name() <<
949 " field" << endl;
950 cnpy::load(temporalModesSimulation,
951 folder_temporalModesSimulation + f_field->name() + ".npy");
952 }
953
954 Info << endl;
955 return temporalModesSimulation;
956}
957
958template<typename T>
959void PODTemplate<T>::compute_lambda(Eigen::MatrixXd& temporalModes)
960{
961 for (int p = 0; p < l_nmodes; p++)
962 {
963 for (int i = 0; i < l_nSnapshot; i++)
964 {
965 lambda(p) += temporalModes(i, p) * temporalModes(i, p);
966 }
967
968 lambda(p) /= l_nSnapshot;
969 }
970}
971
972
973template<typename T>
974void PODTemplate<T>::lift(PtrList<T>& snapshots)
975{
976 if (lifting)
977 {
978 PtrList<T> omfield;
979 computeLift(snapshots, liftfield, omfield, inletIndex);
980 snapshots = omfield;
981 }
982
983 if (b_centeredOrNot)
984 {
985 for (label k = 0; k < snapshots.size(); k++)
986 {
987 ITHACAutilities::subtractFields(snapshots[k], *f_meanField);
988 }
989 }
990}
991
992template<typename T>
993void PODTemplate<T>::lift(T& snapshot)
994{
995 PtrList<T> snapshots(1);
996 snapshots.set(0, new T(snapshot.name(), snapshot));
997 lift(snapshots);
998 snapshot = snapshots[0];
999 List<Eigen::VectorXd> snapshotsBC = Foam2Eigen::field2EigenBC(snapshots[0]);
1000
1001 for (int k = 0; k < snapshotsBC.size(); k++)
1002 {
1003 ITHACAutilities::assignBC(snapshot, k, snapshotsBC[k]);
1004 }
1005}
1006
1007// Specialisation
1008template PODTemplate<volTensorField>::PODTemplate(Parameters*
1009 myParameters, const word& myfield_name, const word& mySnapshots_path);
1010// template PODTemplate<volTensorField>::PODTemplate(m_parameters* myParameters, const word& myfield_name);
1011// template PODTemplate<volTensorField>::PODTemplate(Parameters* myParameters, const word& myfield_name, bool b_centeredOrNot);
1012template PODTemplate<volTensorField>::~PODTemplate();
1013template void PODTemplate<volTensorField>::define_paths();
1014template void PODTemplate<volTensorField>::computeMeanField();
1015template void PODTemplate<volTensorField>::appendMeanfieldtoSpatialModes(
1016 PtrList<volTensorField>& spatialModes);
1017template void PODTemplate<volTensorField>::findTempFile(Eigen::MatrixXd* covMat,
1018 int* index1, int* index2);
1019template void PODTemplate<volTensorField>::deleteTempCovMatrix(int i, int j);
1020
1021template word PODTemplate<volTensorField>::nameTempCovMatrix(int i, int j);
1022template void PODTemplate<volTensorField>::saveTempCovMatrix(
1023 Eigen::MatrixXd& covMatrix, int i, int j);
1024template void PODTemplate<volTensorField>::deletePreviousTempCovMatrix_N(
1025 int* valI, int* valJ, int i, int j, int N);
1026
1027template Eigen::MatrixXd PODTemplate<volTensorField>::buildCovMatrix();
1028template void PODTemplate<volTensorField>::addCovMatrixTriCoeff(
1029 Eigen::MatrixXd& covMatrix,
1030 PtrList<volTensorField>& snapshots,
1031 indexTri& indTri);
1032template void PODTemplate<volTensorField>::addCovMatrixSquareCoeff(
1033 Eigen::MatrixXd& covMatrix,
1034 PtrList<volTensorField>& snapshots1,
1035 PtrList<volTensorField>& snapshots2,
1036 indexSquare& indSquare);
1037template void PODTemplate<volTensorField>::diagonalisation(
1038 Eigen::MatrixXd& covMatrix, Eigen::VectorXd& eigenValueseig,
1039 Eigen::MatrixXd& eigenVectoreig);
1040template PtrList<volTensorField>
1041PODTemplate<volTensorField>::computeSpatialModes(Eigen::VectorXd&
1042 eigenValueseig, Eigen::MatrixXd& eigenVectoreig);
1043// template List<Eigen::MatrixXd> PODTemplate<volTensorField>::computeModesEig(Eigen::VectorXd& eigenValueseigLam, Eigen::MatrixXd& eigenVectoreig);
1044template Eigen::MatrixXd PODTemplate<volTensorField>::computeTemporalModes(
1045 Eigen::VectorXd& eigenValueseig, Eigen::MatrixXd& eigenVectoreig);
1046template void PODTemplate<volTensorField>::getModes(PtrList<volTensorField>&
1047 spatialModes, Eigen::MatrixXd& temporalModes,
1048 Eigen::MatrixXd& temporalModesSimulation, Eigen::MatrixXd& covMatrix);
1049template Eigen::MatrixXd
1050PODTemplate<volTensorField>::computeSimulationTemporalModes(
1051 PtrList<volTensorField>& spatialModes);
1052template void PODTemplate<volTensorField>::compute_lambda(
1053 Eigen::MatrixXd& temporalModes);
1054template void PODTemplate<volTensorField>::lift(PtrList<volTensorField>&
1055 snapshots);
1056template void PODTemplate<volTensorField>::lift(volTensorField& snapshot);
1057
1058// Specialisation
1059template PODTemplate<volVectorField>::PODTemplate(Parameters*
1060 myParameters, const word& myfield_name, const word& mySnapshots_path);
1061// template PODTemplate<volVectorField>::PODTemplate(m_parameters* myParameters, const word& myfield_name);
1062// template PODTemplate<volVectorField>::PODTemplate(Parameters* myParameters, const word& myfield_name, bool b_centeredOrNot);
1063template PODTemplate<volVectorField>::~PODTemplate();
1064template void PODTemplate<volVectorField>::define_paths();
1065template void PODTemplate<volVectorField>::computeMeanField();
1066template void PODTemplate<volVectorField>::appendMeanfieldtoSpatialModes(
1067 PtrList<volVectorField>& spatialModes);
1068template Eigen::MatrixXd PODTemplate<volVectorField>::buildCovMatrix();
1069template void PODTemplate<volVectorField>::addCovMatrixTriCoeff(
1070 Eigen::MatrixXd& covMatrix,
1071 PtrList<volVectorField>& snapshots,
1072 indexTri& indTri);
1073template void PODTemplate<volVectorField>::addCovMatrixSquareCoeff(
1074 Eigen::MatrixXd& covMatrix,
1075 PtrList<volVectorField>& snapshots1,
1076 PtrList<volVectorField>& snapshots2,
1077 indexSquare& indSquare);
1078template void PODTemplate<volVectorField>::diagonalisation(
1079 Eigen::MatrixXd& covMatrix, Eigen::VectorXd& eigenValueseig,
1080 Eigen::MatrixXd& eigenVectoreig);
1081template PtrList<volVectorField>
1082PODTemplate<volVectorField>::computeSpatialModes(Eigen::VectorXd&
1083 eigenValueseig, Eigen::MatrixXd& eigenVectoreig);
1084// template List<Eigen::MatrixXd> PODTemplate<volVectorField>::computeModesEig(Eigen::VectorXd& eigenValueseigLam, Eigen::MatrixXd& eigenVectoreig);
1085template Eigen::MatrixXd PODTemplate<volVectorField>::computeTemporalModes(
1086 Eigen::VectorXd& eigenValueseig, Eigen::MatrixXd& eigenVectoreig);
1087template void PODTemplate<volVectorField>::getModes(PtrList<volVectorField>&
1088 spatialModes, Eigen::MatrixXd& temporalModes,
1089 Eigen::MatrixXd& temporalModesSimulation, Eigen::MatrixXd& covMatrix);
1090template Eigen::MatrixXd
1091PODTemplate<volVectorField>::computeSimulationTemporalModes(
1092 PtrList<volVectorField>& spatialModes);
1093template void PODTemplate<volVectorField>::compute_lambda(
1094 Eigen::MatrixXd& temporalModes);
1095template void PODTemplate<volVectorField>::lift(PtrList<volVectorField>&
1096 snapshots);
1097template void PODTemplate<volVectorField>::lift(volVectorField& snapshot);
1098
1099// Specialisation
1100template PODTemplate<volScalarField>::PODTemplate(Parameters*
1101 myParameters, const word& myfield_name, const word& mySnapshots_path);
1102// template PODTemplate<volScalarField>::PODTemplate(m_parameters* myParameters, const word& myfield_name);
1103// template PODTemplate<volScalarField>::PODTemplate(Parameters* myParameters, const word& myfield_name, bool b_centeredOrNot);
1104template PODTemplate<volScalarField>::~PODTemplate();
1105template void PODTemplate<volScalarField>::define_paths();
1106template void PODTemplate<volScalarField>::computeMeanField();
1107template void PODTemplate<volScalarField>::appendMeanfieldtoSpatialModes(
1108 PtrList<volScalarField>& spatialModes);
1109template Eigen::MatrixXd PODTemplate<volScalarField>::buildCovMatrix();
1110template void PODTemplate<volScalarField>::addCovMatrixTriCoeff(
1111 Eigen::MatrixXd& covMatrix,
1112 PtrList<volScalarField>& snapshots,
1113 indexTri& indTri);
1114template void PODTemplate<volScalarField>::addCovMatrixSquareCoeff(
1115 Eigen::MatrixXd& covMatrix,
1116 PtrList<volScalarField>& snapshots1,
1117 PtrList<volScalarField>& snapshots2,
1118 indexSquare& indSquare);
1119template void PODTemplate<volScalarField>::diagonalisation(
1120 Eigen::MatrixXd& covMatrix, Eigen::VectorXd& eigenValueseig,
1121 Eigen::MatrixXd& eigenVectoreig);
1122template PtrList<volScalarField>
1123PODTemplate<volScalarField>::computeSpatialModes(Eigen::VectorXd&
1124 eigenValueseig, Eigen::MatrixXd& eigenVectoreig);
1125// template List<Eigen::MatrixXd> PODTemplate<volScalarField>::computeModesEig(Eigen::VectorXd& eigenValueseigLam, Eigen::MatrixXd& eigenVectoreig);
1126template Eigen::MatrixXd PODTemplate<volScalarField>::computeTemporalModes(
1127 Eigen::VectorXd& eigenValueseig, Eigen::MatrixXd& eigenVectoreig);
1128template void PODTemplate<volScalarField>::getModes(PtrList<volScalarField>&
1129 spatialModes, Eigen::MatrixXd& temporalModes,
1130 Eigen::MatrixXd& temporalModesSimulation, Eigen::MatrixXd& covMatrix);
1131template Eigen::MatrixXd
1132PODTemplate<volScalarField>::computeSimulationTemporalModes(
1133 PtrList<volScalarField>& spatialModes);
1134template void PODTemplate<volScalarField>::compute_lambda(
1135 Eigen::MatrixXd& temporalModes);
1136template void PODTemplate<volScalarField>::lift(PtrList<volScalarField>&
1137 snapshots);
1138template void PODTemplate<volScalarField>::lift(volScalarField& snapshot);
1139
1140
1141
1142void computeLift(PtrList<volTensorField>& Lfield,
1143 PtrList<volTensorField>& liftfield, PtrList<volTensorField>& omfield,
1144 Eigen::MatrixXi inletIndex)
1145{
1146 scalar u_bc;
1147 scalar u_lf;
1148 scalar area;
1149
1150 for (label k = 0; k < inletIndex.rows(); k++)
1151 {
1152 label p = inletIndex(k, 0);
1153 label l = inletIndex(k, 1);
1154 area = gSum(Lfield[0].mesh().magSf().boundaryField()[p]);
1155 u_lf = gSum(liftfield[k].mesh().magSf().boundaryField()[p] *
1156 liftfield[k].boundaryField()[p]).component(l) / area;
1157 M_Assert(std::abs(u_lf) > 1e-5,
1158 "The lift cannot be computed. Please, check your inletIndex definition");
1159
1160 for (label j = 0; j < Lfield.size(); j++)
1161 {
1162 if (k == 0)
1163 {
1164 u_bc = gSum(Lfield[j].mesh().magSf().boundaryField()[p] *
1165 Lfield[j].boundaryField()[p]).component(l) / area;
1166 volTensorField C(Lfield[0].name(), Lfield[j] - liftfield[k]*u_bc / u_lf);
1167 omfield.append(C.clone());
1168 }
1169 else
1170 {
1171 u_bc = gSum(omfield[j].mesh().magSf().boundaryField()[p] *
1172 omfield[j].boundaryField()[p]).component(l) / area;
1173 volTensorField C(Lfield[0].name(), omfield[j] - liftfield[k]*u_bc / u_lf);
1174 omfield.set(j, C.clone());
1175 }
1176 }
1177 }
1178}
1179
1180void computeLift(PtrList<volVectorField>& Lfield,
1181 PtrList<volVectorField>& liftfield, PtrList<volVectorField>& omfield,
1182 Eigen::MatrixXi inletIndex)
1183{
1184 scalar u_bc;
1185 scalar u_lf;
1186 scalar area;
1187
1188 for (label k = 0; k < inletIndex.rows(); k++)
1189 {
1190 label p = inletIndex(k, 0);
1191 label l = inletIndex(k, 1);
1192 area = gSum(Lfield[0].mesh().magSf().boundaryField()[p]);
1193 u_lf = gSum(liftfield[k].mesh().magSf().boundaryField()[p] *
1194 liftfield[k].boundaryField()[p]).component(l) / area;
1195 M_Assert(std::abs(u_lf) > 1e-5,
1196 "The lift cannot be computed. Please, check your inletIndex definition");
1197
1198 for (label j = 0; j < Lfield.size(); j++)
1199 {
1200 if (k == 0)
1201 {
1202 u_bc = gSum(Lfield[j].mesh().magSf().boundaryField()[p] *
1203 Lfield[j].boundaryField()[p]).component(l) / area;
1204 volVectorField C(Lfield[0].name(), Lfield[j] - liftfield[k]*u_bc / u_lf);
1205 omfield.append(C.clone());
1206 }
1207 else
1208 {
1209 u_bc = gSum(omfield[j].mesh().magSf().boundaryField()[p] *
1210 omfield[j].boundaryField()[p]).component(l) / area;
1211 volVectorField C(Lfield[0].name(), omfield[j] - liftfield[k]*u_bc / u_lf);
1212 omfield.set(j, C.clone());
1213 }
1214 }
1215 }
1216}
1217
1218void computeLift(PtrList<volScalarField>& Lfield,
1219 PtrList<volScalarField>& liftfield, PtrList<volScalarField>& omfield,
1220 Eigen::MatrixXi inletIndex)
1221{
1222 scalar t_bc;
1223 scalar t_lf;
1224 scalar area;
1225
1226 for (label k = 0; k < inletIndex.rows(); k++)
1227 {
1228 label p = inletIndex(k, 0);
1229 area = gSum(Lfield[0].mesh().magSf().boundaryField()[p]);
1230 t_lf = gSum(liftfield[k].mesh().magSf().boundaryField()[p] *
1231 liftfield[k].boundaryField()[p]) / area;
1232
1233 for (label j = 0; j < Lfield.size(); j++)
1234 {
1235 if (k == 0)
1236 {
1237 t_bc = gSum(Lfield[j].mesh().magSf().boundaryField()[p] *
1238 Lfield[j].boundaryField()[p]) / area;
1239 volScalarField C(Lfield[0].name(), Lfield[j] - liftfield[k]*t_bc / t_lf);
1240 omfield.append(C.clone());
1241 }
1242 else
1243 {
1244 t_bc = gSum(omfield[j].mesh().magSf().boundaryField()[p] *
1245 omfield[j].boundaryField()[p]) / area;
1246 volScalarField C(Lfield[0].name(), omfield[j] - liftfield[k]*t_bc / t_lf);
1247 omfield.set(j, C.clone());
1248 }
1249 }
1250 }
1251}
1252
1253}
static List< Eigen::VectorXd > field2EigenBC(GeometricField< scalar, PatchField, GeoMesh > &field)
Convert an OpenFOAM scalar field to a List of Eigen Vectors, one for each boundary.
Definition Foam2Eigen.C:253
namespace for the computation of the POD, it exploits bot the method of snapshots and SVD.
void ReadDenseMatrix(MatrixType &Matrix, word folder, word MatrixName)
Read a dense matrix from a binary format file.
void exportFields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &field, word folder, word fieldname)
Function to export a scalar of vector field.
void read_fields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &Lfield, word Name, fileName casename, int first_snap, int n_snap)
Function to read a list of fields from the name of the field and casename.
bool containsSubstring(std::string contain, std::string contained)
Returns true if contained is a substring of contain, false otherwise.
void multField(T &f1, double alpha)
Multiplication between a field of type vol[Scalar|Vector|Tensor]Field and a double.
void setToZero(T &f1)
Set a field of type vol[Scalar|Vector|Tensor]Field to 0.
Eigen::MatrixXd dot_product_POD(PtrList< T > &v, PtrList< T > &w, const word &hilbertSpacePOD, const double &weightBC, const word &patchBC, const double &weightH1)
Perform the dot product of two PtrList of type T.
Definition ITHACAnorm.C:41
void addFields(T &f1, const T &f2c, double alpha)
Perform the following operation f1 + f2 * alpha with f1 and f2 being of type vol[Scalar|Vector|Tensor...
double dot_product_L2(const volVectorField &v, const volVectorField &w)
Perform the L2 dot product of v and w.
Definition ITHACAnorm.C:182
void assignBC(GeometricField< scalar, fvPatchField, volMesh > &s, label BC_ind, double value)
Assign uniform Boundary Condition to a volScalarField.
bool check_file(std::string fileName)
Function that returns true if a file exists.
void subtractFields(T &f1, const T &f2)
Perform the substraction (f1 - f2) between two fields of type vol[Scalar|Vector|Tensor]Field and alph...