Loading...
Searching...
No Matches
Modes.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ██╗████████╗██╗ ██╗ █████╗ ██████╗ █████╗ ███████╗██╗ ██╗
3 ██║╚══██╔══╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ██╔════╝██║ ██║
4 ██║ ██║ ███████║███████║██║ ███████║█████╗█████╗ ██║ ██║
5 ██║ ██║ ██╔══██║██╔══██║██║ ██╔══██║╚════╝██╔══╝ ╚██╗ ██╔╝
6 ██║ ██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ╚████╔╝
7 ╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═══╝
8
9 * In real Time Highly Advanced Computational Applications for Finite Volumes
10 * Copyright (C) 2017 by the ITHACA-FV authors
11-------------------------------------------------------------------------------
12
13License
14 This file is part of ITHACA-FV
15
16 ITHACA-FV is free software: you can redistribute it and/or modify
17 it under the terms of the GNU Lesser General Public License as published by
18 the Free Software Foundation, either version 3 of the License, or
19 (at your option) any later version.
20
21 ITHACA-FV is distributed in the hope that it will be useful,
22 but WITHOUT ANY WARRANTY; without even the implied warranty of
23 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 GNU Lesser General Public License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with ITHACA-FV. If not, see <http://www.gnu.org/licenses/>.
28
29\*---------------------------------------------------------------------------*/
30
31
34
35#include "Modes.H"
36
37template<class Type, template<class> class PatchField, class GeoMesh>
39{
40 NBC = 0;
41
42 for (label i = 0; i < (this->first()).boundaryFieldRef().size(); i++)
43 {
44 if ((this->first()).boundaryFieldRef()[i].type() != "processor")
45 {
46 NBC++;
47 }
48 }
49
50 EigenModes.resize(NBC + 1);
51 EigenModes[0] = Foam2Eigen::PtrList2Eigen(this->toPtrList());
52 List<Eigen::MatrixXd> BC = Foam2Eigen::PtrList2EigenBC(this->toPtrList());
53
54 for (label i = 0; i < NBC; i++)
55 {
56 EigenModes[i + 1] = BC[i];
57 }
58
59 return EigenModes;
60}
61
62template<class Type, template<class> class PatchField, class GeoMesh>
64 fvMatrix<Type>& Af, label numberOfModes,
65 word projType)
66{
67 M_Assert(projType == "G" || projType == "PG",
68 "Projection type can be G for Galerkin or PG for Petrov-Galerkin");
69 List<Eigen::MatrixXd> LinSys;
70 LinSys.resize(2);
71
72 if (EigenModes.size() == 0)
73 {
74 toEigen();
75 }
76
77 Eigen::SparseMatrix<double> Ae;
78 Eigen::VectorXd be;
80
81 if (numberOfModes == 0)
82 {
83 if (projType == "G")
84 {
85 LinSys[0] = EigenModes[0].transpose() * Ae * EigenModes[0];
86 LinSys[1] = EigenModes[0].transpose() * be;
87 }
88
89 if (projType == "PG")
90 {
91 LinSys[0] = (Ae * EigenModes[0]).transpose() * Ae * EigenModes[0];
92 LinSys[1] = (Ae * EigenModes[0]).transpose() * be;
93 }
94 }
95 else
96 {
97 M_Assert(numberOfModes <= EigenModes[0].cols(),
98 "Number of required modes for projection is higher then the number of available ones");
99
100 if (projType == "G")
101 {
102 LinSys[0] = ((EigenModes[0]).leftCols(numberOfModes)).transpose() * Ae *
103 (EigenModes[0]).leftCols(numberOfModes);
104 LinSys[1] = ((EigenModes[0]).leftCols(numberOfModes)).transpose() * be;
105 }
106
107 if (projType == "PG")
108 {
109 LinSys[0] = (Ae * ((EigenModes[0]).leftCols(numberOfModes))).transpose() * Ae *
110 (EigenModes[0]).leftCols(numberOfModes);
111 LinSys[1] = (Ae * ((EigenModes[0]).leftCols(numberOfModes))).transpose() * be;
112 }
114
115 return LinSys;
116}
117
118template<class Type, template<class> class PatchField, class GeoMesh>
120 GeometricField<Type, PatchField, GeoMesh>&
121 field, label numberOfModes, word projType, fvMatrix<Type>* Af)
122{
123 M_Assert(projType == "F" || projType == "G" || projType == "PG",
124 "Projection type can be F for Frobenius, G for Galerkin or PG for Petrov-Galerkin");
125 Eigen::MatrixXd fieldEig = Foam2Eigen::field2Eigen(field);
126 auto vol = ITHACAutilities::getMassMatrixFV(field);
127 Eigen::MatrixXd projField;
128 Eigen::MatrixXd M;
129 Eigen::MatrixXd b;
130
131 if (EigenModes.size() == 0)
132 {
133 toEigen();
134 }
135
136 if (numberOfModes == 0)
137 {
138 if (projType == "F")
139 {
140 vol = Eigen::VectorXd::Ones(vol.size());
141 b = EigenModes[0].transpose() * vol.asDiagonal() * fieldEig;
142 M = EigenModes[0].transpose() * EigenModes[0].transpose();
143 projField = M.fullPivLu().solve(b);
144 }
145 else if (projType == "G")
146 {
147 projField = EigenModes[0].transpose() * vol.asDiagonal() * fieldEig;
148 }
149 else if (projType == "PG")
150 {
151 M_Assert(Af != NULL,
152 "Using a Petrov-Galerkin projection you have to provide also the system matrix");
153 Eigen::SparseMatrix<double> Ae;
154 Eigen::VectorXd be;
155 Foam2Eigen::fvMatrix2Eigen(*Af, Ae, be);
156 projField = (Ae * EigenModes[0]).transpose() * vol.asDiagonal() * fieldEig;
157 }
158 }
159 else
160 {
161 M_Assert(numberOfModes <= EigenModes[0].cols(),
162 "Number of required modes for projection is higher then the number of available ones");
163
164 if (projType == "F")
165 {
166 vol = Eigen::VectorXd::Ones(vol.size());
167 M = EigenModes[0].leftCols(numberOfModes).transpose() * EigenModes[0].leftCols(
168 numberOfModes);
169 b = ((EigenModes[0]).leftCols(numberOfModes)).transpose() *
170 vol.asDiagonal() * fieldEig;
171 projField = M.fullPivLu().solve(b);
172 }
173 else if (projType == "G")
174 {
175 projField = ((EigenModes[0]).leftCols(numberOfModes)).transpose() *
176 vol.asDiagonal() * fieldEig;
177 }
178 else if (projType == "PG")
179 {
180 M_Assert(Af != NULL,
181 "Using a Petrov-Galerkin projection you have to provide also the system matrix");
182 Eigen::SparseMatrix<double> Ae;
183 Eigen::VectorXd be;
184 Foam2Eigen::fvMatrix2Eigen(*Af, Ae, be);
185 projField = (Ae * ((EigenModes[0]).leftCols(numberOfModes))).transpose() *
186 vol.asDiagonal() * fieldEig;
187 }
188 }
189
190 return projField;
191}
192
193template<class Type, template<class> class PatchField, class GeoMesh>
194GeometricField<Type, PatchField, GeoMesh>
196 GeometricField<Type, PatchField, GeoMesh>&
197 field, label numberOfModes, word projType, fvMatrix<Type>* Af)
198{
199 Eigen::MatrixXd proj = project(field, numberOfModes, projType, Af);
200 GeometricField<Type, PatchField, GeoMesh> projSnap = field;
201 reconstruct(projSnap, proj, projSnap.name());
202 return projSnap;
203}
204
205template<class Type, template<class> class PatchField, class GeoMesh>
207 PtrList<GeometricField<Type, PatchField, GeoMesh>>&
208 fields,
209 label numberOfModes, word projType, fvMatrix<Type>* Af)
210{
211 M_Assert(projType == "G" || projType == "PG",
212 "Projection type can be G for Galerking or PG for Petrov-Galerkin");
213 Eigen::MatrixXd fieldEig = Foam2Eigen::PtrList2Eigen(fields);
214 auto vol = ITHACAutilities::getMassMatrixFV(fields[0]);
215 Eigen::MatrixXd projField;
216
217 if (EigenModes.size() == 0)
218 {
219 toEigen();
220 }
222 if (numberOfModes == 0)
223 {
224 if (projType == "F")
225 {
226 vol = Eigen::VectorXd::Ones(vol.size());
227 projField = EigenModes[0].transpose() * vol.asDiagonal() * fieldEig;
228 }
229 else if (projType == "G")
230 {
231 projField = EigenModes[0].transpose() * vol.asDiagonal() * fieldEig;
232 }
233 else if (projType == "PG")
234 {
235 M_Assert(Af != NULL,
236 "Using a Petrov-Galerkin projection you have to provide also the system matrix");
237 Eigen::SparseMatrix<double> Ae;
238 Eigen::VectorXd be;
239 Foam2Eigen::fvMatrix2Eigen(*Af, Ae, be);
240 projField = (Ae * EigenModes[0]).transpose() * vol.asDiagonal() * fieldEig;
241 }
242 }
243 else
244 {
245 M_Assert(numberOfModes <= EigenModes[0].cols(),
246 "Number of required modes for projection is higher then the number of available ones");
247
248 if (projType == "F")
249 {
250 vol = Eigen::VectorXd::Ones(vol.size());
251 projField = ((EigenModes[0]).leftCols(numberOfModes)).transpose() *
252 vol.asDiagonal() * fieldEig;
253 }
254 else if (projType == "G")
255 {
256 projField = ((EigenModes[0]).leftCols(numberOfModes)).transpose() *
257 vol.asDiagonal() * fieldEig;
258 }
259 else if (projType == "PG")
260 {
261 M_Assert(Af != NULL,
262 "Using a Petrov-Galerkin projection you have to provide also the system matrix");
263 Eigen::SparseMatrix<double> Ae;
264 Eigen::VectorXd be;
265 Foam2Eigen::fvMatrix2Eigen(*Af, Ae, be);
266 projField = (Ae * ((EigenModes[0]).leftCols(numberOfModes))).transpose() *
267 vol.asDiagonal() * fieldEig;
268 }
269 }
270
271 return projField;
272}
273template<class Type, template<class> class PatchField, class GeoMesh>
274GeometricField<Type, PatchField, GeoMesh>
276 GeometricField<Type, PatchField, GeoMesh>& inputField,
277 Eigen::MatrixXd Coeff,
278 word Name)
279{
280 if (EigenModes.size() == 0)
281 {
282 toEigen();
283 }
284
285 label Nmodes = Coeff.rows();
286 Eigen::VectorXd InField = EigenModes[0].leftCols(Nmodes) * Coeff;
287
288 if (inputField.name() == "nut")
289 {
290 InField = (InField.array() < 0).select(0, InField);
291 }
292
293 inputField = Foam2Eigen::Eigen2field(inputField, InField);
294 inputField.rename(Name);
295
296 for (label i = 0; i < NBC; i++)
297 {
298 Eigen::VectorXd BF = EigenModes[i + 1].leftCols(Nmodes) * Coeff;
299
300 if (inputField.name() == "nut")
301 {
302 BF = (BF.array() < 0).select(0, BF);
303 }
304
305 ITHACAutilities::assignBC(inputField, i, BF);
306 }
307
308 return inputField;
309}
310template<class Type, template<class> class PatchField, class GeoMesh>
311PtrList<GeometricField<Type, PatchField, GeoMesh>>
313 GeometricField<Type, PatchField, GeoMesh>& inputField,
314 List < Eigen::MatrixXd> Coeff,
315 word Name)
316{
317 PtrList<GeometricField<Type, PatchField, GeoMesh>> inputFields;
318 inputFields.resize(0);
319
320 for (label i = 0; i < Coeff.size(); i++)
321 {
322 inputField = reconstruct(inputField, Coeff[i], Name);
323 inputFields.append(inputField.clone());
324 }
325
326 return inputFields;
327}
328
329
330template<class Type, template<class> class PatchField, class GeoMesh>
332 PtrList<GeometricField<Type, PatchField, GeoMesh>> snapshots,
333 PtrList<GeometricField<Type, PatchField, GeoMesh>>& projSnapshots,
334 PtrList<volScalarField> Volumes,
335 label numberOfModes,
336 word innerProduct)
337{
338 if (EigenModes.size() == 0)
339 {
340 toEigen();
341 }
342
343 M_Assert(snapshots.size() == Volumes.size(),
344 "The number of snapshots and the number of volumes vectors must be equal");
345 M_Assert(numberOfModes <= this->size(),
346 "The number of Modes used for the projection cannot be bigger than the number of available modes");
347 M_Assert(innerProduct == "L2" || innerProduct == "Frobenius",
348 "The chosen inner product is not implemented");
349 projSnapshots.resize(snapshots.size());
350 label dim = std::nearbyint(EigenModes[0].rows() /
351 Volumes[0].size()); //Checking if volumes and modes have the same size that means check if the problem is vector or scalar
352 Eigen::MatrixXd totVolumes(Volumes[0].size()*dim, Volumes.size());
353
354 for (label i = 0; i < Volumes.size(); i++)
355 {
356 totVolumes.col(i) = Foam2Eigen::field2Eigen(Volumes[i]);
357 }
358
359 totVolumes.replicate(dim, 1);
360 Eigen::MatrixXd Modes;
361
362 if (numberOfModes == 0)
363 {
364 Modes = EigenModes[0];
365 }
366 else
367 {
368 Modes = EigenModes[0].leftCols(numberOfModes);
369 }
370
371 Eigen::MatrixXd M;
372 Eigen::MatrixXd projSnapI;
373 Eigen::MatrixXd projSnapCoeff;
374
375 for (label i = 0; i < snapshots.size(); i++)
376 {
377 GeometricField<Type, PatchField, GeoMesh> Fr = snapshots[0];
378 Eigen::MatrixXd F_eigen = Foam2Eigen::field2Eigen(snapshots[i]);
379
380 if (innerProduct == "L2")
381 {
382 M = Modes.transpose() * (totVolumes.col(i)).asDiagonal() * Modes;
383 projSnapI = Modes.transpose() * (totVolumes.col(i)).asDiagonal() * F_eigen;
384 }
385 else //Frobenius
386 {
387 M = Modes.transpose() * Modes;
388 projSnapI = Modes.transpose() * F_eigen;
389 }
390
391 projSnapCoeff = M.fullPivLu().solve(projSnapI);
392 reconstruct(Fr, projSnapCoeff, "projSnap");
393 projSnapshots.set(i, Fr.clone());
394 }
395}
396template<class Type, template<class> class PatchField, class GeoMesh>
398 PtrList<GeometricField<Type, PatchField, GeoMesh>> snapshots,
399 PtrList<GeometricField<Type, PatchField, GeoMesh>>& projSnapshots,
400 PtrList<volScalarField> Volumes, word innerProduct)
401{
402 label numberOfModes = 0;
403 projectSnapshots(snapshots, projSnapshots, Volumes, numberOfModes,
404 innerProduct);
405}
406
407template<class Type, template<class> class PatchField, class GeoMesh>
409 PtrList<GeometricField<Type, PatchField, GeoMesh>> snapshots,
410 PtrList<GeometricField<Type, PatchField, GeoMesh>>& projSnapshots,
411 label numberOfModes,
412 word innerProduct)
413{
414 if (EigenModes.size() == 0)
415 {
416 toEigen();
417 }
418
419 M_Assert(numberOfModes <= this->size(),
420 "The number of Modes used for the projection cannot be bigger than the number of available modes");
421 M_Assert(innerProduct == "L2" || innerProduct == "Frobenius",
422 "The chosen inner product is not implemented");
423 projSnapshots.resize(snapshots.size());
424 Eigen::MatrixXd Modes;
425
426 if (numberOfModes == 0)
427 {
428 Modes = EigenModes[0];
429 }
430 else
431 {
432 Modes = EigenModes[0].leftCols(numberOfModes);
433 }
434
435 Eigen::MatrixXd M_vol;
436 Eigen::MatrixXd M;
437 Eigen::MatrixXd projSnapI;
438 Eigen::MatrixXd projSnapCoeff;
439
440 for (label i = 0; i < snapshots.size(); i++)
441 {
442 GeometricField<Type, PatchField, GeoMesh> Fr = snapshots[0];
443 Eigen::MatrixXd F_eigen = Foam2Eigen::field2Eigen(snapshots[i]);
444
445 if (innerProduct == "L2")
446 {
447 M_vol = ITHACAutilities::getMassMatrixFV(snapshots[i]);
448 }
449 else if (innerProduct == "Frobenius")
450 {
451 M_vol = Eigen::VectorXd::Identity(F_eigen.rows(), 1);
452 }
453 else
454 {
455 std::cout << "Inner product not defined" << endl;
456 exit(0);
457 }
458
459 M = Modes.transpose() * M_vol.asDiagonal() * Modes;
460 projSnapI = Modes.transpose() * M_vol.asDiagonal() * F_eigen;
461 projSnapCoeff = M.fullPivLu().solve(projSnapI);
462 reconstruct(Fr, projSnapCoeff, "projSnap");
463 projSnapshots.set(i, Fr.clone());
464 }
465}
466template<class Type, template<class> class PatchField, class GeoMesh>
468 PtrList<GeometricField<Type, PatchField, GeoMesh>> snapshots,
469 PtrList<GeometricField<Type, PatchField, GeoMesh>>& projSnapshots,
470 word innerProduct)
471{
472 label numberOfModes = 0;
473 projectSnapshots(snapshots, projSnapshots, numberOfModes, innerProduct);
474}
475
476template<class Type, template<class> class PatchField, class GeoMesh>
478 PtrList<GeometricField<Type, PatchField, GeoMesh>>& modes)
479{
480 this->resize(modes.size());
481
482 for (label i = 0; i < modes.size(); i++)
483 {
484 (*this).set(i, modes[i].clone());
485 }
486}
487
488
#define M_Assert(Expr, Msg)
Header file of the Modes class.
static GeometricField< scalar, PatchField, GeoMesh > Eigen2field(GeometricField< scalar, PatchField, GeoMesh > &field, Eigen::VectorXd &eigen_vector, bool correctBC=true)
Convert a vector in Eigen format into an OpenFOAM scalar GeometricField.
Definition Foam2Eigen.C:517
static Eigen::VectorXd field2Eigen(GeometricField< tensor, PatchField, GeoMesh > &field)
Convert a vector OpenFOAM field into an Eigen Vector.
Definition Foam2Eigen.C:40
static List< Eigen::MatrixXd > PtrList2EigenBC(PtrList< GeometricField< scalar, PatchField, GeoMesh > > &fields, label Nfields=-1)
Convert an OpenFOAM scalar field to a List of Eigen Vectors, one for each boundary.
Definition Foam2Eigen.C:268
static Eigen::MatrixXd PtrList2Eigen(PtrList< GeometricField< Type, PatchField, GeoMesh > > &fields, label Nfields=-1)
Convert a PtrList of snapshots to Eigen matrix (only internal field)
Definition Foam2Eigen.C:649
static void fvMatrix2Eigen(fvMatrix< type_foam_matrix > foam_matrix, type_A &A, type_B &b)
Convert a FvMatrix OpenFOAM matrix (Linear System) into a Eigen Matrix A and a source vector b.
Implementation of a container class derived from PtrList.
Definition Modes.H:69
GeometricField< Type, PatchField, GeoMesh > reconstruct(GeometricField< Type, PatchField, GeoMesh > &inputField, Eigen::MatrixXd Coeff, word Name)
Function to reconstruct the solution starting from the coefficients, in this case the field is passed...
Definition Modes.C:275
List< Eigen::MatrixXd > toEigen()
Method that convert a PtrList of modes into Eigen matrices filling the EigenModes object.
Definition Modes.C:38
List< Eigen::MatrixXd > project(fvMatrix< Type > &Af, label numberOfModes=0, word projType="G")
A function that project an FvMatrix (OpenFoam linear System) on the modes.
Definition Modes.C:63
void projectSnapshots(PtrList< GeometricField< Type, PatchField, GeoMesh > > snapshots, PtrList< GeometricField< Type, PatchField, GeoMesh > > &projSnapshots, label numberOfModes=0, word innerProduct="L2")
Function to project a list of fields into the modes manifold.
Definition Modes.C:408
GeometricField< Type, PatchField, GeoMesh > projectSnapshot(GeometricField< Type, PatchField, GeoMesh > &field, label numberOfModes=0, word projType="G", fvMatrix< Type > *Af=NULL)
A function that project and reconstruct a snapshot on the modes.
Definition Modes.C:195
void operator=(const PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes)
Definition Modes.C:477
Tf resize(coldSideSize)
Eigen::VectorXd getMassMatrixFV(GeometricField< Type, PatchField, GeoMesh > &snapshot)
Gets a vector containing the volumes of each cell of the mesh.
void assignBC(GeometricField< scalar, fvPatchField, volMesh > &s, label BC_ind, double value)
Assign uniform Boundary Condition to a volScalarField.
label i
Definition pEqn.H:46