Canoe
Comprehensive Atmosphere N' Ocean Engine
change_to_buoyancy.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <iomanip>
3 #include <sstream>
4 
5 // athena
6 #include <athena/coordinates/coordinates.hpp>
7 #include <athena/hydro/hydro.hpp>
8 #include <athena/stride_iterator.hpp>
9 
10 // canoe
11 #include <air_parcel.hpp>
12 #include <impl.hpp>
13 
14 // utils
15 #include <utils/ndarrays.hpp>
16 
17 // snap
18 #include "../thermodynamics/thermodynamics.hpp"
19 #include "decomposition.hpp"
20 
22  AthenaArray<Real> const &w, Coordinates *pco,
23  Real grav, int kl, int ku, int jl, int ju,
24  int il, int iu) {
25  for (int k = kl; k <= ku; ++k)
26  for (int j = jl; j <= ju; ++j)
27  for (int i = iu; i >= il; --i)
28  psf(k, j, i) = psf(k, j, i + 1) + grav * w(IDN, k, j, i) * pco->dx1f(i);
29 }
30 
32  int jl, int ju) {
33  auto pmb = pmy_block_;
34  auto pco = pmb->pcoord;
35  auto pthermo = Thermodynamics::GetInstance();
36 
37  Real grav = -pmb->phydro->hsrc.GetG1(); // positive downward pointing
38 
39  int is = pmb->is, ie = pmb->ie;
40 
41  if (grav == 0.) return;
42 
43  std::stringstream msg;
44  if (NGHOST < 3) {
45  msg << "### FATAL ERROR in function [Hydro::DecomposePressure]" << std::endl
46  << "number of ghost cells (NGHOST) must be at least 3" << std::endl;
47  ATHENA_ERROR(msg);
48  }
49 
50  FindNeighbors();
51 
52  if (has_top_neighbor) {
53  RecvFromTop(psf_, kl, ku, jl, ju);
54  } else {
55  // adiabatic extrapolation
56  for (int k = kl; k <= ku; ++k)
57  for (int j = jl; j <= ju; ++j) {
58  Real dz = pco->dx1f(ie);
59  auto &&var = AirParcelHelper::gather_from_primitive(pmb, k, j, ie);
60 
61  // adiabatic extrapolation for half a grid
62  pthermo->Extrapolate(&var, dz / 2.,
64 
65  psf_(k, j, ie + 1) = var.w[IPR];
66  }
67  }
68  IntegrateDownwards(psf_, w, pco, grav, kl, ku, jl, ju, is, ie);
69 
70  if (has_bot_neighbor) SendToBottom(psf_, kl, ku, jl, ju);
71 
72  // decompose pressure
73  for (int k = kl; k <= ku; ++k)
74  for (int j = jl; j <= ju; ++j) {
75  // save pressure and density
76  for (int i = is - NGHOST; i <= ie + NGHOST; ++i) {
77  pres_(k, j, i) = w(IPR, k, j, i);
78  dens_(k, j, i) = w(IDN, k, j, i);
79  }
80  // decompose pressure and density
81  for (int i = is; i <= ie; ++i) {
82  Real psv;
83  // interpolate hydrostatic pressure, prevent divided by zero
84  if (fabs(psf_(k, j, i) - psf_(k, j, i + 1)) < 1.E-6)
85  psv = (psf_(k, j, i) + psf_(k, j, i + 1)) / 2.;
86  else
87  psv = (psf_(k, j, i) - psf_(k, j, i + 1)) /
88  log(psf_(k, j, i) / psf_(k, j, i + 1));
89  w(IPR, k, j, i) -= psv;
90 
91  w(IDN, k, j, i) = (pres_(k, j, i - 1) - pres_(k, j, i + 1)) /
92  (pco->x1v(i + 1) - pco->x1v(i - 1)) -
93  dens_(k, j, i) * grav;
94  }
95 
96  // fix boundary condition
97  if (pmb->pbval->block_bcs[inner_x1] != BoundaryFlag::block)
98  w(IDN, k, j, is) = (pres_(k, j, is) - pres_(k, j, is + 1)) /
99  (pco->x1v(is + 1) - pco->x1v(is)) -
100  sqrt(dens_(k, j, is) * dens_(k, j, is + 1)) * grav;
101 
102  if (pmb->pbval->block_bcs[outer_x1] != BoundaryFlag::block)
103  w(IDN, k, j, ie) = (pres_(k, j, ie - 1) - pres_(k, j, ie)) /
104  (pco->x1v(ie) - pco->x1v(ie - 1)) -
105  sqrt(dens_(k, j, ie) * dens_(k, j, ie - 1)) * grav;
106  }
107 
108  SyncNewVariables(w, kl, ku, jl, ju);
109  ApplyHydroBoundary(w, psf_, kl, ku, jl, ju);
110 
111  /* debug
112  if (Globals::my_rank == 0) {
113  //int km = (kl + ku)/2;
114  //int jm = (jl + ju)/2;
115  int km = ku;
116  int jm = ju;
117  std::cout << "my.gid = " << pmb->gid << std::endl;
118  std::cout << "bblock.gid = " << bblock.snb.gid << std::endl;
119  std::cout << "===== k = " << km << " j = " << jm << std::endl;
120  for (int i = is - NGHOST; i <= ie + NGHOST; ++i) {
121  if (i == is)
122  std::cout << "-------- ";
123  if (i == 0)
124  std::cout << "i = " << "-1/2 ";
125  else if (i == 1)
126  std::cout << "i = " << "+1/2 ";
127  else
128  std::cout << "i = " << i-1 << "+1/2 ";
129  std::cout << "psf = " << std::setprecision(8) << psf_(km,jm,i) <<
130  std::endl; std::cout << "i = " << i << " "; std::cout << " pre = " <<
131  w(IPR,km,jm,i) << " den = " << w(IDN,km,jm,i) << std::endl; if (i == ie)
132  std::cout << "-------- ";
133  if (i == ie + NGHOST) {
134  std::cout << "i = " << i+1 << "+1/2 ";
135  std::cout << "psf = " << psf_(km,jm,i+1) << std::endl;
136  }
137  }
138  std::cout << "==========" << std::endl;
139  }*/
140 
141  // finish MPI communication
143  WaitToFinishSync(w, kl, ku, jl, ju);
144 }
145 
147  AthenaArray<Real> &wl,
148  AthenaArray<Real> &wr, int k, int j,
149  int il, int iu) {
150  auto pmb = pmy_block_;
151  auto pco = pmb->pcoord;
152  auto pthermo = Thermodynamics::GetInstance();
153 
154  Real grav = -pmb->phydro->hsrc.GetG1(); // positive downward pointing
155  int is = pmb->is, ie = pmb->ie;
156  if (grav == 0.) return;
157 
158  for (int i = is - NGHOST; i <= ie + NGHOST; ++i) {
159  w(IPR, k, j, i) = pres_(k, j, i);
160  w(IDN, k, j, i) = dens_(k, j, i);
161  }
162 
163  Real mdpdz;
164  for (int i = il; i <= iu; ++i) {
165  wr(IPR, i) += psf_(k, j, i);
166  if (wr(IPR, i) < 0.) wr(IPR, i) = psf_(k, j, i);
167 
168  wl(IPR, i + 1) += psf_(k, j, i + 1);
169  if (wl(IPR, i + 1) < 0.) wl(IPR, i + 1) = psf_(k, j, i + 1);
170 
171  mdpdz = (w(IPR, k, j, i - 1) - w(IPR, k, j, i)) /
172  (pco->x1v(i) - pco->x1v(i - 1));
173  wr(IDN, i) = (mdpdz - wr(IDN, i)) / grav;
174  if (wr(IDN, i) < 0.) wr(IDN, i) = mdpdz / grav;
175 
176  wl(IDN, i + 1) = (mdpdz - wl(IDN, i + 1)) / grav;
177  if (wl(IDN, i + 1) < 0.) wl(IDN, i + 1) = mdpdz / grav;
178  }
179 
180  // adiabatic extrapolation for a grid
181  Real dz = pco->dx1f(is);
182  auto &&air0 = AirParcelHelper::gather_from_primitive(pmb, k, j, is);
183  auto air1 = air0;
184  air1.ToMoleFraction();
185  pthermo->Extrapolate(&air1, -dz, Thermodynamics::Method::ReversibleAdiabat,
186  grav);
187 
188  mdpdz = (air1.w[IPR] - air0.w[IPR]) / dz;
189  if (pmb->pbval->block_bcs[inner_x1] == BoundaryFlag::reflect) {
190  for (int i = il + 1; i < is; ++i) {
191  wl(IDN, i) = wl(IDN, 2 * is - i);
192  wr(IDN, i) = wr(IDN, 2 * is - i);
193  }
194  wl(IDN, is) = (mdpdz - wl(IDN, is)) / grav;
195  wr(IDN, is) = (mdpdz - wr(IDN, is)) / grav;
196  } else if (pmb->pbval->block_bcs[inner_x1] == BoundaryFlag::outflow) {
197  for (int i = il + 1; i < is; ++i)
198  wl(IDN, i) = wr(IDN, i) = sqrt(w(IDN, k, j, i) * w(IDN, k, j, i - 1));
199  wl(IDN, is) = (mdpdz - wl(IDN, is)) / grav;
200  wr(IDN, is) = (mdpdz - wr(IDN, is)) / grav;
201  }
202 
203  // adiabatic extrapolation for a grid
204  air0 = AirParcelHelper::gather_from_primitive(pmb, k, j, ie);
205  air1 = air0;
206  air1.ToMoleFraction();
207  pthermo->Extrapolate(&air1, dz, Thermodynamics::Method::ReversibleAdiabat,
208  grav);
209 
210  mdpdz = (air0.w[IPR] - air1.w[IPR]) / dz;
211  if (pmb->pbval->block_bcs[outer_x1] == BoundaryFlag::reflect) {
212  for (int i = ie + 2; i <= iu + 1; ++i) {
213  wl(IDN, i) = wl(IDN, 2 * ie - i + 2);
214  wr(IDN, i) = wr(IDN, 2 * ie - i + 2);
215  }
216  wl(IDN, ie + 1) = (mdpdz - wl(IDN, ie + 1)) / grav;
217  wr(IDN, ie + 1) = (mdpdz - wr(IDN, ie + 1)) / grav;
218  } else if (pmb->pbval->block_bcs[outer_x1] == BoundaryFlag::outflow) {
219  for (int i = ie + 2; i <= iu + 1; ++i)
220  wl(IDN, i) = wr(IDN, i) = sqrt(w(IDN, k, j, i) * w(IDN, k, j, i - 1));
221  wl(IDN, ie + 1) = (mdpdz - wl(IDN, ie + 1)) / grav;
222  wr(IDN, ie + 1) = (mdpdz - wr(IDN, ie + 1)) / grav;
223  }
224 
225  /* debug
226  int km = (pmb->ks + pmb->ke)/2, jm = (pmb->js + pmb->je)/2;
227  if (Globals::my_rank == 0 && km == k & jm == j) {
228  std::cout << "my.gid = " << pmb->gid << std::endl;
229  std::cout << "bblock.gid = " << bblock.snb.gid << std::endl;
230  std::cout << "===== k = " << km << " j = " << jm << std::endl;
231  for (int i = il; i <= iu; ++i) {
232  if (i == is)
233  std::cout << "-------- ";
234  if (i == 0)
235  std::cout << "i = " << "-1/2 ";
236  else if (i == 1)
237  std::cout << "i = " << "+1/2 ";
238  else
239  std::cout << "i = " << i-1 << "+1/2 ";
240  std::cout << "psf = " << psf_(km,jm,i)
241  << " wl(IPR) = " << wl(IPR,i)
242  << " wr(IPR) = " << wr(IPR,i)
243  << " wl(IDN) = " << wl(IDN,i)
244  << " wr(IDN) = " << wr(IDN,i)
245  << std::endl;
246  std::cout << "i = " << i << " ";
247  std::cout << " pre = " << w(IPR,km,jm,i) << " den = " << w(IDN,km,jm,i) <<
248  std::endl; if (i == ie) std::cout << "-------- "; if (i == ie + NGHOST) {
249  std::cout << "i = " << i+1 << "+1/2 ";
250  std::cout << "psf = " << psf_(km,jm,i+1) << std::endl;
251  }
252  }
253  std::cout << "==========" << std::endl;
254  }*/
255 }
void IntegrateDownwards(AthenaArray< Real > &psf, AthenaArray< Real > const &w, Coordinates *pco, Real grav, int kl, int ku, int jl, int ju, int il, int iu)
AthenaArray< Real > psf_
MeshBlock * pmy_block_
AthenaArray< Real > pres_
AthenaArray< Real > dens_
void WaitToFinishSync(AthenaArray< Real > &w, int kl, int ku, int jl, int ju)
void ApplyHydroBoundary(AthenaArray< Real > &w, AthenaArray< Real > &psf, int kl, int ku, int jl, int ju)
void RecvFromTop(AthenaArray< Real > &psf, int kl, int ku, int jl, int ju)
void SyncNewVariables(AthenaArray< Real > const &w, int kl, int ku, int jl, int ju)
void WaitToFinishSend()
void RestoreFromBuoyancy(AthenaArray< Real > &w, AthenaArray< Real > &wl, AthenaArray< Real > &wr, int k, int j, int il, int iu)
void ChangeToBuoyancy(AthenaArray< Real > &w, int kl, int ku, int jl, int ju)
void FindNeighbors()
void SendToBottom(AthenaArray< Real > const &psf, int kl, int ku, int jl, int ju)
static Thermodynamics const * GetInstance()
Return a pointer to the one and only instance of Thermodynamics.
AirParcel gather_from_primitive(MeshBlock const *pmb, int k, int j, int i)
Definition: air_parcel.cpp:507