Introduction
The problem consists of a turbulent steady Navier-Stokes problem solved using the SIMPLE algorithm. The setup involves parameterized viscosity and inlet velocities, demonstrating ROM for turbulent incompressible flows.
A detailed look into the code
Let's have a look into the code of tutorial 18.
The necessary header files
First of all let's have a look into the header files which have to be included, indicating what they are responsible for:
<SteadyNSSimple.H> is the base class for steady NS problems solved with SIMPLE. <ITHACAstream.H> is responsible for reading and exporting the fields and other sorts of data. <ITHACAPOD.H> is for the computation of the POD modes. <ReducedSimpleSteadyNS.H> is for the reduced-order steady NS problem. <forces.H> and <IOmanip.H> are for forces computation and I/O manipulation.
Implementation of the tutorial18 class
We define the tutorial18 class as a child of the SteadyNSSimple class. The constructor is defined with members that are the fields required to be manipulated during the resolution of the full order problem. Such fields are also initialized with the same initial conditions in the solver.
{
public:
:
U(_U()),
p(_p()),
phi(_phi())
{}
volVectorField& U;
volScalarField& p;
surfaceScalarField& phi;
Implementation of a parametrized full order steady NS problem and preparation of the the reduced ma...
tutorial18(int argc, char *argv[])
Constructor.
Inside the tutorial18 class we define the offlineSolve method. If the offline solve has been previously performed, then the method just reads the existing snapshots including turbulent fields. If not, it loops over the viscosity parameters, changes the viscosity, and performs the full-order simulations.
void offlineSolve()
{
Vector<double> inl(0, 0, 0);
List<scalar> mu_now(1);
{
auto nut = _mesh().lookupObject<volScalarField>("nut");
mu_samples =
}
else if (offline)
{
mu_samples =
}
else
{
Vector<double> Uinl(1, 0, 0);
label BCind = 0;
for (label i = 0; i < mu.rows(); i++)
{
mu_now[0] = mu(i, 0);
change_viscosity(mu_now[0]);
assignIF(U, Uinl);
truthSolve2(mu_now);
nutFields.clear();
auto nut = _mesh().lookupObject<volScalarField>("nut");
}
}
}
void readConvergedFields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &Lfield, GeometricField< Type, PatchField, GeoMesh > &field, fileName casename)
Function to read a list of volVectorField from name of the field including only converged snapshots.
void readMiddleFields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &Lfield, GeometricField< Type, PatchField, GeoMesh > &field, fileName casename)
Funtion to read a list of volVectorField from name of the field including all the intermediate snapsh...
List< Eigen::MatrixXd > readMatrix(word folder, word mat_name)
Read a three dimensional matrix from a txt file in Eigen format.
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 readLastFields(PtrList< GeometricField< Type, PatchField, GeoMesh > > &Lfield, const GeometricField< Type, PatchField, GeoMesh > &field, const fileName casename)
Funtion to read a list of volVectorField from name of the field including only the last snapshots.
bool isTurbulent()
This function checks if the case is turbulent.
Definition of the main function
The main function sets up the problem parameters, performs the offline phase, computes POD modes, and solves the online reduced problem.
First, the tutorial object is constructed and parameters are read:
example._runTime());
int NmodesUout = para->ITHACAdict->lookupOrDefault<int>("NmodesUout", 15);
int NmodesPout = para->ITHACAdict->lookupOrDefault<int>("NmodesPout", 15);
int NmodesUproj = para->ITHACAdict->lookupOrDefault<int>("NmodesUproj", 10);
int NmodesPproj = para->ITHACAdict->lookupOrDefault<int>("NmodesPproj", 10);
word filename("./par");
example.inletIndex.resize(1, 2);
example.inletIndex(0, 0) = 0;
example.inletIndex(0, 1) = 0;
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.
The offline solve is performed:
The snapshots are homogenized using the lifting function:
example.computeLift(example.Ufield, example.liftfield, example.Uomfield);
and the POD modes are extracted. If the case is turbulent, also the modes for the eddy viscosity field are extracted and the RBF interpolator object is created (to find the eddy viscosity coefficients also for test parameters):
example.podex, 0, 0, NmodesUout);
example.podex, 0, 0, NmodesPout);
{
example.podex, 0, 0, example.NNutModesOut);
example.getTurbRBF(example.NNutModes);
}
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.
The reduced object is then created and the lists storing the reconstructions are initialzied:
PtrList<volVectorField> U_rec_list;
PtrList<volScalarField> P_rec_list;
Class where it is implemented a reduced problem for the steady Navier-stokes problem.
Then, the inlet velocities are read and the maximum number of iterations for the online solver is set to 2000:
word vel_file(para->ITHACAdict->lookup("online_velocities"));
reduced.maxIterOn = para->ITHACAdict->lookupOrDefault<int>("maxIterOn", 2000);
This final loop solves the online system for all the viscosities:
for (label k = 0; k < parOn.size(); k++)
{
scalar mu_now = parOn(k, 0);
example.restart();
example.change_viscosity(mu_now);
reduced.setOnlineVelocity(vel);
{
reduced.solveOnline_Simple(mu_now, example.NUmodes, example.NPmodes,
example.NNutModes);
}
else
{
reduced.solveOnline_Simple(mu_now, example.NUmodes, example.NPmodes,
example.NNutModes);
}
}
This completes the tutorial for turbulent steady NS with SIMPLE algorithm.
The plain code
The plain code is available here.