40template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
42 PtrList<GeometricField<Type, PatchField, GeoMesh >> & snapshots,
43 PtrList<GeometricField<Type, PatchField, GeoMesh >>& ModesGlobal,
45 label Npar, label NnestedOut)
48 List<PtrList<GeometricField<Type, PatchField, GeoMesh >>>
50 label Nt = snapshots.size() / Npar;
51 SnapMatrixNested.setSize(Nt);
52 for (label
i = 0;
i < Npar;
i++)
54 SnapMatrixNested[
i].resize(Nt);
55 for (label j = 0; j < Nt; j++)
57 SnapMatrixNested[
i].set(j, snapshots[j + Nt*
i].clone());
61 List<PtrList<GeometricField<Type, PatchField, GeoMesh >>> UModesNested;
62 PtrList<GeometricField<Type, PatchField, GeoMesh >> y;
63 UModesNested.setSize(Nt);
65 for (label
i = 0;
i < Npar;
i++)
70 for (label
i = 0;
i < Npar;
i++)
74 for (label j = 0; j < y.size(); j++)
76 ModesGlobal.append(y[j].clone());
82 PtrList<volScalarField>& snapshots, PtrList<volScalarField>& ModesGlobal,
83 word fieldName, label Npar, label NnestedOut);
86 PtrList<volVectorField>& snapshots, PtrList<volVectorField>& ModesGlobal,
87 word fieldName, label Npar, label NnestedOut);
89template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
91 PtrList<GeometricField<Type, PatchField, GeoMesh >> & snapshots,
92 PtrList<GeometricField<Type, PatchField, GeoMesh >>& modes,
93 word fieldName,
bool podex,
bool supex,
bool sup, label nmodes,
97 word PODkey =
"POD_" + fieldName;
98 word PODnorm =
para->ITHACAdict->lookupOrDefault<word>(PODkey,
"L2");
100 PODnorm ==
"Frobenius",
"The PODnorm can be only L2 or Frobenius");
101 Info <<
"Performing POD for " << fieldName <<
" using the " << PODnorm <<
104 if ((podex == 0 && sup == 0) || (supex == 0 && sup == 1))
106 if (
para->eigensolver ==
"spectra" )
110 nmodes = snapshots.size() - 2;
113 M_Assert(nmodes <= snapshots.size() - 2,
114 "The number of requested modes cannot be bigger than the number of Snapshots - 2");
120 nmodes = snapshots.size();
123 M_Assert(nmodes <= snapshots.size(),
124 "The number of requested modes cannot be bigger than the number of Snapshots");
129 label NBC = snapshots[0].boundaryField().size();
130 Eigen::MatrixXd _corMatrix;
136 else if (PODnorm ==
"Frobenius")
141 if (Pstream::parRun())
143 reduce(_corMatrix, sumOp<Eigen::MatrixXd>());
146 Eigen::VectorXd eigenValueseig;
147 Eigen::MatrixXd eigenVectoreig;
148 modes.resize(nmodes);
149 Info <<
"####### Performing the POD using EigenDecomposition " <<
150 fieldName <<
" #######" << endl;
151 label ncv = snapshots.size();
152 Spectra::DenseSymMatProd<double> op(_corMatrix);
153 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> esEg;
155 if (
para->eigensolver ==
"spectra")
157 Spectra::SymEigsSolver<Spectra::DenseSymMatProd<double>> es(op, nmodes, ncv);
158 std::cout <<
"Using Spectra EigenSolver " << std::endl;
160 es.compute(Spectra::SortRule::LargestAlge);
161 M_Assert(es.info() == Spectra::CompInfo::Successful,
162 "The Eigenvalue Decomposition did not succeed");
163 eigenVectoreig = es.eigenvectors().real();
164 eigenValueseig = es.eigenvalues().real();
167 else if (
para->eigensolver ==
"eigen")
169 std::cout <<
"Using Eigen EigenSolver " << std::endl;
170 esEg.compute(_corMatrix);
171 M_Assert(esEg.info() == Eigen::Success,
172 "The Eigenvalue Decomposition did not succeed");
173 eigenVectoreig = esEg.eigenvectors().real().rowwise().reverse().leftCols(
175 eigenValueseig = esEg.eigenvalues().real().array().reverse();
178 if (eigenValueseig.array().minCoeff() < 0)
180 eigenValueseig = eigenValueseig.array() + 2 * abs(
181 eigenValueseig.array().minCoeff());
184 Info <<
"####### End of the POD for " << snapshots[0].name() <<
" #######" <<
190 Eigen::MatrixXd modesEig = (SnapMatrix* eigenVectoreig);
193 Eigen::MatrixXd normFact(nmodes, 1);
194 for (label
i = 0;
i < nmodes;
i++)
198 normFact(
i, 0) = std::sqrt((modesEig.col(
i).transpose() * V.asDiagonal() *
199 modesEig.col(
i))(0, 0));
200 if (Pstream::parRun())
202 normFact(
i, 0) = (modesEig.col(
i).transpose() * V.asDiagonal() *
203 modesEig.col(
i))(0, 0);
207 else if (PODnorm ==
"Frobenius")
209 normFact(
i, 0) = std::sqrt((modesEig.col(
i).transpose() * modesEig.col(
i))(0,
211 if (Pstream::parRun())
213 normFact(
i, 0) = (modesEig.col(
i).transpose() * modesEig.col(
i))(0, 0);
218 if (Pstream::parRun())
220 reduce(normFact, sumOp<Eigen::MatrixXd>());
223 if (Pstream::parRun())
225 normFact = normFact.cwiseSqrt();
227 List<Eigen::MatrixXd> modesEigBC;
228 modesEigBC.resize(NBC);
230 for (label
i = 0;
i < NBC;
i++)
232 modesEigBC[
i] = (SnapMatrixBC[
i] * eigenVectoreig);
234 std::cout << normFact << std::endl;
236 for (label
i = 0;
i < nmodes;
i++)
238 modesEig.col(
i) = modesEig.col(
i).array() / normFact(
i, 0);
240 for (label j = 0; j < NBC; j++)
242 modesEigBC[j].col(
i) = modesEigBC[j].col(
i).array() / normFact(
i, 0);
245 for (label
i = 0;
i < modes.size();
i++)
247 GeometricField<Type, PatchField, GeoMesh> tmp2(snapshots[0].name(),
249 Eigen::VectorXd vec = modesEig.col(
i);
252 for (label k = 0; k < NBC; k++)
257 modes.set(
i, tmp2.clone());
259 eigenValueseig = eigenValueseig / eigenValueseig.sum();
260 Eigen::VectorXd cumEigenValues(eigenValueseig);
262 for (label j = 1; j < cumEigenValues.size(); ++j)
264 cumEigenValues(j) += cumEigenValues(j - 1);
266 Info <<
"####### Saving the POD bases for " << snapshots[0].name() <<
272 snapshots[0].name());
279 "./ITHACAoutput/POD/Eigenvalues_" + snapshots[0].name(),
para->precision,
282 "./ITHACAoutput/POD/CumEigenvalues_" + snapshots[0].name(),
para->precision,
287 Info <<
"Reading the existing modes" << endl;
292 "./ITHACAoutput/supremizer/");
302 PtrList<volVectorField>& snapshots, PtrList<volVectorField>& modes,
303 word fieldName,
bool podex,
bool supex,
bool sup, label nmodes,
307 PtrList<volScalarField>& snapshots, PtrList<volScalarField>& modes,
308 word fieldName,
bool podex,
bool supex,
bool sup, label nmodes,
312 PtrList<surfaceScalarField>& snapshots, PtrList<surfaceScalarField>& modes,
313 word fieldName,
bool podex,
bool supex,
bool sup, label nmodes,
316template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
318 GeometricField<Type, PatchField, GeoMesh>& templateField,
320 PtrList<GeometricField<Type, PatchField, GeoMesh >> & modes,
327 autoPtr<GeometricField<Type, PatchField, GeoMesh >> meanField)
331 word PODkey =
"POD_" + fieldName;
332 word PODnorm =
para->ITHACAdict->lookupOrDefault<word>(PODkey,
"L2");
334 M_Assert(PODnorm ==
"L2" || PODnorm ==
"Frobenius",
335 "The PODnorm can be only L2 or Frobenius");
336 Info <<
"Performing memory efficient POD for " << fieldName
337 <<
" using the " << PODnorm <<
" norm" << endl;
339 if ((podex == 0 && sup == 0) || (supex == 0 && sup == 1))
342 fileName rootPath(
".");
343 Foam::Time runTime2(Foam::Time::controlDictName, rootPath, snapshotsPath);
344 label nSnaps = runTime2.times().size() - 2;
345 std::cout <<
"Found " << nSnaps <<
" time directories" << endl;
351 <<
"Error: No time directories found in " << snapshotsPath
356 if (
para->eigensolver ==
"spectra")
364 "The number of requested modes cannot be bigger than the number of snapshots - 2");
374 "The number of requested modes cannot be bigger than the number of snapshots");
378 Eigen::MatrixXd _corMatrix(nSnaps, nSnaps);
379 _corMatrix.setZero();
380 List<Eigen::MatrixXd> SnapMatrixBC;
381 label NBC = templateField.boundaryField().size();
382 SnapMatrixBC.resize(NBC);
385 for (label
i = 0;
i < NBC;
i++)
387 SnapMatrixBC[
i].resize(templateField.boundaryField()[
i].size(), nSnaps);
391 for (label
i = 0;
i < nSnaps;
i++)
394 GeometricField<Type, PatchField, GeoMesh> snapI =
406 for (label k = 0; k < NBC; k++)
408 SnapMatrixBC[k].col(
i) = snapIBC[k];
412 for (label j =
i; j < nSnaps; j++)
414 GeometricField<Type, PatchField, GeoMesh> snapJ =
436 _corMatrix(j,
i) = _corMatrix(
i, j);
440 Info <<
"Processed snapshot " <<
i + 1 <<
" of " << nSnaps << endl;
444 if (Pstream::parRun())
446 reduce(_corMatrix, sumOp<Eigen::MatrixXd>());
450 Eigen::VectorXd eigenValues;
451 Eigen::MatrixXd eigenVectors;
452 Info <<
"####### Performing the POD using EigenDecomposition " <<
453 fieldName <<
" #######" << endl;
455 if (
para->eigensolver ==
"spectra")
458 std::cout <<
"Using Spectra EigenSolver " << std::endl;
459 Spectra::DenseSymMatProd<double> op(_corMatrix);
460 Spectra::SymEigsSolver<Spectra::DenseSymMatProd<double >>
461 solver(op, nmodes, nSnaps);
463 solver.compute(Spectra::SortRule::LargestAlge);
464 M_Assert(solver.info() == Spectra::CompInfo::Successful,
465 "Eigenvalue decomposition failed");
466 eigenVectors = solver.eigenvectors().real();
467 eigenValues = solver.eigenvalues().real();
470 else if (
para->eigensolver ==
"eigen")
473 std::cout <<
"Using Eigen EigenSolver " << std::endl;
474 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> solver(_corMatrix);
475 M_Assert(solver.info() == Eigen::Success,
476 "Eigenvalue decomposition failed");
477 eigenVectors = solver.eigenvectors().real().rowwise().reverse().leftCols(
479 eigenValues = solver.eigenvalues().real().array().reverse();
483 if (eigenValues.array().minCoeff() < 0)
485 eigenValues = eigenValues.array() + 2 * abs(
486 eigenValues.array().minCoeff());
489 Info <<
"####### End of the POD for " << fieldName <<
" #######" << endl;
491 modes.resize(nmodes);
493 GeometricField<Type, PatchField, GeoMesh> firstSnap =
496 for (label
i = 0;
i < nmodes;
i++)
499 GeometricField<Type, PatchField, GeoMesh> modeI
503 templateField.name(),
504 templateField.time().timeName(),
505 templateField.mesh(),
509 templateField.mesh(),
510 dimensioned<Type>(
"zero", templateField.dimensions(), Zero),
511 firstSnap.boundaryField().types()
515 for (label j = 0; j < nSnaps; j++)
517 GeometricField<Type, PatchField, GeoMesh> snapJ =
519 modeI += snapJ * eigenVectors(j,
i);
534 if (Pstream::parRun())
536 reduce(normFactor, sumOp<scalar>());
539 normFactor = Foam::sqrt(normFactor);
541 modeI *= dimensionedScalar(
"normFactor", dimless, 1.0 / normFactor);
544 for (label k = 0; k < NBC; k++)
546 Eigen::VectorXd bcValues = SnapMatrixBC[k] * eigenVectors.col(
i);
547 bcValues = bcValues / normFactor;
553 modeI.correctBoundaryConditions();
556 modes.set(
i, modeI.clone());
557 Info <<
"Constructed mode " <<
i + 1 <<
" of " << nmodes << endl;
571 eigenValues = eigenValues / eigenValues.sum();
572 Eigen::VectorXd cumEigenValues = eigenValues;
574 for (label j = 1; j < cumEigenValues.size(); ++j)
576 cumEigenValues(j) += cumEigenValues(j - 1);
581 "./ITHACAoutput/POD/Eigenvalues_" + fieldName,
para->precision,
para->outytpe);
583 "./ITHACAoutput/POD/CumEigenvalues_" + fieldName,
para->precision,
589 Info <<
"Reading existing modes" << endl;
594 "./ITHACAoutput/supremizer/");
605 GeometricField<scalar, fvPatchField, volMesh>&,
607 PtrList<GeometricField<scalar, fvPatchField, volMesh >> &,
614 autoPtr<GeometricField<scalar, fvPatchField, volMesh >>
620 GeometricField<vector, fvPatchField, volMesh>&,
622 PtrList<GeometricField<vector, fvPatchField, volMesh >> &,
629 autoPtr<GeometricField<vector, fvPatchField, volMesh >>
632template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
634 GeometricField<Type, PatchField, GeoMesh>& templateField,
636 autoPtr<GeometricField<Type, PatchField, GeoMesh >> & meanField,
640 fileName rootPath(
".");
641 Foam::Time runTime2(Foam::Time::controlDictName, rootPath, snapshotsPath);
642 label nSnaps = runTime2.times().size() - 2;
643 std::cout <<
"Found " << nSnaps <<
" time directories" << endl;
648 Info <<
"Computing the mean of snapshots" << endl;
650 *meanField = templateField * 0.;
651 for(
int i = 0;
i<nSnaps;
i++)
654 GeometricField<Type, PatchField, GeoMesh> snapI =
660 *meanField *= 1. / nSnaps;
665 Info <<
"Reading the mean of snapshots" << endl;
672 GeometricField<scalar, fvPatchField, volMesh>&,
674 autoPtr<GeometricField<scalar, fvPatchField, volMesh >> &,
680 GeometricField<vector, fvPatchField, volMesh>&,
682 autoPtr<GeometricField<vector, fvPatchField, volMesh >> &,
686template<
class Type,
template<
class>
class PatchField,
class GeoMesh >
688 PtrList<GeometricField<Type, PatchField, GeoMesh >> & snapshots,
689 PtrList<GeometricField<Type, PatchField, GeoMesh >>& modes,
690 word fieldName,
bool podex,
bool supex,
bool sup, label nmodes,
697 nmodes = snapshots.size() - 2;
700 M_Assert(nmodes <= snapshots.size() - 2,
701 "The number of requested modes cannot be bigger than the number of Snapshots - 2");
703 if ((podex == 0 && sup == 0) || (supex == 0 && sup == 1))
707 label NBC = snapshots[0].boundaryField().size();
709 Eigen::VectorXd eigenValueseig;
710 Eigen::MatrixXd eigenVectoreig;
711 modes.resize(nmodes);
712 Info <<
"####### Performing the POD using EigenDecomposition " <<
713 snapshots[0].name() <<
" #######" << endl;
714 label ncv = snapshots.size();
715 Spectra::DenseSymMatProd<double> op(_corMatrix);
716 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> esEg;
717 Spectra::SymEigsSolver<Spectra::DenseSymMatProd<double >>
719 if (
para->eigensolver ==
"spectra")
721 std::cout <<
"Using Spectra EigenSolver " << std::endl;
723 es.compute(Spectra::SortRule::LargestAlge);
724 M_Assert(es.info() == Spectra::CompInfo::Successful,
725 "The Eigenvalue Decomposition did not succeed");
726 eigenVectoreig = es.eigenvectors().real();
727 eigenValueseig = es.eigenvalues().real();
730 else if (
para->eigensolver ==
"eigen")
732 std::cout <<
"Using Eigen EigenSolver " << std::endl;
733 esEg.compute(_corMatrix);
734 M_Assert(esEg.info() == Eigen::Success,
735 "The Eigenvalue Decomposition did not succeed");
736 eigenVectoreig = esEg.eigenvectors().real().rowwise().reverse().leftCols(
738 eigenValueseig = esEg.eigenvalues().real().reverse();
741 Info <<
"####### End of the POD for " << snapshots[0].name() <<
" #######" <<
743 Eigen::VectorXd eigenValueseigLam =
744 eigenValueseig.real().array().cwiseInverse().sqrt() ;
745 Eigen::VectorXd eigenValueseigWeigted = eigenValueseig.head(
746 nmodes).real().array() ;
747 Eigen::MatrixXd modesEig = (SnapMatrix* eigenVectoreig) *
748 eigenValueseigLam.head(nmodes).asDiagonal() *
749 eigenValueseigWeigted.asDiagonal();
750 List<Eigen::MatrixXd> modesEigBC;
751 modesEigBC.resize(NBC);
753 for (label
i = 0;
i < NBC;
i++)
755 modesEigBC[
i] = (SnapMatrixBC[
i] * eigenVectoreig) *
756 eigenValueseigLam.asDiagonal() * eigenValueseigWeigted.asDiagonal();
758 for (label
i = 0;
i < modes.size();
i++)
760 GeometricField<Type, PatchField, GeoMesh> tmp2(snapshots[0].name(),
762 Eigen::VectorXd vec = modesEig.col(
i);
765 for (label k = 0; k < tmp2.boundaryField().size(); k++)
770 modes.set(
i, tmp2.clone());
772 eigenValueseig = eigenValueseig / eigenValueseig.sum();
773 Eigen::VectorXd cumEigenValues(eigenValueseig);
775 for (label j = 1; j < cumEigenValues.size(); ++j)
777 cumEigenValues(j) += cumEigenValues(j - 1);
779 Info <<
"####### Saving the POD bases for " << snapshots[0].name() <<
786 snapshots[0].name());
793 "./ITHACAoutput/POD/Eigenvalues_" + snapshots[0].name(),
para->precision,
796 "./ITHACAoutput/POD/CumEigenvalues_" + snapshots[0].name(),
para->precision,
801 Info <<
"Reading the existing modes" << endl;
806 "./ITHACAoutput/supremizer/");
816 PtrList<volScalarField>& snapshots, PtrList<volScalarField>& modes,
817 word fieldName,
bool podex,
bool supex,
bool sup, label nmodes,
821 PtrList<volVectorField>& snapshots, PtrList<volVectorField>& modes,
822 word fieldName,
bool podex,
bool supex,
bool sup, label nmodes,
825template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
827 PtrList<GeometricField<Type, PatchField, GeoMesh >> & snapshots,
828 PtrList<GeometricField<Type, PatchField, GeoMesh >>& modes,
829 word fieldName,
bool podex,
bool supex,
bool sup, label nmodes,
834 if ((podex == 0 && sup == 0) || (supex == 0 && sup == 1))
836 PtrList<volVectorField> Bases;
837 modes.resize(nmodes);
838 Info <<
"####### Performing POD using Singular Value Decomposition for " <<
839 snapshots[0].name() <<
" #######" << endl;
842 Eigen::VectorXd V3dSqrt = V.array().sqrt();
843 Eigen::VectorXd V3dInv = V3dSqrt.array().cwiseInverse();
844 auto VMsqr = V3dSqrt.asDiagonal();
845 auto VMsqrInv = V3dInv.asDiagonal();
846 Eigen::MatrixXd SnapMatrix2 = VMsqr * SnapMatrix;
847 Eigen::JacobiSVD<Eigen::MatrixXd>
svd(SnapMatrix2,
848 Eigen::ComputeThinU | Eigen::ComputeThinV);
849 Info <<
"####### End of the POD for " << snapshots[0].name() <<
" #######" <<
851 Eigen::VectorXd eigenValueseig;
852 Eigen::MatrixXd eigenVectoreig;
853 eigenValueseig =
svd.singularValues().real();
854 eigenVectoreig =
svd.matrixU().real();
855 Eigen::MatrixXd modesEig = VMsqrInv * eigenVectoreig;
856 GeometricField<Type, PatchField, GeoMesh> tmb_bu(snapshots[0].name(),
859 for (label
i = 0;
i < nmodes;
i++)
861 Eigen::VectorXd vec = modesEig.col(
i);
863 modes.set(
i, tmb_bu.clone());
866 eigenValueseig = eigenValueseig / eigenValueseig.sum();
867 Eigen::VectorXd cumEigenValues(eigenValueseig);
869 for (label j = 1; j < cumEigenValues.size(); ++j)
871 cumEigenValues(j) += cumEigenValues(j - 1);
874 Info <<
"####### Saving the POD bases for " << snapshots[0].name() <<
880 snapshots[0].name());
889 "./ITHACAoutput/POD/Eigenvalues_" + snapshots[0].name(),
para->precision,
892 "./ITHACAoutput/POD/CumEigenvalues_" + snapshots[0].name(),
para->precision,
897 Info <<
"Reading the existing modes" << endl;
902 "./ITHACAoutput/supremizer/");
912 PtrList<volScalarField>& snapshots, PtrList<volScalarField>& modes,
913 word fieldName,
bool podex,
bool supex,
bool sup, label nmodes,
917 PtrList<volVectorField>& snapshots, PtrList<volVectorField>& modes,
918 word fieldName,
bool podex,
bool supex,
bool sup, label nmodes,
923Eigen::MatrixXd
corMatrix(PtrList<volScalarField>& snapshots)
925 Info <<
"########## Filling the correlation matrix for " << snapshots[0].name()
926 <<
"##########" << endl;
927 Eigen::MatrixXd matrix( snapshots.size(), snapshots.size());
929 for (label
i = 0;
i < snapshots.size();
i++)
931 for (label j = 0; j <=
i; j++)
933 matrix(
i, j) = fvc::domainIntegrate(snapshots[
i] * snapshots[j]).value();
937 for (label
i = 1;
i < snapshots.size();
i++)
939 for (label j = 0; j <
i; j++)
941 matrix(j,
i) = matrix(
i, j);
951Eigen::MatrixXd
corMatrix(PtrList<volVectorField>& snapshots)
953 Info <<
"########## Filling the correlation matrix for " << snapshots[0].name()
954 <<
"##########" << endl;
955 Eigen::MatrixXd matrix( snapshots.size(), snapshots.size());
957 for (label
i = 0;
i < snapshots.size();
i++)
959 for (label j = 0; j <=
i; j++)
961 matrix(
i, j) = fvc::domainIntegrate(snapshots[
i] & snapshots[j]).value();
965 for (label
i = 1;
i < snapshots.size();
i++)
967 for (label j = 0; j <
i; j++)
969 matrix(j,
i) = matrix(
i, j);
978Eigen::MatrixXd
corMatrix(List<Eigen::SparseMatrix<double >> &
981 Info <<
"########## Filling the correlation matrix for the matrix list ##########"
983 Eigen::MatrixXd matrix(snapshots.size(), snapshots.size());
984 for (label
i = 0;
i < snapshots.size();
i++)
986 for (label j = 0; j <=
i; j++)
989 for (label k = 0; k < snapshots[
i].cols(); k++)
991 res += snapshots[
i].col(k).dot(snapshots[j].
col(k));
998 for (label
i = 1;
i < snapshots.size();
i++)
1000 for (label j = 0; j <
i; j++)
1002 matrix(j,
i) = matrix(
i, j);
1013 Info <<
"########## Filling the correlation matrix for the matrix list ##########"
1015 Eigen::MatrixXd matrix( snapshots.size(), snapshots.size());
1017 for (label
i = 0;
i < snapshots.size();
i++)
1019 for (label j = 0; j <=
i; j++)
1021 matrix(
i, j) = (snapshots[
i].transpose() * snapshots[j]).trace();
1025 for (label
i = 1;
i < snapshots.size();
i++)
1027 for (label j = 0; j <
i; j++)
1029 matrix(j,
i) = matrix(
i, j);
1039template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
1040void exportBases(PtrList<GeometricField<Type, PatchField, GeoMesh >> & s,
1041 PtrList<GeometricField<Type, PatchField, GeoMesh >>& bases,
1042 word fieldName,
bool sup)
1048 for (label
i = 0;
i < s.size();
i++)
1050 mkDir(
"./ITHACAoutput/supremizer/" + name(
i + 1));
1051 fieldname =
"./ITHACAoutput/supremizer/" + name(
i + 1) +
"/" +
1053 OFstream os(fieldname);
1054 bases[
i].writeHeader(os);
1062 for (label
i = 0;
i < s.size();
i++)
1064 mkDir(
"./ITHACAoutput/POD/" + name(
i + 1));
1065 fieldname =
"./ITHACAoutput/POD/" + name(
i + 1) +
"/" + bases[
i].name();
1066 OFstream os(fieldname);
1067 bases[
i].writeHeader(os);
1074 PtrList<volVectorField>& bases, word fieldName,
bool sup);
1076 PtrList<volScalarField>& bases, word fieldName,
bool sup);
1084 mkDir(
"./ITHACAoutput/supremizer/");
1085 fieldname =
"./ITHACAoutput/supremizer/Eigenvalues_" + name;
1086 OFstream os(fieldname);
1088 for (label
i = 0;
i < Eigenvalues.size();
i++)
1090 os << Eigenvalues[
i] << endl;
1096 mkDir(
"./ITHACAoutput/POD/");
1097 fieldname =
"./ITHACAoutput/POD/Eigenvalues_" + name;
1098 OFstream os(fieldname);
1100 for (label
i = 0;
i < Eigenvalues.size();
i++)
1102 os << Eigenvalues[
i] << endl;
1113 mkDir(
"./ITHACAoutput/supremizer/");
1114 fieldname =
"./ITHACAoutput/supremizer/cumEigenvalues_" + name;
1115 OFstream os(fieldname);
1117 for (label
i = 0;
i < cumEigenvalues.size();
i++)
1119 os << cumEigenvalues[
i] << endl;
1125 mkDir(
"./ITHACAoutput/POD/");
1126 fieldname =
"./ITHACAoutput/POD/cumEigenvalues_" + name;
1127 OFstream os(fieldname);
1129 for (label
i = 0;
i < cumEigenvalues.size();
i++)
1131 os << cumEigenvalues[
i] << endl;
1137std::tuple<List<Eigen::SparseMatrix<double >>, List<Eigen::VectorXd >>
1139 List<Eigen::VectorXd>& b, label nmodesA, label nmodesB, word MatrixName)
1142 List<Eigen::SparseMatrix<double >> ModesA(nmodesA);
1143 List<Eigen::VectorXd> ModesB(nmodesB);
1147 if (nmodesA >
A.size() - 2 || nmodesB >
A.size() - 2 )
1150 "The number of requested modes cannot be bigger than the number of Snapshots - 2"
1155 scalarField eigenValuesA(nmodesA);
1156 scalarField cumEigenValuesA(nmodesA);
1157 scalarField eigenValuesB(nmodesB);
1158 scalarField cumEigenValuesB(nmodesB);
1159 List<scalarField> eigenVectorA(nmodesA);
1160 List<scalarField> eigenVectorB(nmodesB);
1162 for (label
i = 0;
i < nmodesA;
i++)
1164 eigenVectorA[
i].setSize(
A.size());
1167 for (label
i = 0;
i < nmodesB;
i++)
1169 eigenVectorB[
i].setSize(
A.size());
1173 Eigen::MatrixXd corMatrixB =
corMatrix(b);
1174 Info <<
"####### Performing the POD for the Matrix List #######" << endl;
1175 Spectra::DenseSymMatProd<double> opA(corMatrixA);
1176 Spectra::DenseSymMatProd<double> opB(corMatrixB);
1177 Spectra::SymEigsSolver<Spectra:: DenseSymMatProd<double >>
1178 esA(opA, nmodesA, nmodesA + 10);
1179 Spectra::SymEigsSolver<Spectra:: DenseSymMatProd<
double
1181 esB(opB, nmodesB, nmodesB + 10);
1184 esA.compute(Spectra::SortRule::LargestAlge);
1190 Info <<
"####### End of the POD for the Matrix List #######" << endl;
1191 Eigen::VectorXd eigenValueseigA;
1192 Eigen::MatrixXd eigenVectorseigA;
1193 Eigen::VectorXd eigenValueseigB;
1194 Eigen::MatrixXd eigenVectorseigB;
1196 if (esA.info() == Spectra::CompInfo::Successful)
1198 eigenValueseigA = esA.eigenvalues().real();
1199 eigenVectorseigA = esA.eigenvectors().real();
1201 if (esB.info() == Spectra::CompInfo::Successful && nmodesB != 1)
1203 eigenValueseigB = esB.eigenvalues().real();
1204 eigenVectorseigB = esB.eigenvectors().real();
1206 else if (nmodesB == 1)
1208 eigenValueseigB.resize(1);
1209 eigenVectorseigB.resize(
A.size(), nmodesB);
1210 eigenValueseigB(0) = 1;
1211 eigenVectorseigB = eigenVectorseigB * 0;
1212 eigenVectorseigB(0, 0) = 1;
1216 Info <<
"The Eigenvalue solver in ITHACAPOD.H did not converge, exiting the code"
1223 Info <<
"The Eigenvalue solver in ITHACAPOD.H did not converge, exiting the code"
1227 for (label
i = 0;
i < nmodesA;
i++)
1229 eigenValuesA[
i] = eigenValueseigA(
i) / eigenValueseigA.sum();
1231 for (label
i = 0;
i < nmodesB;
i++)
1233 eigenValuesB[
i] = eigenValueseigB(
i) / eigenValueseigB.sum();
1235 for (label
i = 0;
i < nmodesA;
i++)
1237 for (label k = 0; k <
A.size(); k++)
1239 eigenVectorA[
i][k] = eigenVectorseigA(k,
i);
1242 for (label
i = 0;
i < nmodesB;
i++)
1244 for (label k = 0; k <
A.size(); k++)
1246 eigenVectorB[
i][k] = eigenVectorseigB(k,
i);
1249 cumEigenValuesA[0] = eigenValuesA[0];
1250 cumEigenValuesB[0] = eigenValuesB[0];
1252 for (label
i = 1;
i < nmodesA;
i++)
1254 cumEigenValuesA[
i] = cumEigenValuesA[
i - 1] + eigenValuesA[
i];
1256 for (label
i = 1;
i < nmodesB;
i++)
1258 cumEigenValuesB[
i] = cumEigenValuesB[
i - 1] + eigenValuesB[
i];
1260 Eigen::SparseMatrix<double> tmp_A;
1261 Eigen::VectorXd tmp_B;
1263 for (label
i = 0;
i < nmodesA;
i++)
1265 tmp_A = eigenVectorA[
i][0] *
A[0];
1267 for (label k = 1; k <
A.size(); k++)
1269 tmp_A += eigenVectorA[
i][k] *
A[k];
1274 for (label
i = 0;
i < nmodesB;
i++)
1276 tmp_B = eigenVectorB[
i][0] * b[0];
1278 for (label k = 1; k <
A.size(); k++)
1280 tmp_B += eigenVectorB[
i][k] * b[k];
1286 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"eigenValuesA_" + MatrixName);
1288 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"cumEigenValuesA_" + MatrixName);
1290 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"eigenValuesB_" + MatrixName);
1292 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"cumEigenValuesB_" + MatrixName);
1294 for (label
i = 0;
i < ModesA.size();
i++)
1297 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"A_" + MatrixName + name(
i));
1299 for (label
i = 0;
i < ModesB.size();
i++)
1302 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"B_" + MatrixName + name(
i));
1307 for (label
i = 0;
i < nmodesA;
i++)
1310 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"A_" + MatrixName + name(
i));
1313 for (label
i = 0;
i < nmodesB;
i++)
1316 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"B_" + MatrixName + name(
i));
1319 std::tuple <List<Eigen::SparseMatrix<double >>, List<Eigen::VectorXd >> tupla;
1320 tupla = std::make_tuple(ModesA, ModesB);
1326 Eigen::MatrixXd Ortho = Matrix;
1328 for (label
i = 0;
i < Matrix.cols();
i++)
1330 for (label k = 0; k <
i; k++)
1332 double num = Ortho.col(k).transpose() * Matrix.col(
i);
1333 double den = (Ortho.col(k).transpose() * Ortho.col(k));
1334 double fact = num / den;
1335 Ortho.col(
i) -= fact* Ortho.col(k) ;
1338 Ortho.col(
i).normalize();
1344template<
class Type,
template<
class>
class PatchField,
class GeoMesh>
1346 PtrList<GeometricField<Type, PatchField, GeoMesh >> & snapshots,
1347 PtrList<GeometricField<Type, PatchField, GeoMesh >>& modes,
1348 PtrList<volScalarField>& Volumes, word fieldName,
bool podex,
bool supex,
1349 bool sup, label nmodes,
bool correctBC)
1353 if (nmodes == 0 &&
para->eigensolver ==
"spectra")
1355 nmodes = snapshots.size() - 2;
1358 if (nmodes == 0 &&
para->eigensolver ==
"eigen")
1360 nmodes = snapshots.size();
1363 if (
para->eigensolver ==
"spectra")
1365 M_Assert(nmodes <= snapshots.size() - 2,
1366 "The number of requested modes cannot be bigger than the number of Snapshots - 2");
1369 if ((podex == 0 && sup == 0) || (supex == 0 && sup == 1))
1373 label NBC = snapshots[0].boundaryField().size();
1375 Eigen::MatrixXd _corMatrix(snapshots.size(), snapshots.size());
1376 Info <<
"Filling the correlation matrix for field " << snapshots[0].name() <<
1379 for (label
i = 0;
i < snapshots.size();
i++)
1381 for (label j = 0; j <=
i; j++)
1383 Eigen::VectorXd Mij = (V.col(
i).array() * V.col(j).array());
1384 Mij = Mij.array().abs().sqrt();
1385 _corMatrix(
i, j) = SnapMatrix.col(
i).transpose() * Mij.asDiagonal() *
1390 std::cout << std::endl;
1392 for (label
i = 1;
i < snapshots.size();
i++)
1394 for (label j = 0; j <
i; j++)
1396 _corMatrix(j,
i) = _corMatrix(
i, j);
1400 Eigen::VectorXd eigenValueseig;
1401 Eigen::MatrixXd eigenVectoreig;
1402 modes.resize(nmodes);
1403 Info <<
"####### Performing the POD using EigenDecomposition for " <<
1404 snapshots[0].name() <<
" #######" << endl;
1405 label ncv = snapshots.size();
1406 Spectra::DenseSymMatProd<double> op(_corMatrix);
1407 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> esEg;
1409 if (
para->eigensolver ==
"spectra")
1411 Spectra::SymEigsSolver< Spectra::DenseSymMatProd<double >>
1412 es(op, nmodes, ncv);
1413 std::cout <<
"Using Spectra EigenSolver " << std::endl;
1415 es.compute(Spectra::SortRule::LargestAlge);
1416 M_Assert(es.info() == Spectra::CompInfo::Successful,
1417 "The Eigenvalue Decomposition did not succeed");
1418 eigenVectoreig = es.eigenvectors().real();
1419 eigenValueseig = es.eigenvalues().real();
1422 else if (
para->eigensolver ==
"eigen")
1424 std::cout <<
"Using Eigen EigenSolver " << std::endl;
1425 esEg.compute(_corMatrix);
1426 M_Assert(esEg.info() == Eigen::Success,
1427 "The Eigenvalue Decomposition did not succeed");
1428 eigenVectoreig = esEg.eigenvectors().real().rowwise().reverse().leftCols(
1430 eigenValueseig = esEg.eigenvalues().real().reverse().head(nmodes);
1433 Info <<
"####### End of the POD for " << snapshots[0].name() <<
" #######" <<
1435 Eigen::VectorXd eigenValueseigLam =
1436 eigenValueseig.real().array().cwiseInverse().sqrt() ;
1437 Eigen::MatrixXd modesEig = (SnapMatrix* eigenVectoreig) *
1438 eigenValueseigLam.asDiagonal();
1439 List<Eigen::MatrixXd> modesEigBC;
1440 modesEigBC.resize(NBC);
1442 for (label
i = 0;
i < NBC;
i++)
1444 modesEigBC[
i] = (SnapMatrixBC[
i] * eigenVectoreig) *
1445 eigenValueseigLam.asDiagonal();
1447 for (label
i = 0;
i < modes.size();
i++)
1449 GeometricField<Type, PatchField, GeoMesh> tmp2(snapshots[0].name(),
1451 Eigen::VectorXd vec = modesEig.col(
i);
1455 for (label k = 0; k < tmp2.boundaryField().size(); k++)
1460 modes.set(
i, tmp2.clone());
1462 eigenValueseig = eigenValueseig / eigenValueseig.sum();
1463 Eigen::VectorXd cumEigenValues(eigenValueseig);
1465 for (label j = 1; j < cumEigenValues.size(); ++j)
1467 cumEigenValues(j) += cumEigenValues(j - 1);
1469 Info <<
"####### Saving the POD bases for " << snapshots[0].name() <<
" #######"
1473 "./ITHACAoutput/POD/Eigenvalues_" + snapshots[0].name(),
para->precision,
1476 "./ITHACAoutput/POD/CumEigenvalues_" + snapshots[0].name(),
para->precision,
1481 Info <<
"Reading the existing modes" << endl;
1495 PtrList<volScalarField>& snapshots, PtrList<volScalarField>& modes,
1496 PtrList<volScalarField>& Volumes, word fieldName,
bool podex,
bool supex,
1497 bool sup, label nmodes,
bool correctBC);
1500 PtrList<volVectorField>& snapshots, PtrList<volVectorField>& modes,
1501 PtrList<volScalarField>& Volumes, word fieldName,
bool podex,
bool supex,
1502 bool sup, label nmodes,
bool correctBC);
1504template<
typename type_matrix>
1505std::tuple<List<Eigen::SparseMatrix<double >>, List<Eigen::VectorXd >>
1506DEIMmodes(PtrList<type_matrix> & MatrixList, label nmodesA, label nmodesB,
1510 List<Eigen::SparseMatrix<double >> ModesA(nmodesA);
1511 List<Eigen::VectorXd> ModesB(nmodesB);
1515 M_Assert(nmodesA <= MatrixList.size() - 2
1516 && nmodesB <= MatrixList.size() - 2,
1517 "The number of requested modes cannot be bigger than the number of Snapshots - 2");
1518 std::tuple<List<Eigen::SparseMatrix<double >>, List<Eigen::VectorXd >> snapshots =
1520 Eigen::MatrixXd corMatrixA =
corMatrix(std::get<0>(snapshots));
1521 Eigen::MatrixXd corMatrixB =
corMatrix(std::get<1>(snapshots));
1522 Eigen::VectorXd eigenValueseigA;
1523 Eigen::MatrixXd eigenVectorseigA;
1524 Eigen::VectorXd eigenValueseigB;
1525 Eigen::MatrixXd eigenVectorseigB;
1527 if (
para->eigensolver ==
"spectra")
1529 Info <<
"####### Performing the POD decomposition for the Matrix List using Spectra #######"
1531 Spectra::DenseSymMatProd<double> opA(corMatrixA);
1532 Spectra::DenseSymMatProd<double> opB(corMatrixB);
1533 label ncvA = MatrixList.size();
1534 label ncvB = MatrixList.size();
1535 Spectra::SymEigsSolver<Spectra:: DenseSymMatProd<double >>
1536 esA(opA, nmodesA, ncvA);
1537 Spectra::SymEigsSolver<Spectra:: DenseSymMatProd<
double
1539 esB(opB, nmodesB, ncvB);
1542 esA.compute(Spectra::SortRule::LargestAlge);
1543 M_Assert(esA.info() == Spectra::CompInfo::Successful,
1544 "The Eigenvalue Decomposition did not succeed");
1548 esB.compute(Spectra::SortRule::LargestAlge);
1549 M_Assert(esB.info() == Spectra::CompInfo::Successful,
1550 "The Eigenvalue Decomposition did not succeed");
1552 Info <<
"####### End of the POD decomposition for the Matrix List #######" <<
1554 eigenValueseigA = esA.eigenvalues().real();
1555 eigenVectorseigA = esA.eigenvectors().real();
1559 eigenValueseigB = esB.eigenvalues().real();
1560 eigenVectorseigB = esB.eigenvectors().real();
1564 eigenValueseigB.resize(1);
1565 eigenVectorseigB.resize(MatrixList.size(), nmodesB);
1566 eigenValueseigB(0) = 1;
1567 eigenVectorseigB = eigenVectorseigB * 0;
1568 eigenVectorseigB(0, 0) = 1;
1571 else if (
para->eigensolver ==
"eigen")
1573 Info <<
"####### Performing the POD decomposition for the Matrix List using Eigen #######"
1575 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> esEgA;
1576 esEgA.compute(corMatrixA);
1577 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> esEgB;
1578 esEgB.compute(corMatrixB);
1579 M_Assert(esEgA.info() == Eigen::Success,
1580 "The Eigenvalue Decomposition did not succeed");
1581 M_Assert(esEgB.info() == Eigen::Success,
1582 "The Eigenvalue Decomposition did not succeed");
1583 eigenVectorseigA = esEgA.eigenvectors().real().rowwise().reverse().leftCols(
1585 eigenValueseigA = esEgA.eigenvalues().real().reverse().head(nmodesA);
1586 eigenVectorseigB = esEgB.eigenvectors().real().rowwise().reverse().leftCols(
1588 eigenValueseigB = esEgB.eigenvalues().real().reverse().head(nmodesB);
1590 Eigen::SparseMatrix<double> tmp_A;
1591 Eigen::VectorXd tmp_B;
1593 for (label
i = 0;
i < nmodesA;
i++)
1595 tmp_A = eigenVectorseigA(0,
i) * std::get<0>(snapshots)[0];
1597 for (label k = 1; k < MatrixList.size(); k++)
1599 tmp_A += eigenVectorseigA(k,
i) * std::get<0>(snapshots)[k];
1604 for (label
i = 0;
i < nmodesB;
i++)
1606 tmp_B = eigenVectorseigB(0,
i) * std::get<1>(snapshots)[0];
1608 for (label k = 1; k < MatrixList.size(); k++)
1610 tmp_B += eigenVectorseigB(k,
i) * std::get<1>(snapshots)[k];
1615 eigenValueseigA = eigenValueseigA / eigenValueseigA.sum();
1616 eigenValueseigB = eigenValueseigB / eigenValueseigB.sum();
1617 Eigen::VectorXd cumEigenValuesA(eigenValueseigA);
1618 Eigen::VectorXd cumEigenValuesB(eigenValueseigB);
1620 for (label j = 1; j < cumEigenValuesA.size(); ++j)
1622 cumEigenValuesA(j) += cumEigenValuesA(j - 1);
1624 for (label j = 1; j < cumEigenValuesB.size(); ++j)
1626 cumEigenValuesB(j) += cumEigenValuesB(j - 1);
1628 for (label
i = 0;
i < ModesA.size();
i++)
1631 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"A_" + MatrixName + name(
i));
1633 for (label
i = 0;
i < ModesB.size();
i++)
1636 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"B_" + MatrixName + name(
i));
1639 "./ITHACAoutput/DEIM/" + MatrixName +
"/eigenValuesA",
para->precision,
1642 "./ITHACAoutput/DEIM/" + MatrixName +
"/eigenValuesB",
para->precision,
1645 "./ITHACAoutput/DEIM/" + MatrixName +
"/cumEigenValuesA",
para->precision,
1648 "./ITHACAoutput/DEIM/" + MatrixName +
"/cumEigenValuesB",
para->precision,
1653 for (label
i = 0;
i < nmodesA;
i++)
1656 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"A_" + MatrixName + name(
i));
1659 for (label
i = 0;
i < nmodesB;
i++)
1662 "./ITHACAoutput/DEIM/" + MatrixName +
"/",
"B_" + MatrixName + name(
i));
1665 std::tuple <List<Eigen::SparseMatrix<double >>, List<Eigen::VectorXd >> tupla;
1666 tupla = std::make_tuple(ModesA, ModesB);
1670template std::tuple<List<Eigen::SparseMatrix<double >>, List<Eigen::VectorXd >>
1671DEIMmodes(PtrList<fvScalarMatrix>& MatrixList, label nmodesA,
1675template std::tuple<List<Eigen::SparseMatrix<double >>, List<Eigen::VectorXd >>
1676DEIMmodes(PtrList<fvVectorMatrix> & MatrixList, label nmodesA,
1680template<
class Type,
template<
class>
class PatchField,
class GeoMesh >
1681PtrList<GeometricField<Type, PatchField, GeoMesh >>
DEIMmodes(
1682 PtrList<GeometricField<Type, PatchField, GeoMesh >>& snapshots, label nmodes,
1683 word FunctionName, word fieldName)
1686 word PODkey =
"POD_" + fieldName;
1687 word PODnorm =
para->ITHACAdict->lookupOrDefault<word>(PODkey,
"L2");
1689 PODnorm ==
"Frobenius",
"The PODnorm can be only L2 or Frobenius");
1690 Info <<
"Performing POD for " << fieldName <<
" using the " << PODnorm <<
1692 PtrList<GeometricField<Type, fvPatchField, volMesh >> modes;
1693 bool correctBC =
true;
1694 if (nmodes == 0 &&
para->eigensolver ==
"spectra")
1696 nmodes = snapshots.size() - 2;
1699 if (nmodes == 0 &&
para->eigensolver ==
"eigen")
1701 nmodes = snapshots.size();
1704 if (
para->eigensolver ==
"spectra")
1706 M_Assert(nmodes <= snapshots.size() - 2,
1707 "The number of requested modes cannot be bigger than the number of Snapshots - 2");
1714 label NBC = snapshots[0].boundaryField().size();
1715 Eigen::MatrixXd _corMatrix;
1717 if (PODnorm ==
"L2")
1721 else if (PODnorm ==
"Frobenius")
1726 if (Pstream::parRun())
1728 reduce(_corMatrix, sumOp<Eigen::MatrixXd>());
1731 Eigen::VectorXd eigenValueseig;
1732 Eigen::MatrixXd eigenVectoreig;
1733 modes.resize(nmodes);
1734 Info <<
"####### Performing the POD using EigenDecomposition " <<
1735 fieldName <<
" #######" << endl;
1736 label ncv = snapshots.size();
1737 Spectra::DenseSymMatProd<double> op(_corMatrix);
1738 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> esEg;
1740 if (
para->eigensolver ==
"spectra")
1742 Spectra::SymEigsSolver< Spectra::DenseSymMatProd<double >>
1743 es(op, nmodes, ncv);
1744 std::cout <<
"Using Spectra EigenSolver " << std::endl;
1746 es.compute(Spectra::SortRule::LargestAlge);
1747 M_Assert(es.info() == Spectra::CompInfo::Successful,
1748 "The Eigenvalue Decomposition did not succeed");
1749 eigenVectoreig = es.eigenvectors().real();
1750 eigenValueseig = es.eigenvalues().real();
1753 else if (
para->eigensolver ==
"eigen")
1755 std::cout <<
"Using Eigen EigenSolver " << std::endl;
1756 esEg.compute(_corMatrix);
1757 M_Assert(esEg.info() == Eigen::Success,
1758 "The Eigenvalue Decomposition did not succeed");
1759 eigenVectoreig = esEg.eigenvectors().real().rowwise().reverse().leftCols(
1761 eigenValueseig = esEg.eigenvalues().real().array().reverse();
1764 if (eigenValueseig.array().minCoeff() < 0)
1766 eigenValueseig = eigenValueseig.array() + 2 * abs(
1767 eigenValueseig.array().minCoeff());
1770 Info <<
"####### End of the POD for " << snapshots[0].name() <<
" #######" <<
1772 Eigen::MatrixXd modesEig = (SnapMatrix* eigenVectoreig);
1774 Eigen::MatrixXd normFact(nmodes, 1);
1775 for (label
i = 0;
i < nmodes;
i++)
1777 if (PODnorm ==
"L2")
1779 normFact(
i, 0) = std::sqrt((modesEig.col(
i).transpose() * V.asDiagonal() *
1780 modesEig.col(
i))(0, 0));
1781 if (Pstream::parRun())
1783 normFact(
i, 0) = (modesEig.col(
i).transpose() * V.asDiagonal() *
1784 modesEig.col(
i))(0, 0);
1788 else if (PODnorm ==
"Frobenius")
1790 normFact(
i, 0) = std::sqrt((modesEig.col(
i).transpose() * modesEig.col(
i))(0,
1792 if (Pstream::parRun())
1794 normFact(
i, 0) = (modesEig.col(
i).transpose() * modesEig.col(
i))(0, 0);
1799 if (Pstream::parRun())
1801 reduce(normFact, sumOp<Eigen::MatrixXd>());
1804 if (Pstream::parRun())
1806 normFact = normFact.cwiseSqrt();
1808 List<Eigen::MatrixXd> modesEigBC;
1809 modesEigBC.resize(NBC);
1811 for (label
i = 0;
i < NBC;
i++)
1813 modesEigBC[
i] = (SnapMatrixBC[
i] * eigenVectoreig);
1815 std::cout << normFact << std::endl;
1817 for (label
i = 0;
i < nmodes;
i++)
1819 modesEig.col(
i) = modesEig.col(
i).array() / normFact(
i, 0);
1821 for (label j = 0; j < NBC; j++)
1823 modesEigBC[j].col(
i) = modesEigBC[j].col(
i).array() / normFact(
i, 0);
1826 for (label
i = 0;
i < modes.size();
i++)
1828 GeometricField<Type, PatchField, GeoMesh> tmp2(snapshots[0].name(),
1830 Eigen::VectorXd vec = modesEig.col(
i);
1833 for (label k = 0; k < NBC; k++)
1838 modes.set(
i, tmp2.clone());
1840 eigenValueseig = eigenValueseig / eigenValueseig.sum();
1841 Eigen::VectorXd cumEigenValues(eigenValueseig);
1843 for (label j = 1; j < cumEigenValues.size(); ++j)
1845 cumEigenValues(j) += cumEigenValues(j - 1);
1847 Info <<
"####### Saving the POD bases for " << snapshots[0].name() <<
1851 for (label
i = 0;
i < modes.size();
i++)
1857 "./ITHACAoutput/DEIM/eigenValues_" + fieldName,
para->precision,
1860 "./ITHACAoutput/DEIM/cumEigenValues_" + fieldName,
para->precision,
1865 Info <<
"Reading the existing modes" << endl;
1871template<
class Field_type,
class Field_type_2>
1873 PtrList<Field_type>& snapshots, PtrList<Field_type>& modes,
1874 PtrList<Field_type_2>& fields2, word fieldName,
bool podex,
bool supex,
1875 bool sup, label nmodes,
bool correctBC)
1879 if ((podex == 0 && sup == 0) || (supex == 0 && sup == 1))
1881 if (
para->eigensolver ==
"spectra" )
1885 nmodes = snapshots.size() - 2;
1888 M_Assert(nmodes <= snapshots.size() - 2,
1889 "The number of requested modes cannot be bigger than the number of Snapshots - 2");
1895 nmodes = snapshots.size();
1898 M_Assert(nmodes <= snapshots.size(),
1899 "The number of requested modes cannot be bigger than the number of Snapshots");
1904 label NBC = fields2[0].boundaryField().size();
1906 Eigen::MatrixXd _corMatrix = SnapMatrix.transpose() * VM.asDiagonal() *
1909 if (Pstream::parRun())
1911 reduce(_corMatrix, sumOp<Eigen::MatrixXd>());
1914 Eigen::VectorXd eigenValueseig;
1915 Eigen::MatrixXd eigenVectoreig;
1916 modes.resize(nmodes);
1917 Info <<
"####### Performing the POD using EigenDecomposition " <<
1918 fields2[0].name() <<
" #######" << endl;
1919 label ncv = snapshots.size();
1920 Spectra::DenseSymMatProd<double> op(_corMatrix);
1921 Eigen::SelfAdjointEigenSolver<Eigen::MatrixXd> esEg;
1923 if (
para->eigensolver ==
"spectra")
1925 Spectra::SymEigsSolver<Spectra::DenseSymMatProd<double >>
1926 es(op, nmodes, ncv);
1927 std::cout <<
"Using Spectra EigenSolver " << std::endl;
1929 es.compute(Spectra::SortRule::LargestAlge);
1930 M_Assert(es.info() == Spectra::CompInfo::Successful,
1931 "The Eigenvalue Decomposition did not succeed");
1932 eigenVectoreig = es.eigenvectors().real();
1933 eigenValueseig = es.eigenvalues().real();
1936 else if (
para->eigensolver ==
"eigen")
1938 std::cout <<
"Using Eigen EigenSolver " << std::endl;
1939 esEg.compute(_corMatrix);
1940 M_Assert(esEg.info() == Eigen::Success,
1941 "The Eigenvalue Decomposition did not succeed");
1942 eigenVectoreig = esEg.eigenvectors().real().rowwise().reverse().leftCols(
1944 eigenValueseig = esEg.eigenvalues().real().reverse().head(nmodes);
1947 Info <<
"####### End of the POD for " << snapshots[0].name() <<
" #######" <<
1949 Eigen::VectorXd eigenValueseigLam =
1950 eigenValueseig.real().array().cwiseInverse().abs().sqrt() ;
1951 Eigen::MatrixXd modesEig = (SnapMatrix* eigenVectoreig) *
1952 eigenValueseigLam.asDiagonal();
1953 List<Eigen::MatrixXd> modesEigBC;
1954 modesEigBC.resize(NBC);
1956 for (label
i = 0;
i < modes.size();
i++)
1958 Field_type tmp2(snapshots[0].name(), snapshots[0] * 0);
1960 for (label j = 0; j < snapshots.size(); j++)
1962 tmp2 += eigenValueseigLam(
i) * eigenVectoreig.col(
i)(j) * snapshots[j];
1965 modes.set(
i, tmp2.clone());
1967 eigenValueseig = eigenValueseig / eigenValueseig.sum();
1968 Eigen::VectorXd cumEigenValues(eigenValueseig);
1970 for (label j = 1; j < cumEigenValues.size(); ++j)
1972 cumEigenValues(j) += cumEigenValues(j - 1);
1974 Info <<
"####### Saving the POD bases for " << snapshots[0].name() <<
1980 snapshots[0].name());
1987 "./ITHACAoutput/POD/Eigenvalues_" + snapshots[0].name(),
para->precision,
1990 "./ITHACAoutput/POD/CumEigenvalues_" + snapshots[0].name(),
para->precision,
1995 Info <<
"Reading the existing modes" << endl;
2009 PtrList<surfaceScalarField>& snapshots, PtrList<surfaceScalarField>& modes,
2010 PtrList<volVectorField>& fields2, word fieldName,
bool podex,
bool supex,
2011 bool sup, label nmodes,
bool correctBC);
2014 PtrList<volScalarField>& snapshots, PtrList<volScalarField>& modes,
2015 PtrList<volVectorField>& fields2, word fieldName,
bool podex,
bool supex,
2016 bool sup, label nmodes,
bool correctBC);
2018template PtrList<volScalarField>
2020 PtrList<volScalarField>& SnapShotsMatrix,
2022 word FunctionName, word FieldName);
2024template PtrList<volVectorField>
2026 PtrList<volVectorField>& SnapShotsMatrix,
2028 word FunctionName, word FieldName);
2032 const GeometricField<scalar, fvPatchField, volMesh>& field1,
2033 const GeometricField<scalar, fvPatchField, volMesh>& field2)
2035 return fvc::domainIntegrate(field1 * field2).value();
2040 const GeometricField<vector, fvPatchField, volMesh>& field1,
2041 const GeometricField<vector, fvPatchField, volMesh>& field2)
2043 return fvc::domainIntegrate(field1 & field2).value();
2048 const GeometricField<scalar, fvPatchField, volMesh>& field1,
2049 const GeometricField<scalar, fvPatchField, volMesh>& field2)
2051 return sum(field1.primitiveField() * field2.primitiveField());
2056 const GeometricField<vector, fvPatchField, volMesh>& field1,
2057 const GeometricField<vector, fvPatchField, volMesh>& field2)
2059 return sum(field1.primitiveField()&field2.primitiveField());
Header file of the EigenFunctions class.
Header file of the ITHACAPOD 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 List< Eigen::VectorXd > field2EigenBC(GeometricField< scalar, PatchField, GeoMesh > &field)
Convert an OpenFOAM scalar field to a List of Eigen Vectors, one for each boundary.
static std::tuple< List< Eigen::SparseMatrix< double > >, List< Eigen::VectorXd > > LFvMatrix2LSM(PtrList< fvMatrix< Type > > &MatrixList)
Convert a PtrList of OpenFOAM fvMatrix into a tuple of lists of Eigen Sparse Matrices and source vect...
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.
static Eigen::MatrixXd PtrList2Eigen(PtrList< GeometricField< Type, PatchField, GeoMesh > > &fields, label Nfields=-1)
Convert a PtrList of snapshots to Eigen matrix (only internal field)
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.
bool saveMarketVector(const VectorType &vec, const std::string &filename, label prec, std::_Ios_Fmtflags outytpe=std::ios_base::scientific)
namespace for the computation of the POD, it exploits bot the method of snapshots and SVD.
scalar computeFrobeniusInnerProduct(const GeometricField< scalar, fvPatchField, volMesh > &field1, const GeometricField< scalar, fvPatchField, volMesh > &field2)
void exportcumEigenvalues(scalarField cumEigenvalues, fileName name, bool sup)
Export the cumulative eigenvalues as a txt file.
void getModesMemoryEfficient(GeometricField< Type, PatchField, GeoMesh > &templateField, word snapshotsPath, PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes, word fieldName, bool podex, bool supex, bool sup, label nmodes, bool correctBC, autoPtr< GeometricField< Type, PatchField, GeoMesh > > meanField)
Gets the modes in a memory-efficient manner.
void exportEigenvalues(scalarField Eigenvalues, fileName name, bool sup)
Exports the eigenvalues as a txt file.
scalar computeInnerProduct(const GeometricField< scalar, fvPatchField, volMesh > &field1, const GeometricField< scalar, fvPatchField, volMesh > &field2)
void getMeanMemoryEfficient(GeometricField< Type, PatchField, GeoMesh > &templateField, word snapshotsPath, autoPtr< GeometricField< Type, PatchField, GeoMesh > > &meanField, bool meanex)
Gets the mean field in a memory-efficient manner.
void getModes(PtrList< GeometricField< Type, PatchField, GeoMesh > > &snapshots, PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes, word fieldName, bool podex, bool supex, bool sup, label nmodes, bool correctBC)
Computes the bases or reads them for a field.
std::tuple< List< Eigen::SparseMatrix< double > >, List< Eigen::VectorXd > > DEIMmodes(List< Eigen::SparseMatrix< double > > &A, List< Eigen::VectorXd > &b, label nmodesA, label nmodesB, word MatrixName)
Get the DEIM modes for a generic non a parametrized matrix coming from a differential operator functi...
void getNestedSnapshotMatrix(PtrList< GeometricField< Type, PatchField, GeoMesh > > &snapshots, PtrList< GeometricField< Type, PatchField, GeoMesh > > &ModesGlobal, word fieldName, label Npar, label NnestedOut)
Nested-POD approach.
void exportBases(PtrList< GeometricField< Type, PatchField, GeoMesh > > &s, PtrList< GeometricField< Type, PatchField, GeoMesh > > &bases, word fieldName, bool sup)
Export the Bases.
void getModesSVD(PtrList< GeometricField< Type, PatchField, GeoMesh > > &snapshots, PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes, word fieldName, bool podex, bool supex, bool sup, label nmodes, bool correctBC)
Gets the bases for a scalar field using SVD instead of the method of snapshots.
Eigen::MatrixXd corMatrix(PtrList< volScalarField > &snapshots)
Construct the Correlation Matrix for Scalar Field.
void GrammSchmidt(Eigen::MatrixXd &Matrix)
Performs GrammSchmidt orthonormalization on an Eigen Matrix.
void getWeightedModes(PtrList< GeometricField< Type, PatchField, GeoMesh > > &snapshots, PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes, word fieldName, bool podex, bool supex, bool sup, label nmodes, bool correctBC)
Computes the weighted bases (using the nested-pod approach) or read them for a vector field.
void SaveSparseMatrix(Eigen::SparseMatrix< T, Nrows, IND > &m, word folder, word MatrixName)
Export an Eigen sparse matrix into bynary format file.
GeometricField< Type, PatchField, GeoMesh > readFieldByIndex(const GeometricField< Type, PatchField, GeoMesh > &field, fileName casename, label index)
Function to read a single field by index from a folder.
void ReadDenseMatrix(MatrixType &Matrix, word folder, word MatrixName)
Read a dense matrix from a binary format file.
void exportFields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &field, word folder, word fieldname)
Function to export a scalar of vector field.
void exportSolution(GeometricField< Type, PatchField, GeoMesh > &s, fileName subfolder, fileName folder, word fieldName)
Export a field to file in a certain folder and subfolder.
void exportList(T &list, word folder, word filename)
Export a list to file.
void SaveDenseMatrix(MatrixType &Matrix, word folder, word MatrixName)
Save a dense matrix to a binary format file.
void read_fields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &Lfield, word Name, fileName casename, int first_snap, int n_snap)
Function to read a list of fields from the name of the field and casename.
void ReadSparseMatrix(Eigen::SparseMatrix< T, Nrows, IND > &m, word folder, word MatrixName)
Read an Eigen sparse matrix from a bynary format file.
Eigen::VectorXd getMassMatrixFV(GeometricField< Type, PatchField, GeoMesh > &snapshot)
Gets a vector containing the volumes of each cell of the mesh.
Eigen::MatrixXd getMassMatrix(PtrList< GeometricField< Type, PatchField, GeoMesh > > &modes, label Nmodes, bool consider_volumes)
Gets the mass matrix using the eigen routine.
void assignBC(GeometricField< scalar, fvPatchField, volMesh > &s, label BC_ind, double value)
Assign uniform Boundary Condition to a volScalarField.
bool check_folder(word folder)
Checks if a folder exists.
void createSymLink(word folder)
Creates symbolic links to 0, system and constant.
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)