Canoe
Comprehensive Atmosphere N' Ocean Engine
hitran_absorber.cpp
Go to the documentation of this file.
1 // C/C++
2 #include <algorithm>
3 #include <cmath>
4 #include <cstring>
5 #include <iostream>
6 #include <stdexcept>
7 #include <string>
8 
9 // canoe
10 #include <air_parcel.hpp>
11 #include <configure.hpp>
12 #include <constants.hpp>
13 
14 // climath
15 #include <climath/interpolation.h>
16 
17 // athena
18 #include <athena/athena.hpp>
19 
20 // harp
21 #include "hitran_absorber.hpp"
22 
23 // netcdf
24 #ifdef NETCDFOUTPUT
25 extern "C" {
26 #include <netcdf.h>
27 }
28 #endif
29 
30 std::ostream &operator<<(std::ostream &os, HitranAbsorber const &ab) {
31  for (int i = 0; i < 3; ++i) {
32  os << "Axis " << i << " = " << ab.len_[i] << std::endl;
33  if (i == 0) {
34  os << "Minimum value = "
35  << *std::min_element(ab.axis_.begin(), ab.axis_.begin() + ab.len_[i])
36  << std::endl;
37  os << "Maximum value = "
38  << *std::max_element(ab.axis_.begin(), ab.axis_.begin() + ab.len_[i])
39  << std::endl;
40  } else {
41  os << "Minimum value = "
42  << *std::min_element(ab.axis_.begin() + ab.len_[i - 1],
43  ab.axis_.begin() + ab.len_[i])
44  << std::endl;
45  os << "Maximum value = "
46  << *std::max_element(ab.axis_.begin() + ab.len_[i - 1],
47  ab.axis_.begin() + ab.len_[i])
48  << std::endl;
49  }
50  }
51  os << "No. of kcoeff = " << ab.kcoeff_.size() << std::endl;
52  os << "Minimum value = "
53  << *std::min_element(ab.kcoeff_.begin(), ab.kcoeff_.end()) << std::endl;
54  os << "Maximum value = "
55  << *std::max_element(ab.kcoeff_.begin(), ab.kcoeff_.end()) << std::endl;
56  return os;
57 }
58 
59 Real HitranAbsorber::getRefTemp(Real pres) const {
60  int nlevel = refatm_.GetDim1();
61  int jl = -1, ju = nlevel, jm;
62  // make sure pressure is in ascending order
63  while (ju - jl > 1) {
64  jm = (ju + jl) >> 1;
65  if (pres < refatm_(IPR, jm))
66  ju = jm;
67  else
68  jl = jm;
69  }
70 
71  // prevent interpolation problem at boundary
72  if (jl == -1) jl = 0;
73  if (ju == nlevel) ju = nlevel - 1;
74  if (jl == ju) return refatm_(IDN, jl);
75 
76  // assert(jl >= 0 && ju < nlevel);
77  Real result = log(refatm_(IPR, jl) / pres) * log(refatm_(IDN, ju)) +
78  log(pres / refatm_(IPR, ju)) * log(refatm_(IDN, jl));
79  result = exp(result / log(refatm_(IPR, jl) / refatm_(IPR, ju)));
80  return result;
81 }
82 
83 void HitranAbsorber::LoadCoefficient(std::string fname, size_t bid) {
84 #ifdef NETCDFOUTPUT
85  int fileid, dimid, varid, err;
86  char tname[80];
87  nc_open(fname.c_str(), NC_NETCDF4, &fileid);
88 
89  nc_inq_dimid(fileid, "Wavenumber", &dimid);
90  nc_inq_dimlen(fileid, dimid, len_);
91  nc_inq_dimid(fileid, "Pressure", &dimid);
92  nc_inq_dimlen(fileid, dimid, len_ + 1);
93  snprintf(tname, sizeof(tname), "%s", "T_");
94  snprintf(tname, sizeof(tname), "%s%s", tname, GetName().c_str());
95  nc_inq_dimid(fileid, tname, &dimid);
96  nc_inq_dimlen(fileid, dimid, len_ + 2);
97 
98  axis_.resize(len_[0] + len_[1] + len_[2]);
99 
100  nc_inq_varid(fileid, "Wavenumber", &varid);
101  nc_get_var_double(fileid, varid, axis_.data());
102  err = nc_inq_varid(fileid, "Pressure", &varid);
103  if (err != NC_NOERR) throw std::runtime_error(nc_strerror(err));
104  err = nc_get_var_double(fileid, varid, axis_.data() + len_[0]);
105  if (err != NC_NOERR) throw std::runtime_error(nc_strerror(err));
106  nc_inq_varid(fileid, tname, &varid);
107  nc_get_var_double(fileid, varid, axis_.data() + len_[0] + len_[1]);
108 
109  Real *temp = new Real[len_[1]];
110  nc_inq_varid(fileid, "Temperature", &varid);
111  nc_get_var_double(fileid, varid, temp);
112 
113  refatm_.NewAthenaArray(NHYDRO, len_[1]);
114  for (int i = 0; i < len_[1]; i++) {
115  refatm_(IPR, i) = axis_[len_[0] + i];
116  refatm_(IDN, i) = temp[i];
117  }
118 
119  kcoeff_.resize(len_[0] * len_[1] * len_[2]);
120  nc_inq_varid(fileid, GetName().c_str(), &varid);
121  nc_get_var_double(fileid, varid, kcoeff_.data());
122  nc_close(fileid);
123  delete[] temp;
124 #endif
125 }
126 
127 Real HitranAbsorber::GetAttenuation(Real wave1, Real wave2,
128  AirParcel const &var) const {
129  // first axis is wavenumber, second is pressure, third is temperature anomaly
130  Real val, coord[3] = {wave1, var.w[IPR], var.w[IDN] - getRefTemp(var.w[IPR])};
131  interpn(&val, coord, kcoeff_.data(), axis_.data(), len_, 3, 1);
132 
133  Real dens = var.w[IPR] / (Constants::Rgas * var.w[IDN]);
134  Real x0 = 1.;
135  if (GetSpeciesIndex(0) == 0) {
136  for (int n = 1; n <= NVAPOR; ++n) x0 -= var.w[n];
137  } else {
138  x0 = var.w[GetSpeciesIndex(0)];
139  }
140  return 1.E-3 * exp(val) * dens * x0; // ln(m*2/kmol) -> 1/m
141 }
Real *const w
Definition: air_parcel.hpp:36
std::vector< Real > axis_
std::vector< Real > kcoeff_
void LoadCoefficient(std::string fname, size_t bid=0) override
Load absorption coefficient from file.
Real GetAttenuation(Real wave1, Real wave2, AirParcel const &var) const override
Get attenuation coefficient [1/m].
Real getRefTemp(Real pres) const
AthenaArray< Real > refatm_
std::string GetName() const
int GetSpeciesIndex(int n) const
std::ostream & operator<<(std::ostream &os, HitranAbsorber const &ab)
void interpn(double *val, double const *coor, double const *data, double const *axis, size_t const *len, int ndim, int nval)
Definition: interpn.c:12
double const Rgas
Definition: constants.hpp:5
float temp
Definition: fit_ammonia.py:6