In this tutorial we implement a test where we use the Discrete Empirical Interpolation Method for a case where we have a non-linear dependency with respect to the input parameters.
The following image illustrates the computational domain which is the same as the previous example
The physical problem is given by a heat transfer problem which is described by the Poisson equation:
In this case, even if the problem is linear, due to non-linearity with respect to the input parameter of the conductivity constant it is not possible to have an affine decomposition of the discretized differential operator.
We seek therefore an approximate affine expansion of the differential operator of this type:
#include "fvCFD.H"
#include "IOmanip.H"
#include "fvOptions.H"
#include "simpleControl.H"
#include <chrono>
#include "fvMeshSubset.H"
#include <chrono>
#include <Eigen/SVD>
#include <Eigen/SparseLU>
{
public:
{
volScalarField
yPos =
T.mesh().C().component(vector::Y).ref();
volScalarField
xPos =
T.mesh().C().component(vector::X).ref();
for (
auto i = 0;
i <
nu.size();
i++)
{
nu[
i] = std::exp(- 2 * std::pow(
xPos[
i] - mu(0) - 1,
2) - 2 * std::pow(
yPos[
i] - mu(1) - 0.5, 2)) + 1;
}
nu.correctBoundaryConditions();
fvScalarMatrix TiEqn22
(
fvm::laplacian(
nu,
T,
"Gauss linear")
);
return TiEqn22;
}
{
Eigen::SparseMatrix<double> Mr;
Eigen::VectorXd br;
{
theta(
i) = Mr.coeffRef(ind_row, ind_col);
}
}
{
Eigen::SparseMatrix<double> Mr;
Eigen::VectorXd br;
{
}
}
autoPtr<volScalarField>
fieldA;
autoPtr<volScalarField>
fieldB;
};
{
public:
:
{
(
IOobject
(
"ITHACAdict",
"./system",
IOobject::MUST_READ,
IOobject::NO_WRITE
)
);
}
PtrList<fvScalarMatrix>
Mlist;
{
{
}
else
{
for (
int i = 0;
i < par.rows();
i++)
{
fvScalarMatrix Teqn =
DEIMmatrice->evaluate_expression(
T, par.row(
i));
Teqn.solve();
Mlist.append((Teqn).clone());
}
}
};
{
auto t1 = std::chrono::high_resolution_clock::now();
auto t2 = std::chrono::high_resolution_clock::now();
auto time_span = std::chrono::duration_cast<std::chrono::duration<double >>
(t2 - t1);
for (
int i = 0;
i < par.rows();
i++)
{
fvScalarMatrix Teqn =
DEIMmatrice->evaluate_expression(
T, par.row(
i));
t1 = std::chrono::high_resolution_clock::now();
Teqn.solve();
t2 = std::chrono::high_resolution_clock::now();
time_span = std::chrono::duration_cast<std::chrono::duration<double >>
(t2 - t1);
}
};
{
}
{
fvMesh&
mesh =
const_cast<fvMesh&
>(
T.mesh());
DEIMmatrice->fieldA = autoPtr<volScalarField>(
new volScalarField(
DEIMmatrice->fieldB = autoPtr<volScalarField>(
new volScalarField(
{
}
{
}
};
{
auto t1 = std::chrono::high_resolution_clock::now();
auto t2 = std::chrono::high_resolution_clock::now();
auto time_span = std::chrono::duration_cast<std::chrono::duration<double >>
(t2 - t1);
for (
int i = 0;
i < par_new.rows();
i++)
{
t1 = std::chrono::high_resolution_clock::now();
Eigen::MatrixXd thetaonA =
DEIMmatrice->onlineCoeffsA(par_new.row(
i));
Eigen::MatrixXd thetaonB =
DEIMmatrice->onlineCoeffsB(par_new.row(
i));
Eigen::VectorXd x =
A.fullPivLu().solve(B);
t2 = std::chrono::high_resolution_clock::now();
time_span = std::chrono::duration_cast<std::chrono::duration<double >>
(t2 - t1);
volScalarField Tred(
"Tred",
T);
}
}
};
int main(
int argc,
char* argv[])
{
example._runTime());
example.OfflineSolve(example.mu, "Offline");
example.podex, 0, 0, 20);
example.PODDEIM();
example.OnlineSolve(par_new1, "Online_red");
example_new.OnlineSolveFull(par_new1, "Online_full");
std::cout << std::endl << "The FOM Solve took: " << example_new.time_full <<
" seconds." << std::endl;
std::cout << std::endl << "The ROM Solve took: " << example.time_rom <<
" seconds." << std::endl;
std::cout << std::endl << "The Speed-up is: " << example_new.time_full /
example.time_rom << std::endl << std::endl;
example.Tonline);
std::cout << "The mean L2 error is: " << error.mean() << std::endl;
exit(0);
}
Header file of the EigenFunctions class.
Header file of the Foam2Eigen class.
Header file of the ITHACAPOD class.
Header file of the ITHACAstream class, it contains the implementation of several methods for input ou...
Header file of the ITHACAutilities namespace.
PtrList< fvScalarMatrix > Mlist
std::vector< Eigen::MatrixXd > ReducedMatricesA
std::vector< Eigen::MatrixXd > ReducedVectorsB
DEIMLaplacian(int argc, char *argv[])
DEIM_function * DEIMmatrice
void OnlineSolve(Eigen::MatrixXd par_new, word Folder)
void OnlineSolveFull(Eigen::MatrixXd par, word Folder)
Eigen::MatrixXd ModesTEig
void OfflineSolve(Eigen::MatrixXd par, word Folder)
Eigen::MatrixXd onlineCoeffsA(Eigen::MatrixXd mu)
PtrList< volScalarField > fieldsB
static volScalarField evaluate_expression(volScalarField &S, Eigen::MatrixXd mu)
Eigen::MatrixXd onlineCoeffsB(Eigen::MatrixXd mu)
autoPtr< volScalarField > fieldB
autoPtr< volScalarField > fieldA
PtrList< volScalarField > fieldsA
autoPtr< IOList< label > > xyz_Arow
List< label > localMagicPointsAcol
autoPtr< IOList< label > > magicPointsAcol
List< label > localMagicPointsB
autoPtr< IOList< label > > xyz_B
DEIM(PtrList< T > &SnapShotsMatrix, label MaxModes, word FunctionName, word FieldName)
Construct DEIM for non-linear function.
List< label > localMagicPointsArow
autoPtr< IOList< label > > xyz_Acol
autoPtr< IOList< label > > magicPointsB
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::MatrixXd PtrList2Eigen(PtrList< GeometricField< Type, PatchField, GeoMesh > > &fields, label Nfields=-1)
Convert a PtrList of snapshots to Eigen matrix (only internal field)
static void fvMatrix2Eigen(fvMatrix< type_foam_matrix > foam_matrix, type_A &A, type_B &b)
Convert a FvMatrix OpenFOAM matrix (Linear System) into a Eigen Matrix A and a source vector b.
Class for the definition of some general parameters, the parameters must be defined from the file ITH...
static ITHACAparameters * getInstance()
Gets an instance of ITHACAparameters, to be used if the instance is already existing.
Class to implement a full order laplacian parametrized problem.
PtrList< volScalarField > Tonline
List of snapshots for the solution.
autoPtr< fvMesh > _mesh
Mesh.
volScalarModes Tmodes
List of POD modes.
PtrList< volScalarField > Tfield
List of snapshots for the solution.
bool offline
Boolean variable, it is 1 if the Offline phase has already been computed, else 0.
IOdictionary * ITHACAdict
dictionary to store input output infos
Header file of the laplacianProblem class.
Eigen::SparseMatrix< T > MVproduct(List< Eigen::SparseMatrix< T > > &A, Eigen::DenseBase< Eigen::Matrix< T, Eigen::Dynamic, Eigen::Dynamic > > &C)
Sparse Matrix-Vector product between a list of sparse matrices and a vector of coefficients.
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.
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 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.
Eigen::MatrixXd rand(label rows, label cols, double min, double max)
Generates random matrix with random values in an interval.
double errorL2Abs(GeometricField< vector, fvPatchField, volMesh > &field1, GeometricField< vector, fvPatchField, volMesh > &field2, volScalarField &Volumes)
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))