Canoe
Comprehensive Atmosphere N' Ocean Engine
k_epsilon_turbulence.cpp
Go to the documentation of this file.
1 // \brief implement K-Epsilon turbulence
3 
4 // C/C++ headers
5 #include <algorithm> // min,max
6 
7 // Athena++ headers
8 #include <athena/athena.hpp>
9 #include <athena/coordinates/coordinates.hpp>
10 #include <athena/hydro/hydro.hpp>
11 #include <athena/mesh/mesh.hpp>
12 
13 // snap
14 #include "turbulence_model.hpp"
15 
16 KEpsilonTurbulence::KEpsilonTurbulence(MeshBlock *pmb, ParameterInput *pin)
17  : TurbulenceModel(pmb, pin) {
18  cmu_ = pin->GetOrAddReal("turbulence", "kepsilon.cmu", 0.09);
19  c1_ = pin->GetOrAddReal("turbulence", "kepsilon.c1", 1.44);
20  c2_ = pin->GetOrAddReal("turbulence", "kepsilon.c2", 1.92);
21  sigk_ = pin->GetOrAddReal("turbulence", "kepsilon.sigk", 1.0);
22  sige_ = pin->GetOrAddReal("turbulence", "kepsilon.sige", 1.3);
23 
24  // velocity scale, v ~ 1 m/s, tke ~ v^2 ~ 1 m^2/s^2
25  Real tke0 = pin->GetOrAddReal("turbulence", "kepsilon.tke0", 1.);
26 
27  int il = pmb->is - NGHOST;
28  int jl = pmb->js;
29  int kl = pmb->ks;
30  int iu = pmb->ie + NGHOST;
31  int ju = pmb->je;
32  int ku = pmb->ke;
33  if (pmb->block_size.nx2 > 1) {
34  jl -= NGHOST;
35  ju += NGHOST;
36  }
37  if (pmb->block_size.nx3 > 1) {
38  kl -= NGHOST;
39  ku += NGHOST;
40  }
41 
42  for (int k = kl; k <= ku; ++k)
43  for (int j = jl; j <= ju; ++j)
44  for (int i = il; i <= iu; ++i) {
45  w(1, k, j, i) = tke0;
46  // eps ~ tke/T ~ v^2/(dx/v) ~ v^3/dx
47  Real volume = pmb->pcoord->GetCellVolume(k, j, i);
48  Real eps0 = pow(tke0, 1.5) / pow(volume, 1. / 3.);
49  w(0, k, j, i) = eps0;
50  }
51 }
52 
54  auto pmb = pmy_block;
55  auto phydro = pmb->phydro;
56 
57  for (int k = pmb->ks; k <= pmb->ke; ++k)
58  for (int j = pmb->js; j <= pmb->je; ++j)
59  for (int i = pmb->is; i <= pmb->ie; ++i) {
60  Real rhod = phydro->w(IDN, k, j, i);
61  u(0, k, j, i) = w(0, k, j, i) * rhod;
62  u(1, k, j, i) = w(1, k, j, i) * rhod;
63  mut(k, j, i) =
64  cmu_ * rhod * w(1, k, j, i) * w(1, k, j, i) / w(0, k, j, i);
65  }
66 }
67 
68 inline Real Laplace_(AthenaArray<Real> const &mut, AthenaArray<Real> const &v,
69  int k, int j, int i, Coordinates *pcoord) {
70  Real result = 0.;
71  Mesh *pm = pcoord->pmy_block->pmy_mesh;
72 
73  // first dimension
74  Real mut_p = (mut(k, j, i + 1) + mut(k, j, i)) / 2.;
75  Real mut_m = (mut(k, j, i) + mut(k, j, i - 1)) / 2.;
76  Real gradv_p =
77  (v(k, j, i + 1) - v(k, j, i)) / (pcoord->x1v(i + 1) - pcoord->x1v(i));
78  Real gradv_m =
79  (v(k, j, i) - v(k, j, i - 1)) / (pcoord->x1v(i) - pcoord->x1v(i - 1));
80  result += (mut_p * gradv_p - mut_m * gradv_m) / pcoord->dx1f(i);
81 
82  // second dimension
83  if (pm->f2) {
84  mut_p = (mut(k, j + 1, i) + mut(k, j, i)) / 2.;
85  mut_m = (mut(k, j, i) + mut(k, j - 1, i)) / 2.;
86  gradv_p =
87  (v(k, j + 1, i) - v(k, j, i)) / (pcoord->x2v(j + 1) - pcoord->x2v(j));
88  gradv_m =
89  (v(k, j, i) - v(k, j - 1, i)) / (pcoord->x2v(j) - pcoord->x2v(j - 1));
90  result += (mut_p * gradv_p - mut_m * gradv_m) / pcoord->dx2f(j);
91  }
92 
93  // third dimension
94  if (pm->f3) {
95  mut_p = (mut(k + 1, j, i) + mut(k, j, i)) / 2.;
96  mut_m = (mut(k, j, i) + mut(k - 1, j, i)) / 2.;
97  gradv_p =
98  (v(k + 1, j, i) - v(k, j, i)) / (pcoord->x3v(k + 1) - pcoord->x3v(k));
99  gradv_m =
100  (v(k, j, i) - v(k - 1, j, i)) / (pcoord->x3v(k) - pcoord->x3v(k - 1));
101  result += (mut_p * gradv_p - mut_m * gradv_m) / pcoord->dx3f(k);
102  }
103 
104  return result;
105 }
106 
107 inline Real ShearProduction_(AthenaArray<Real> const &w, int k, int j, int i,
108  Coordinates *pcoord) {
109  Real result = 0.;
110  Mesh *pm = pcoord->pmy_block->pmy_mesh;
111  Real gradv, gradv1, gradv2, gradv3, gradv4;
112 
113  // first dimension
114  gradv = (w(IM1, k, j, i + 1) - w(IM1, k, j, i - 1)) /
115  (pcoord->x1v(i + 1) - pcoord->x1v(i - 1));
116  result += 2 * gradv * gradv;
117 
118  // second dimension
119  if (pm->f2) {
120  gradv = (w(IM2, k, j + 1, i) - w(IM2, k, j - 1, i)) /
121  (pcoord->x2v(j + 1) - pcoord->x2v(j - 1));
122  gradv1 = (w(IM1, k, j + 1, i) - w(IM1, k, j - 1, i)) /
123  (pcoord->x2v(j + 1) - pcoord->x2v(j - 1));
124  gradv2 = (w(IM2, k, j, i + 1) - w(IM2, k, j, i - 1)) /
125  (pcoord->x1v(i + 1) - pcoord->x1v(i - 1));
126  result += 2 * gradv * gradv + (gradv1 + gradv2) * (gradv1 + gradv2);
127  }
128 
129  // thrid dimension
130  if (pm->f3) {
131  gradv = (w(IM3, k + 1, j, i) - w(IM3, k - 1, j, i)) /
132  (pcoord->x3v(k + 1) - pcoord->x3v(k - 1));
133  gradv1 = (w(IM1, k + 1, j, i) - w(IM1, k - 1, j, i)) /
134  (pcoord->x3v(k + 1) - pcoord->x3v(k - 1));
135  gradv2 = (w(IM3, k, j, i + 1) - w(IM3, k, j, i - 1)) /
136  (pcoord->x1v(i + 1) - pcoord->x1v(i - 1));
137  gradv3 = (w(IM2, k + 1, j, i) - w(IM2, k - 1, j, i)) /
138  (pcoord->x3v(k + 1) - pcoord->x3v(k - 1));
139  gradv4 = (w(IM3, k, j + 1, i) - w(IM3, k, j - 1, i)) /
140  (pcoord->x2v(j + 1) - pcoord->x2v(j - 1));
141  result += 2 * gradv * gradv + (gradv1 + gradv2) * (gradv1 + gradv2) +
142  (gradv3 + gradv4) * (gradv3 + gradv4);
143  }
144 
145  return result;
146 }
147 
149  // std::cout << "driving turbulence" << std::endl;
150  auto pmb = pmy_block;
151  auto phydro = pmb->phydro;
152 
153  int ks = pmb->ks, js = pmb->js, is = pmb->is;
154  int ke = pmb->ke, je = pmb->je, ie = pmb->ie;
155 
156  AthenaArray<Real> eps, tke;
157  eps.InitWithShallowSlice(w, 4, 0, 1);
158  tke.InitWithShallowSlice(w, 4, 1, 1);
159 
160  Real s1, s2, s3;
161  for (int k = ks; k <= ke; ++k)
162  for (int j = js; j <= je; ++j)
163  for (int i = is; i <= ie; ++i) {
164  Real rhod = phydro->w(IDN, k, j, i);
165  // shear production
166  Real shear = ShearProduction_(w, k, j, i, pmb->pcoord);
167  // std::cout << "shear = " << shear << std::endl;
168 
169  // turbulent dissipation, de/dt, eq2.2-1
170  s1 = c1_ * mut(k, j, i) * eps(k, j, i) / tke(k, j, i) * shear;
171  s2 = Laplace_(mut, eps, k, j, i, pmb->pcoord) / sige_;
172  s3 = -c2_ * eps(k, j, i) * eps(k, j, i) / tke(k, j, i) * rhod;
173  u(0, k, j, i) += (s1 + s2) * dt;
174  if (u(0, k, j, i) + s3 * dt > 0)
175  u(0, k, j, i) += s3 * dt;
176  else
177  u(0, k, j, i) /= 2.;
178  // std::cout << "u = " << u(0,k,j,i) << std::endl;
179 
180  // turbulent kinetic energy, dk/dt, eq 2.2-2
181  s1 = mut(k, j, i) * shear;
182  s2 = Laplace_(mut, tke, k, j, i, pmb->pcoord) / sigk_;
183  s3 = -eps(k, j, i) * rhod;
184  u(1, k, j, i) += (s1 + s2) * dt;
185  if (u(1, k, j, i) + s3 * dt > 0.)
186  u(1, k, j, i) += s3 * dt;
187  else
188  u(1, k, j, i) /= 2.;
189  }
190 }
191 
193  AthenaArray<Real> &kappa,
194  const AthenaArray<Real> &prim,
195  const AthenaArray<Real> &bcc, int il,
196  int iu, int jl, int ju, int kl,
197  int ku) {
198  AthenaArray<Real> eps, tke;
199  eps.InitWithShallowSlice(w, 4, 0, 1);
200  tke.InitWithShallowSlice(w, 4, 1, 1);
201 
202  for (int k = kl; k <= ku; ++k) {
203  for (int j = jl; j <= ju; ++j) {
204 #pragma omp simd
205  for (int i = il; i <= iu; ++i) {
206  // dynamic turbulent diffusivity
207  mut(k, j, i) = cmu_ * prim(IDN, k, j, i) * tke(k, j, i) * tke(k, j, i) /
208  eps(k, j, i);
209 
210  // kinematic turbulent viscosity, mu_t = c_mu*k^2/epsilon, eq2.2-3
211  nu(HydroDiffusion::DiffProcess::iso, k, j, i) =
212  mut(k, j, i) / prim(IDN, k, j, i);
213  kappa(HydroDiffusion::DiffProcess::iso, k, j, i) =
214  nu(HydroDiffusion::DiffProcess::iso, k, j, i);
215  }
216  }
217  }
218 }
KEpsilonTurbulence(MeshBlock *pmb, ParameterInput *pin)
void SetDiffusivity(AthenaArray< Real > &nu, AthenaArray< Real > &kappa, const AthenaArray< Real > &w, const AthenaArray< Real > &bc, int il, int iu, int jl, int ju, int kl, int ku)
AthenaArray< Real > u
MeshBlock * pmy_block
AthenaArray< Real > mut
AthenaArray< Real > w
Real ShearProduction_(AthenaArray< Real > const &w, int k, int j, int i, Coordinates *pcoord)
Real Laplace_(AthenaArray< Real > const &mut, AthenaArray< Real > const &v, int k, int j, int i, Coordinates *pcoord)