Canoe
Comprehensive Atmosphere N' Ocean Engine
latent_heating.cpp
Go to the documentation of this file.
1 #include "../coordinates/coordinates.hpp"
2 #include "../hydro/hydro.hpp"
3 #include "../hydro/srcterms/hydro_srcterms.hpp"
4 #include "../thermodynamics/thermodynamics.hpp"
5 #include "diagnostics.hpp"
6 
7 LatentHeating::LatentHeating(MeshBlock *pmb) : Diagnostics(pmb, "Lvheating") {
8  type = "SCALARS";
9  grid = "--C";
10  long_name = "Latent Heating";
11  units = "W/m^3";
12  data.NewAthenaArray(1, 1, 1, ncells1_);
13 }
14 
15 LatentHeating::~LatentHeating() { data.DeleteAthenaArray(); }
16 
17 void LatentHeating::Progress(AthenaArray<Real> const &w) {
18  MeshBlock *pmb = pmy_block_;
19  Hydro *phydro = pmb->phydro;
20  Coordinates *pcoord = pmb->pcoord;
21  Thermodynamics *pthermo = pmb->pthermo;
22 
23  int is = pmb->is, js = pmb->js, ks = pmb->ks;
24  int ie = pmb->ie, je = pmb->je, ke = pmb->ke;
25  int iH2O = 1, iH2Oc = 3, iH2Op = 5;
26 
27  AthenaArray<Real> &x1flux = phydro->flux[X1DIR];
28  AthenaArray<Real> &x2flux = phydro->flux[X2DIR];
29  AthenaArray<Real> &x3flux = phydro->flux[X3DIR];
30 
31  if (ncycle == 0) {
32  std::fill(data.data(), data.data() + data.GetSize(), 0.);
33  }
34 
35  for (int k = ks; k <= ke; ++k)
36  for (int j = js; j <= je; ++j) {
37  pcoord->CellVolume(k, j, is, ie, vol_);
38  for (int i = is; i <= ie; ++i) {
39  // mass flux divergence of water cloud, and droplets
40  Real div = 0.;
41  // surface area
42  Real x1area_l, x1area_r, x2area_l, x2area_r, x3area_l, x3area_r;
43  // calculate area of each interface
44  x1area_l = pcoord->GetFace1Area(k, j, i);
45  x1area_r = pcoord->GetFace1Area(k, j, i + 1);
46  x2area_l = pcoord->GetFace2Area(k, j, i);
47  x2area_r = pcoord->GetFace2Area(k, j + 1, i);
48  x3area_l = pcoord->GetFace3Area(k, j, i);
49  x3area_r = pcoord->GetFace3Area(k + 1, j, i);
50  // calculate local mass flux divergence of water [kg/(m^3 s)]
51  div = (x1area_r * x1flux(iH2O, k, j, i + 1) -
52  x1area_l * x1flux(iH2O, k, j, i)) +
53  (x2area_r * x2flux(iH2O, k, j + 1, i) -
54  x2area_l * x2flux(iH2O, k, j, i)) +
55  (x3area_r * x3flux(iH2O, k + 1, j, i) -
56  x3area_l * x3flux(iH2O, k, j, i));
57  // data(n,k,j,i) = -div/pcoord->GetCellVolume(k,j,i);
58  div /= -vol_(i);
59  // calculate vapor, cloud, and precip changes, dq/dt [kg/(m^3 s)]
60  Real dqdt = (w(iH2O, k, j, i) * w(IDN, k, j, i) -
61  pmb->ruser_meshblock_data[4](iH2O, k, j, i)) /
62  pmb->pmy_mesh->dt;
63  // local tendency due to chemistry (evaporation and autoconversion)
64  // data(n,k,j,i) = dqdt-data(n,k,j,i);
65  Real Lv =
66  2.2E6; // pthermo->GetLatent(iH2O,pthermo->Temp(w.at(k,j,i)));
67  data(i) -= Lv * (dqdt - div) * vol_(i);
68  pmb->ruser_meshblock_data[4](iH2O, k, j, i) =
69  w(iH2O, k, j, i) * w(IDN, k, j, i);
70  }
71  }
72  ncycle++;
73 }
74 
75 void LatentHeating::Finalize(AthenaArray<Real> const &w) {
76  MeshBlock *pmb = pmy_block_;
77 
78  int is = pmb->is, js = pmb->js, ks = pmb->ks;
79  int ie = pmb->ie, je = pmb->je, ke = pmb->ke;
80 
81  Real *total_vol = new Real[ncells1_];
82  std::fill(total_vol, total_vol + ncells1_, 0.);
83  // calculate total volume
84  for (int k = ks; k <= ke; ++k)
85  for (int j = js; j <= je; ++j) {
86  pmb->pcoord->CellVolume(k, j, is, ie, vol_);
87  for (int i = is; i <= ie; ++i) total_vol[i] += vol_(i);
88  }
89 
90  // take time and spatial average
91  if (ncycle > 0) {
92  // sum over all ranks
93 #ifdef MPI_PARALLEL
94  MPI_Allreduce(MPI_IN_PLACE, data.data(), data.GetSize(), MPI_ATHENA_REAL,
95  MPI_SUM, MPI_COMM_WORLD);
96  MPI_Allreduce(MPI_IN_PLACE, total_vol, ncells1_, MPI_ATHENA_REAL, MPI_SUM,
97  MPI_COMM_WORLD);
98 #endif
99  for (int i = is; i <= ie; ++i) {
100  data(i) /= ncycle * total_vol[i];
101  }
102  }
103 
104  // clear cycle;
105  delete[] total_vol;
106  ncycle = 0;
107 }