9 #include <yaml-cpp/yaml.h>
12 #include <athena/coordinates/coordinates.hpp>
13 #include <athena/mesh/mesh.hpp>
16 #include <application/application.hpp>
17 #include <application/exceptions.hpp>
20 #include <configure.hpp>
32 RadiationBand::RTSolverDisort::RTSolverDisort(
RadiationBand *pmy_band,
33 YAML::Node
const &rad)
34 : RTSolver(pmy_band,
"Disort") {
35 if (rad[
"Disort"]) setFlagsFromNode(rad[
"Disort"]);
39 void RadiationBand::RTSolverDisort::Resize(
int nlyr,
int nstr,
int nuphi,
41 SetAtmosphereDimension(nlyr, nstr, nstr, nstr);
42 SetIntensityDimension(nuphi, 1, numu);
49 SetUserAzimuthalAngle(&uphi, 1);
50 SetUserOpticalDepth(&utau, 1);
51 SetUserCosinePolarAngle(&umu, 1);
69 void RadiationBand::RTSolverDisort::Prepare(MeshBlock
const *pmb,
int k,
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;
78 Real
time = pmb->pmy_mesh->time;
81 ray = planet->ParentZenithAngle(
time, pcoord->x2v(
j), pcoord->x3v(k));
82 dist_au = planet->ParentDistanceInAu(
time);
84 ray = pmb->pimpl->prad->GetRayInput(0);
85 dist_au = pmb->pimpl->GetDistanceInAu();
88 if (ds_.flag.ibcnd != 0) {
89 throw ValueError(
"RTSolverDisort::CalRadtranFlux",
"ibcnd", ds_.flag.ibcnd,
93 pmy_band_->Regroup(pmb, X1DIR);
94 myrank_in_column_ = pmy_band_->GetRankInGroup();
97 if (ds_.flag.planck) {
98 pmy_band_->PackTemperature();
99 pmy_band_->Transfer(pmb, 0);
100 pmy_band_->UnpackTemperature(&ds_);
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];
116 ds_.bc.fbeam = planet->ParentInsolationFlux(wmin, wmax, dist_au);
122 pmb->pcoord->Face1Area(k,
j, pmb->is, pmb->ie + 1, farea_);
123 pmb->pcoord->CellVolume(k,
j, pmb->is, pmb->ie, vol_);
128 void RadiationBand::RTSolverDisort::CalBandFlux(MeshBlock
const *pmb,
int k,
129 int j,
int il,
int iu) {
132 dist_au = pmb->pimpl->planet->ParentDistanceInAu(
time);
134 dist_au = pmb->pimpl->GetDistanceInAu();
139 for (
auto &spec : pmy_band_->pgrid_->spec) {
143 ds_.bc.fbeam = pmb->pimpl->planet->ParentInsolationFlux(
144 spec.wav1, spec.wav2, dist_au);
147 ds_.wvnmlo = spec.wav1;
148 ds_.wvnmhi = spec.wav2;
152 pmy_band_->PackSpectralGrid(
b);
153 pmy_band_->Transfer(pmb, 1);
154 pmy_band_->UnpackSpectralGrid(&ds_);
157 c_disort(&ds_, &ds_out_);
160 addDisortFlux(pmb->pcoord,
b++, k,
j, il, iu);
164 void RadiationBand::RTSolverDisort::addDisortFlux(
Coordinates const *pcoord,
165 int n,
int k,
int j,
int il,
167 auto &bflxup = pmy_band_->bflxup;
168 auto &bflxdn = pmy_band_->bflxdn;
170 auto &flxup = pmy_band_->flxup_;
171 auto &flxdn = pmy_band_->flxdn_;
172 auto &spec = pmy_band_->pgrid_->spec;
175 for (
int i = il; i <= iu; ++i) {
176 int m = ds_.nlyr - (myrank_in_column_ * (iu - il) + i - il);
180 flxup(n, i) = ds_out_.rad[m].flup;
185 flxdn(n, i) = ds_out_.rad[m].rfldir + ds_out_.rad[m].rfldn;
187 bflxup(k,
j, i) += spec[n].wght * flxup(n, i);
188 bflxdn(k,
j, i) += spec[n].wght * flxdn(n, i);
198 Real bflxup1 = bflxup(k,
j, iu);
199 Real bflxdn1 = bflxdn(k,
j, iu);
201 for (
int i = iu - 1; i >= il; --i) {
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);
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);
214 void RadiationBand::RTSolverDisort::CalBandRadiance(MeshBlock
const *pmb,
int k,
216 if (ds_.flag.onlyfl) {
217 throw RuntimeError(
"RTSolverDisort::CalBandRadiance",
218 "Only flux calculation is requested");
222 throw RuntimeError(
"RTSolverDisort::CalBandRadiance",
223 "Only toa radiance (ds.ntau = 1) is supported");
226 int nrays = ds_.nphi * ds_.ntau * ds_.numu;
228 if (nrays != pmy_band_->GetNumOutgoingRays()) {
229 throw RuntimeError(
"RTSolverDisort::CalBandRadiance",
230 "Number of outgoing rays does not match");
235 dist_au = pmb->pimpl->planet->ParentDistanceInAu(
time);
237 dist_au = pmb->pimpl->GetDistanceInAu();
242 for (
auto &spec : pmy_band_->pgrid_->spec) {
246 ds_.bc.fbeam = pmb->pimpl->planet->ParentInsolationFlux(
247 spec.wav1, spec.wav2, dist_au);
250 ds_.wvnmlo = spec.wav1;
251 ds_.wvnmhi = spec.wav2;
255 pmy_band_->PackSpectralGrid(
b);
256 pmy_band_->Transfer(pmb, 1);
257 pmy_band_->UnpackSpectralGrid(&ds_);
260 c_disort(&ds_, &ds_out_);
263 addDisortRadiance(pmb->pcoord,
b++, k,
j);
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;
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];
const uint64_t CorrelatedK