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
120 if (exact)
121 {
122 DMDEigenModes = Ym * V * S.asDiagonal() * esEg.eigenvectors();
123 DMDEigenModesBC.resize(YmBC.size());
124
125 for (label i = 0; i < YmBC.size(); i++)
126 {
127 DMDEigenModesBC[i] = YmBC[i] * V * S.asDiagonal() * esEg.eigenvectors();
128 }
129 }
130 else
131 {
132 Eigen::VectorXd eigenValueseigLam =
133 S.array().sqrt();
134 PODm = (Xm * V) * eigenValueseigLam.asDiagonal();
135 PODmBC.resize(XmBC.size());
136
137 for (label i = 0; i < XmBC.size(); i++)
138 {
139 PODmBC[i] = (XmBC[i] * V) * eigenValueseigLam.asDiagonal();
140 }
141
142 DMDEigenModes = PODm * esEg.eigenvectors();
143 DMDEigenModesBC.resize(PODmBC.size());
144
145 for (label i = 0; i < PODmBC.size(); i++)
146 {
147 DMDEigenModesBC[i] = PODmBC[i] * esEg.eigenvectors();
148 }
149 }
150
151 Amplitudes = DMDEigenModes.real().fullPivLu().solve(Xm.col(0));
152
153 if (exportDMDmodes)
154 {
155 convert2Foam();
156 Info << "exporting the DMDmodes for " << snapshotsDMD[0].name() << endl;
157 ITHACAstream::exportFields(DMDmodesReal.toPtrList(), "ITHACAoutput/DMD/",
158 snapshotsDMD[0].name() + "_Modes_" + name(SVD_rank) + "_Real");
159 ITHACAstream::exportFields(DMDmodesImag.toPtrList(), "ITHACAoutput/DMD/",
160 snapshotsDMD[0].name() + "_Modes_" + name(SVD_rank) + "_Imag");
161 }
162}
163
164template<class Type, template<class> class PatchField, class GeoMesh>
166 double tFinal, double dt)
167{
168 Eigen::VectorXcd omega = eigenValues.array().log() / originalDT;
169 label ncols = static_cast<label>((tFinal - tStart) / dt ) + 1;
170 dynamics.resize(SVD_rank_public, ncols);
171 label i = 0;
172
173 for (double t = tStart; t <= tFinal; t += dt)
174 {
175 Eigen::VectorXcd coli = (omega * t).array().exp() * Amplitudes.array();
176 dynamics.col(i) = coli;
177 i++;
178 }
179}
180
181
182template<class Type, template<class> class PatchField, class GeoMesh>
184{
185 Eigen::MatrixXcd eigs = eigenValues;
186 mkDir(exportFolder);
187 std::string path = exportFolder + "/eigs.npy";
188 cnpy::save(eigs, path);
189 return;
190}
191
192
193template<class Type, template<class> class PatchField, class GeoMesh>
195 word fieldName)
196{
197 PtrList<GeometricField<Type, PatchField, GeoMesh>> snapshotsrec;
198
199 for (label i = 0; i < dynamics.cols(); i++)
200 {
201 Eigen::MatrixXcd col = DMDEigenModes * dynamics.col(i);
202 Eigen::VectorXd vec = col.real();
203 GeometricField<Type, PatchField, GeoMesh> tmp2("TMP",
204 snapshotsDMD[0] * 0);
205 tmp2 = Foam2Eigen::Eigen2field(tmp2, vec);
206
207 for (label k = 0; k < tmp2.boundaryField().size(); k++)
208 {
209 Eigen::VectorXd vecBC = (DMDEigenModesBC[k] * dynamics.col(i)).real();
210 ITHACAutilities::assignBC(tmp2, k, vecBC);
211 }
212
213 snapshotsrec.append(tmp2.clone());
214 }
215
216 ITHACAstream::exportFields(snapshotsrec, exportFolder, fieldName);
217}
218template<class Type, template<class> class PatchField, class GeoMesh>
220{
221 DMDmodesReal.resize(DMDEigenModes.cols());
222 DMDmodesImag.resize(DMDEigenModes.cols());
223 GeometricField<Type, PatchField, GeoMesh> tmp2Real(
224 snapshotsDMD[0].name(), snapshotsDMD[0] * 0);
225 GeometricField<Type, PatchField, GeoMesh> tmp2Imag(
226 snapshotsDMD[0].name(), snapshotsDMD[0] * 0);
227
228 for (label i = 0; i < DMDmodesReal.size(); i++)
229 {
230 Eigen::VectorXd vecReal = DMDEigenModes.col(i).real();
231 Eigen::VectorXd vecImag = DMDEigenModes.col(i).imag();
232 tmp2Real = Foam2Eigen::Eigen2field(tmp2Real, vecReal);
233 tmp2Imag = Foam2Eigen::Eigen2field(tmp2Imag, vecImag);
234
235 // Adjusting boundary conditions
236 for (label k = 0; k < tmp2Real.boundaryField().size(); k++)
237 {
238 ITHACAutilities::assignBC(tmp2Real, k, DMDEigenModesBC[k].col(i).real());
239 ITHACAutilities::assignBC(tmp2Imag, k, DMDEigenModesBC[k].col(i).imag());
240 }
241
242 DMDmodesReal.set(i, tmp2Real.clone());
243 DMDmodesImag.set(i, tmp2Imag.clone());
244 }
245}
Header file of the ITHACADMD class.
#define M_Assert(Expr, Msg)
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 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
Class of the computation of the DMD, it exploits the SVD methods.
Definition ITHACADMD.H:70
void convert2Foam()
Convert the EigenModes in Matrix form into OpenFOAM GeometricFields.
Definition ITHACADMD.C:219
ITHACADMD(PtrList< GeometricField< Type, PatchField, GeoMesh > > &snapshots, double dt)
Constructs the object.
Definition ITHACADMD.C:37
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:165
void reconstruct(word exportFolder, word fieldName)
Reconstruct and export the solution using the computed dynamics.
Definition ITHACADMD.C:194
void exportEigs(word exportFolder)
Export the eigenvalues in numpy format.
Definition ITHACADMD.C:183
void getModes(label SVD_rank=-1, bool exact=true, bool exportDMDmodes=false)
Get the DMD modes.
Definition ITHACADMD.C:50
bool redSVD
If true, it uses the Randomized SVD.
Definition ITHACADMD.H:122
Class for the definition of some general parameters, the parameters must be defined from the file ITH...
IOdictionary * ITHACAdict
Dictionary for input objects from file.
static ITHACAparameters * getInstance()
Gets an instance of ITHACAparameters, to be used if the instance is already 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)
singVal col(i)
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)
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))