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}
218
219template<class Type, template<class> class PatchField, class GeoMesh>
221{
222 DMDmodesReal.resize(DMDEigenModes.cols());
223 DMDmodesImag.resize(DMDEigenModes.cols());
224 GeometricField<Type, PatchField, GeoMesh> tmp2Real(
225 snapshotsDMD[0].name(), snapshotsDMD[0] * 0);
226 GeometricField<Type, PatchField, GeoMesh> tmp2Imag(
227 snapshotsDMD[0].name(), snapshotsDMD[0] * 0);
228
229 for (label i = 0; i < DMDmodesReal.size(); i++)
230 {
231 Eigen::VectorXd vecReal = DMDEigenModes.col(i).real();
232 Eigen::VectorXd vecImag = DMDEigenModes.col(i).imag();
233 tmp2Real = Foam2Eigen::Eigen2field(tmp2Real, vecReal);
234 tmp2Imag = Foam2Eigen::Eigen2field(tmp2Imag, vecImag);
235
236 // Adjusting boundary conditions
237 for (label k = 0; k < tmp2Real.boundaryField().size(); k++)
238 {
239 ITHACAutilities::assignBC(tmp2Real, k, DMDEigenModesBC[k].col(i).real());
240 ITHACAutilities::assignBC(tmp2Imag, k, DMDEigenModesBC[k].col(i).imag());
241 }
242
243 DMDmodesReal.set(i, tmp2Real.clone());
244 DMDmodesImag.set(i, tmp2Imag.clone());
245 }
246}
247
Header file of the ITHACADMD 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:533
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:273
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:665
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:220
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:165
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:194
Eigen::MatrixXcd dynamics
Complex Eigen::Matrix used to store the Dynamics of the DMD modes.
Definition ITHACADMD.H:110
List< Eigen::MatrixXcd > PODmBC
List of complex matrices used to store the POD modes on the boundaries, used only for compution in th...
Definition ITHACADMD.H:104
void exportEigs(word exportFolder)
Export the eigenvalues in numpy format.
Definition ITHACADMD.C:183
Modes< Type, PatchField, GeoMesh > DMDmodesImag
Modes object used to store the Imaginary part of the DMD modes.
Definition ITHACADMD.H:89
List< Eigen::MatrixXcd > DMDEigenModesBC
DMD modes on the boundary stored in a List of complex Eigen::Matrix, it is the object used for comput...
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< Type, PatchField, GeoMesh > DMDmodesReal
Modes object used to store the Real part of the DMD modes.
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 PODm
Complex matrix used to store the POD modes, used only for compution in the projected approach.
Definition ITHACADMD.H:101
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(const 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.