"""
A very simple example which demonstrates how to configure a patch-based
Finite Volume solver in Peano4. The code relies on snippets from ExaHyPE2.
However, it relies only on ExaHyPE's C/FORTRAN compute kernels, i.e. the
sophisticated build environment of this H2020 project is not used. The
solver simulates the simple Euler equations.
"""
import os
import peano4
import peano4.datamodel
import peano4.solversteps
import peano4.output
import peano4.visualisation
output_files = [ f for f in os.listdir(".") if f.endswith(".peano-patch-file") ]
for f in output_files:
os.remove(f)
project = peano4.Project( ["examples", "finitevolumes"], "finitevolumes", "." )
patch_size = 13
unknowns = 5
patch = peano4.datamodel.Patch( (patch_size,patch_size,patch_size), unknowns, "Q" )
project.datamodel.add_cell(patch)
patch_overlap = peano4.datamodel.Patch( (2,patch_size,patch_size), unknowns, "Q" )
project.datamodel.add_face(patch_overlap)
create_grid = peano4.solversteps.Step( "CreateGrid" )
create_grid.use_face(patch_overlap)
create_grid.use_cell(patch)
create_grid.add_action_set( peano4.toolbox.blockstructured.ProjectPatchOntoFaces(patch,patch_overlap) )
project.solversteps.add_step(create_grid)
print_solution = peano4.solversteps.Step( "PlotSolution" )
print_solution.use_cell(patch)
print_solution.use_face(patch_overlap)
print_solution.remove_all_actions()
plotter = peano4.toolbox.blockstructured.PlotPatchesInPeanoBlockFormat("solution",patch,"Q")
print_solution.add_action_set( plotter )
project.solversteps.add_step(print_solution)
perform_time_step = peano4.solversteps.Step( "TimeStep" )
perform_time_step.use_cell(patch)
perform_time_step.use_face(patch_overlap)
functor = """
auto eigenvalues = [](double Q[5], const tarch::la::Vector<DIMENSIONS,double>& x, int normal, double lambda[5]) -> void {
constexpr double gamma = 1.4;
const double irho = 1./Q[0];
#if DIMENSIONS==3
const double p = (gamma-1) * (Q[4] - 0.5*irho*Q[1]*Q[1]+Q[2]*Q[2]+Q[3]*Q[3]);
#else
const double p = (gamma-1) * (Q[4] - 0.5*irho*Q[1]*Q[1]+Q[2]*Q[2]);
#endif
const double u_n = Q[normal + 1] * irho;
assertion10( gamma * p * irho>=0.0, gamma, p, irho, x, normal, Q[0], Q[1], Q[2], Q[3], Q[4] );
const double c = std::sqrt(gamma * p * irho);
lambda[0] = u_n;
lambda[1] = u_n;
lambda[2] = u_n;
lambda[3] = u_n + c;
lambda[4] = u_n - c;
assertion4( lambda[0]==lambda[0], u_n, c, x, normal );
assertion4( lambda[1]==lambda[1], u_n, c, x, normal );
assertion4( lambda[2]==lambda[2], u_n, c, x, normal );
assertion4( lambda[3]==lambda[3], u_n, c, x, normal );
assertion4( lambda[4]==lambda[4], u_n, c, x, normal );
};
auto flux = [](double Q[5], const tarch::la::Vector<DIMENSIONS,double>& x, int normal, double F[5]) -> void {
assertion5( Q[0]==Q[0], Q[0], Q[1], Q[2], Q[3], Q[4] );
assertion5( Q[1]==Q[1], Q[0], Q[1], Q[2], Q[3], Q[4] );
assertion5( Q[2]==Q[2], Q[0], Q[1], Q[2], Q[3], Q[4] );
assertion5( Q[3]==Q[3], Q[0], Q[1], Q[2], Q[3], Q[4] );
assertion5( Q[4]==Q[4], Q[0], Q[1], Q[2], Q[3], Q[4] );
assertion5( Q[0]>1e-12, Q[0], Q[1], Q[2], Q[3], Q[4] );
constexpr double gamma = 1.4;
const double irho = 1./Q[0];
#if DIMENSIONS==3
const double p = (gamma-1) * (Q[4] - 0.5*irho*Q[1]*Q[1]+Q[2]*Q[2]+Q[3]*Q[3]);
#else
const double p = (gamma-1) * (Q[4] - 0.5*irho*Q[1]*Q[1]+Q[2]*Q[2]);
#endif
switch (normal) {
case 0:
{
F[0] = Q[1];
F[1] = irho*Q[1]*Q[1] + p;
F[2] = irho*Q[2]*Q[1];
F[3] = (DIMENSIONS==3) ? irho*Q[3]*Q[1] : 0.0;
F[4] = irho*(Q[4]+p)*Q[1];
}
break;
case 1:
{
F[0] = Q[2];
F[1] = irho*Q[1]*Q[2];
F[2] = irho*Q[2]*Q[2] + p;
F[3] = (DIMENSIONS==3) ? irho*Q[3]*Q[2] : 0.0;
F[4] = irho*(Q[4]+p)*Q[2];
}
break;
case 2:
{
F[0] = Q[3];
F[1] = irho*Q[1]*Q[3];
F[2] = irho*Q[2]*Q[3];
F[3] = (DIMENSIONS==3) ? irho*Q[3]*Q[3] + p : 0.0;
F[4] = irho*(Q[4]+p)*Q[3];
}
break;
}
assertion( F[0]==F[0] );
assertion( F[1]==F[1] );
assertion( F[2]==F[2] );
assertion( F[3]==F[3] );
assertion( F[4]==F[4] );
};
auto splitRiemann1d = [&flux, &eigenvalues](double QL[5], double QR[5], const tarch::la::Vector<DIMENSIONS,double>& x, double dx, double dt, int normal, double F[5]) -> void {{
double averageQ[5];
for (int unknown=0; unknown<5; unknown++) {{
averageQ[unknown] = 0.5 * (QL[unknown] + QR[unknown]);
assertion4(averageQ[unknown]==averageQ[unknown], x, dx, dt, normal);
}}
double averageF[5];
double lambdas[5];
flux(averageQ,x,normal,averageF);
double lambdaMax = 0.0;
eigenvalues(averageQ,x,normal,lambdas);
for (int unknown=0; unknown<5; unknown++) {{
assertion(lambdas[unknown]==lambdas[unknown]);
lambdaMax = std::max(lambdaMax,lambdas[unknown]);
}}
for (int unknown=0; unknown<5; unknown++) {{
assertion( QR[unknown]==QR[unknown] );
assertion( QL[unknown]==QL[unknown] );
F[unknown] = averageF[unknown] - 0.5 * lambdaMax * (QR[unknown] - QL[unknown]);
assertion9( F[unknown]==F[unknown], averageF[unknown], lambdas[unknown], QR[unknown], QL[unknown], unknown, x, dx, dt, normal );
}}
}};
constexpr int PatchSize = 13;
constexpr int HaloSize = 1;
double dt = 0.0001;
double dx = marker.h()(0) / PatchSize;
assertion( dx>=tarch::la::NUMERICAL_ZERO_DIFFERENCE );
dfor(cell,PatchSize) {{ // DOFS_PER_AXIS
tarch::la::Vector<DIMENSIONS,double> voxelCentre = marker.x()
- static_cast<double>((PatchSize/2+HaloSize)) * tarch::la::Vector<DIMENSIONS,double>(dx)
+ tarch::la::multiplyComponents(cell.convertScalar<double>(), tarch::la::Vector<DIMENSIONS,double>(dx));
tarch::la::Vector<DIMENSIONS,int> currentVoxel = cell + tarch::la::Vector<DIMENSIONS,int>(HaloSize); // OVERLAP / Halo layer size
int currentVoxelSerialised = peano4::utils::dLinearised(currentVoxel,PatchSize + 2*HaloSize);
double accumulatedNumericalFlux[] = { 0.0, 0.0, 0.0, 0.0, 0.0 };
double numericalFlux[5];
for (int d=0; d<DIMENSIONS; d++) {
tarch::la::Vector<DIMENSIONS,int> neighbourVoxel = currentVoxel;
tarch::la::Vector<DIMENSIONS,double> x = voxelCentre;
neighbourVoxel(d) -= 1;
int neighbourVoxelSerialised = peano4::utils::dLinearised(neighbourVoxel,PatchSize + 2*HaloSize);
x(d) -= 0.5 * dx;
assertion(neighbourVoxel(d)>=0);
splitRiemann1d(
oldQWithHalo + neighbourVoxelSerialised*5,
oldQWithHalo + currentVoxelSerialised*5,
x, dx, dt, d,
numericalFlux
);
for (int unknown=0; unknown<5; unknown++) {
//accumulatedNumericalFlux[unknown] -= numericalFlux[unknown];
accumulatedNumericalFlux[unknown] += numericalFlux[unknown];
assertion( numericalFlux[unknown]==numericalFlux[unknown] );
assertion( accumulatedNumericalFlux[unknown]==accumulatedNumericalFlux[unknown] );
}
neighbourVoxel(d) += 2;
neighbourVoxelSerialised = peano4::utils::dLinearised(neighbourVoxel,PatchSize + 2*HaloSize);
x(d) += 1.0 * dx;
splitRiemann1d(
oldQWithHalo + currentVoxelSerialised*5,
oldQWithHalo + neighbourVoxelSerialised*5,
x, dx, dt, d,
numericalFlux
);
for (int unknown=0; unknown<5; unknown++) {
//accumulatedNumericalFlux[unknown] += numericalFlux[unknown];
accumulatedNumericalFlux[unknown] -= numericalFlux[unknown];
assertion( numericalFlux[unknown]==numericalFlux[unknown] );
assertion( accumulatedNumericalFlux[unknown]==accumulatedNumericalFlux[unknown] );
}
}
int destinationVoxelSerialised = peano4::utils::dLinearised(cell,PatchSize);
for (int unknown=0; unknown<5; unknown++) {{
assertion( originalPatch[ destinationVoxelSerialised*5+unknown ]==originalPatch[ destinationVoxelSerialised*5+unknown ] );
assertion( accumulatedNumericalFlux[unknown]==accumulatedNumericalFlux[unknown] );
originalPatch[ destinationVoxelSerialised*5+unknown ] += dt / dx * accumulatedNumericalFlux[unknown];
}}
}}
"""
perform_time_step.add_action_set( peano4.toolbox.blockstructured.ReconstructPatchAndApplyFunctor(patch,patch_overlap,functor,"","") )
perform_time_step.add_action_set( peano4.toolbox.blockstructured.ProjectPatchOntoFaces(patch,patch_overlap) )
perform_time_step.add_action_set( plotter )
project.solversteps.add_step(perform_time_step)
project.output.makefile.parse_configure_script_outcome( "../../.." )
project.constants.export( "PatchSize", patch_size )
project.constants.export( "NumberOfUnknownsPerCell", unknowns )
project.generate(peano4.output.Overwrite.Default)
project.build()
success = project.run( ["myarguments"] )
if success:
convert = peano4.visualisation.Convert( "solution" )
convert.set_visualisation_tools_path( "/home/tobias/git/Peano/src/visualisation" )
convert.extract_fine_grid()
convert.convert_to_vtk()