ReFRACtor
absco_hdf.cc
Go to the documentation of this file.
1 #include "absco_hdf.h"
2 #include "fp_exception.h"
3 #include <iomanip>
4 using namespace FullPhysics;
5 using namespace blitz;
6 #ifdef HAVE_LUA
7 #include "register_lua.h"
8 namespace FullPhysics {
9 void register_lua_AbscoHdf(lua_State *ls) { \
10 luabind::module(ls) [
11 luabind::class_<AbscoHdf,Absco,boost::shared_ptr<GasAbsorption> >
12 ("AbscoHdf")
13 .def(luabind::constructor<const std::string&>())
14 .def(luabind::constructor<const std::string&,double>())
15 .def(luabind::constructor<const std::string&,const SpectralBound&,
16  const std::vector<double>&>())
17 ];}
18 }
19 #endif
20 
21 //-----------------------------------------------------------------------
25 //-----------------------------------------------------------------------
26 
27 AbscoHdf::AbscoHdf(const std::string& Fname, double Table_scale,
28  int Cache_nline)
29 {
30  load_file(Fname, Table_scale, Cache_nline);
31 }
32 
33 //-----------------------------------------------------------------------
37 //-----------------------------------------------------------------------
38 
39 AbscoHdf::AbscoHdf(const std::string& Fname,
40  const SpectralBound& Spectral_bound,
41  const std::vector<double>& Table_scale,
42  int Cache_nline)
43 {
44  load_file(Fname, Spectral_bound, Table_scale, Cache_nline);
45 }
46 
47 //-----------------------------------------------------------------------
53 //-----------------------------------------------------------------------
54 
55 void AbscoHdf::load_file(const std::string& Fname)
56 {
57  load_file(Fname, sb, table_scale_, cache_nline);
58 }
59 
60 //-----------------------------------------------------------------------
65 //-----------------------------------------------------------------------
66 
67 void AbscoHdf::load_file(const std::string& Fname, double Table_scale,
68  int Cache_nline)
69 {
70  SpectralBound empty;
71  std::vector<double> tscale;
72  tscale.push_back(Table_scale);
73  load_file(Fname, empty, tscale, Cache_nline);
74 }
75 
76 //-----------------------------------------------------------------------
81 //-----------------------------------------------------------------------
82 
83 void AbscoHdf::load_file(const std::string& Fname,
84  const SpectralBound& Spectral_bound,
85  const std::vector<double>& Table_scale,
86  int Cache_nline)
87 {
88  sb = Spectral_bound;
89  std::vector<double> tcopy(Table_scale);
90  table_scale_.swap(tcopy);
91  if(sb.number_spectrometer() > 0 &&
92  (int) table_scale_.size() != sb.number_spectrometer()) {
93  Exception e;
94  e << "Table_scale size needs to match the number of spectrometers\n"
95  << " Table_scale size: " << table_scale_.size() << "\n"
96  << " Number spectrometer: " << sb.number_spectrometer();
97  throw e;
98  }
99  if(sb.number_spectrometer() ==0 && (int) table_scale_.size() != 1) {
100  Exception e;
101  e << "Table_scale size needs to be exactly 1\n"
102  << " Table_scale size: " << table_scale_.size() << "\n";
103  throw e;
104  }
105  cache_nline = Cache_nline;
106  cache_double_lbound = 0;
107  cache_double_ubound = 0;
108  cache_float_lbound = 0;
109  cache_float_ubound = 0;
110 
111  // Reset caches
112  read_cache_float.resize(0,0,0,0);
113  read_cache_double.resize(0,0,0,0);
114 
115  hfile.reset(new HdfFile(Fname));
116 
117  // Read optional metadata
118  if (hfile->has_object("Extent_Range")) {
119  extent_range.reference(hfile->read_field<double, 2>("Extent_Range"));
120  extent_index.reference(hfile->read_field<int, 2>("Extent_Index"));
121  }
122 
123  // Read data fields
124  pgrid.reference(hfile->read_field<double, 1>("Pressure"));
125  tgrid.reference(hfile->read_field<double, 2>("Temperature"));
126  wngrid.reference(hfile->read_field<double, 1>("Wavenumber"));
127  wnfront = &wngrid(0);
128 
129  // This may have a "\0" in it, so we create a string twice, the
130  // second one ends at the first "\0".
131  std::string t = hfile->read_field<std::string>("Gas_Index");
132  field_name = std::string("Gas_") + t.c_str() + "_Absorption";
133  // Determine if data is float or double. We use this to optimize the
134  // read.
135  H5::DataSet d = hfile->h5_file().openDataSet(field_name);
136  if(d.getDataType().getSize() == 4)
137  is_float_ = true;
138  else
139  is_float_ = false;
140  std::string bindex = "";
141  try {
142  bindex = hfile->read_field<std::string>("Broadener_Index");
143  bindex = std::string(bindex.c_str()); // In case this ends in "\0"
144  } catch(const Exception& E) {
145  // It is ok if we don't have a broadener, this just means that we
146  // are reading a 3D file.
147  }
148  if(bindex == "")
149  ; // Nothing to do
150  else if(bindex == "01")
151  // This is HITRAN index 01, which is H2O. This is documented in
152  // HITRAN papers, such as "The HITRAN 2008 molecular spectroscopic
153  // database", Journal of Quantitative Spectroscopy and Radiative
154  // Transfer, vol. 110, pp. 533-572 (2009)
155  bname = "h2o";
156  else {
157  Exception e;
158  e << "Right now we only support H2O as a broadener (HITRAN index \"01\"). "
159  << "File " << Fname << " has index of \"" << bindex << "\"";
160  throw e;
161  }
162 
163  if(bname != "")
164  bvmr.reference(hfile->read_field<double, 1>("Broadener_" + bindex + "_VMR"));
165 }
166 
167 // Find the array locations where the wavenumber is contained
168 // If no extents are defined, this just returns beginning and end of whole absco array
169 const std::pair<double*, double*> AbscoHdf::wn_extent(double Wn_in) const
170 {
171  if (extent_range.rows() > 0) {
172  // Find first valid range and return
173  for (int range_idx = 0; range_idx < extent_range.rows(); range_idx++) {
174  if (extent_range(range_idx, 0) <= Wn_in && Wn_in <= extent_range(range_idx, 1)) {
175  int beg_idx = extent_index(range_idx, 0);
176  int end_idx = extent_index(range_idx, 1);
177  // Remove const to satisfy std::pair constructor
178  double* beg_loc = const_cast<double*>(&wngrid(beg_idx));
179  double* end_loc = const_cast<double*>(&wngrid(end_idx));
180  return std::pair<double*, double*>(beg_loc, end_loc);
181  }
182  }
183 
184  // If nothing matches in loop above then the wave number was not
185  // found within one of the ranges
186  Exception err;
187  err << "The ABSCO file " << hfile->file_name()
188  << " does not have an extent that contains the wavenumber: "
189  << std::setprecision(8) << Wn_in;
190  throw err;
191  } else {
192  double* wnback = const_cast<double *>(&wngrid(wngrid.rows() - 1));
193 
194  if (Wn_in >= *wnfront && Wn_in <= *wnback) {
195  return std::pair<double*, double*>(wnfront, wnback);
196  } else {
197  Exception err;
198  err << "The ASBCO file " << hfile->file_name() << "\n"
199  << " does not have data for wavenumber: " << Wn_in;
200  throw err;
201  }
202  }
203 }
204 
205 double AbscoHdf::table_scale(double wn) const
206 {
207  if(sb.number_spectrometer() > 0) {
208  int index = sb.spectral_index(DoubleWithUnit(wn, "cm^-1"));
209  if(index < 0)
210  return 0.0;
211  return table_scale_[index];
212  }
213  return table_scale_[0];
214 }
215 
216 // See base class for description
217 bool AbscoHdf::have_data(double wn) const
218 {
219  try {
220  // If wn_extent does not exception, then we know we have
221  // a wavenumber that falls with in a range, no need to check again
222  // now just check that the table scale for a wn is non zero
223  auto extents = wn_extent(wn);
224  return table_scale(wn) > 0.0;
225  } catch (Exception e) {
226  // If there is an exception that means wn_extent did
227  // not find a valid wavenumber
228  return false;
229  }
230 }
231 
232 // Calculate the wn index number of the data.
233 int AbscoHdf::wn_index(double Wn_in) const
234 {
235  // This will throw an exception if it can not find the wavenumber's locations
236  auto extent = wn_extent(Wn_in);
237 
238  double *wnptr = std::lower_bound(extent.first, extent.second, Wn_in);
239  double f = (Wn_in - *(wnptr - 1)) / (*wnptr - *(wnptr - 1));
240  if(f > 0.1 && f < 0.9) {
241  Exception e;
242  e << std::setprecision(8)
243  << "AbscoHDF does not interpolate in wavenumber direction.\n"
244  << "The interpolation doesn't work well near peaks, so we\n"
245  << "just don't do it. The requested Wn needs to be within 10%\n"
246  << "of the absco wn grid, return the value for the closest number.\n"
247  << "Wn: " << Wn_in << "\n"
248  << "Wnptr - 1: " << *(wnptr - 1) << "\n"
249  << "Wnptr: " << *wnptr << "\n"
250  << "Frac: " << f << " (should be < 0.1 or > 0.9)\n"
251  << "AbscoHdf:\n"
252  << *this << "\n";
253  throw e;
254  }
255  if(f < 0.5) // First point is closest.
256  --wnptr;
257  return (int) (wnptr - wnfront);
258 }
259 
260 // See base class for description
261 Array<double, 3> AbscoHdf::read_double(double Wn_in) const
262 {
263  int wi = wn_index(Wn_in);
264  if(wi < cache_double_lbound ||
265  wi >= cache_double_ubound)
266  swap<double>(wi);
267  return read_cache<double>()(Range::all(), Range::all(), Range::all(),
268  wi - cache_double_lbound);
269 }
270 
271 // See base class for description
272 Array<float, 3> AbscoHdf::read_float(double Wn_in) const
273 {
274  int wi = wn_index(Wn_in);
275  if(wi < cache_float_lbound ||
276  wi >= cache_float_ubound)
277  swap<float>(wi);
278  return read_cache<float>()(Range::all(), Range::all(), Range::all(),
279  wi - cache_float_lbound);
280 }
281 
282 //-----------------------------------------------------------------------
285 //-----------------------------------------------------------------------
286 
287 template<class T> void AbscoHdf::swap(int i) const
288 {
289  // First time through, set up space for cache.
290  if(read_cache<T>().extent(fourthDim) == 0)
291  read_cache<T>().resize(tgrid.rows(), tgrid.cols(),
292  std::max(1, number_broadener_vmr()),
293  cache_nline);
294  int nl = read_cache<T>().extent(fourthDim);
295  // Either read 3d or 4d data. We tell which kind by whether or not
296  // we have a number_broadener_vmr() > 0 or not.
297  TinyVector<int, 4> start, size;
298  start = 0, 0, 0, (i / nl) * nl;
299  size = tgrid.rows(), tgrid.cols(), std::max(number_broadener_vmr(), 1),
300  std::min(nl, wngrid.rows() - start(3));
301  bound_set<T>((i / nl) * nl, size(3));
302  if(number_broadener_vmr() > 0) {
303  // 4d case
304  read_cache<T>()(Range::all(), Range::all(), Range::all(), Range(0, size(3) - 1)) =
305  hfile->read_field<T, 4>(field_name, start, size);
306  } else {
307  // 3d case
308  TinyVector<int, 3> start2, size2;
309  start2 = 0, 0, (i / nl) * nl;
310  size2 = tgrid.rows(), tgrid.cols(),
311  std::min(nl, wngrid.rows() - start(3));
312  read_cache<T>()(Range::all(), Range::all(), 0, Range(0, size(3) - 1)) =
313  hfile->read_field<T, 3>(field_name, start2, size2);
314  }
315 }
316 
317 void AbscoHdf::print(std::ostream& Os) const
318 {
319  Os << "AbscoHdf" << "\n"
320  << " File name: " << hfile->file_name() << "\n";
321  if(sb.number_spectrometer() ==0)
322  Os << " Scale factor: " << table_scale_[0] << "\n";
323  else {
324  Os << " Scale factor: [";
325  for(int i = 0; i < (int) table_scale_.size(); ++i) {
326  Os << table_scale_[i];
327  if(i < (int) table_scale_.size() - 1)
328  Os << ", ";
329  }
330  Os << "]\n";
331  }
332 }
This is the base of the exception hierarchy for Full Physics code.
Definition: fp_exception.h:16
AbscoHdf(const std::string &Fname, double Table_scale=1.0, int Cache_nline=5000)
Read the given Absco file.
Definition: absco_hdf.cc:27
virtual blitz::Array< float, 3 > read_float(double wn) const
Definition: absco_hdf.cc:272
This class reads and writes a HDF5 file.
Definition: hdf_file.h:39
Apply value function to a blitz array.
This gives the upper and lower bounds of the SpectralWindow.
virtual const std::pair< double *, double * > wn_extent(double Wn_in) const
Definition: absco_hdf.cc:169
virtual blitz::Array< double, 3 > read_double(double wn) const
Return either a blitz::Array<double, 3> or blitz::Array<float, 3>, depending on the type of the under...
Definition: absco_hdf.cc:261
We frequently have a double with units associated with it.
Contains classes to abstract away details in various Spurr Radiative Transfer software.
Definition: doxygen_python.h:1
def(luabind::constructor< int >()) .def("rows"
virtual void print(std::ostream &Os) const
Definition: absco_hdf.cc:317
virtual double table_scale(double wn) const
Scale to apply to underlying ABSCO data to get the absorption_cross_section.
Definition: absco_hdf.cc:205
void load_file(const std::string &Fname)
Load file, using the same table scaling as we already have.
Definition: absco_hdf.cc:55
virtual bool have_data(double wn) const
Return true if we have data for the given wave number.
Definition: absco_hdf.cc:217

Copyright © 2017, California Institute of Technology.
ALL RIGHTS RESERVED.
U.S. Government Sponsorship acknowledged.
Generated Fri Aug 24 2018 15:44:08