Introduction
This tutorial builds a reduced order model for the classic lid-driven cavity benchmark. The two‑dimensional square cavity has side length $L=1.0$ m and a structured 64×64 mesh. A uniform tangential velocity $U_{lid}=1.0$ m/s is prescribed on the top wall; no-slip boundary conditions hold on the remaining walls. The Reynolds number based on the lid velocity is 100 (laminar flow).
An explicit Forward‑Euler time discretization is used both at the full‑order and reduced levels. The full order model (FOM) is simulated for a constant time step $\Delta t=0.005$ s over a total time of 1 s during the offline stage.
The geometry is sketched here: 
The discretize‑then‑project approach is adopted: the fully discrete Navier–Stokes equations are projected onto the POD basis. No supremizer modes are needed since the time discretization already enforces pressure stability.
The forcing field used in the unsteady Navier–Stokes problem is defined as
F = 1e-2 * (ParcelOFDriver::randomField(T.mesh()));
A detailed look into the code
Header files
The following headers are required:
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 ReducedUnsteadyNSExplicit class.
Header file of the UnsteadyNSExplicit class.
Derived from UnsteadyNSExplicit, the class manages the velocity, pressure and flux fields used during offline/online computations. The offline solve is defined as usual: it performs the simulations (truthSolve) if the data are not found; if the data already exists, it only reads the fields which will be used for the ROM.
{
public:
:
U(_U()),
p(_p()),
phi(_phi())
{}
volVectorField& U;
volScalarField& p;
surfaceScalarField& phi;
void offlineSolve()
{
Vector<double> inl(1, 0, 0);
List<scalar> mu_now(1);
{
{
}
}
else
{
for (label i = 0; i <
mu.cols(); i++)
{
}
}
}
};
Implementation of a parametrized full order unsteady NS problem and preparation of the the reduced ...
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.
PtrList< surfaceScalarField > Phifield
List of pointers used to form the flux snapshots matrix.
word fluxMethod
Flux Method.
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.
Main function overview
The main routine configures parameters, executes offline snapshot generation, and constructs the reduced system. Key steps:
- Parse mode counts from the ITHACAdict dictionary, set parameter sampling (viscosity). In this case, the parameter assumes only one value (0.01).
example._runTime());
int NmodesUout = para->ITHACAdict->lookupOrDefault<int>("NmodesUout", 15);
int NmodesPout = para->ITHACAdict->lookupOrDefault<int>("NmodesPout", 15);
int NmodesSUPout = 0;
int NmodesUproj = para->ITHACAdict->lookupOrDefault<int>("NmodesUproj", 10);
int NmodesPproj = para->ITHACAdict->lookupOrDefault<int>("NmodesPproj", 10);
int NmodesSUPproj = 0;
example.Pnumber = 1;
example.Tnumber = 1;
example.setParameters();
example.mu_range(0, 0) = 0.01;
example.mu_range(0, 1) = 0.01;
example.genEquiPar();
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.
- Configure inlet boundary indices and timing parameters.
example.inletIndex.resize(1, 2);
example.inletIndex(0, 0) = 0;
example.inletIndex(0, 1) = 0;
example.startTime = 0.0;
example.finalTime = 1.0;
example.timeStep = 0.005;
example.writeEvery = 0.005;
- Run example.offlineSolve() to generate or load snapshots.
- Compute POD modes for velocity, pressure (and flux if consistent method).
example.podex, 0, 0,
NmodesUout);
example.podex, 0, 0,
NmodesPout);
if (example.fluxMethod == "consistent")
{
example.podex, 0, 0,
NmodesUout);
}
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.
- Project reduced matrices via discretizeThenProject.
example.discretizeThenProject("./Matrices", NmodesUproj, NmodesPproj,
NmodesSUPproj);
- Build ReducedUnsteadyNSExplicit object and perform online simulations for new lid velocities. Time-stepping parameters are identical to the FOM.
reduced.nu = 0.01;
reduced.tstart = 0.0;
reduced.finalTime = 1.0;
reduced.dt = 0.005;
reduced.storeEvery = 0.005;
reduced.exportEvery = 0.005;
Eigen::MatrixXd vel_now(1, 1);
vel_now(0, 0) = 1;
reduced.solveOnline(vel_now, 1);
Class where it is implemented a reduced problem for the unsteady Navier-stokes problem.
- Reconstruct reduced solution with :
reduced.reconstruct(false, "./ITHACAoutput/Reconstruction/");
The plain code
The plain code is available here.