Files
aa1d6441f8 General hyperbolic class and Refactored Ex18, Ex18p (#3598)
* include cfl

* include 2x2 periodic mesh to have 2^N elements.

* include computation of initial max char speed for t=0

* reorder classes to avoid incomplete type

* fix function spaces for solution variables

* Initial conditions and problems. Not yet done I think

* problem setting

* begin time stepping implementation

* Initial state assignment

* arg parser!

* default periodic square mesh updated

it seems that 2x2 periodic mesh does not work.
-> This is because 2x2 contains both 0->1 edge and 1->0 edge on the boundary
due to periodic constraint.
I believe that is why 3x3 elements are used in the data folder.

* correct errors in euler flux functions

* General Hyperbolic Form updated

* Burgers example included

* Rename FE_Evolution to HCL

* Give operators more meaningful names

* remove Aflux and include divA.
This will allow us to update operators within HCL class

* Allow variable size of invMe to handle p-refine.
invMe Type: DenseTensor -> vector<DenseMatrix>

* Update method included for HCL.
It is not tested yet.
Also, since Operator does not have Update method,
we needed to restrict Operator to NonlinearForm

* Finalize update functionality. Visualization not yet implemented.
Tested with derefine and refine after system construction.
Current code seems to give correct result.
May require further verification.

* update burgers equation

* Fix 1-d bug!
As MFEM positive/negative elements ordering
does not respect the original mesh ordering,
normal vector can be positive or negative in 1D.
We check this by checking integration point is either right or left for 1D.

* move global constants (num_eq, gas.. etc) inside of the classes

* revert back visualization code.

* Add comments and reorder classes

* Remove redundant example code as it is not used anymore.

* rename and move problem-specific defintions to cpp files

* Merged debugged code.

* shallow water an example with periodic boundary included

* rename num_equation to num_equations and include GetIntRule

* Element-wise form integrator for further refactoring

* just testing...

* rename to DGHyperbolicConservationLaws

* max_char_speed now shared by pointer

* use reference instead of pointer

* Rename HCL class to DGHCL

* Form now have pointer to max_char_speed which points to HCL class max_char_speed.
max_char_speed is not exposed to outside.
Use getter instead.

* MPI_Reduce -> MPI_All_Reduce as all workers share the same max_char_speed

* rename faceform to hyperbolic faceform

* Include HyperbolicElementForm for accurate flux evaluation

* Rename form to formintegrator as this is appropriate name

* evaluation template for element assembly

* funval -> state for readibility

* fix bug in the arguments of AssembleElementVector

* compute flux now takes correct function arguments

* ElementFormIntegrator is done. Not yet tested.🤞

* Euler problem is verified.
Burgers and shallow water will be updated

* correct typo Hyperboilic.... :(

* Burgers done. Euler typo fixed

* Shallow water also done!

* Shallow water gauss bump problem included

* include transformations to flux evaluation functions

* This fixes Allow HCL flux functions utilize space-dependent evaluation dohyun-cse/mfem#1.
Advection equation is now included

* Now DGHCL takes nonlinear form as an input argument to handle ParNonlinearForm

* Parallel euler implementation

* remove hello from..

* print function updated

* code cleanup

* Euler cleanup and parallel version bug fix

* Burgers code cleanup and parallel implementation

* shallow water updated.

* advection serial parallel done.

* correct typo in option (parallel refine)

* move hyperbolic_conservation_laws file to fem folder

* include path update

* Take NonlinearForm as reference, not a pointer. Updated Makefile, too.

* Documentation and change some variable names

* form integrators are now in heap memory to avoid malloc error

* changed nonlinear form as a pointer
It seems that PyMFEM does not like reference of nonlinear form... :(

* ignore generated files

* max_char_speed get set method instead of pointer

* nonilnForm pointer update

* nonlinearForm pass by reference

* typo correction

* Test for PyMFEM.. Other examples are not updated yet

* example scripts updated

* ternary to max function

* simplify creating parallel version.

* p-refinement done. test needed.

* testing begins!

* update procedure for main class is included.

* Testing. Still having problem. Not identified yet

* Correct size, but incorrect values.

* p-refinement done and remove nonlinear form exposure.
Parallel checking is done by dynamic_cast.
Therefore, there is no reason to expose nonlienar form to user.
This simplifies class creation :)

* p-refinement test done.

It seems that p-refinement does not result in more accurate solution.

* add option for refinement. h-refinement impl start

* h-refine works fine, but threshold should be modified to obtain bounded number of elements.

* namespace update

* examples tested.

* h-refinement done. Update marking procedure by using confidence interval

* formatting and remove cout from derefine

* include adaptive code to make file

* visualization update

* NumericalFlux -> RiemannSolver

* It seems that set is ambiguous for SWIG..

* comment on hDerefine and now use VectorFunctionCoefficient for IC and Velocity

* testing....

* make flux related methods public

* remove commented out codes

* make style

* doxygen update

* update ex18 with new implementation

* Combine Element/Face Form integrators.

* astyle

* remove redundant ;

* remove refinement procedures.

* thread safe clause

* remove using namespace from hpp file

* ProlongToMaxOrderDG included with interpolation

* remove lambda_function type and return VectorFunctionCoeff for initial/velocity

* removed sinpi

* Some comments

* remove other examples and style

* remove examples not included anymore

* std::cout to mfem::out and correct minor bugs

* ignore mesh file

* update makefile

* remove MPI from serial

* remove unused captured variables in lambda functions

* style

* remove ex34 from makefile and reorder initialization

* remove initialization for auxiliary variables in formintegrator

* remove gas constant from the euler system

* fix broken parts due to uninitialization

* move initialization of local variables inside of FormIntegrator constructor

* forgot to update the other constructor!

* ignore mesh and gridfunctions

* resolved memory leak. Need to check

* remove pragma omp atomic

* remove delete nonlinearForm

* resolve shadowing

* correct dof report and remove barrier in visualization

* forgot to update variable name in euler form

* nonlinearForm memory leak resolved.

destructor of nonlinearForm always delete integrators.
This results in double deletion of the form integrator if we use for both domain and face integration.
To resolve this issue, just create two integrators and pass it to nonlinearForm

* proper header setting and faster test by reducing mesh size

* delete ex18.hpp

* move lengthy functions to cpp

* header order changed

* simpler inclusion.. still have duplicated symbols

* resolved linker problem and include pnonlinear

* remove commented out functions

* documentation

* fixing memory leak..

* delete nonlinearForm

* formatting

* distclean update

* Ignore binaries and result files

* copyright

* Riemann solver comment, input updated.
Riemann solver is now passed as reference

* pass riemann solver by reference

* move default normal flux eval to cpp

* Advection uses inferred dimension from velocity field

* integration rule uses Jacobian order, too

* delete not implemented

* mark override

* format

* unique ptr and mark override

* use single HyperbolicFormIntegrator

* static GetRule

* proper creation without copying

* proper jacobian order in GetRule

* moved member function implementation to cpp file

* new line

* pass by reference

* removed 4x4 mesh and update ignore

* doxygen updated

* remove constructor with integration rule.
Users can set integration rule via NonlinearFormIntegrator::SetIntRule

* useExternalData to indicate ownership of integrator for nonlinear form

* extract flux function from the form integrator

As suggested by @pazner, flux function is now seperated from form integrator. By doing so, riemann solver takes simpler argument but can access to equation-specific information.

* documentation

* documentation --

* initialization order

* update naming of form integrators

* initialization order...

* use normal wavespeed

* shorter Rusanov flux evaluation

* minor code style update

See, https://github.com/mfem/mfem/pull/3598#pullrequestreview-1803234677

* fix syntax error due to pointer -> reference

* std::

* Update fem/nonlinearform.hpp

Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>

* return Mesh instead of string

* Moved DG to ex18.hpp and other styling updates
- Ex18p not yet updated

* update similar to previous commit

* remove ResetMaxChar in the constructor + comment update

Since reset max char will be called each Mult() call, we do not need reset in the constructor

* comment and include functional

* removed inlined namewspace

* style

* move common functions to hpp

* formatting and minor fixes in parallel code.

* update filename and fix typo in `GetMovingVortexInit`

* add hyperbolic to changelog and ex18 comment update

* removed Kelvin–Helmholtz instability example

It is hard to get a satisfactory result with the current DG method without additional treatment.

* fluxFunction is now input of RiemannSolver::Eval instead of being a member.

* compatibility check between flux function and Riemann solver

Some Riemann solver are system-specific. Such Riemann solver can prevent user-error by overriding `IsCompatible`.

* More error-proofing constructors of `RiemannSolver` and `HyperbolicFormIntegrator`

* documentation

* header file description updated

* add examples in the comment

* style

* copyright update

* use unique_ptr in the constructor to make ownership clear

* removed unused member, dim

* Some minor edits, mostly formatting

* add option for pre-assembly

* remove unused ComputeFlux

* keep momentum variable as in serial code

* Fix warnings

* preassembly by default and minor optimization

* remove mutable vector and revert back variable name

flux is now a local variable that changes size at each element. So, it would better to remove it from member variables.

* std::sqrt instead of sqrt

* another minor optimization

* rename options and add comments

* linearized->interpolated

* typo correction in comment

* remove auto from example

Co-authored-by: Chris Vogl <vogl2@llnl.gov>

* Comment update
Correct condition check comment on weak-divergence, and additional comments on auxiliary variable

* Momentum for visualization should be shifted.
FE implementation is correct, but visualization was using u[0,dim). It should be u[1,dim) and now fixed.

* example comments

* style..

* strangely, a trailing space was not updated.

* Fix the thread-safe build. Some doxygen and formatting tweaks.

* fix doxygen error

* Some small tweaks in ex18/ex18p; remove small diffs between the
serial and the parallel versions.

* Small formatting tweaks in ex18.hpp

* unused problem mesh transform

* Remove transformation dependent integration order

* Minor formatting

* support general precision

* format

---------

Co-authored-by: adam-sim-dev <adam.d.schmidt@hotmail.com>
Co-authored-by: Will Pazner <11493037+pazner@users.noreply.github.com>
Co-authored-by: Veselin Dobrev <dobrev@llnl.gov>
Co-authored-by: Chris Vogl <vogl2@llnl.gov>
Co-authored-by: Veselin Dobrev <v-dobrev@users.noreply.github.com>
2024-04-03 13:30:41 -07:00

312 lines
11 KiB
C++

// MFEM Example 18
//
// Compile with: make ex18
//
// Sample runs:
//
// ex18 -p 1 -r 2 -o 1 -s 3
// ex18 -p 1 -r 1 -o 3 -s 4
// ex18 -p 1 -r 0 -o 5 -s 6
// ex18 -p 2 -r 1 -o 1 -s 3 -mf
// ex18 -p 2 -r 0 -o 3 -s 3 -mf
//
// Description: This example code solves the compressible Euler system of
// equations, a model nonlinear hyperbolic PDE, with a
// discontinuous Galerkin (DG) formulation.
//
// (u_t, v)_T - (F(u), ∇ v)_T + <F̂(u,n), [[v]]>_F = 0
//
// where (⋅,⋅)_T is volume integration, and <⋅,⋅>_F is face
// integration, F is the Euler flux function, and F̂ is the
// numerical flux.
//
// Specifically, it solves for an exact solution of the equations
// whereby a vortex is transported by a uniform flow. Since all
// boundaries are periodic here, the method's accuracy can be
// assessed by measuring the difference between the solution and
// the initial condition at a later time when the vortex returns
// to its initial location.
//
// Note that as the order of the spatial discretization increases,
// the timestep must become smaller. This example currently uses a
// simple estimate derived by Cockburn and Shu for the 1D RKDG
// method. An additional factor can be tuned by passing the --cfl
// (or -c shorter) flag.
//
// The example demonstrates usage of DGHyperbolicConservationLaws
// that wraps NonlinearFormIntegrators containing element and face
// integration schemes. In this case the system also involves an
// external approximate Riemann solver for the DG interface flux.
// By default, weak-divergence is pre-assembled in element-wise
// manner, which corresponds to (I_h(F(u_h)), ∇ v). This yields
// better performance and similar accuracy for the included test
// problems. This can be turned off and use nonlinear assembly
// similar to matrix-free assembly when -mf flag is provided.
// It also demonstrates how to use GLVis for in-situ visualization
// of vector grid function and how to set top-view.
//
// We recommend viewing examples 9, 14 and 17 before viewing this
// example.
#include "mfem.hpp"
#include <fstream>
#include <iostream>
#include <sstream>
#include "ex18.hpp"
using namespace std;
using namespace mfem;
int main(int argc, char *argv[])
{
// 1. Parse command-line options.
int problem = 1;
const real_t specific_heat_ratio = 1.4;
const real_t gas_constant = 1.0;
string mesh_file = "";
int IntOrderOffset = 1;
int ref_levels = 1;
int order = 3;
int ode_solver_type = 4;
real_t t_final = 2.0;
real_t dt = -0.01;
real_t cfl = 0.3;
bool visualization = true;
bool preassembleWeakDiv = true;
int vis_steps = 50;
int precision = 8;
cout.precision(precision);
OptionsParser args(argc, argv);
args.AddOption(&mesh_file, "-m", "--mesh",
"Mesh file to use. If not provided, then a periodic square"
" mesh will be used.");
args.AddOption(&problem, "-p", "--problem",
"Problem setup to use. See EulerInitialCondition().");
args.AddOption(&ref_levels, "-r", "--refine",
"Number of times to refine the mesh uniformly.");
args.AddOption(&order, "-o", "--order",
"Order (degree) of the finite elements.");
args.AddOption(&ode_solver_type, "-s", "--ode-solver",
"ODE solver: 1 - Forward Euler,\n\t"
" 2 - RK2 SSP, 3 - RK3 SSP, 4 - RK4, 6 - RK6.");
args.AddOption(&t_final, "-tf", "--t-final", "Final time; start time is 0.");
args.AddOption(&dt, "-dt", "--time-step",
"Time step. Positive number skips CFL timestep calculation.");
args.AddOption(&cfl, "-c", "--cfl-number",
"CFL number for timestep calculation.");
args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
"--no-visualization",
"Enable or disable GLVis visualization.");
args.AddOption(&preassembleWeakDiv, "-ea", "--element-assembly-divergence",
"-mf", "--matrix-free-divergence",
"Weak divergence assembly level\n"
" ea - Element assembly with interpolated F\n"
" mf - Nonlinear assembly in matrix-free manner");
args.AddOption(&vis_steps, "-vs", "--visualization-steps",
"Visualize every n-th timestep.");
args.ParseCheck();
// 2. Read the mesh from the given mesh file. When the user does not provide
// mesh file, use the default mesh file for the problem.
Mesh mesh = mesh_file.empty() ? EulerMesh(problem) : Mesh(mesh_file);
const int dim = mesh.Dimension();
const int num_equations = dim + 2;
// Refine the mesh to increase the resolution. In this example we do
// 'ref_levels' of uniform refinement, where 'ref_levels' is a command-line
// parameter.
for (int lev = 0; lev < ref_levels; lev++)
{
mesh.UniformRefinement();
}
// 3. Define the ODE solver used for time integration. Several explicit
// Runge-Kutta methods are available.
ODESolver *ode_solver = NULL;
switch (ode_solver_type)
{
case 1: ode_solver = new ForwardEulerSolver; break;
case 2: ode_solver = new RK2Solver(1.0); break;
case 3: ode_solver = new RK3SSPSolver; break;
case 4: ode_solver = new RK4Solver; break;
case 6: ode_solver = new RK6Solver; break;
default:
cout << "Unknown ODE solver type: " << ode_solver_type << '\n';
return 3;
}
// 4. Define the discontinuous DG finite element space of the given
// polynomial order on the refined mesh.
DG_FECollection fec(order, dim);
// Finite element space for a scalar (thermodynamic quantity)
FiniteElementSpace fes(&mesh, &fec);
// Finite element space for a mesh-dim vector quantity (momentum)
FiniteElementSpace dfes(&mesh, &fec, dim, Ordering::byNODES);
// Finite element space for all variables together (total thermodynamic state)
FiniteElementSpace vfes(&mesh, &fec, num_equations, Ordering::byNODES);
// This example depends on this ordering of the space.
MFEM_ASSERT(fes.GetOrdering() == Ordering::byNODES, "");
cout << "Number of unknowns: " << vfes.GetVSize() << endl;
// 5. Define the initial conditions, save the corresponding mesh and grid
// functions to files. These can be opened with GLVis using:
// "glvis -m euler-mesh.mesh -g euler-1-init.gf" (for x-momentum).
// Initialize the state.
VectorFunctionCoefficient u0 = EulerInitialCondition(problem,
specific_heat_ratio,
gas_constant);
GridFunction sol(&vfes);
sol.ProjectCoefficient(u0);
GridFunction mom(&dfes, sol.GetData() + fes.GetNDofs());
// Output the initial solution.
{
ostringstream mesh_name;
mesh_name << "euler-mesh.mesh";
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(precision);
mesh_ofs << mesh;
for (int k = 0; k < num_equations; k++)
{
GridFunction uk(&fes, sol.GetData() + k * fes.GetNDofs());
ostringstream sol_name;
sol_name << "euler-" << k << "-init.gf";
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(precision);
sol_ofs << uk;
}
}
// 6. Set up the nonlinear form with euler flux and numerical flux
EulerFlux flux(dim, specific_heat_ratio);
RusanovFlux numericalFlux(flux);
DGHyperbolicConservationLaws euler(
vfes, std::unique_ptr<HyperbolicFormIntegrator>(
new HyperbolicFormIntegrator(numericalFlux, IntOrderOffset)),
preassembleWeakDiv);
// 7. Visualize momentum with its magnitude
socketstream sout;
if (visualization)
{
char vishost[] = "localhost";
int visport = 19916;
sout.open(vishost, visport);
if (!sout)
{
visualization = false;
cout << "Unable to connect to GLVis server at " << vishost << ':'
<< visport << endl;
cout << "GLVis visualization disabled.\n";
}
else
{
sout.precision(precision);
// Plot magnitude of vector-valued momentum
sout << "solution\n" << mesh << mom;
sout << "window_title 'momentum, t = 0'\n";
sout << "view 0 0\n"; // view from top
sout << "keys jlm\n"; // turn off perspective and light, show mesh
sout << "pause\n";
sout << flush;
cout << "GLVis visualization paused."
<< " Press space (in the GLVis window) to resume it.\n";
}
}
// 8. Time integration
// When dt is not specified, use CFL condition.
// Compute h_min and initial maximum characteristic speed
real_t hmin = infinity();
if (cfl > 0)
{
for (int i = 0; i < mesh.GetNE(); i++)
{
hmin = min(mesh.GetElementSize(i, 1), hmin);
}
// Find a safe dt, using a temporary vector. Calling Mult() computes the
// maximum char speed at all quadrature points on all faces (and all
// elements with -mf).
Vector z(sol.Size());
euler.Mult(sol, z);
real_t max_char_speed = euler.GetMaxCharSpeed();
dt = cfl * hmin / max_char_speed / (2 * order + 1);
}
// Start the timer.
tic_toc.Clear();
tic_toc.Start();
// Init time integration
real_t t = 0.0;
euler.SetTime(t);
ode_solver->Init(euler);
// Integrate in time.
bool done = false;
for (int ti = 0; !done;)
{
real_t dt_real = min(dt, t_final - t);
ode_solver->Step(sol, t, dt_real);
if (cfl > 0) // update time step size with CFL
{
real_t max_char_speed = euler.GetMaxCharSpeed();
dt = cfl * hmin / max_char_speed / (2 * order + 1);
}
ti++;
done = (t >= t_final - 1e-8 * dt);
if (done || ti % vis_steps == 0)
{
cout << "time step: " << ti << ", time: " << t << endl;
if (visualization)
{
sout << "window_title 'momentum, t = " << t << "'\n";
sout << "solution\n" << mesh << mom << flush;
}
}
}
tic_toc.Stop();
cout << " done, " << tic_toc.RealTime() << "s." << endl;
// 9. Save the final solution. This output can be viewed later using GLVis:
// "glvis -m euler-mesh-final.mesh -g euler-1-final.gf" (for x-momentum).
{
ostringstream mesh_name;
mesh_name << "euler-mesh-final.mesh";
ofstream mesh_ofs(mesh_name.str().c_str());
mesh_ofs.precision(precision);
mesh_ofs << mesh;
for (int k = 0; k < num_equations; k++)
{
GridFunction uk(&fes, sol.GetData() + k * fes.GetNDofs());
ostringstream sol_name;
sol_name << "euler-" << k << "-final.gf";
ofstream sol_ofs(sol_name.str().c_str());
sol_ofs.precision(precision);
sol_ofs << uk;
}
}
// 10. Compute the L2 solution error summed for all components.
const real_t error = sol.ComputeLpError(2, u0);
cout << "Solution error: " << error << endl;
// Free the used memory.
delete ode_solver;
return 0;
}