Loading...
Searching...
No Matches
08DEIM.C

Introduction to tutorial 8

In this tutorial we propose an example concerning the usage of the Discrete Empirical Interpolation Method (implemented in the HyperReduction class) for the approximation of a non-linear function. The following image illustrates the computational domain used to discretize the problem

Computational Domain

The non-linear function is described by a parametric Gaussian function:

\[ S(\mathbf{x},\mathbf{\mu}) = e^{-2(x-\mu_x-1)^2 - 2(y-\mu_y-0.5)^2}, \]

that is depending on the parameter vector \(\mathbf{\mu} = [\mu_x, \mu_y] \) and on the location inside the domain \( \mathbf{x} = [x,y] \). A training set of 100 samples is used to construct the "DEIM" modes which are later used for the approximation.

The necessary header files

First of all let's have a look to the header files that needs to be included and what they are responsible for: The header files of ITHACA-FV necessary for this tutorial are: <Foam2Eigen.H> for Eigen to OpenFOAM conversion of objects, <ITHACAstream.H> for ITHACA-FV input-output operations. <ITHACAPOD.H> for the POD decomposition, <hyperReduction.templates.H> for the "DEIM" approximation.

A detailed look into the code

The OpenFOAM header files:

#include "fvCFD.H"
#include "fvOptions.H"
#include "simpleControl.H"
#include "simpleControl.H"
#include "fvMeshSubset.H"

ITHACA-FV header files

#include "Foam2Eigen.H"
#include "ITHACAstream.H"
#include "ITHACAPOD.H"
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.

chrono to compute the speedup

#include <chrono>

Construction of the function to be approximated with the "DEIM" method from the HyperReduction class.

class DEIM_function : public HyperReduction<PtrList<volScalarField>&>
{
public:
HyperReduction(label n_modes, label n_nodes, Eigen::VectorXi initialSeeds, word problemName, SnapshotsLists &&...snapshotsLists)
Construct HyperReduction class, interpolation-based.

Method with the explicit definition of the non-linear function

static volScalarField evaluate_expression(volScalarField& S, Eigen::MatrixXd mu)
{
volScalarField yPos = S.mesh().C().component(vector::Y).ref();
volScalarField xPos = S.mesh().C().component(vector::X).ref();
for (auto i = 0; i < S.size(); i++)
{
S[i] = std::exp( - 2 * std::pow(xPos[i] - mu(0) - 1,
2) - 2 * std::pow(yPos[i] - mu(1) - 0.5, 2));
}
label i
Definition pEqn.H:46
volScalarField xPos
volScalarField yPos
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))
return S;
}

Method with the expression for the evaluation of the online coefficients

Eigen::VectorXd onlineCoeffs(Eigen::MatrixXd mu)
{
theta.resize(nodePoints().size());
auto f = evaluate_expression(subField(), mu);
for (int i = 0; i < nodePoints().size(); i++)
{
// double on_coeff = f[localMagicPoints[i]];
theta(i) = f[localNodePoints[i]];
}
return theta;
}

Now let's have a look to important command in the main function. Read parameters from the ITHACAdict file

int NDEIM = para->ITHACAdict->lookupOrDefault<int>("NDEIM", 15);
Foam::fvMesh & mesh
Definition createMesh.H:47
Foam::Time & runTime
Definition createTime.H:33
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.

Definition of the parameter samples to train the non-linear function

Eigen::MatrixXd pars = ITHACAutilities::rand(100, 2, -0.5, 0.5);
Eigen::MatrixXd rand(label rows, label cols, double min, double max)
Generates random matrix with random values in an interval.

Offline training of the function and assembly of the snapshots list

// Perform the offline phase
for (int i = 0; i < 100; i++)
{
Sp.append((S).clone());
ITHACAstream::exportSolution(S, name(i + 1), "./ITHACAoutput/Offline/");
}
static volScalarField evaluate_expression(volScalarField &S, Eigen::MatrixXd mu)
Definition 08DEIM.C:45
void exportSolution(GeometricField< Type, PatchField, GeoMesh > &s, fileName subfolder, fileName folder, word fieldName)
Export a field to file in a certain folder and subfolder.

Compute the "DEIM" modes using the ITHACAPOD class

Eigen::VectorXd normalizingWeights = ITHACAutilities::getMassMatrixFV(Sp[0]).array();
PtrList<volScalarField> modes = ITHACAPOD::DEIMmodes(Sp, NDEIM, "GappyDEIM", S.name());
snapshotsModes = Foam2Eigen::PtrList2Eigen(modes);
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:638
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...
Definition ITHACAPOD.C:784
Eigen::VectorXd getMassMatrixFV(GeometricField< Type, PatchField, GeoMesh > &snapshot)
Gets a vector containing the volumes of each cell of the mesh.

Construction of the HyperReduction object passing the maximum number of "DEIM" modes NDEIM, the initSeeds (none in this tutorial), the name used to store the output "DEIM" and the list of snapshots Sp. The constructor is taking the number of modes and the number of point to compute, for the "DEIM" method these numbers are equal.

Eigen::VectorXi initSeeds(0);
DEIM_function c(NDEIM, NDEIM, initSeeds, "DEIM", Sp);

Compute the "DEIM" method HyperReduction::offlineGappyDEIM passing the "DEIM" modes and the normalizingWeights

c.offlineGappyDEIM(snapshotsModes, normalizingWeights);

Command to generate the submeshes used for pointwise evaluation of the function

c.generateSubmesh(2, mesh);
c.subField = c.interpolateField<volScalarField>(Sp[0]);

Definition of a new sample value to test the accuracy of the method \( \mu* = (0,0) \)

Eigen::MatrixXd par_new(2, 1);
par_new(0, 0) = 0;
par_new(1, 0) = 0;

Evaluation of the function using "DEIM" and reconstruction of the field

Eigen::VectorXd aprfield = c.MatrixOnline * c.onlineCoeffs(par_new);
// Transform to an OpenFOAM field and export
volScalarField S2("S_online", Foam2Eigen::Eigen2field(S, aprfield));
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:506

Export the approximation

ITHACAstream::exportSolution(S2, name(1), "./ITHACAoutput/Online/");

Evaluate the function on in \(\mu*\) using the FOM

Export the FOM field

ITHACAstream::exportSolution(S, name(1), "./ITHACAoutput/Online/");

Compute the error and print it

Info << ITHACAutilities::errorL2Rel(S2, S) << endl;
double errorL2Rel(GeometricField< T, fvPatchField, volMesh > &field1, GeometricField< T, fvPatchField, volMesh > &field2, List< label > *labels)
Computes the relative error between two geometric Fields in L2 norm.

The plain program

Here there's the plain code

/*---------------------------------------------------------------------------*\
██╗████████╗██╗ ██╗ █████╗ ██████╗ █████╗ ███████╗██╗ ██╗
██║╚══██╔══╝██║ ██║██╔══██╗██╔════╝██╔══██╗ ██╔════╝██║ ██║
██║ ██║ ███████║███████║██║ ███████║█████╗█████╗ ██║ ██║
██║ ██║ ██╔══██║██╔══██║██║ ██╔══██║╚════╝██╔══╝ ╚██╗ ██╔╝
██║ ██║ ██║ ██║██║ ██║╚██████╗██║ ██║ ██║ ╚████╔╝
╚═╝ ╚═╝ ╚═╝ ╚═╝╚═╝ ╚═╝ ╚═════╝╚═╝ ╚═╝ ╚═╝ ╚═══╝
* In real Time Highly Advanced Computational Applications for Finite Volumes
* Copyright (C) 2017 by the ITHACA-FV authors
-------------------------------------------------------------------------------
License
This file is part of ITHACA-FV
ITHACA-FV is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
ITHACA-FV is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with ITHACA-FV. If not, see <http://www.gnu.org/licenses/>.
Description
Example of the reconstruction of a non-linear function using the DEIM
SourceFiles
08DEIM.C
\*---------------------------------------------------------------------------*/
#include "fvCFD.H"
#include "fvOptions.H"
#include "simpleControl.H"
#include "simpleControl.H"
#include "fvMeshSubset.H"
#include "Foam2Eigen.H"
#include "ITHACAstream.H"
#include "ITHACAPOD.H"
#include <chrono>
class DEIM_function : public HyperReduction<PtrList<volScalarField>&>
{
public:
static volScalarField evaluate_expression(volScalarField& S, Eigen::MatrixXd mu)
{
volScalarField yPos = S.mesh().C().component(vector::Y).ref();
volScalarField xPos = S.mesh().C().component(vector::X).ref();
for (auto i = 0; i < S.size(); i++)
{
S[i] = std::exp( - 2 * std::pow(xPos[i] - mu(0) - 1,
2) - 2 * std::pow(yPos[i] - mu(1) - 0.5, 2));
}
return S;
}
Eigen::VectorXd onlineCoeffs(Eigen::MatrixXd mu)
{
theta.resize(nodePoints().size());
auto f = evaluate_expression(subField(), mu);
for (int i = 0; i < nodePoints().size(); i++)
{
// double on_coeff = f[localMagicPoints[i]];
}
return theta;
}
Eigen::VectorXd theta;
PtrList<volScalarField> fields;
autoPtr<volScalarField> subField;
};
int main(int argc, char* argv[])
{
// Read parameters from ITHACAdict file
#include "setRootCase.H"
Foam::Time runTime(Foam::Time::controlDictName, args);
Foam::fvMesh mesh
(
Foam::IOobject
(
Foam::fvMesh::defaultRegion,
runTime.timeName(),
Foam::IOobject::MUST_READ
)
);
int NDEIM = para->ITHACAdict->lookupOrDefault<int>("NDEIM", 15);
simpleControl simple(mesh);
#include "createFields.H"
// List of volScalarField where the snapshots are stored
PtrList<volScalarField> Sp;
// Non linear function
volScalarField S
(
IOobject
(
"S",
runTime.timeName(),
IOobject::NO_READ,
IOobject::AUTO_WRITE
),
T.mesh(),
dimensionedScalar("zero", dimensionSet(0, 0, -1, 1, 0, 0, 0), 0)
);
// Parameters used to train the non-linear function
Eigen::MatrixXd pars = ITHACAutilities::rand(100, 2, -0.5, 0.5);
// To compare with the same parameters, save data and then load it
// cnpy::load(pars, "./random100.npy");
// cnpy::save(pars, "./random100.npy");
// Perform the offline phase
for (int i = 0; i < 100; i++)
{
Sp.append((S).clone());
ITHACAstream::exportSolution(S, name(i + 1), "./ITHACAoutput/Offline/");
}
Eigen::MatrixXd snapshotsModes;
// To use the DEIMmodes method from ITHACAPOD :
Eigen::VectorXd normalizingWeights = ITHACAutilities::getMassMatrixFV(Sp[0]).array();
PtrList<volScalarField> modes = ITHACAPOD::DEIMmodes(Sp, NDEIM, "GappyDEIM", S.name());
snapshotsModes = Foam2Eigen::PtrList2Eigen(modes);
// To use the SVD modes from the HyperReduction class :
// Eigen::VectorXd normalizingWeights;
// c.getModesSVD(c.snapshotsListTuple, snapshotsModes, normalizingWeights);
// Create DEIM object with given number of basis functions
Eigen::VectorXi initSeeds(0);
DEIM_function c(NDEIM, NDEIM, initSeeds, "DEIM", Sp);
// Compute the DEIM
c.offlineGappyDEIM(snapshotsModes, normalizingWeights);
// To access the same folder hierarchy as before :
// c.problemName = "Gaussian_function";
// c.offlineGappyDEIM(snapshotsModes, normalizingWeights, "ITHACAoutput/DEIM/"+c.problemName);
// Generate the submeshes with the depth of the layer
c.generateSubmesh(2, mesh);
c.subField = c.interpolateField<volScalarField>(Sp[0]);
// Define a new online parameter
Eigen::MatrixXd par_new(2, 1);
par_new(0, 0) = 0;
par_new(1, 0) = 0;
// Online evaluation of the non linear function
Eigen::VectorXd aprfield = c.MatrixOnline * c.onlineCoeffs(par_new);
// Transform to an OpenFOAM field and export
volScalarField S2("S_online", Foam2Eigen::Eigen2field(S, aprfield));
ITHACAstream::exportSolution(S2, name(1), "./ITHACAoutput/Online/");
// Evaluate the full order function and export it
ITHACAstream::exportSolution(S, name(1), "./ITHACAoutput/Online/");
// Compute the L2 error and print it
Info << ITHACAutilities::errorL2Rel(S2, S) << endl;
return 0;
}
autoPtr< volScalarField > subField
Definition 08DEIM.C:74
Eigen::VectorXd theta
Definition 08DEIM.C:72
PtrList< volScalarField > fields
Definition 08DEIM.C:73
void onlineCoeffs()
Function to get the onlineCoeffs of the DEIM approx.
List< label > localNodePoints
Indices of the local node points in the subMesh.
autoPtr< IOList< label > > nodePoints
Nodes in the case of the a nonlinear function.
volScalarField & T
Definition createT.H:46
int main(int argc, char *argv[])
simpleControl simple(mesh)