Canoe
Comprehensive Atmosphere N' Ocean Engine
radiation_band.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <sstream>
3 #include <stdexcept>
4 #include <type_traits>
5 #include <vector>
6 
7 // athena
8 #include <athena/mesh/mesh.hpp>
9 #include <athena/outputs/outputs.hpp>
10 #include <athena/parameter_input.hpp>
11 #include <athena/utils/utils.hpp>
12 
13 // canoe
14 #include <configure.hpp>
15 
16 // climath
17 #include <climath/core.h>
18 
19 // application
20 #include <application/application.hpp>
21 #include <application/exceptions.hpp>
22 
23 // utils
25 #include <utils/fileio.hpp>
26 #include <utils/ndarrays.hpp>
27 #include <utils/vectorize.hpp>
28 
29 // opacity
30 #include <opacity/absorber.hpp>
31 
32 // harp
33 #include "radiation.hpp"
34 #include "radiation_band.hpp"
35 #include "rt_solvers.hpp"
36 
37 RadiationBand::RadiationBand(std::string myname, YAML::Node const &rad)
38  : NamedGroup(myname) {
39  Application::Logger app("harp");
40  app->Log("Initialize RadiationBand " + myname);
41 
42  if (!rad[myname]) {
43  throw NotFoundError("RadiationBand", myname);
44  }
45 
46  auto my = rad[myname];
47 
48  if (my["parameters"]) {
49  SetRealsFrom(my["parameters"]);
50  }
51 
53 
54  wrange_ = pgrid_->ReadRangeFrom(my);
55 
56  if (my["outdir"]) {
57  std::string dirstr = my["outdir"].as<std::string>();
59  }
60 
61  // set absorbers
62  if (my["opacity"]) {
63  auto names = my["opacity"].as<std::vector<std::string>>();
65  }
66 
67  // set rt solver
68  if (my["rt-solver"]) {
69  psolver_ = CreateRTSolverFrom(my["rt-solver"].as<std::string>(), rad);
70  } else {
71  psolver_ = nullptr;
72  }
73 
74  char buf[80];
75  snprintf(buf, sizeof(buf), "%.2f - %.2f", wrange_.first, wrange_.second);
76  app->Log("Spectral range", buf);
77  app->Log("Number of spectral bins", pgrid_->spec.size());
78 }
79 
81  Application::Logger app("harp");
82  app->Log("Destroy RadiationBand " + GetName());
83 }
84 
85 void RadiationBand::Resize(int nc1, int nc2, int nc3, int nstr) {
86  // allocate memory for spectral properties
87  tem_.resize(nc1);
88  temf_.resize(nc1 + 1);
89 
90  tau_.NewAthenaArray(pgrid_->spec.size(), nc1);
91  tau_.ZeroClear();
92 
93  ssa_.NewAthenaArray(pgrid_->spec.size(), nc1);
94  ssa_.ZeroClear();
95 
96  toa_.NewAthenaArray(pgrid_->spec.size(), rayOutput_.size());
97  toa_.ZeroClear();
98 
99  pmom_.NewAthenaArray(pgrid_->spec.size(), nc1, nstr + 1);
100  pmom_.ZeroClear();
101 
102  flxup_.NewAthenaArray(pgrid_->spec.size(), nc1);
103  flxup_.ZeroClear();
104 
105  flxdn_.NewAthenaArray(pgrid_->spec.size(), nc1);
106  flxdn_.ZeroClear();
107 
108  // band properties
109  btau.NewAthenaArray(nc3, nc2, nc1);
110  bssa.NewAthenaArray(nc3, nc2, nc1);
111  bpmom.NewAthenaArray(nstr + 1, nc3, nc2, nc1);
112 
114 }
115 
116 void RadiationBand::ResizeSolver(int nlyr, int nstr, int nuphi, int numu) {
117  if (psolver_ != nullptr) psolver_->Resize(nlyr, nstr, nuphi, numu);
118 }
119 
121  for (auto &absorber : absorbers_) {
122  if (absorber->GetName() == name) {
123  return absorber;
124  }
125  }
126 
127  throw NotFoundError("RadiationBand", "Absorber " + name);
128 
129  return nullptr;
130 }
131 
132 void RadiationBand::CalBandFlux(MeshBlock const *pmb, int k, int j, int il,
133  int iu) {
134  // reset flux of this column
135  for (int i = il; i <= iu; ++i) {
136  bflxup(k, j, i) = 0.;
137  bflxdn(k, j, i) = 0.;
138  }
139 
140  psolver_->Prepare(pmb, k, j);
141  psolver_->CalBandFlux(pmb, k, j, il, iu);
142 }
143 
144 void RadiationBand::CalBandRadiance(MeshBlock const *pmb, int k, int j) {
145  // reset radiance of this column
146  for (int n = 0; n < GetNumOutgoingRays(); ++n) {
147  btoa(n, k, j) = 0.;
148  btoa(n, k, j) = 0.;
149  }
150 
151  psolver_->Prepare(pmb, k, j);
152  psolver_->CalBandRadiance(pmb, k, j);
153 }
154 
155 void RadiationBand::WriteAsciiHeader(OutputParameters const *pout) const {
157 
158  char fname[80], number[6];
159  snprintf(number, sizeof(number), "%05d", pout->file_number);
160  snprintf(fname, sizeof(fname), "%s.radiance.%s.txt", GetName().c_str(),
161  number);
162  FILE *pfile = fopen(fname, "w");
163 
164  fprintf(pfile, "# Bin Radiances of Band %s: %.3g - %.3g\n", GetName().c_str(),
165  wrange_.first, wrange_.second);
166  fprintf(pfile, "# Ray output size: %lu\n", rayOutput_.size());
167 
168  fprintf(pfile, "# Polar angles: ");
169  for (auto &ray : rayOutput_) {
170  fprintf(pfile, "%.3f", rad2deg(acos(ray.mu)));
171  }
172  fprintf(pfile, "\n");
173 
174  fprintf(pfile, "# Azimuthal angles: ");
175  for (auto &ray : rayOutput_) {
176  fprintf(pfile, "%.3f", rad2deg(ray.phi));
177  }
178  fprintf(pfile, "\n");
179 
180  fprintf(pfile, "#%12s%12s", "wave1", "wave2");
181  for (size_t j = 0; j < rayOutput_.size(); ++j) {
182  fprintf(pfile, "%12s%lu", "Radiance", j + 1);
183  }
184  fprintf(pfile, "%12s\n", "weight");
185 
186  fclose(pfile);
187 }
188 
189 void RadiationBand::WriteAsciiData(OutputParameters const *pout) const {
191 
192  char fname[80], number[6];
193  snprintf(number, sizeof(number), "%05d", pout->file_number);
194  snprintf(fname, sizeof(fname), "%s.radiance.%s.txt", GetName().c_str(),
195  number);
196  FILE *pfile = fopen(fname, "w");
197 
198  for (size_t i = 0; i < pgrid_->spec.size(); ++i) {
199  fprintf(pfile, "%13.3g%12.3g", pgrid_->spec[i].wav1, pgrid_->spec[i].wav2);
200  for (size_t j = 0; j < rayOutput_.size(); ++j) {
201  fprintf(pfile, "%12.3f", toa_(i, j));
202  }
204  (wrange_.first != wrange_.second)) {
205  fprintf(pfile, "%12.3g\n",
206  pgrid_->spec[i].wght / (wrange_.second - wrange_.first));
207  } else {
208  fprintf(pfile, "%12.3g\n", pgrid_->spec[i].wght);
209  }
210  }
211 
212  fclose(pfile);
213 }
214 
215 std::shared_ptr<RadiationBand::RTSolver> RadiationBand::CreateRTSolverFrom(
216  std::string const &rt_name, YAML::Node const &rad) {
217  std::shared_ptr<RTSolver> psolver;
218 
219  if (rt_name == "Lambert") {
220  psolver = std::make_shared<RTSolverLambert>(this, rad);
221 #ifdef RT_DISORT
222  } else if (rt_name == "Disort") {
223  psolver = std::make_shared<RTSolverDisort>(this, rad);
224 #endif // RT_DISORT
225  } else {
226  throw NotFoundError("RadiationBand", rt_name);
227  }
228 
229  return psolver;
230 }
231 
233  Application::Logger app("harp");
234  app->Log("Load Radiation bands from " + filename);
235 
236  std::vector<RadiationBandPtr> bands;
237 
238  std::ifstream stream(filename);
239  if (stream.good() == false) {
240  app->Error("Cannot open radiation bands file: " + filename);
241  }
242  YAML::Node rad = YAML::Load(stream);
243 
244  for (auto bname : rad["bands"]) {
245  auto p = std::make_shared<RadiationBand>(bname.as<std::string>(), rad);
246  bands.push_back(p);
247  }
248 
249  return bands;
250 }
251 
253  std::string key) {
254  std::vector<RadiationBandPtr> bands;
255 
256  auto rt_band_files =
257  Vectorize<std::string>(pin->GetOrAddString("radiation", key, "").c_str());
258 
259  for (auto &filename : rt_band_files) {
260  auto &&tmp = CreateFrom(filename);
261  bands.insert(bands.end(), tmp.begin(), tmp.end());
262  }
263 
264  return bands;
265 }
std::shared_ptr< Absorber > AbsorberPtr
Definition: absorber.hpp:70
static AbsorberPtr CreateFrom(YAML::Node const &my, std::string band_name)
Create an absorber from YAML node.
int TestFlag(uint64_t flag) const
std::string GetName() const
void SetRealsFrom(YAML::Node const &node)
void CalBandFlux(MeshBlock const *pmb, int k, int j, int il, int iu)
Calculate band radiative fluxes.
std::shared_ptr< Absorber > GetAbsorberByName(std::string const &name)
Get an individual absorber by name.
AthenaArray< Real > flxdn_
spectral bin downward flux
std::vector< Real > temf_
temperature at cell boundary (face)
std::pair< Real, Real > wrange_
identify wave- number (wavelength, frequency) range
AthenaArray< Real > bpmom
band phase function moments
void ResizeSolver(int nlyr, int nstr=8, int nuphi=1, int numu=1)
Allocate memory for radiation solver.
std::shared_ptr< RTSolver > psolver_
radiative transfer solver
AthenaArray< Real > pmom_
spectral bin phase function moments
size_t GetNumOutgoingRays()
Get number of outgoing rays.
std::shared_ptr< SpectralGridBase > pgrid_
spectral grid
AthenaArray< Real > toa_
spectral bin top-of-the-atmosphere radiance
void CalBandRadiance(MeshBlock const *pmb, int k, int j)
Calculate band radiances.
AthenaArray< Real > flxup_
spectral bin upward flux
AthenaArray< Real > btau
band optical depth
std::shared_ptr< RTSolver > CreateRTSolverFrom(std::string const &name, YAML::Node const &rad)
Create radiative transfer solver from YAML node.
AthenaArray< Real > bflxup
band upward flux
AthenaArray< Real > ssa_
spectral bin single scattering albedo
AthenaArray< Real > btoa
band top-of-the-atmosphere radiance
std::vector< Real > tem_
temperature at cell center
RadiationBand(std::string name, YAML::Node const &rad)
void WriteAsciiData(OutputParameters const *) const override
std::vector< std::shared_ptr< Absorber > > absorbers_
all absorbers
void Resize(int nc1, int nc2=1, int nc3=1, int nstr=8)
Allocate memory for radiation band.
AthenaArray< Real > tau_
spectral bin optical depth
AthenaArray< Real > bflxdn
band downward flux
void WriteAsciiHeader(OutputParameters const *) const override
std::vector< Direction > rayOutput_
outgoing rays
AthenaArray< Real > bssa
band single scattering albedo
virtual ~RadiationBand()
static RadiationBandContainer CreateFrom(ParameterInput *pin, std::string key)
static SpectralGridPtr CreateFrom(YAML::Node const &my)
double rad2deg(double phi)
Definition: core.h:40
const uint64_t WriteBinRadiance
Definition: radiation.hpp:95
const uint64_t Normalize
Definition: radiation.hpp:94
std::vector< Direction > parse_radiation_directions(std::string str)
Definition: radiation.cpp:195
std::vector< RadiationBandPtr > RadiationBandContainer