Introduction
This tutorial demonstrates reduced order modeling for an unsteady turbulent Navier–Stokes problem with Reynolds-averaged eddy viscosity treated via radial basis function (RBF) interpolation. The flow is driven by a parameterized inlet velocity and turbulence is accounted for through an eddy-viscosity field.
A detailed look into the code
Let's now have a look at the code of tutorial 21.
The necessary header files
The code relies on the unsteady turbulent solver and the standard ITHACA utilities:
#include "UnsteadyNSTurb.H"
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 ReducedUnsteadyNSTurb class.
Header file of the reducedUnsteadyNS class.
Header file of the unsteadyNS class.
Additional headers provide Eigen for linear algebra, utilities for mesh/I/O, flux options and Foam2Eigen conversions.
Implementation of the tutorial21 class
The tutorial class inherits from UnsteadyNSTurb and stores references to the velocity, pressure and eddy viscosity (nut) fields. The offline solve method reads existing snapshots if available, otherwise loops over inlet velocity parameter samples, updates boundary conditions and calls the full-order solver:
{
public:
:
U(_U()),
p(_p()),
nut(_nut())
{}
volVectorField& U;
volScalarField& p;
volScalarField& nut;
void offlineSolve(std::string offlinepath)
{
Vector<double> inl(1, 0, 0);
List<scalar> mu_now(1);
label BCind = 0;
{
}
else
{
for (label i = 0; i <
mu.cols(); i++)
{
}
}
}
};
Implementation of a parametrized full order unsteady NS problem and preparation of the reduced matr...
PtrList< volScalarField > nutFields
List of snapshots for the solution for eddy viscosity.
void assignBC(volVectorField &s, label BC_ind, Vector< double > &value)
Assign Boundary Condition to a volVectorField.
bool offline
Boolean variable, it is 1 if the Offline phase has already been computed, else 0.
Eigen::MatrixXd mu
Row matrix of parameters.
void truthSolve()
Perform a TruthSolve.
PtrList< volScalarField > Pfield
List of pointers used to form the pressure snapshots matrix.
PtrList< volVectorField > Ufield
List of pointers used to form the velocity snapshots matrix.
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.
bool check_folder(word folder)
Checks if a folder exists.
Main function
The main routine configures the parameter sampling, discretization and performs the offline stage:
example._runTime());
int NmodesU = para->ITHACAdict->lookupOrDefault<int>("NmodesU", 10);
example.Pnumber = 1;
example.Tnumber = 2;
example.setParameters();
example.mu_range(0, 0) = 1.0;
example.mu_range(0, 1) = 1.1;
example.genEquiPar();
example.inletIndex.resize(1, 2);
example.inletIndex(0, 0) = 0;
example.inletIndex(0, 1) = 0;
example.startTime = 0;
example.finalTime = 5;
example.timeStep = 0.001;
example.writeEvery = 0.1;
example.offlineSolve("./ITHACAoutput/Offline/");
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.
Then, it defines the RBF interpolation data:
auto mu_mat =
example.velRBF = mu_mat.col(1);
List< Eigen::MatrixXd > readMatrix(word folder, word mat_name)
Read a three dimensional matrix from a txt file in Eigen format.
It solves the supremizer problem and apply the lifting function to homogenize the velocity field:
example.solvesupremizer();
example.liftSolve();
example.computeLift(example.Ufield, example.liftfield, example.Uomfield);
void exportFields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &field, word folder, word fieldname)
Function to export a scalar of vector field.
void normalizeFields(PtrList< GeometricField< Type, fvPatchField, volMesh > > &fields)
Normalize list of Geometric fields.
It then performs a POD decomposition for the velocity, the pressure and the eddy viscosity:
example.podex,
example.supex, 0, NmodesProject);
example.podex,
example.supex, 0, NmodesProject);
example.podex,
example.supex, 0, NmodesProject);
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.
It solves the supremizer problem based on the pressure modes (not snapshots, as before), computes the reduced order matrices with supremizer stabilization, and create the object for the eddy viscosity RBF:
example.solvesupremizer("modes");
example.projectSUP("./Matrices", NmodesU, NmodesP, NmodesSUP,
NmodesNUT, true);
example);
Class where it is implemented a reduced problem for the unsteady Navier-stokes problem.
Then, some settings for the reduced eddy viscosity and the penalty factor are done, and the matrix storing the RBF coefficients is innitialized:
pod_rbf.nu = 1e-05;
pod_rbf.tauU.resize(1, 1);
pod_rbf.tstart = 0;
pod_rbf.finalTime = 10.1;
pod_rbf.dt = 0.005;
pod_rbf.storeEvery = 0.005;
pod_rbf.exportEvery = 0.1;
Eigen::MatrixXd rbfCoeff;
rbfCoeff.resize(NmodesNUT + 1, 1);
Finally, it performs an online solve for the new values of inlet velocities:
for (label k = 0; k < 1; k++)
{
Eigen::MatrixXd velNow(1, 1);
velNow(0, 0) = 1.05;
pod_rbf.tauU(0, 0) = 0;
pod_rbf.solveOnlineSUP(velNow);
rbfCoeff.col(k) = pod_rbf.rbfCoeffMat.col(k);
Eigen::MatrixXd tmp_sol(pod_rbf.y.rows() + 1, 1);
tmp_sol(0) = k + 1;
tmp_sol.col(0).tail(pod_rbf.y.rows()) = pod_rbf.y;
pod_rbf.online_solution.append(tmp_sol);
}
The matrices of the interpolated eddy viscosity coefficients and of the online solutions are saved:
"./ITHACAoutput/Matrices/");
"./ITHACAoutput/Matrices/");
"./ITHACAoutput/red_coeff");
"./ITHACAoutput/red_coeff");
"./ITHACAoutput/red_coeff");
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 ...
The remaining part is for reconstructing the solution, computing the FOM counterparts for comparison, and computing the relative L2 errors. The FOM counterpart solutions are stored in the folder Offline_check, and the errors are stored in the ErrorsL2 and ErrorsFrob directories.
pod_rbf.reconstruct(true, "./ITHACAoutput/Reconstruction/");
example2.Pnumber = 1;
example2.Tnumber = 2;
example2.setParameters();
example2.mu_range(0, 0) = 1.05;
example2.mu_range(0, 1) = 1.05;
example2.genEquiPar();
example2.inletIndex.resize(1, 2);
example2.inletIndex(0, 0) = 0;
example2.inletIndex(0, 1) = 0;
example2.startTime = 0;
example2.finalTime = 5;
example2.timeStep = 0.001;
example2.writeEvery = 0.1;
example2.offlineSolve("./ITHACAoutput/Offline_check/");
pod_rbf.uRecFields);
pod_rbf.pRecFields);
pod_rbf.nutRecFields);
"./ITHACAoutput/ErrorsFrob/");
"./ITHACAoutput/ErrorsFrob/");
"./ITHACAoutput/ErrorsFrob/");
pod_rbf.uRecFields);
pod_rbf.pRecFields);
pod_rbf.nutRecFields);
"./ITHACAoutput/ErrorsL2/");
"./ITHACAoutput/ErrorsL2/");
"./ITHACAoutput/ErrorsL2/");
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.
double errorFrobRel(GeometricField< Type, PatchField, GeoMesh > &field1, GeometricField< Type, PatchField, GeoMesh > &field2, List< label > *labels)
Computes the relative error between two Fields in the Frobenius norm.
Usage
Before running the 21unsteadyNSTurb_RBF application, the mesh should be built by running create_mesh.
The plain code
The plain code is available here.