37template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
39 GeometricField<Type, PatchField, GeoMesh>& snapshot,
40 double _tol, word _PODnorm)
42 Info <<
"WARNING: the projection of the BC has not been implemented yet!" <<
47 PODnorm ==
"Frobenius",
"The PODnorm can be only L2 or Frobenius");
51template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
53 GeometricField<Type, PatchField, GeoMesh>& snapshot)
55 Info <<
"Initializing the incremental POD" << endl;
56 M_Assert(tolleranceSVD > 0,
"Set up the tollerance before initialization");
57 M_Assert(rank == 0,
"POD already initialized");
66 massVector.asDiagonal() *
69 GeometricField<Type, PatchField, GeoMesh> tmp(snapshot);
71 this->append(tmp.clone());
78 if (snapNorm > tolleranceSVD)
82 this->append(snapshot / snapNorm);
92 Info <<
"Initialization ended" << endl;
95template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
97 GeometricField<Type, PatchField, GeoMesh>& snapshot)
99 Info <<
"********************************************************************"
101 Info <<
"Adding a snapshot" << endl;
102 Info <<
"Initial rank = " << rank << endl;
104 double projectionError;
105 double relProjectionError;
109 initialize(snapshot);
112 Eigen::VectorXd redCoeff = project(snapshot);
113 GeometricField<Type, PatchField, GeoMesh> projectSnap = projectSnapshot(
115 GeometricField<Type, PatchField, GeoMesh> orthoSnap(snapshot - projectSnap);
123 else if (PODnorm ==
"Frobenius")
125 projectionError = snapshotEig.transpose() * snapshotEig -
126 (redCoeff.transpose() * redCoeff)(0, 0);
127 projectionError = Foam::sqrt(std::abs(projectionError));
128 relProjectionError = projectionError / (snapshotEig.transpose() * snapshotEig);
131 Info <<
"Relative projection error = " << relProjectionError << endl;
132 Eigen::MatrixXd Q = Eigen::MatrixXd::Zero(rank + 1, rank + 1);
134 Q.topRightCorner(rank, 1) = redCoeff;
135 Q(rank, rank) = projectionError;
137 if (relProjectionError < tolleranceSVD)
139 Info <<
"Projection error is smaller than the tollerance" << endl;
143 Eigen::JacobiSVD<Eigen::MatrixXd>
svd(Q,
144 Eigen::ComputeThinU | Eigen::ComputeThinV);
145 Eigen::MatrixXd newModes =
svd.matrixU();
146 Eigen::VectorXd newSingVal =
svd.singularValues();
148 if (relProjectionError < tolleranceSVD || rank >= snapshotEig.size())
150 Info <<
"Projection error is small or matrix is full rank." <<
151 endl <<
"SVD rank held constant" << endl;
152 this->EigenModes[0] = this->EigenModes[0] * newModes.topLeftCorner(rank, rank);
157 Info <<
"New snapshot is not in the span of the POD space." << endl
158 <<
"SVD rank increases" << endl;
159 orthogonalSnap = orthogonalSnap / projectionError;
160 Eigen::MatrixXd temp(this->EigenModes[0].rows(),
161 this->EigenModes[0].cols() + 1);
162 temp << this->EigenModes[0], orthogonalSnap;
163 this->EigenModes[0] = temp * newModes;
168 Info <<
"New POD rank = " << rank << endl;
169 double orthogonalPar;
173 orthogonalPar = std::abs(
174 this->EigenModes[0].
col(this->EigenModes[0].cols() - 1).transpose() *
175 massVector.asDiagonal() * this->EigenModes[0].col(0));
177 else if (PODnorm ==
"Frobenius")
179 orthogonalPar = std::abs(this->EigenModes[0].
col(0).transpose() *
180 this->EigenModes[0].
col(this->EigenModes[0].cols() - 1));
183 double EPS = 2.2204e-16;
184 Info <<
"Orthogonality = " << orthogonalPar << endl;
186 if (orthogonalPar > std::min(tolleranceSVD, EPS * this->EigenModes[0].rows()))
188 Info <<
"Orthogonalization required" << endl;
194 else if (PODnorm ==
"Frobenius")
196 Eigen::HouseholderQR<Eigen::MatrixXd> qr(this->EigenModes[0]);
197 Eigen::MatrixXd thinQ(Eigen::MatrixXd::Identity(this->EigenModes[0].rows(),
199 this->EigenModes[0] = qr.householderQ() * thinQ;
204 Info <<
"********************************************************************"
208template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
213 for (label
i = 0;
i < rank;
i++)
215 GeometricField<Type, PatchField, GeoMesh> tmp(this->first().name(),
217 Eigen::VectorXd vec = this->EigenModes[0].col(
i);
219 this->set(
i, tmp.clone());
222template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
224 GeometricField<Type, PatchField, GeoMesh>& inputField,
228 Eigen::VectorXd projField;
230 if (numberOfModes == 0)
234 projField = this->EigenModes[0].transpose() * fieldEig;
236 else if (PODnorm ==
"Frobenius")
238 projField = this->EigenModes[0].transpose() * fieldEig;
243 M_Assert(numberOfModes <= this->EigenModes[0].cols(),
244 "Number of required modes for projection is higher then the number of available ones");
248 projField = (this->EigenModes[0].leftCols(numberOfModes)).transpose() *
249 massVector.asDiagonal() * fieldEig;
251 else if (PODnorm ==
"Frobenius")
253 projField = (this->EigenModes[0].leftCols(numberOfModes)).transpose() *
261template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
262GeometricField<Type, PatchField, GeoMesh>
264 GeometricField<Type, PatchField, GeoMesh>& inputField,
265 Eigen::MatrixXd Coeff,
268 if (this->EigenModes.size() == 0)
273 label Nmodes = Coeff.rows();
274 Eigen::VectorXd InField = this->EigenModes[0].leftCols(Nmodes) * Coeff;
276 inputField.rename(Name);
277 Info <<
"WARNING: Boundary conditions are not reconstructed using incremental POD"
282template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
283GeometricField<Type, PatchField, GeoMesh>
285 GeometricField<Type, PatchField, GeoMesh>& snapshot,
288 Eigen::MatrixXd
Modes;
289 Eigen::MatrixXd M_vol;
291 Eigen::MatrixXd projSnapI;
292 Eigen::MatrixXd projSnapCoeff;
294 if (numberOfModes == 0)
296 Modes = this->EigenModes[0];
300 Modes = this->EigenModes[0].leftCols(numberOfModes);
303 GeometricField<Type, PatchField, GeoMesh> Fr = snapshot;
308 M =
Modes.transpose() * massVector.asDiagonal() *
Modes;
309 projSnapI =
Modes.transpose() * massVector.asDiagonal() * F_eigen;
311 else if (PODnorm ==
"Frobenius")
314 projSnapI =
Modes.transpose() * F_eigen;
318 std::cout <<
"Inner product not defined" << endl;
322 projSnapCoeff = M.fullPivLu().solve(projSnapI);
323 reconstruct(Fr, projSnapCoeff,
"projSnap");
327template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
329 PtrList<GeometricField<Type, PatchField, GeoMesh>> snapshots,
330 PtrList<GeometricField<Type, PatchField, GeoMesh>>& projSnapshots,
333 M_Assert(numberOfModes <= this->size(),
334 "The number of Modes used for the projection cannot be bigger than the number of available modes");
335 projSnapshots.resize(snapshots.size());
336 Eigen::MatrixXd
Modes;
338 if (numberOfModes == 0)
340 Modes = this->EigenModes[0];
344 Modes = this->EigenModes[0].leftCols(numberOfModes);
347 Eigen::MatrixXd M_vol;
349 Eigen::MatrixXd projSnapI;
350 Eigen::MatrixXd projSnapCoeff;
352 for (label
i = 0;
i < snapshots.size();
i++)
354 GeometricField<Type, PatchField, GeoMesh> Fr = snapshots[0];
359 M =
Modes.transpose() * massVector.asDiagonal() *
Modes;
360 projSnapI =
Modes.transpose() * massVector.asDiagonal() * F_eigen;
362 else if (PODnorm ==
"Frobenius")
365 projSnapI =
Modes.transpose() * F_eigen;
369 std::cout <<
"Inner product not defined" << endl;
373 projSnapCoeff = M.fullPivLu().solve(projSnapI);
374 reconstruct(Fr, projSnapCoeff,
"projSnap");
375 projSnapshots.set(
i, Fr.clone());
381template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
Header file of the EigenFunctions 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.
static Eigen::VectorXd field2Eigen(GeometricField< tensor, PatchField, GeoMesh > &field)
Convert a vector OpenFOAM field into an Eigen Vector.
Implementation of a container class derived from PtrList.
Implementation of a incremental POD algorithm according to Oxberry et al.
void addSnapshot(GeometricField< Type, PatchField, GeoMesh > &snapshot)
Add a snapshot to the POD space.
void initialize(GeometricField< Type, PatchField, GeoMesh > &snapshot)
Initialize the incremental POD algorithm.
void fillPtrList()
Fill the POD modes prtList from the Eigen matrix.
void writeModes()
Write to modes to file.
void projectSnapshots(PtrList< GeometricField< Type, PatchField, GeoMesh > > snapshots, PtrList< GeometricField< Type, PatchField, GeoMesh > > &projSnapshots, label numberOfModes=0)
Project a list of snapshots onto the reduced space.
Eigen::VectorXd project(GeometricField< Type, PatchField, GeoMesh > &inputField, label numberOfModes=0)
Project a field into the reduced space.
GeometricField< Type, PatchField, GeoMesh > reconstruct(GeometricField< Type, PatchField, GeoMesh > &inputField, Eigen::MatrixXd Coeff, word Name)
Reconstruct a field from the reduced coefficients.
incrementalPOD()
Constructors.
GeometricField< Type, PatchField, GeoMesh > projectSnapshot(GeometricField< Type, PatchField, GeoMesh > &snapshot, label numberOfModes=0)
Project a snapshot onto the POD space.
Header file of the incrementalPOD class.
void weightedGramSchmidt(Eigen::MatrixXd &matrix, Eigen::VectorXd &weights)
Weighted Gram-Schmidt orthogonalization.
void exportFields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &field, word folder, word fieldname)
Function to export a scalar of vector field.
void exportMatrix(Eigen::Matrix< T, -1, dim > &matrix, word Name, word type, word folder)
Export the reduced matrices in numpy (type=python), matlab (type=matlab) and txt (type=eigen) format ...
double L2Norm(GeometricField< scalar, fvPatchField, volMesh > &field)
Eigen::VectorXd getMassMatrixFV(GeometricField< Type, PatchField, GeoMesh > &snapshot)
Gets a vector containing the volumes of each cell of the mesh.
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)
Eigen::MatrixXd singularValues