MFEM  v4.3.0
Finite element discretization library
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Pages
navier_kovasznay.cpp
Go to the documentation of this file.
1 // Copyright (c) 2010-2021, Lawrence Livermore National Security, LLC. Produced
2 // at the Lawrence Livermore National Laboratory. All Rights reserved. See files
3 // LICENSE and NOTICE for details. LLNL-CODE-806117.
4 //
5 // This file is part of the MFEM library. For more information and source code
6 // availability visit https://mfem.org.
7 //
8 // MFEM is free software; you can redistribute it and/or modify it under the
9 // terms of the BSD-3 license. We welcome feedback and contributions, see file
10 // CONTRIBUTING.md for details.
11 //
12 // Navier Kovasznay example
13 //
14 // Solve for the steady Kovasznay flow at Re = 40 defined by
15 //
16 // u = [1 - exp(L * x) * cos(2 * pi * y),
17 // L / (2 * pi) * exp(L * x) * sin(2 * pi * y)],
18 //
19 // p = 1/2 * (1 - exp(2 * L * x)),
20 //
21 // with L = Re/2 - sqrt(Re^2/4 + 4 * pi^2).
22 //
23 // The problem domain is set up like this
24 //
25 // +-------------+
26 // | |
27 // | |
28 // | |
29 // | |
30 // Inflow -> | | -> Outflow
31 // | |
32 // | |
33 // | |
34 // | |
35 // | |
36 // +-------------+
37 //
38 // and Dirichlet boundary conditions are applied for the velocity on every
39 // boundary. The problem, although steady state, is time integrated up to the
40 // final time and the solution is compared with the known exact solution.
41 
42 #include "navier_solver.hpp"
43 #include <fstream>
44 
45 using namespace mfem;
46 using namespace navier;
47 
48 struct s_NavierContext
49 {
50  int ser_ref_levels = 1;
51  int order = 6;
52  double kinvis = 1.0 / 40.0;
53  double t_final = 10 * 0.001;
54  double dt = 0.001;
55  double reference_pressure = 0.0;
56  double reynolds = 1.0 / kinvis;
57  double lam = 0.5 * reynolds
58  - sqrt(0.25 * reynolds * reynolds + 4.0 * M_PI * M_PI);
59  bool pa = true;
60  bool ni = false;
61  bool visualization = false;
62  bool checkres = false;
63 } ctx;
64 
65 void vel_kovasznay(const Vector &x, double t, Vector &u)
66 {
67  double xi = x(0);
68  double yi = x(1);
69 
70  u(0) = 1.0 - exp(ctx.lam * xi) * cos(2.0 * M_PI * yi);
71  u(1) = ctx.lam / (2.0 * M_PI) * exp(ctx.lam * xi) * sin(2.0 * M_PI * yi);
72 }
73 
74 double pres_kovasznay(const Vector &x, double t)
75 {
76  double xi = x(0);
77 
78  return 0.5 * (1.0 - exp(2.0 * ctx.lam * xi)) + ctx.reference_pressure;
79 }
80 
81 int main(int argc, char *argv[])
82 {
83  MPI_Session mpi(argc, argv);
84 
85  OptionsParser args(argc, argv);
86  args.AddOption(&ctx.ser_ref_levels,
87  "-rs",
88  "--refine-serial",
89  "Number of times to refine the mesh uniformly in serial.");
90  args.AddOption(&ctx.order,
91  "-o",
92  "--order",
93  "Order (degree) of the finite elements.");
94  args.AddOption(&ctx.dt, "-dt", "--time-step", "Time step.");
95  args.AddOption(&ctx.t_final, "-tf", "--final-time", "Final time.");
96  args.AddOption(&ctx.pa,
97  "-pa",
98  "--enable-pa",
99  "-no-pa",
100  "--disable-pa",
101  "Enable partial assembly.");
102  args.AddOption(&ctx.ni,
103  "-ni",
104  "--enable-ni",
105  "-no-ni",
106  "--disable-ni",
107  "Enable numerical integration rules.");
108  args.AddOption(&ctx.visualization,
109  "-vis",
110  "--visualization",
111  "-no-vis",
112  "--no-visualization",
113  "Enable or disable GLVis visualization.");
114  args.AddOption(
115  &ctx.checkres,
116  "-cr",
117  "--checkresult",
118  "-no-cr",
119  "--no-checkresult",
120  "Enable or disable checking of the result. Returns -1 on failure.");
121  args.Parse();
122  if (!args.Good())
123  {
124  if (mpi.Root())
125  {
126  args.PrintUsage(mfem::out);
127  }
128  return 1;
129  }
130  if (mpi.Root())
131  {
132  args.PrintOptions(mfem::out);
133  }
134 
135  Mesh mesh = Mesh::MakeCartesian2D(2, 4, Element::QUADRILATERAL, false, 1.5,
136  2.0);
137 
138  mesh.EnsureNodes();
139  GridFunction *nodes = mesh.GetNodes();
140  *nodes -= 0.5;
141 
142  for (int i = 0; i < ctx.ser_ref_levels; ++i)
143  {
144  mesh.UniformRefinement();
145  }
146 
147  if (mpi.Root())
148  {
149  std::cout << "Number of elements: " << mesh.GetNE() << std::endl;
150  }
151 
152  auto *pmesh = new ParMesh(MPI_COMM_WORLD, mesh);
153  mesh.Clear();
154 
155  // Create the flow solver.
156  NavierSolver flowsolver(pmesh, ctx.order, ctx.kinvis);
157  flowsolver.EnablePA(ctx.pa);
158  flowsolver.EnableNI(ctx.ni);
159 
160  // Set the initial condition.
161  ParGridFunction *u_ic = flowsolver.GetCurrentVelocity();
162  VectorFunctionCoefficient u_excoeff(pmesh->Dimension(), vel_kovasznay);
163  u_ic->ProjectCoefficient(u_excoeff);
164 
166 
167  // Add Dirichlet boundary conditions to velocity space restricted to
168  // selected attributes on the mesh.
169  Array<int> attr(pmesh->bdr_attributes.Max());
170  attr = 1;
171  flowsolver.AddVelDirichletBC(vel_kovasznay, attr);
172 
173  double t = 0.0;
174  double dt = ctx.dt;
175  double t_final = ctx.t_final;
176  bool last_step = false;
177 
178  flowsolver.Setup(dt);
179 
180  double err_u = 0.0;
181  double err_p = 0.0;
182  ParGridFunction *u_gf = nullptr;
183  ParGridFunction *p_gf = nullptr;
184 
185  ParGridFunction p_ex_gf(flowsolver.GetCurrentPressure()->ParFESpace());
186  GridFunctionCoefficient p_ex_gf_coeff(&p_ex_gf);
187 
188  for (int step = 0; !last_step; ++step)
189  {
190  if (t + dt >= t_final - dt / 2)
191  {
192  last_step = true;
193  }
194 
195  flowsolver.Step(t, dt, step);
196 
197  // Compare against exact solution of velocity and pressure.
198  u_gf = flowsolver.GetCurrentVelocity();
199  p_gf = flowsolver.GetCurrentPressure();
200 
201  u_excoeff.SetTime(t);
202  p_excoeff.SetTime(t);
203 
204  // Remove mean value from exact pressure solution.
205  p_ex_gf.ProjectCoefficient(p_excoeff);
206  flowsolver.MeanZero(p_ex_gf);
207 
208  err_u = u_gf->ComputeL2Error(u_excoeff);
209  err_p = p_gf->ComputeL2Error(p_ex_gf_coeff);
210 
211  double cfl = flowsolver.ComputeCFL(*u_gf, dt);
212 
213  if (mpi.Root())
214  {
215  printf("%5s %8s %8s %8s %11s %11s\n",
216  "Order",
217  "CFL",
218  "Time",
219  "dt",
220  "err_u",
221  "err_p");
222  printf("%5.2d %8.2E %.2E %.2E %.5E %.5E err\n",
223  ctx.order,
224  cfl,
225  t,
226  dt,
227  err_u,
228  err_p);
229  fflush(stdout);
230  }
231  }
232 
233  if (ctx.visualization)
234  {
235  char vishost[] = "localhost";
236  int visport = 19916;
237  socketstream sol_sock(vishost, visport);
238  sol_sock.precision(8);
239  sol_sock << "parallel " << mpi.WorldSize() << " " << mpi.WorldRank()
240  << "\n";
241  sol_sock << "solution\n" << *pmesh << *u_ic << std::flush;
242  }
243 
244  flowsolver.PrintTimingData();
245 
246  // Test if the result for the test run is as expected.
247  if (ctx.checkres)
248  {
249  double tol_u = 1e-6;
250  double tol_p = 1e-5;
251  if (err_u > tol_u || err_p > tol_p)
252  {
253  if (mpi.Root())
254  {
255  mfem::out << "Result has a larger error than expected."
256  << std::endl;
257  }
258  return -1;
259  }
260  }
261 
262  delete pmesh;
263 
264  return 0;
265 }
int WorldSize() const
Return MPI_COMM_WORLD&#39;s size.
void PrintTimingData()
Print timing summary of the solving routine.
Class for grid function - Vector with associated FE space.
Definition: gridfunc.hpp:30
Coefficient defined by a GridFunction. This coefficient is mesh dependent.
int GetNE() const
Returns number of elements.
Definition: mesh.hpp:846
virtual void ProjectCoefficient(Coefficient &coeff)
Project coeff Coefficient to this GridFunction. The projection computation depends on the choice of t...
Definition: pgridfunc.cpp:493
void Setup(double dt)
Initialize forms, solvers and preconditioners.
void MeanZero(ParGridFunction &v)
Remove the mean from a ParGridFunction.
A simple convenience class that calls MPI_Init() at construction and MPI_Finalize() at destruction...
void Parse()
Parse the command-line options. Note that this function expects all the options provided through the ...
Definition: optparser.cpp:150
double ComputeCFL(ParGridFunction &u, double dt)
Compute CFL.
constexpr char vishost[]
void UniformRefinement(int i, const DSTable &, int *, int *, int *)
Definition: mesh.cpp:9143
constexpr int visport
ParGridFunction * GetCurrentPressure()
Return a pointer to the current pressure ParGridFunction.
bool Root() const
Return true if WorldRank() == 0.
void EnablePA(bool pa)
Enable partial assembly for every operator.
void AddVelDirichletBC(VectorCoefficient *coeff, Array< int > &attr)
Add a Dirichlet boundary condition to the velocity field.
void PrintUsage(std::ostream &out) const
Print the usage message.
Definition: optparser.cpp:457
void SetTime(double t)
Set the time for time dependent coefficients.
Definition: coefficient.hpp:48
A general vector function coefficient.
int WorldRank() const
Return MPI_COMM_WORLD&#39;s rank.
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 &#39;var&#39; to receive the value. Enable/disable tags are used to set the bool...
Definition: optparser.hpp:82
static Mesh MakeCartesian2D(int nx, int ny, Element::Type type, bool generate_edges=false, double sx=1.0, double sy=1.0, bool sfc_ordering=true)
Definition: mesh.cpp:3287
ParGridFunction * GetCurrentVelocity()
Return a pointer to the current velocity ParGridFunction.
virtual double ComputeL2Error(Coefficient *exsol[], const IntegrationRule *irs[]=NULL) const
Definition: pgridfunc.hpp:273
void PrintOptions(std::ostream &out) const
Print the options.
Definition: optparser.cpp:327
RefCoord t[3]
void Clear()
Clear the contents of the Mesh.
Definition: mesh.hpp:828
A general function coefficient.
Vector data type.
Definition: vector.hpp:60
void GetNodes(Vector &node_coord) const
Definition: mesh.cpp:7343
void Step(double &time, double dt, int cur_step, bool provisional=false)
Compute solution at the next time step t+dt.
double u(const Vector &xvec)
Definition: lor_mms.hpp:24
Class for parallel grid function.
Definition: pgridfunc.hpp:32
OutStream out(std::cout)
Global stream used by the library for standard output. Initially it uses the same std::streambuf as s...
Definition: globals.hpp:66
Class for parallel meshes.
Definition: pmesh.hpp:32
Transient incompressible Navier Stokes solver in a split scheme formulation.
int main()
void EnsureNodes()
Definition: mesh.cpp:4849
ParFiniteElementSpace * ParFESpace() const
Definition: pgridfunc.hpp:108
bool Good() const
Return true if the command line options were parsed successfully.
Definition: optparser.hpp:150