MFEM v4.8.0
Finite element discretization library
Loading...
Searching...
No Matches
ex18p.cpp
Go to the documentation of this file.
1// MFEM Example 18 - Parallel Version
2//
3// Compile with: make ex18p
4//
5// Sample runs:
6//
7// mpirun -np 4 ex18p -p 1 -rs 2 -rp 1 -o 1 -s 3
8// mpirun -np 4 ex18p -p 1 -rs 1 -rp 1 -o 3 -s 4
9// mpirun -np 4 ex18p -p 1 -rs 1 -rp 1 -o 5 -s 6
10// mpirun -np 4 ex18p -p 2 -rs 1 -rp 1 -o 1 -s 3 -mf
11// mpirun -np 4 ex18p -p 2 -rs 1 -rp 1 -o 3 -s 3 -mf
12//
13// Description: This example code solves the compressible Euler system of
14// equations, a model nonlinear hyperbolic PDE, with a
15// discontinuous Galerkin (DG) formulation in parallel.
16//
17// (u_t, v)_T - (F(u), ∇ v)_T + <F̂(u,n), [[v]]>_F = 0
18//
19// where (⋅,⋅)_T is volume integration, and <⋅,⋅>_F is face
20// integration, F is the Euler flux function, and F̂ is the
21// numerical flux.
22//
23// Specifically, it solves for an exact solution of the equations
24// whereby a vortex is transported by a uniform flow. Since all
25// boundaries are periodic here, the method's accuracy can be
26// assessed by measuring the difference between the solution and
27// the initial condition at a later time when the vortex returns
28// to its initial location.
29//
30// Note that as the order of the spatial discretization increases,
31// the timestep must become smaller. This example currently uses a
32// simple estimate derived by Cockburn and Shu for the 1D RKDG
33// method. An additional factor can be tuned by passing the --cfl
34// (or -c shorter) flag.
35//
36// The example demonstrates usage of DGHyperbolicConservationLaws
37// that wraps NonlinearFormIntegrators containing element and face
38// integration schemes. In this case the system also involves an
39// external approximate Riemann solver for the DG interface flux.
40// By default, weak-divergence is pre-assembled in element-wise
41// manner, which corresponds to (I_h(F(u_h)), ∇ v). This yields
42// better performance and similar accuracy for the included test
43// problems. This can be turned off and use nonlinear assembly
44// similar to matrix-free assembly when -mf flag is provided.
45// It also demonstrates how to use GLVis for in-situ visualization
46// of vector grid function and how to set top-view.
47//
48// We recommend viewing examples 9, 14 and 17 before viewing this
49// example.
50
51#include "mfem.hpp"
52#include <fstream>
53#include <iostream>
54#include <sstream>
55#include "ex18.hpp"
56
57using namespace std;
58using namespace mfem;
59
60int main(int argc, char *argv[])
61{
62 // 0. Parallel setup
63 Mpi::Init(argc, argv);
64 const int numProcs = Mpi::WorldSize();
65 const int myRank = Mpi::WorldRank();
67
68 // 1. Parse command-line options.
69 int problem = 1;
70 const real_t specific_heat_ratio = 1.4;
71 const real_t gas_constant = 1.0;
72
73 string mesh_file = "";
74 int IntOrderOffset = 1;
75 int ser_ref_levels = 0;
76 int par_ref_levels = 1;
77 int order = 3;
78 int ode_solver_type = 4;
79 real_t t_final = 2.0;
80 real_t dt = -0.01;
81 real_t cfl = 0.3;
82 bool visualization = true;
83 bool preassembleWeakDiv = true;
84 int vis_steps = 50;
85
86 int precision = 8;
87 cout.precision(precision);
88
89 OptionsParser args(argc, argv);
90 args.AddOption(&mesh_file, "-m", "--mesh",
91 "Mesh file to use. If not provided, then a periodic square"
92 " mesh will be used.");
93 args.AddOption(&problem, "-p", "--problem",
94 "Problem setup to use. See EulerInitialCondition().");
95 args.AddOption(&ser_ref_levels, "-rs", "--serial-refine",
96 "Number of times to refine the serial mesh uniformly.");
97 args.AddOption(&par_ref_levels, "-rp", "--parallel-refine",
98 "Number of times to refine the parallel mesh uniformly.");
99 args.AddOption(&order, "-o", "--order",
100 "Order (degree) of the finite elements.");
101 args.AddOption(&ode_solver_type, "-s", "--ode-solver",
103 args.AddOption(&t_final, "-tf", "--t-final", "Final time; start time is 0.");
104 args.AddOption(&dt, "-dt", "--time-step",
105 "Time step. Positive number skips CFL timestep calculation.");
106 args.AddOption(&cfl, "-c", "--cfl-number",
107 "CFL number for timestep calculation.");
108 args.AddOption(&visualization, "-vis", "--visualization", "-no-vis",
109 "--no-visualization",
110 "Enable or disable GLVis visualization.");
111 args.AddOption(&preassembleWeakDiv, "-ea", "--element-assembly-divergence",
112 "-mf", "--matrix-free-divergence",
113 "Weak divergence assembly level\n"
114 " ea - Element assembly with interpolated F\n"
115 " mf - Nonlinear assembly in matrix-free manner");
116 args.AddOption(&vis_steps, "-vs", "--visualization-steps",
117 "Visualize every n-th timestep.");
118 args.ParseCheck();
119
120 // 2. Read the mesh from the given mesh file. When the user does not provide
121 // mesh file, use the default mesh file for the problem.
122 Mesh mesh = mesh_file.empty() ? EulerMesh(problem) : Mesh(mesh_file);
123 const int dim = mesh.Dimension();
124 const int num_equations = dim + 2;
125
126 // Refine the mesh to increase the resolution. In this example we do
127 // 'ser_ref_levels' of uniform refinement, where 'ser_ref_levels' is a
128 // command-line parameter.
129 for (int lev = 0; lev < ser_ref_levels; lev++)
130 {
131 mesh.UniformRefinement();
132 }
133
134 // Define a parallel mesh by a partitioning of the serial mesh. Refine this
135 // mesh further in parallel to increase the resolution. Once the parallel
136 // mesh is defined, the serial mesh can be deleted.
137 ParMesh pmesh = ParMesh(MPI_COMM_WORLD, mesh);
138 mesh.Clear();
139
140 // Refine the mesh to increase the resolution. In this example we do
141 // 'par_ref_levels' of uniform refinement, where 'par_ref_levels' is a
142 // command-line parameter.
143 for (int lev = 0; lev < par_ref_levels; lev++)
144 {
145 pmesh.UniformRefinement();
146 }
147
148 // 3. Define the ODE solver used for time integration. Several explicit
149 // Runge-Kutta methods are available.
150 unique_ptr<ODESolver> ode_solver = ODESolver::SelectExplicit(ode_solver_type);
151
152 // 4. Define the discontinuous DG finite element space of the given
153 // polynomial order on the refined mesh.
154 DG_FECollection fec(order, dim);
155 // Finite element space for a scalar (thermodynamic quantity)
156 ParFiniteElementSpace fes(&pmesh, &fec);
157 // Finite element space for a mesh-dim vector quantity (momentum)
158 ParFiniteElementSpace dfes(&pmesh, &fec, dim, Ordering::byNODES);
159 // Finite element space for all variables together (total thermodynamic state)
160 ParFiniteElementSpace vfes(&pmesh, &fec, num_equations, Ordering::byNODES);
161
162 // This example depends on this ordering of the space.
163 MFEM_ASSERT(fes.GetOrdering() == Ordering::byNODES, "");
164
165 HYPRE_BigInt glob_size = vfes.GlobalTrueVSize();
166 if (Mpi::Root())
167 {
168 cout << "Number of unknowns: " << glob_size << endl;
169 }
170
171 // 5. Define the initial conditions, save the corresponding mesh and grid
172 // functions to files. These can be opened with GLVis using:
173 // "glvis -np 4 -m euler-mesh -g euler-1-init" (for x-momentum).
174
175 // Initialize the state.
177 specific_heat_ratio,
178 gas_constant);
179 ParGridFunction sol(&vfes);
180 sol.ProjectCoefficient(u0);
181 ParGridFunction mom(&dfes, sol.GetData() + fes.GetNDofs());
182 // Output the initial solution.
183 {
184 ostringstream mesh_name;
185 mesh_name << "euler-mesh." << setfill('0') << setw(6) << Mpi::WorldRank();
186 ofstream mesh_ofs(mesh_name.str().c_str());
187 mesh_ofs.precision(precision);
188 mesh_ofs << pmesh;
189
190 for (int k = 0; k < num_equations; k++)
191 {
192 ParGridFunction uk(&fes, sol.GetData() + k * fes.GetNDofs());
193 ostringstream sol_name;
194 sol_name << "euler-" << k << "-init." << setfill('0') << setw(6)
195 << Mpi::WorldRank();
196 ofstream sol_ofs(sol_name.str().c_str());
197 sol_ofs.precision(precision);
198 sol_ofs << uk;
199 }
200 }
201
202 // 6. Set up the nonlinear form with euler flux and numerical flux
203 EulerFlux flux(dim, specific_heat_ratio);
204 RusanovFlux numericalFlux(flux);
206 vfes, std::unique_ptr<HyperbolicFormIntegrator>(
207 new HyperbolicFormIntegrator(numericalFlux, IntOrderOffset)),
208 preassembleWeakDiv);
209
210 // 7. Visualize momentum with its magnitude
211 socketstream sout;
212 if (visualization)
213 {
214 char vishost[] = "localhost";
215 int visport = 19916;
216
217 sout.open(vishost, visport);
218 if (!sout)
219 {
220 visualization = false;
221 if (Mpi::Root())
222 {
223 cout << "Unable to connect to GLVis server at " << vishost << ':'
224 << visport << endl;
225 cout << "GLVis visualization disabled.\n";
226 }
227 }
228 else
229 {
230 sout.precision(precision);
231 // Plot magnitude of vector-valued momentum
232 sout << "parallel " << numProcs << " " << myRank << "\n";
233 sout << "solution\n" << pmesh << mom;
234 sout << "window_title 'momentum, t = 0'\n";
235 sout << "view 0 0\n"; // view from top
236 sout << "keys jlm\n"; // turn off perspective and light, show mesh
237 sout << "pause\n";
238 sout << flush;
239 if (Mpi::Root())
240 {
241 cout << "GLVis visualization paused."
242 << " Press space (in the GLVis window) to resume it.\n";
243 }
244 MPI_Barrier(pmesh.GetComm());
245 }
246 }
247
248 // 8. Time integration
249
250 // When dt is not specified, use CFL condition.
251 // Compute h_min and initial maximum characteristic speed
252 real_t hmin = infinity();
253 if (cfl > 0)
254 {
255 for (int i = 0; i < pmesh.GetNE(); i++)
256 {
257 hmin = min(pmesh.GetElementSize(i, 1), hmin);
258 }
259 MPI_Allreduce(MPI_IN_PLACE, &hmin, 1, MPITypeMap<real_t>::mpi_type, MPI_MIN,
260 pmesh.GetComm());
261 // Find a safe dt, using a temporary vector. Calling Mult() computes the
262 // maximum char speed at all quadrature points on all faces (and all
263 // elements with -mf).
264 Vector z(sol.Size());
265 euler.Mult(sol, z);
266
267 real_t max_char_speed = euler.GetMaxCharSpeed();
268 MPI_Allreduce(MPI_IN_PLACE, &max_char_speed, 1, MPITypeMap<real_t>::mpi_type,
269 MPI_MAX,
270 pmesh.GetComm());
271 dt = cfl * hmin / max_char_speed / (2 * order + 1);
272 }
273
274 // Start the timer.
275 tic_toc.Clear();
276 tic_toc.Start();
277
278 // Init time integration
279 real_t t = 0.0;
280 euler.SetTime(t);
281 ode_solver->Init(euler);
282
283 // Integrate in time.
284 bool done = false;
285 for (int ti = 0; !done;)
286 {
287 real_t dt_real = min(dt, t_final - t);
288
289 ode_solver->Step(sol, t, dt_real);
290 if (cfl > 0) // update time step size with CFL
291 {
292 real_t max_char_speed = euler.GetMaxCharSpeed();
293 MPI_Allreduce(MPI_IN_PLACE, &max_char_speed, 1, MPITypeMap<real_t>::mpi_type,
294 MPI_MAX,
295 pmesh.GetComm());
296 dt = cfl * hmin / max_char_speed / (2 * order + 1);
297 }
298 ti++;
299
300 done = (t >= t_final - 1e-8 * dt);
301 if (done || ti % vis_steps == 0)
302 {
303 if (Mpi::Root())
304 {
305 cout << "time step: " << ti << ", time: " << t << endl;
306 }
307 if (visualization)
308 {
309 sout << "window_title 'momentum, t = " << t << "'\n";
310 sout << "parallel " << numProcs << " " << myRank << "\n";
311 sout << "solution\n" << pmesh << mom << flush;
312 }
313 }
314 }
315
316 tic_toc.Stop();
317 if (Mpi::Root())
318 {
319 cout << " done, " << tic_toc.RealTime() << "s." << endl;
320 }
321
322 // 9. Save the final solution. This output can be viewed later using GLVis:
323 // "glvis -np 4 -m euler-mesh-final -g euler-1-final" (for x-momentum).
324 {
325 ostringstream mesh_name;
326 mesh_name << "euler-mesh-final." << setfill('0') << setw(6)
327 << Mpi::WorldRank();
328 ofstream mesh_ofs(mesh_name.str().c_str());
329 mesh_ofs.precision(precision);
330 mesh_ofs << pmesh;
331
332 for (int k = 0; k < num_equations; k++)
333 {
334 ParGridFunction uk(&fes, sol.GetData() + k * fes.GetNDofs());
335 ostringstream sol_name;
336 sol_name << "euler-" << k << "-final." << setfill('0') << setw(6)
337 << Mpi::WorldRank();
338 ofstream sol_ofs(sol_name.str().c_str());
339 sol_ofs.precision(precision);
340 sol_ofs << uk;
341 }
342 }
343
344 // 10. Compute the L2 solution error summed for all components.
345 const real_t error = sol.ComputeLpError(2, u0);
346 if (Mpi::Root())
347 {
348 cout << "Solution error: " << error << endl;
349 }
350
351 return 0;
352}
Time dependent DG operator for hyperbolic conservation laws.
Definition ex18.hpp:32
void Mult(const Vector &x, Vector &y) const override
Apply nonlinear form to obtain M⁻¹(DIVF + JUMP HAT(F))
Definition ex18.hpp:168
Euler flux.
int GetNDofs() const
Returns number of degrees of freedom. This is the number of Local Degrees of Freedom.
Definition fespace.hpp:845
Ordering::Type GetOrdering() const
Return the ordering method.
Definition fespace.hpp:876
Abstract hyperbolic form integrator, assembling (F(u, x), ∇v) and <F̂(u⁻,u⁺,x) n, [v]> terms for scal...
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Definition hypre.cpp:33
Arbitrary order "L2-conforming" discontinuous finite elements.
Definition fe_coll.hpp:346
Mesh data type.
Definition mesh.hpp:64
void Clear()
Clear the contents of the Mesh.
Definition mesh.hpp:761
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1282
int Dimension() const
Dimension of the reference space used within the elements.
Definition mesh.hpp:1216
real_t GetElementSize(int i, int type=0)
Get the size of the i-th element relative to the perfect reference element.
Definition mesh.cpp:107
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition mesh.cpp:11295
static bool Root()
Return true if the rank in MPI_COMM_WORLD is zero.
static int WorldRank()
Return the MPI rank in MPI_COMM_WORLD.
static int WorldSize()
Return the size of MPI_COMM_WORLD.
static void Init(int &argc, char **&argv, int required=default_thread_required, int *provided=nullptr)
Singleton creation with Mpi::Init(argc, argv).
static MFEM_EXPORT std::string ExplicitTypes
Definition ode.hpp:185
static MFEM_EXPORT std::unique_ptr< ODESolver > SelectExplicit(const int ode_solver_type)
Definition ode.cpp:46
void ParseCheck(std::ostream &out=mfem::out)
void AddOption(bool *var, const char *enable_short_name, const char *enable_long_name, const char *disable_short_name, const char *disable_long_name, const char *description, bool required=false)
Add a boolean option and set 'var' to receive the value. Enable/disable tags are used to set the bool...
Definition optparser.hpp:82
Abstract parallel finite element space.
Definition pfespace.hpp:29
HYPRE_BigInt GlobalTrueVSize() const
Definition pfespace.hpp:346
Class for parallel grid function.
Definition pgridfunc.hpp:50
real_t ComputeLpError(const real_t p, Coefficient &exsol, Coefficient *weight=NULL, const IntegrationRule *irs[]=NULL, const Array< int > *elems=NULL) const override
Returns ||u_ex - u_h||_Lp in parallel for scalar fields.
void ProjectCoefficient(Coefficient &coeff) override
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Class for parallel meshes.
Definition pmesh.hpp:34
MPI_Comm GetComm() const
Definition pmesh.hpp:402
Rusanov flux, also known as local Lax-Friedrichs, F̂ n = ½(F(u⁺,x)n + F(u⁻,x)n) - ½λ(u⁺ - u⁻) where λ...
double RealTime()
Return the number of real seconds elapsed since the stopwatch was started.
Definition tic_toc.cpp:432
void Start()
Start the stopwatch. The elapsed time is not cleared.
Definition tic_toc.cpp:411
void Stop()
Stop the stopwatch.
Definition tic_toc.cpp:422
void Clear()
Clear the elapsed time on the stopwatch and restart it if it's running.
Definition tic_toc.cpp:406
virtual void SetTime(const real_t t_)
Set the current time.
Definition operator.hpp:394
A general vector function coefficient.
Vector data type.
Definition vector.hpp:82
int Size() const
Returns the size of the vector.
Definition vector.hpp:226
real_t * GetData() const
Return a pointer to the beginning of the Vector data.
Definition vector.hpp:235
int open(const char hostname[], int port)
Open the socket stream on 'port' at 'hostname'.
int problem
Definition ex15.cpp:62
int dim
Definition ex24.cpp:53
int main()
HYPRE_Int HYPRE_BigInt
real_t infinity()
Define a shortcut for std::numeric_limits<double>::infinity()
Definition vector.hpp:47
Mesh EulerMesh(const int problem)
Definition ex18.hpp:299
VectorFunctionCoefficient EulerInitialCondition(const int problem, const real_t specific_heat_ratio, const real_t gas_constant)
Definition ex18.hpp:317
StopWatch tic_toc
Definition tic_toc.cpp:450
float real_t
Definition config.hpp:43
const char vishost[]
Helper struct to convert a C++ type to an MPI type.