Loading...
Searching...
No Matches
ITHACADMD.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
13 License
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
33
34#include "ITHACADMD.H"
35
36template<class Type, template<class> class PatchField, class GeoMesh>
38 PtrList<GeometricField<Type, PatchField, GeoMesh >> & snapshots, double dt)
39 :
40 snapshotsDMD(snapshots),
41 NSnaps(snapshots.size()),
42 originalDT(dt)
43{
45 redSVD = para->ITHACAdict->lookupOrDefault<bool>("redSVD", false);
46}
47
48
49template<class Type, template<class> class PatchField, class GeoMesh>
50void ITHACADMD<Type, PatchField, GeoMesh>::getModes(label SVD_rank, bool exact,
51 bool exportDMDmodes)
52{
53 // Check the rank if rank < 0, full rank.
54 if (SVD_rank < 0)
55 {
56 SVD_rank = NSnaps - 1;
57 }
58
59 std::string assertMessage = "The SVD_rank is equal to: " + name(
60 SVD_rank) +
61 ", it cannot be bigger than the number of snapshots - 1. NSnapshots is equal to: "
62 + name(NSnaps);
63 SVD_rank_public = SVD_rank;
64 M_Assert(SVD_rank < NSnaps, assertMessage.c_str());
65 // Convert the OpenFoam Snapshots to Matrix
66 Eigen::MatrixXd SnapEigen = Foam2Eigen::PtrList2Eigen(snapshotsDMD);
67 List<Eigen::MatrixXd> SnapEigenBC = Foam2Eigen::PtrList2EigenBC(snapshotsDMD);
68 Eigen::MatrixXd Xm = SnapEigen.leftCols(NSnaps - 1);
69 Eigen::MatrixXd Ym = SnapEigen.rightCols(NSnaps - 1);
70 List<Eigen::MatrixXd> XmBC(SnapEigenBC.size());
71 List<Eigen::MatrixXd> YmBC(SnapEigenBC.size());
72
73 for (label i = 0 ; i < SnapEigenBC.size() ; i++)
74 {
75 XmBC[i] = SnapEigenBC[i].leftCols(NSnaps - 1);
76 YmBC[i] = SnapEigenBC[i].rightCols(NSnaps - 1);
77 }
78
79 Eigen::MatrixXcd U;
80 Eigen::MatrixXcd V;
81 Eigen::VectorXd S;
82
83 if (redSVD)
84 {
85 Info << "SVD using Randomized method" << endl;
86 RedSVD::RedSVD<Eigen::MatrixXd> svd(Xm, SVD_rank);
87 U = svd.matrixU();
88 V = svd.matrixV();
89 S = svd.singularValues().array().cwiseInverse();
90 }
91 else
92 {
93 Info << "SVD using JacobiSVD" << endl;
94 Eigen::JacobiSVD<Eigen::MatrixXd> svd(Xm,
95 Eigen::ComputeThinU | Eigen::ComputeThinV);
96 U = svd.matrixU().leftCols(SVD_rank);
97 V = svd.matrixV().leftCols(SVD_rank);
98 S = svd.singularValues().head(SVD_rank).array().cwiseInverse();
99 }
100
101 Eigen::MatrixXcd A_tilde = U.transpose().conjugate() * Ym *
102 V *
103 S.asDiagonal();
104 Eigen::ComplexEigenSolver<Eigen::MatrixXcd> esEg(A_tilde);
105 eigenValues = esEg.eigenvalues();
106 Eigen::VectorXd ln = eigenValues.array().log().imag().abs();
107 // Sort based on The Frequencies
108 typedef std::pair<double, label> mypair;
109 std::vector<mypair> sortedList(ln.size());
110
111 for (label i = 0; i < ln.size(); i++)
112 {
113 sortedList[i].first = ln(i);
114 sortedList[i].second = i;
115 }
116
117 std::sort(sortedList.begin(), sortedList.end(),
118 std::less<std::pair<double, label >> ());
119 if (exact)
120 {
121 DMDEigenModes = Ym* V* S.asDiagonal() * esEg.eigenvectors();
122 DMDEigenModesBC.resize(YmBC.size());
123 for (label i = 0; i < YmBC.size(); i++)
124 {
125 DMDEigenModesBC[i] = YmBC[i] * V* S.asDiagonal() * esEg.eigenvectors();
126 }
127 }
128
129 else
130 {
131 Eigen::VectorXd eigenValueseigLam =
132 S.array().sqrt();
133 PODm = (Xm* V) * eigenValueseigLam.asDiagonal();
134 PODmBC.resize(XmBC.size());
135
136 for (label i = 0; i < XmBC.size(); i++)
138 PODmBC[i] = (XmBC[i] * V) * eigenValueseigLam.asDiagonal();
139 }
140
141 DMDEigenModes = PODm* esEg.eigenvectors();
142 DMDEigenModesBC.resize(PODmBC.size());
143
144 for (label i = 0; i < PODmBC.size(); i++)
145 {
146 DMDEigenModesBC[i] = PODmBC[i] * esEg.eigenvectors();
147 }
148 }
149 Amplitudes = DMDEigenModes.real().fullPivLu().solve(Xm.col(0));
150 if (exportDMDmodes)
151 {
152 convert2Foam();
153 Info << "exporting the DMDmodes for " << snapshotsDMD[0].name() << endl;
154 ITHACAstream::exportFields(DMDmodesReal.toPtrList(), "ITHACAoutput/DMD/",
155 snapshotsDMD[0].name() + "_Modes_" + name(SVD_rank) + "_Real");
156 ITHACAstream::exportFields(DMDmodesImag.toPtrList(), "ITHACAoutput/DMD/",
157 snapshotsDMD[0].name() + "_Modes_" + name(SVD_rank) + "_Imag");
159}
160
161template<class Type, template<class> class PatchField, class GeoMesh >
163 double tFinal, double dt)
164{
165 Eigen::VectorXcd omega = eigenValues.array().log() / originalDT;
166 label ncols = static_cast<label>((tFinal - tStart) / dt ) + 1;
167 dynamics.resize(SVD_rank_public, ncols);
168 label i = 0;
169
170 for (double t = tStart; t <= tFinal; t += dt)
171 {
172 Eigen::VectorXcd coli = (omega * t).array().exp() * Amplitudes.array();
173 dynamics.col(i) = coli;
174 i++;
175 }
176}
177
178
179template<class Type, template<class> class PatchField, class GeoMesh>
181{
182 Eigen::MatrixXcd eigs = eigenValues;
183 mkDir(exportFolder);
184 std::string path = exportFolder + "/eigs.npy";
185 cnpy::save(eigs, path);
186 return;
187}
188
189
190template<class Type, template<class> class PatchField, class GeoMesh>
192 word fieldName)
193{
194 PtrList<GeometricField<Type, PatchField, GeoMesh >> snapshotsrec;
195 for (label i = 0; i < dynamics.cols(); i++)
196 {
197 Eigen::MatrixXcd col = DMDEigenModes* dynamics.col(i);
198 Eigen::VectorXd vec = col.real();
199 GeometricField<Type, PatchField, GeoMesh> tmp2("TMP",
200 snapshotsDMD[0] * 0);
201 tmp2 = Foam2Eigen::Eigen2field(tmp2, vec);
202
203 for (label k = 0; k < tmp2.boundaryField().size(); k++)
204 {
205 Eigen::VectorXd vecBC = (DMDEigenModesBC[k] * dynamics.col(i)).real();
206 ITHACAutilities::assignBC(tmp2, k, vecBC);
207 }
208
209 snapshotsrec.append(tmp2.clone());
210 }
211
212 ITHACAstream::exportFields(snapshotsrec, exportFolder, fieldName);
213}
214
215template<class Type, template<class> class PatchField, class GeoMesh>
217{
218 DMDmodesReal.resize(DMDEigenModes.cols());
219 DMDmodesImag.resize(DMDEigenModes.cols());
220 GeometricField<Type, PatchField, GeoMesh> tmp2Real(
221 snapshotsDMD[0].name(), snapshotsDMD[0] * 0);
222 GeometricField<Type, PatchField, GeoMesh> tmp2Imag(
223 snapshotsDMD[0].name(), snapshotsDMD[0] * 0);
224
225 for (label i = 0; i < DMDmodesReal.size(); i++)
226 {
227 Eigen::VectorXd vecReal = DMDEigenModes.col(i).real();
228 Eigen::VectorXd vecImag = DMDEigenModes.col(i).imag();
229 tmp2Real = Foam2Eigen::Eigen2field(tmp2Real, vecReal);
230 tmp2Imag = Foam2Eigen::Eigen2field(tmp2Imag, vecImag);
231
232 // Adjusting boundary conditions
233 for (label k = 0; k < tmp2Real.boundaryField().size(); k++)
234 {
235 ITHACAutilities::assignBC(tmp2Real, k, DMDEigenModesBC[k].col(i).real());
236 ITHACAutilities::assignBC(tmp2Imag, k, DMDEigenModesBC[k].col(i).imag());
237 }
238
239 DMDmodesReal.set(i, tmp2Real.clone());
240 DMDmodesImag.set(i, tmp2Imag.clone());
241 }
242}
243
Header file of the ITHACADMD class.
#define M_Assert(Expr, Msg)
ITHACAparameters * para
Definition NLsolve.H:40
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:514
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:270
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:646
Class of the computation of the DMD, it exploits the SVD methods.
Definition ITHACADMD.H:70
PtrList< GeometricField< Type, PatchField, GeoMesh > > snapshotsDMD
PtrList of OpenFOAM GeoometricFields where the snapshots are stored.
Definition ITHACADMD.H:83
void convert2Foam()
Convert the EigenModes in Matrix form into OpenFOAM GeometricFields.
Definition ITHACADMD.C:216
label SVD_rank_public
Rank of the DMD.
Definition ITHACADMD.H:116
ITHACADMD(PtrList< GeometricField< Type, PatchField, GeoMesh > > &snapshots, double dt)
Constructs the object.
Definition ITHACADMD.C:37
Eigen::VectorXd Amplitudes
Amplitudes of DMD.
Definition ITHACADMD.H:107
void getDynamics(double tStart, double tFinal, double dt)
Export the dynamics of DMD given an initial time step, a final one and a time step.
Definition ITHACADMD.C:162
double originalDT
Original time step used to acquire the snapshots.
Definition ITHACADMD.H:119
void reconstruct(word exportFolder, word fieldName)
Reconstruct and export the solution using the computed dynamics.
Definition ITHACADMD.C:191
Eigen::MatrixXcd dynamics
Complex Eigen::Matrix used to store the Dynamics of the DMD modes.
Definition ITHACADMD.H:110
void exportEigs(word exportFolder)
Export the eigenvalues in numpy format.
Definition ITHACADMD.C:180
Modes< scalar, fvPatchField, volMesh > DMDmodesImag
Definition ITHACADMD.H:89
List< Eigen::MatrixXcd > DMDEigenModesBC
Definition ITHACADMD.H:98
label NSnaps
Number of snapshots.
Definition ITHACADMD.H:113
void getModes(label SVD_rank=-1, bool exact=true, bool exportDMDmodes=false)
Get the DMD modes.
Definition ITHACADMD.C:50
Modes< scalar, fvPatchField, volMesh > DMDmodesReal
Definition ITHACADMD.H:86
Eigen::VectorXcd eigenValues
Eigenvalues of the dynamics mode decomposition.
Definition ITHACADMD.H:92
bool redSVD
If true, it uses the Randomized SVD.
Definition ITHACADMD.H:122
Eigen::MatrixXcd DMDEigenModes
DMD modes stored in a complex Eigen::Matrix, it is the object used for computations.
Definition ITHACADMD.H:95
Class for the definition of some general parameters, the parameters must be defined from the file ITH...
static ITHACAparameters * getInstance(fvMesh &mesh, Time &localTime)
Gets an instance of ITHACAparameters, to be used if the instance is not existing.
void exportFields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &field, word folder, word fieldname)
Function to export a scalar of vector field.
void assignBC(GeometricField< scalar, fvPatchField, volMesh > &s, label BC_ind, double value)
Assign uniform Boundary Condition to a volScalarField.
void save(const Eigen::Matrix< T, -1, dim > &mat, const std::string fname)
Info<< endl;Info<< "*********************************************************"<< endl;Info<< "Performing test for the parameterized BC inverse solver"<< endl;Info<< endl;word outputFolder="./ITHACAoutput/parameterizedBCtest_RBFparameter/";volScalarField gTrueField=example_paramBC.list2Field(example_paramBC.gTrue);ITHACAstream::exportSolution(gTrueField, "1", outputFolder, "gTrue");Eigen::VectorXd rbfWidth=EigenFunctions::ExpSpaced(0.001, 100, rbfWidthTest_size);ITHACAstream::exportMatrix(rbfWidth, "rbfShapeParameters", "eigen", outputFolder);Eigen::VectorXd residualNorms;residualNorms.resize(rbfWidthTest_size);Eigen::VectorXd heatFluxL2norm(rbfWidthTest_size);Eigen::VectorXd heatFluxLinfNorm=heatFluxL2norm;Eigen::VectorXd condNumber=heatFluxL2norm;Eigen::MatrixXd singVal;for(int i=0;i< rbfWidthTest_size;i++){ Info<< "*********************************************************"<< endl;Info<< "RBF parameter "<< rbfWidth(i)<< endl;Info<< "Test "<< i+1<< endl;Info<< endl;example_paramBC.set_gParametrized("rbf", rbfWidth(i));example_paramBC.parameterizedBCoffline(1);example_paramBC.parameterizedBC("fullPivLU");volScalarField gParametrizedField=example_paramBC.list2Field(example_paramBC.g);ITHACAstream::exportSolution(gParametrizedField, std::to_string(i+1), outputFolder, "gParametrized");volScalarField &T(example_paramBC._T());ITHACAstream::exportSolution(T, std::to_string(i+1), outputFolder, "T");residualNorms(i)=Foam::sqrt(example_paramBC.residual.squaredNorm());Eigen::MatrixXd A=example_paramBC.Theta.transpose() *example_paramBC.Theta;Eigen::JacobiSVD< Eigen::MatrixXd > svd(A, Eigen::ComputeThinU|Eigen::ComputeThinV)
singVal col(i)
volVectorField & U
label i
Definition pEqn.H:46
volScalarField S(IOobject("S", runTime.timeName(), mesh, IOobject::NO_READ, IOobject::AUTO_WRITE), T.mesh(), dimensionedScalar("zero", dimensionSet(0, 0, -1, 1, 0, 0, 0), 0))