MFEM v4.7.0
Finite element discretization library
Loading...
Searching...
No Matches
navier_turbchan.cpp
Go to the documentation of this file.
1// Copyright (c) 2010-2024, 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// DNS of a channel flow at Re_tau = 180 (variable). A detailed description of
13// the test case can be found at [1]. Like described in the reference, the
14// initial condition is based on the Reichardt function.
15//
16// [1] https://how5.cenaero.be/content/ws2-les-plane-channel-ret550
17
18#include "navier_solver.hpp"
19#include <fstream>
20#include <cmath>
21
22using namespace mfem;
23using namespace navier;
24
25struct s_NavierContext
26{
27 int order = 5;
28 real_t Re_tau = 180.0;
29 real_t kin_vis = 1.0 / Re_tau;
30 real_t t_final = 50.0;
31 real_t dt = -1.0;
33
35{
36 real_t C = 1.8;
37 real_t delta = 1.0;
38
39 return delta * tanh(C * (2.0 * y - 1.0)) / tanh(C);
40}
41
42void accel(const Vector &x, real_t t, Vector &f)
43{
44 f(0) = 1.0;
45 f(1) = 0.0;
46 f(2) = 0.0;
47}
48
49void vel_ic_reichardt(const Vector &coords, real_t t, Vector &u)
50{
51 real_t yp;
52 real_t x = coords(0);
53 real_t y = coords(1);
54 real_t z = coords(2);
55
56 real_t C = 5.17;
57 real_t k = 0.4;
58 real_t eps = 1e-2;
59
60 if (y < 0)
61 {
62 yp = (1.0 + y) * ctx.Re_tau;
63 }
64 else
65 {
66 yp = (1.0 - y) * ctx.Re_tau;
67 }
68
69 u(0) = 1.0 / k * log(1.0 + k * yp) + (C - (1.0 / k) * log(k)) * (1 - exp(
70 -yp / 11.0) - yp / 11.0 * exp(-yp / 3.0));
71
72 real_t kx = 23.0;
73 real_t kz = 13.0;
74
75 real_t alpha = kx * 2.0 * M_PI / 2.0 * M_PI;
76 real_t beta = kz * 2.0 * M_PI / M_PI;
77
78 u(0) += eps * beta * sin(alpha * x) * cos(beta * z);
79 u(1) = eps * sin(alpha * x) * sin(beta * z);
80 u(2) = -eps * alpha * cos(alpha * x) * sin(beta * z);
81}
82
83void vel_wall(const Vector &x, real_t t, Vector &u)
84{
85 u(0) = 0.0;
86 u(1) = 0.0;
87 u(2) = 0.0;
88}
89
90int main(int argc, char *argv[])
91{
92 Mpi::Init();
94
95 real_t Lx = 2.0 * M_PI;
96 real_t Ly = 1.0;
97 real_t Lz = M_PI;
98
99 int N = ctx.order + 1;
100 int NL = static_cast<int>(std::round(64.0 / N)); // Coarse
101 // int NL = std::round(96.0 / N); // Baseline
102 // int NL = std::round(128.0 / N); // Fine
103 real_t LC = M_PI / NL;
104 int NX = 2 * NL;
105 int NY = 2 * static_cast<int>(std::round(48.0 / N));
106 int NZ = NL;
107
108 Mesh mesh = Mesh::MakeCartesian3D(NX, NY, NZ, Element::HEXAHEDRON, Lx, Ly, Lz);
109
110 for (int i = 0; i < mesh.GetNV(); ++i)
111 {
112 real_t *v = mesh.GetVertex(i);
113 v[1] = mesh_stretching_func(v[1]);
114 }
115
116 // Create translation vectors defining the periodicity
117 constexpr real_t zero = 0.0;
118 Vector x_translation({Lx, zero, zero});
119 Vector z_translation({zero, zero, Lz});
120 std::vector<Vector> translations = {x_translation, z_translation};
121
122 // Create the periodic mesh using the vertex mapping defined by the translation vectors
123 Mesh periodic_mesh = Mesh::MakePeriodic(mesh,
124 mesh.CreatePeriodicVertexMapping(translations));
125
126 if (Mpi::Root())
127 {
128 printf("NL=%d NX=%d NY=%d NZ=%d dx+=%f\n", NL, NX, NY, NZ, LC * ctx.Re_tau);
129 std::cout << "Number of elements: " << mesh.GetNE() << std::endl;
130 }
131
132 real_t hmin, hmax, kappa_min, kappa_max;
133 periodic_mesh.GetCharacteristics(hmin, hmax, kappa_min, kappa_max);
134
135 real_t umax = 22.0;
136 ctx.dt = 1.0 / pow(ctx.order, 1.5) * hmin / umax;
137
138 auto *pmesh = new ParMesh(MPI_COMM_WORLD, periodic_mesh);
139
140 // Create the flow solver.
141 NavierSolver flowsolver(pmesh, ctx.order, ctx.kin_vis);
142 flowsolver.EnablePA(true);
143
144 // Set the initial condition.
145 ParGridFunction *u_gf = flowsolver.GetCurrentVelocity();
146 ParGridFunction *p_gf = flowsolver.GetCurrentPressure();
147
148 VectorFunctionCoefficient u_ic_coef(pmesh->Dimension(), vel_ic_reichardt);
149 u_gf->ProjectCoefficient(u_ic_coef);
150
151 Array<int> domain_attr(pmesh->attributes);
152 domain_attr = 1;
153 flowsolver.AddAccelTerm(accel, domain_attr);
154
155 Array<int> attr(pmesh->bdr_attributes.Max());
156 attr[1] = 1;
157 attr[3] = 1;
158 flowsolver.AddVelDirichletBC(vel_wall, attr);
159
160 real_t t = 0.0;
161 real_t dt = ctx.dt;
162 real_t t_final = ctx.t_final;
163 bool last_step = false;
164
165 flowsolver.Setup(dt);
166
167 ParaViewDataCollection pvdc("turbchan", pmesh);
168 pvdc.SetDataFormat(VTKFormat::BINARY32);
169 pvdc.SetHighOrderOutput(true);
170 pvdc.SetLevelsOfDetail(ctx.order);
171 pvdc.SetCycle(0);
172 pvdc.SetTime(t);
173 pvdc.RegisterField("velocity", u_gf);
174 pvdc.RegisterField("pressure", p_gf);
175 pvdc.Save();
176
177 for (int step = 0; !last_step; ++step)
178 {
179 if (t + dt >= t_final - dt / 2)
180 {
181 last_step = true;
182 }
183
184 flowsolver.Step(t, dt, step);
185
186 if (step % 1000 == 0)
187 {
188 pvdc.SetCycle(step);
189 pvdc.SetTime(t);
190 pvdc.Save();
191 }
192
193 if (t > 5.0)
194 {
195 dt = 1e-2;
196 }
197
198 if (Mpi::Root())
199 {
200 printf("%11s %11s\n", "Time", "dt");
201 printf("%.5E %.5E\n", t, dt);
202 fflush(stdout);
203 }
204 }
205
206 flowsolver.PrintTimingData();
207
208 delete pmesh;
209
210 return 0;
211}
virtual void RegisterField(const std::string &field_name, GridFunction *gf)
Add a grid function to the collection.
void SetCycle(int c)
Set time cycle (for time-dependent simulations)
void SetTime(real_t t)
Set physical time (for time-dependent simulations)
static void Init()
Initialize hypre by calling HYPRE_Init() and set default options. After calling Hypre::Init(),...
Definition hypre.hpp:74
Mesh data type.
Definition mesh.hpp:56
int GetNE() const
Returns number of elements.
Definition mesh.hpp:1226
static Mesh MakeCartesian3D(int nx, int ny, int nz, Element::Type type, real_t sx=1.0, real_t sy=1.0, real_t sz=1.0, bool sfc_ordering=true)
Creates a mesh for the parallelepiped [0,sx]x[0,sy]x[0,sz], divided into nx*ny*nz hexahedra if type =...
Definition mesh.cpp:4253
void GetCharacteristics(real_t &h_min, real_t &h_max, real_t &kappa_min, real_t &kappa_max, Vector *Vh=NULL, Vector *Vk=NULL)
Definition mesh.cpp:202
int GetNV() const
Returns number of vertices. Vertices are only at the corners of elements, where you would expect them...
Definition mesh.hpp:1223
static Mesh MakePeriodic(const Mesh &orig_mesh, const std::vector< int > &v2v)
Create a periodic mesh by identifying vertices of orig_mesh.
Definition mesh.cpp:5457
std::vector< int > CreatePeriodicVertexMapping(const std::vector< Vector > &translations, real_t tol=1e-8) const
Creates a mapping v2v from the vertex indices of the mesh such that coincident vertices under the giv...
Definition mesh.cpp:5491
const real_t * GetVertex(int i) const
Return pointer to vertex i's coordinates.
Definition mesh.hpp:1265
static bool Root()
Return true if the rank in MPI_COMM_WORLD is zero.
static void Init(int &argc, char **&argv, int required=default_thread_required, int *provided=nullptr)
Singleton creation with Mpi::Init(argc, argv).
Class for parallel grid function.
Definition pgridfunc.hpp:33
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
Helper class for ParaView visualization data.
void SetHighOrderOutput(bool high_order_output_)
void SetLevelsOfDetail(int levels_of_detail_)
virtual void Save() override
void SetDataFormat(VTKFormat fmt)
A general vector function coefficient.
Vector data type.
Definition vector.hpp:80
Transient incompressible Navier Stokes solver in a split scheme formulation.
void Setup(real_t dt)
Initialize forms, solvers and preconditioners.
void AddVelDirichletBC(VectorCoefficient *coeff, Array< int > &attr)
Add a Dirichlet boundary condition to the velocity field.
ParGridFunction * GetCurrentPressure()
Return a pointer to the current pressure ParGridFunction.
void PrintTimingData()
Print timing summary of the solving routine.
void EnablePA(bool pa)
Enable partial assembly for every operator.
ParGridFunction * GetCurrentVelocity()
Return a pointer to the current velocity ParGridFunction.
void AddAccelTerm(VectorCoefficient *coeff, Array< int > &attr)
Add an acceleration term to the RHS of the equation.
void Step(real_t &time, real_t dt, int cur_step, bool provisional=false)
Compute solution at the next time step t+dt.
Vector beta
const real_t alpha
Definition ex15.cpp:369
int main()
real_t delta
Definition lissajous.cpp:43
real_t u(const Vector &xvec)
Definition lor_mms.hpp:22
float real_t
Definition config.hpp:43
std::function< real_t(const Vector &)> f(real_t mass_coeff)
Definition lor_mms.hpp:30
void vel_ic_reichardt(const Vector &coords, real_t t, Vector &u)
real_t mesh_stretching_func(const real_t y)
struct s_NavierContext ctx
void vel_wall(const Vector &x, real_t t, Vector &u)
void accel(const Vector &x, real_t t, Vector &f)
RefCoord t[3]