Canoe
Comprehensive Atmosphere N' Ocean Engine
rt_solver_disort.cpp
Go to the documentation of this file.
1 
4 // C/C++
5 #include <cmath>
6 #include <iostream>
7 
8 // external
9 #include <yaml-cpp/yaml.h>
10 
11 // athena
12 #include <athena/coordinates/coordinates.hpp>
13 #include <athena/mesh/mesh.hpp>
14 
15 // application
16 #include <application/application.hpp>
17 #include <application/exceptions.hpp>
18 
19 // canoe
20 #include <configure.hpp>
21 #include <impl.hpp>
22 
23 // astro
25 
26 // harp
27 #include "radiation.hpp"
28 #include "rt_solvers.hpp"
29 
30 #ifdef RT_DISORT
31 
32 RadiationBand::RTSolverDisort::RTSolverDisort(RadiationBand *pmy_band,
33  YAML::Node const &rad)
34  : RTSolver(pmy_band, "Disort") {
35  if (rad["Disort"]) setFlagsFromNode(rad["Disort"]);
36 }
37 
39 void RadiationBand::RTSolverDisort::Resize(int nlyr, int nstr, int nuphi,
40  int numu) {
41  SetAtmosphereDimension(nlyr, nstr, nstr, nstr);
42  SetIntensityDimension(nuphi, 1, numu);
43  Finalize();
44 
45  Real utau = 0.;
46  Real uphi = 0.;
47  Real umu = 1.;
48 
49  SetUserAzimuthalAngle(&uphi, 1);
50  SetUserOpticalDepth(&utau, 1);
51  SetUserCosinePolarAngle(&umu, 1);
52 }
53 
68 
69 void RadiationBand::RTSolverDisort::Prepare(MeshBlock const *pmb, int k,
70  int j) {
71  auto &wmin = pmy_band_->wrange_.first;
72  auto &wmax = pmy_band_->wrange_.second;
73  auto planet = pmb->pimpl->planet;
74  auto pcoord = pmb->pcoord;
75 
76  Direction ray;
77  Real dist_au;
78  Real time = pmb->pmy_mesh->time;
79 
80  if (pmy_band_->TestFlag(RadiationFlags::Dynamic)) {
81  ray = planet->ParentZenithAngle(time, pcoord->x2v(j), pcoord->x3v(k));
82  dist_au = planet->ParentDistanceInAu(time);
83  } else {
84  ray = pmb->pimpl->prad->GetRayInput(0);
85  dist_au = pmb->pimpl->GetDistanceInAu();
86  }
87 
88  if (ds_.flag.ibcnd != 0) {
89  throw ValueError("RTSolverDisort::CalRadtranFlux", "ibcnd", ds_.flag.ibcnd,
90  0);
91  }
92 
93  pmy_band_->Regroup(pmb, X1DIR);
94  myrank_in_column_ = pmy_band_->GetRankInGroup();
95 
96  // transfer temperature
97  if (ds_.flag.planck) {
98  pmy_band_->PackTemperature();
99  pmy_band_->Transfer(pmb, 0);
100  pmy_band_->UnpackTemperature(&ds_);
101  }
102 
103  // for (int i = 0; i <= ds_.nlyr; ++i)
104  // std::cout << ds_.temper[i] << std::endl;
105 
106  ds_.bc.umu0 = ray.mu > 1.E-3 ? ray.mu : 1.E-3;
107  ds_.bc.phi0 = ray.phi;
108  if (ds_.flag.planck) {
109  ds_.bc.btemp = ds_.temper[ds_.nlyr];
110  ds_.bc.ttemp = ds_.temper[0];
111  }
112 
113  if (pmy_band_->TestFlag(RadiationFlags::CorrelatedK)) {
114  // stellar source function
115  if (pmy_band_->TestFlag(RadiationFlags::Star))
116  ds_.bc.fbeam = planet->ParentInsolationFlux(wmin, wmax, dist_au);
117  // planck source function
118  ds_.wvnmlo = wmin;
119  ds_.wvnmhi = wmax;
120  }
121 
122  pmb->pcoord->Face1Area(k, j, pmb->is, pmb->ie + 1, farea_);
123  pmb->pcoord->CellVolume(k, j, pmb->is, pmb->ie, vol_);
124 
125  Finalize();
126 }
127 
128 void RadiationBand::RTSolverDisort::CalBandFlux(MeshBlock const *pmb, int k,
129  int j, int il, int iu) {
130  Real dist_au;
131  if (pmy_band_->TestFlag(RadiationFlags::Dynamic)) {
132  dist_au = pmb->pimpl->planet->ParentDistanceInAu(time);
133  } else {
134  dist_au = pmb->pimpl->GetDistanceInAu();
135  }
136 
137  // loop over spectral grids in the band
138  int b = 0;
139  for (auto &spec : pmy_band_->pgrid_->spec) {
140  if (!(pmy_band_->TestFlag(RadiationFlags::CorrelatedK))) {
141  // stellar source function
142  if (pmy_band_->TestFlag(RadiationFlags::Star)) {
143  ds_.bc.fbeam = pmb->pimpl->planet->ParentInsolationFlux(
144  spec.wav1, spec.wav2, dist_au);
145  }
146  // planck source function
147  ds_.wvnmlo = spec.wav1;
148  ds_.wvnmhi = spec.wav2;
149  }
150 
151  // transfer spectral grid data
152  pmy_band_->PackSpectralGrid(b);
153  pmy_band_->Transfer(pmb, 1);
154  pmy_band_->UnpackSpectralGrid(&ds_);
155 
156  // run disort
157  c_disort(&ds_, &ds_out_);
158 
159  // add spectral bin flux
160  addDisortFlux(pmb->pcoord, b++, k, j, il, iu);
161  }
162 }
163 
164 void RadiationBand::RTSolverDisort::addDisortFlux(Coordinates const *pcoord,
165  int n, int k, int j, int il,
166  int iu) {
167  auto &bflxup = pmy_band_->bflxup;
168  auto &bflxdn = pmy_band_->bflxdn;
169 
170  auto &flxup = pmy_band_->flxup_;
171  auto &flxdn = pmy_band_->flxdn_;
172  auto &spec = pmy_band_->pgrid_->spec;
173 
175  for (int i = il; i <= iu; ++i) {
176  int m = ds_.nlyr - (myrank_in_column_ * (iu - il) + i - il);
179  // flux up
180  flxup(n, i) = ds_out_.rad[m].flup;
181 
184  // flux down
185  flxdn(n, i) = ds_out_.rad[m].rfldir + ds_out_.rad[m].rfldn;
186 
187  bflxup(k, j, i) += spec[n].wght * flxup(n, i);
188  bflxdn(k, j, i) += spec[n].wght * flxdn(n, i);
189  }
190 
197  Real volh;
198  Real bflxup1 = bflxup(k, j, iu);
199  Real bflxdn1 = bflxdn(k, j, iu);
200 
201  for (int i = iu - 1; i >= il; --i) {
202  // upward
203  volh = (bflxup1 - bflxup(k, j, i)) / pcoord->dx1f(i) * vol_(i);
204  bflxup1 = bflxup(k, j, i);
205  bflxup(k, j, i) = (bflxup(k, j, i + 1) * farea_(i + 1) - volh) / farea_(i);
206 
207  // downward
208  volh = (bflxdn1 - bflxdn(k, j, i)) / pcoord->dx1f(i) * vol_(i);
209  bflxdn1 = bflxdn(k, j, i);
210  bflxdn(k, j, i) = (bflxdn(k, j, i + 1) * farea_(i + 1) - volh) / farea_(i);
211  }
212 }
213 
214 void RadiationBand::RTSolverDisort::CalBandRadiance(MeshBlock const *pmb, int k,
215  int j) {
216  if (ds_.flag.onlyfl) {
217  throw RuntimeError("RTSolverDisort::CalBandRadiance",
218  "Only flux calculation is requested");
219  }
220 
221  if (ds_.ntau != 1) {
222  throw RuntimeError("RTSolverDisort::CalBandRadiance",
223  "Only toa radiance (ds.ntau = 1) is supported");
224  }
225 
226  int nrays = ds_.nphi * ds_.ntau * ds_.numu;
227 
228  if (nrays != pmy_band_->GetNumOutgoingRays()) {
229  throw RuntimeError("RTSolverDisort::CalBandRadiance",
230  "Number of outgoing rays does not match");
231  }
232 
233  Real dist_au;
234  if (pmy_band_->TestFlag(RadiationFlags::Dynamic)) {
235  dist_au = pmb->pimpl->planet->ParentDistanceInAu(time);
236  } else {
237  dist_au = pmb->pimpl->GetDistanceInAu();
238  }
239 
240  // loop over spectral grids in the band
241  int b = 0;
242  for (auto &spec : pmy_band_->pgrid_->spec) {
243  if (!(pmy_band_->TestFlag(RadiationFlags::CorrelatedK))) {
244  // stellar source function
245  if (pmy_band_->TestFlag(RadiationFlags::Star)) {
246  ds_.bc.fbeam = pmb->pimpl->planet->ParentInsolationFlux(
247  spec.wav1, spec.wav2, dist_au);
248  }
249  // planck source function
250  ds_.wvnmlo = spec.wav1;
251  ds_.wvnmhi = spec.wav2;
252  }
253 
254  // transfer spectral grid data
255  pmy_band_->PackSpectralGrid(b);
256  pmy_band_->Transfer(pmb, 1);
257  pmy_band_->UnpackSpectralGrid(&ds_);
258 
259  // run disort
260  c_disort(&ds_, &ds_out_);
261 
262  // add spectral bin radiance
263  addDisortRadiance(pmb->pcoord, b++, k, j);
264  }
265 }
266 
267 void RadiationBand::RTSolverDisort::addDisortRadiance(Coordinates const *pcoord,
268  int b, int k, int j) {
269  auto &btoa = pmy_band_->btoa;
270  auto &spec = pmy_band_->pgrid_->spec;
271 
272  for (int c = 0; c < ds_.nphi * ds_.ntau * ds_.numu; ++c) {
273  btoa(c, k, j) += spec[b].wght * ds_out_.uu[c];
274  }
275 }
276 
277 #endif // RT_DISORT
const uint64_t Dynamic
Definition: radiation.hpp:87
const uint64_t Star
Definition: radiation.hpp:91
const uint64_t CorrelatedK
Definition: radiation.hpp:89
Real mu
Definition: common.hpp:5
Real phi
Definition: common.hpp:5