HyPar  1.0
Finite-Difference Hyperbolic-Parabolic PDE Solver on Cartesian Grids
2D Euler Equations - Isentropic Vortex Convection

See 2D Euler Equations - Isentropic Vortex Convection to familiarize yourself with this case. This example uses a DMD object that has already been trained (see 2D Euler Equations - Isentropic Vortex Convection).

Location: hypar/Examples/2D/NavierStokes2D/InviscidVortexConvection_libROM_DMD_Predict (This directory contains all the input files needed to run this case.)

Reduced Order Modeling: This example predicts the solution from a trained DMD object. The code does not solve the PDE by discretizing in space and integrating in time.

Governing equations: 2D Euler Equations (navierstokes2d.h - By default, NavierStokes2D::Re is set to -1 which makes the code skip the parabolic terms, i.e., the 2D Euler equations are solved.)

Reference: C.-W. Shu, "Essentially Non-oscillatory and Weighted Essentially Non-oscillatory Schemes for Hyperbolic Conservation Laws", ICASE Report 97-65, 1997

Domain: \(0 \le x,y \le 10\), "periodic" (_PERIODIC_) boundary conditions.

Initial solution: The freestream flow is given by

\begin{equation} \rho_\infty = 1,\ u_\infty = 0.1,\ v_\infty = 0,\ p_\infty = 1 \end{equation}

and a vortex is introduced, specified as

\begin{align} \rho &= \left[ 1 - \frac{\left(\gamma-1\right)b^2}{8\gamma\pi^2} e^{1-r^2} \right]^{\frac{1}{\gamma-1}},\ p = \rho^\gamma, \\ u &= u_\infty - \frac{b}{2\pi} e^{\frac{1}{2}\left(1-r^2\right)} \left(y-y_c\right),\ v = v_\infty + \frac{b}{2\pi} e^{\frac{1}{2}\left(1-r^2\right)} \left(x-x_c\right), \end{align}

where \(b=0.5\) is the vortex strength and \(r = \left[(x-x_c)^2 + (y-y_c)^2 \right]^{1/2}\) is the distance from the vortex center \(\left(x_c,y_c\right) = \left(5,5\right)\).

Reduced Order Modeling:

Note:

In this mode, HyPar will run just like an usual PDE simulation, except that it will swap out the numerical spatial discretization and time integration with the ROM-based prediction. The input files and output files will be the same as a regular simulation with the following comments:

  • Numerical method inputs are ignored (eg. those that specify spatial discretization and time integration methods).
  • In solver.inp, the values for dt, n_iter, and file_op_iter is used only to compute the simulation times at which to compute and write the solution. The time step size, dt, need not respect any CFL criterion.
  • HyPar::ConservationCheck is set to "no" since it is not possible to compute conservation loss for a general domain (because boundary fluxes are not being computed).

Input files required:

librom.inp

begin
mode predict
dmd_dirname DMD
end

DMD Object(s) :
The trained DMD object(s) must be located in the directory specified in librom.inp as dmd_dirname (DMDROMObject::m_dirname). For this example, they were generated using 2D Euler Equations - Isentropic Vortex Convection.

solver.inp

begin
ndims 2
nvars 4
size 64 64
iproc 4 4
ghost 3
n_iter 40
restart_iter 0
dt 1.0
file_op_iter 1
ip_file_type binary
op_file_format binary
op_overwrite no
model navierstokes2d
end

boundary.inp

4
periodic 0 1 0 0 0 10.0
periodic 0 -1 0 0 0 10.0
periodic 1 1 0 10.0 0 0
periodic 1 -1 0 10.0 0 0

physics.inp

begin
gamma 1.4
upwinding roe
end

To generate initial.inp (initial solution) and exact.inp (exact solution), compile and run the following code in the run directory.

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
double power(double x,double a)
{
return(exp(a*log(x)));
}
int main(){
const double pi = 4.0*atan(1.0);
const double GAMMA = 1.4;
int NI,NJ,ndims,n_iter;
double tf, dt;
char ip_file_type[50]; strcpy(ip_file_type,"ascii");
FILE *in, *out;
printf("Reading file \"solver.inp\"...\n");
in = fopen("solver.inp","r");
if (!in) {
printf("Error: Input file \"solver.inp\" not found. Default values will be used.\n");
return(0);
} else {
char word[500];
fscanf(in,"%s",word);
if (!strcmp(word, "begin")) {
while (strcmp(word, "end")) {
fscanf(in,"%s",word);
if (!strcmp(word, "ndims")) fscanf(in,"%d",&ndims);
else if (!strcmp(word, "size")) {
fscanf(in,"%d",&NI);
fscanf(in,"%d",&NJ);
} else if (!strcmp(word, "n_iter")) fscanf(in,"%d",&n_iter);
else if (!strcmp(word, "dt")) fscanf(in,"%lf",&dt);
else if (!strcmp(word, "ip_file_type")) fscanf(in,"%s",ip_file_type);
}
} else printf("Error: Illegal format in solver.inp. Crash and burn!\n");
}
fclose(in);
if (ndims != 2) {
printf("ndims is not 2 in solver.inp. this code is to generate 2D exact solution\n");
return(0);
}
printf("Grid:\t\t\t%d X %d\n",NI,NJ);
int i,j;
double dx = 10.0 / ((double)NI);
double dy = 10.0 / ((double)NJ);
tf = (double)n_iter * dt; double tff = tf;
while (tf > 20) tf -= 20; // Time period
double *x, *y, *u0, *u1, *u2, *u3;
x = (double*) calloc (NI , sizeof(double));
y = (double*) calloc (NJ , sizeof(double));
u0 = (double*) calloc (NI*NJ, sizeof(double));
u1 = (double*) calloc (NI*NJ, sizeof(double));
u2 = (double*) calloc (NI*NJ, sizeof(double));
u3 = (double*) calloc (NI*NJ, sizeof(double));
double u_inf = 0.5;
double v_inf = 0.0;
double b = u_inf;
double x0, y0;
/* Initial solution */
x0 = 5.0, y0 = 5.0;
for (i = 0; i < NI; i++){
for (j = 0; j < NJ; j++){
x[i] = i*dx;
y[j] = j*dy;
int p = NJ*i + j;
double rx, ry;
rx = (x[i] - x0);
ry = (y[j] - y0);
if (rx < -5) { rx += 10; }
else if (rx > 5) { rx -= 10; }
double rsq = rx*rx + ry*ry;
double rho, u, v, P;
double du, dv;
rho = power(1.0 - ((GAMMA-1.0)*b*b)/(8.0*GAMMA*pi*pi) * exp(1.0-rsq), 1.0/(GAMMA-1.0));
P = power(rho,GAMMA);
du = - b/(2.0*pi) * exp(0.5*(1.0-rsq)) * ry;
dv = b/(2.0*pi) * exp(0.5*(1.0-rsq)) * rx;
u = u_inf + du;
v = v_inf + dv;
u0[p] = rho;
u1[p] = rho*u;
u2[p] = rho*v;
u3[p] = P/(GAMMA-1.0) + 0.5*rho*(u*u+v*v);
}
}
if (!strcmp(ip_file_type,"ascii")) {
printf("Writing ASCII initial solution file initial.inp\n");
out = fopen("initial.inp","w");
for (i = 0; i < NI; i++) fprintf(out,"%lf ",x[i]);
fprintf(out,"\n");
for (j = 0; j < NJ; j++) fprintf(out,"%lf ",y[j]);
fprintf(out,"\n");
for (j = 0; j < NJ; j++) {
for (i = 0; i < NI; i++) {
int p = NJ*i + j;
fprintf(out,"%lf ",u0[p]);
}
}
fprintf(out,"\n");
for (j = 0; j < NJ; j++) {
for (i = 0; i < NI; i++) {
int p = NJ*i + j;
fprintf(out,"%lf ",u1[p]);
}
}
fprintf(out,"\n");
for (j = 0; j < NJ; j++) {
for (i = 0; i < NI; i++) {
int p = NJ*i + j;
fprintf(out,"%lf ",u2[p]);
}
}
fprintf(out,"\n");
for (j = 0; j < NJ; j++) {
for (i = 0; i < NI; i++) {
int p = NJ*i + j;
fprintf(out,"%lf ",u3[p]);
}
}
fprintf(out,"\n");
fclose(out);
} else if ((!strcmp(ip_file_type,"binary")) || (!strcmp(ip_file_type,"bin"))) {
printf("Writing binary initial solution file initial.inp\n");
out = fopen("initial.inp","wb");
fwrite(x,sizeof(double),NI,out);
fwrite(y,sizeof(double),NJ,out);
double *U = (double*) calloc (4*NI*NJ,sizeof(double));
for (i=0; i < NI; i++) {
for (j = 0; j < NJ; j++) {
int p = NJ*i + j;
int q = NI*j + i;
U[4*q+0] = u0[p];
U[4*q+1] = u1[p];
U[4*q+2] = u2[p];
U[4*q+3] = u3[p];
}
}
fwrite(U,sizeof(double),4*NI*NJ,out);
free(U);
fclose(out);
}
/* Exact solution */
x0 = 5.0+tf*u_inf, y0 = 5.0;
if (x0 > 10) x0 -= 10; //periodic domain
printf("Final time: %lf, Vortex center: %lf, %lf\n",tff,x0,y0);
for (i = 0; i < NI; i++){
for (j = 0; j < NJ; j++){
x[i] = i*dx;
y[j] = j*dy;
int p = NJ*i + j;
double rx, ry;
rx = (x[i] - x0);
ry = (y[j] - y0);
if (rx < -5) { rx += 10; }
else if (rx > 5) { rx -= 10; }
double rsq = rx*rx + ry*ry;
double rho, u, v, P;
double du, dv;
rho = power(1.0 - ((GAMMA-1.0)*b*b)/(8.0*GAMMA*pi*pi) * exp(1.0-rsq), 1.0/(GAMMA-1.0));
P = power(rho,GAMMA);
du = - b/(2.0*pi) * exp(0.5*(1.0-rsq)) * ry;
dv = b/(2.0*pi) * exp(0.5*(1.0-rsq)) * rx;
u = u_inf + du;
v = v_inf + dv;
u0[p] = rho;
u1[p] = rho*u;
u2[p] = rho*v;
u3[p] = P/(GAMMA-1.0) + 0.5*rho*(u*u+v*v);
}
}
if (!strcmp(ip_file_type,"ascii")) {
printf("Writing ASCII exact solution file exact.inp\n");
out = fopen("exact.inp","w");
for (i = 0; i < NI; i++) fprintf(out,"%lf ",x[i]);
fprintf(out,"\n");
for (j = 0; j < NJ; j++) fprintf(out,"%lf ",y[j]);
fprintf(out,"\n");
for (j = 0; j < NJ; j++) {
for (i = 0; i < NI; i++) {
int p = NJ*i + j;
fprintf(out,"%lf ",u0[p]);
}
}
fprintf(out,"\n");
for (j = 0; j < NJ; j++) {
for (i = 0; i < NI; i++) {
int p = NJ*i + j;
fprintf(out,"%lf ",u1[p]);
}
}
fprintf(out,"\n");
for (j = 0; j < NJ; j++) {
for (i = 0; i < NI; i++) {
int p = NJ*i + j;
fprintf(out,"%lf ",u2[p]);
}
}
fprintf(out,"\n");
for (j = 0; j < NJ; j++) {
for (i = 0; i < NI; i++) {
int p = NJ*i + j;
fprintf(out,"%lf ",u3[p]);
}
}
fprintf(out,"\n");
fclose(out);
} else if ((!strcmp(ip_file_type,"binary")) || (!strcmp(ip_file_type,"bin"))) {
printf("Writing binary exact solution file exact.inp\n");
out = fopen("exact.inp","wb");
fwrite(x,sizeof(double),NI,out);
fwrite(y,sizeof(double),NJ,out);
double *U = (double*) calloc (4*NI*NJ,sizeof(double));
for (i=0; i < NI; i++) {
for (j = 0; j < NJ; j++) {
int p = NJ*i + j;
int q = NI*j + i;
U[4*q+0] = u0[p];
U[4*q+1] = u1[p];
U[4*q+2] = u2[p];
U[4*q+3] = u3[p];
}
}
fwrite(U,sizeof(double),4*NI*NJ,out);
free(U);
fclose(out);
}
free(x);
free(y);
free(u0);
free(u1);
free(u2);
free(u3);
return(0);
}

Output:

Note that iproc is set to

  4 4

in solver.inp (i.e., 4 processors along x, and 4 processors along y). Thus, this example should be run with 16 MPI ranks (or change iproc).

After running the code, there should be the following output files:

  • 41 output files op_00000.bin, op_00001.bin, ... op_00040.bin; these are the solutions as predicted by the ROM .

The first of each of these file sets is the solution at \(t=0\) and the final one is the solution at \(t=40\). Since HyPar::op_overwrite is set to no in solver.inp, a separate file is written for solutions at each output time. All the files are binary (HyPar::op_file_format is set to binary in solver.inp).

The provided Python script (Examples/Python/plotSolution_2DBinary.py) can be used to generate plots from these binary files. Alternatively, HyPar::op_file_format can be set to text or tecplot2d, and Tecplot/VisIt or something similar can be used to plot the resulting files.

The animation shows the evolution of the solution (density).

Solution_2DNavStokVortex_libROM_DMD_Predict.gif

Since the exact solution is available at the final time (exact.inp), the numerical errors are calculated and reported on screen (see below) as well as errors.dat:

64 64 4 4 1.0000000000000000E+00 1.7057960004704812E-06 4.1746751056680860E-06 2.4053620904213429E-05 3.8236610000000000E+00 4.0025190000000004E+00

The numbers are: number of grid points in each dimension (HyPar::dim_global), number of processors in each dimension (MPIVariables::iproc), time step size (HyPar::dt), L1, L2, and L-infinity errors (HyPar::error), solver wall time (seconds) (i.e., not accounting for initialization, and cleaning up), and total wall time.

Expected screen output:

HyPar - Parallel (MPI) version with 16 processes
Compiled with PETSc time integration.
Allocated simulation object(s).
Reading solver inputs from file "solver.inp".
No. of dimensions : 2
No. of variables : 4
Domain size : 64 64
Processes along each dimension : 4 4
Exact solution domain size : 64 64
No. of ghosts pts : 3
No. of iter. : 40
Restart iteration : 0
Time integration scheme : euler
Spatial discretization scheme (hyperbolic) : 1
Split hyperbolic flux term? : no
Interpolation type for hyperbolic term : characteristic
Spatial discretization type (parabolic ) : nonconservative-1stage
Spatial discretization scheme (parabolic ) : 2
Time Step : 1.000000E+00
Check for conservation : no
Screen output iterations : 1
File output iterations : 1
Initial solution file type : binary
Initial solution read mode : serial
Solution file write mode : serial
Solution file format : binary
Overwrite solution file : no
Physical model : navierstokes2d
Partitioning domain and allocating data arrays.
Reading array from binary file initial.inp (Serial mode).
Volume integral of the initial solution:
0: 9.9980704056028685E+01
1: 4.9990352985508352E+01
2: -9.5749398777884853E-07
3: 2.6245709189715654E+02
Reading boundary conditions from boundary.inp.
Boundary periodic: Along dimension 0 and face +1
Boundary periodic: Along dimension 0 and face -1
Boundary periodic: Along dimension 1 and face +1
Boundary periodic: Along dimension 1 and face -1
4 boundary condition(s) read.
Initializing solvers.
Initializing physics. Model = "navierstokes2d"
Reading physical model inputs from file "physics.inp".
Setting up libROM interface.
libROM inputs and parameters:
reduced model dimensionality: 0
sampling frequency: 0
mode: predict
type: DMD
save to file: true
libROM DMD inputs:
number of samples per window: 2147483647
directory name for DMD onjects: DMD
libROMInterface::loadROM() - loading ROM objects.
Loading DMD object (DMD/dmdobj_0000), time window=[0.00e+00,-1.00e+00].
libROM: Predicted solution at time 0.0000e+00 using ROM, wallclock time: 0.013085.
Writing solution file op_00000.bin.
libROM: Predicted solution at time 1.0000e+00 using ROM, wallclock time: 0.035576.
Writing solution file op_00001.bin.
libROM: Predicted solution at time 2.0000e+00 using ROM, wallclock time: 0.033418.
Writing solution file op_00002.bin.
libROM: Predicted solution at time 3.0000e+00 using ROM, wallclock time: 0.135173.
Writing solution file op_00003.bin.
libROM: Predicted solution at time 4.0000e+00 using ROM, wallclock time: 0.089607.
Writing solution file op_00004.bin.
libROM: Predicted solution at time 5.0000e+00 using ROM, wallclock time: 0.107563.
Writing solution file op_00005.bin.
libROM: Predicted solution at time 6.0000e+00 using ROM, wallclock time: 0.060770.
Writing solution file op_00006.bin.
libROM: Predicted solution at time 7.0000e+00 using ROM, wallclock time: 0.125400.
Writing solution file op_00007.bin.
libROM: Predicted solution at time 8.0000e+00 using ROM, wallclock time: 0.116264.
Writing solution file op_00008.bin.
libROM: Predicted solution at time 9.0000e+00 using ROM, wallclock time: 0.098884.
Writing solution file op_00009.bin.
libROM: Predicted solution at time 1.0000e+01 using ROM, wallclock time: 0.057265.
Writing solution file op_00010.bin.
libROM: Predicted solution at time 1.1000e+01 using ROM, wallclock time: 0.050350.
Writing solution file op_00011.bin.
libROM: Predicted solution at time 1.2000e+01 using ROM, wallclock time: 0.032244.
Writing solution file op_00012.bin.
libROM: Predicted solution at time 1.3000e+01 using ROM, wallclock time: 0.034619.
Writing solution file op_00013.bin.
libROM: Predicted solution at time 1.4000e+01 using ROM, wallclock time: 0.086340.
Writing solution file op_00014.bin.
libROM: Predicted solution at time 1.5000e+01 using ROM, wallclock time: 0.031885.
Writing solution file op_00015.bin.
libROM: Predicted solution at time 1.6000e+01 using ROM, wallclock time: 0.041468.
Writing solution file op_00016.bin.
libROM: Predicted solution at time 1.7000e+01 using ROM, wallclock time: 0.036360.
Writing solution file op_00017.bin.
libROM: Predicted solution at time 1.8000e+01 using ROM, wallclock time: 0.077352.
Writing solution file op_00018.bin.
libROM: Predicted solution at time 1.9000e+01 using ROM, wallclock time: 0.044662.
Writing solution file op_00019.bin.
libROM: Predicted solution at time 2.0000e+01 using ROM, wallclock time: 0.042875.
Writing solution file op_00020.bin.
libROM: Predicted solution at time 2.1000e+01 using ROM, wallclock time: 0.047680.
Writing solution file op_00021.bin.
libROM: Predicted solution at time 2.2000e+01 using ROM, wallclock time: 0.067208.
Writing solution file op_00022.bin.
libROM: Predicted solution at time 2.3000e+01 using ROM, wallclock time: 0.030006.
Writing solution file op_00023.bin.
libROM: Predicted solution at time 2.4000e+01 using ROM, wallclock time: 0.100523.
Writing solution file op_00024.bin.
libROM: Predicted solution at time 2.5000e+01 using ROM, wallclock time: 0.067925.
Writing solution file op_00025.bin.
libROM: Predicted solution at time 2.6000e+01 using ROM, wallclock time: 0.033365.
Writing solution file op_00026.bin.
libROM: Predicted solution at time 2.7000e+01 using ROM, wallclock time: 0.054427.
Writing solution file op_00027.bin.
libROM: Predicted solution at time 2.8000e+01 using ROM, wallclock time: 0.129765.
Writing solution file op_00028.bin.
libROM: Predicted solution at time 2.9000e+01 using ROM, wallclock time: 0.063883.
Writing solution file op_00029.bin.
libROM: Predicted solution at time 3.0000e+01 using ROM, wallclock time: 0.054281.
Writing solution file op_00030.bin.
libROM: Predicted solution at time 3.1000e+01 using ROM, wallclock time: 0.071597.
Writing solution file op_00031.bin.
libROM: Predicted solution at time 3.2000e+01 using ROM, wallclock time: 0.070207.
Writing solution file op_00032.bin.
libROM: Predicted solution at time 3.3000e+01 using ROM, wallclock time: 0.073919.
Writing solution file op_00033.bin.
libROM: Predicted solution at time 3.4000e+01 using ROM, wallclock time: 0.077781.
Writing solution file op_00034.bin.
libROM: Predicted solution at time 3.5000e+01 using ROM, wallclock time: 0.067210.
Writing solution file op_00035.bin.
libROM: Predicted solution at time 3.6000e+01 using ROM, wallclock time: 0.080262.
Writing solution file op_00036.bin.
libROM: Predicted solution at time 3.7000e+01 using ROM, wallclock time: 0.046820.
Writing solution file op_00037.bin.
libROM: Predicted solution at time 3.8000e+01 using ROM, wallclock time: 0.059902.
Writing solution file op_00038.bin.
libROM: Predicted solution at time 3.9000e+01 using ROM, wallclock time: 0.044101.
Writing solution file op_00039.bin.
libROM: Predicted solution at time 4.0000e+01 using ROM, wallclock time: 0.095935.
Writing solution file op_00040.bin.
Reading array from binary file exact.inp (Serial mode).
libROM: total prediction/query wallclock time: 2.687957 (seconds).
Computed errors for domain 0:
L1 Error : 1.7057960004704812E-06
L2 Error : 4.1746751056680860E-06
Linfinity Error : 2.4053620904213429E-05
Solver runtime (in seconds): 3.8236610000000000E+00
Total runtime (in seconds): 4.0025190000000004E+00
Deallocating arrays.
Finished.