ReFRACtor
aerosol_optical.cc
Go to the documentation of this file.
1 #include "aerosol_optical.h"
2 #include "fp_exception.h"
3 #include "ostream_pad.h"
4 #include <boost/lexical_cast.hpp>
5 
6 using namespace FullPhysics;
7 using namespace blitz;
8 
9 #ifdef HAVE_LUA
10 #include "register_lua.h"
11 
12 typedef const boost::shared_ptr<AerosolExtinction>& (AerosolOptical::*a1)(int) const;
13 
14 typedef const boost::shared_ptr<AerosolProperty>& (AerosolOptical::*a2)(int) const;
15 
17 .def(luabind::constructor<const std::vector<boost::shared_ptr<AerosolExtinction> >&,
18  const std::vector<boost::shared_ptr<AerosolProperty> >&,
21 .def("number_particle", &AerosolOptical::number_particle)
22 .def("aerosol_extinction", ((a1) &AerosolOptical::aerosol_extinction))
23 .def("aerosol_property", ((a2) &AerosolOptical::aerosol_property))
25 #endif
26 
27 //-----------------------------------------------------------------------
36 //-----------------------------------------------------------------------
37 
39 (const std::vector<boost::shared_ptr<AerosolExtinction> >& Aext,
40  const std::vector<boost::shared_ptr<AerosolProperty> >& Aerosol_prop,
41  const boost::shared_ptr<Pressure>& Press,
43  double Reference_wn)
44 : aext(Aext),
45  aprop(Aerosol_prop),
46  press(Press),
47  rh(Rh),
48  reference_wn_(Reference_wn),
49  cache_is_stale(true),
50  // Need at least 1 jacobian var such as when not running a retrieval
51  nvar(1)
52 {
53  if((int) aprop.size() != number_particle())
54  throw Exception("aprop needs to be size of number_particle()");
55  for(int i = 0; i < number_particle(); ++i) {
56  aprop[i]->add_observer(*this);
57  aext[i]->add_observer(*this);
58  }
59  press->add_observer(*this);
60 }
61 
62 //-----------------------------------------------------------------------
71 //-----------------------------------------------------------------------
72 
73 blitz::Array<std::string, 1> AerosolOptical::aerosol_name_arr() const
74 {
75  blitz::Array<std::string, 1> res((int) aext.size());
76  for(int i = 0; i < res.rows(); i++)
77  res(i) = aext[i]->aerosol_name();
78  return res;
79 }
80 
81 //-----------------------------------------------------------------------
84 //-----------------------------------------------------------------------
85 
86 void AerosolOptical::fill_cache() const
87 {
88  if(!cache_is_stale)
89  return;
90  od_ind_wn.resize(press->number_layer(), number_particle(), nvar);
91  for(int i = 0; i < od_ind_wn.rows(); ++i) {
92  AutoDerivativeWithUnit<double> delta_press =
93  (press->pressure_grid()(i + 1) - press->pressure_grid()(i));
94  AutoDerivative<double> dp = delta_press.convert(units::Pa).value;
95 
96  // Resize number of variables in case surface pressure is not retrieved
97  if (dp.number_variable() == 0)
98  dp.gradient().resize(nvar);
99 
100  for(int j = 0; j < number_particle(); ++j) {
104  od_ind_wn(i, j) = 1.0 / aprop[j]->extinction_coefficient_each_layer(reference_wn_)(i) *
105  dp * aext[j]->extinction_for_layer(i);
106  }
107  }
108  /*
109  std::cout << "# Optical depths for each layer value: " << std::endl
110  << od_ind_wn.value() << std::endl
111  << "# Optical depths for each layer jacobian: " << std::endl
112  << od_ind_wn.jacobian() << std::endl;
113  */
114  nlay = press->number_layer();
115  cache_is_stale = false;
116 }
117 
118 //-----------------------------------------------------------------------
127 //-----------------------------------------------------------------------
128 
131 {
132  Range ra(Range::all());
133  firstIndex i1; secondIndex i2; thirdIndex i3;
134  FunctionTimer ft(timer.function_timer());
135  fill_cache();
136  ArrayAd<double, 2> res(od_ind_wn.copy());
137  for(int i = 0; i < number_particle(); ++i) {
138  ArrayAd<double, 1> t = aprop[i]->extinction_coefficient_each_layer(wn);
139  if(res.is_constant() && !t.is_constant())
141  Array<double, 1> v(res.value()(ra, i));
142  Array<double, 2> jac(res.jacobian()(ra, i, ra));
143  v *= t.value();
144  if(t.is_constant())
145  jac = t.value()(i1) * jac(i1, i2);
146  else
147  jac = t.value()(i1) * jac(i1,i2) + v(i1) * t.jacobian()(i1, i2);
148  }
149  return res;
150 }
151 
152 //-----------------------------------------------------------------------
167 //-----------------------------------------------------------------------
168 
170 (double wn,
171  int particle_index,
172  const ArrayAd<double, 1>& Od) const
173 {
174  firstIndex i1; secondIndex i2; thirdIndex i3;
175  FunctionTimer ft(timer.function_timer());
176  ArrayAd<double, 1> res(Od.copy());
177  ArrayAd<double, 1> t = aprop[particle_index]->scattering_coefficient_each_layer(wn);
178  ArrayAd<double, 1> t2 = aprop[particle_index]->extinction_coefficient_each_layer(wn);
179  t.value() /= t2.value();
180  if(!t.is_constant() && !res.is_constant() &&
181  res.number_variable() != t.number_variable())
182  throw Exception("We don't currently have the code working correctly for combining intermediates and state vector derivatives. We'll need to think through how to do this.");
183  if(!t.is_constant())
184  t.jacobian() = 1 / t2.value()(i1) * t.jacobian()(i1,i2) -
185  t.value()(i1)/(t2.value()(i1) * t2.value()(i1)) * t2.jacobian()(i1,i2);
186  if(res.is_constant() && !t.is_constant())
187  res.resize_number_variable(t.number_variable());
188  Array<double, 1> v(res.value());
189  Array<double, 2> jac(res.jacobian());
190  v *= t.value();
191  if(t.is_constant())
192  jac = t.value()(i1) * jac(i1, i2);
193  else
194  jac = t.value()(i1) * jac(i1,i2) + v(i1) * t.jacobian()(i1,i2);
195  return res;
196 }
197 
198 //-----------------------------------------------------------------------
207 //-----------------------------------------------------------------------
208 
211 {
212  FunctionTimer ft(timer.function_timer());
213  ArrayAd<double, 2> od(optical_depth_each_layer(wn));
214  ArrayAd<double, 1> res(od.rows(), nvar);
215  res.value() = 0;
216  res.jacobian() = 0;
217  for(int i = 0; i < number_particle(); ++i) {
218  ArrayAd<double, 1> t(ssa_each_layer(wn, i, od(Range::all(), i)));
219  res.value() += t.value();
220  res.jacobian() += t.jacobian();
221  }
222  return res;
223 }
224 
225 //-----------------------------------------------------------------------
234 //-----------------------------------------------------------------------
235 
236 ArrayAd<double, 3> AerosolOptical::pf_mom(double wn, int pindex) const
237 {
238  FunctionTimer ft(timer.function_timer());
239  range_check(pindex, 0, number_particle());
240  return aprop[pindex]->phase_function_moment_each_layer(wn);
241 }
242 
243 //-----------------------------------------------------------------------
251 //-----------------------------------------------------------------------
252 
253 blitz::Array<double, 3> AerosolOptical::pf_mom(double wn,
254  const blitz::Array<double, 2>& frac_aer) const
255 {
256  FunctionTimer ft(timer.function_timer());
257  firstIndex i1; secondIndex i2; thirdIndex i3;
258  Range ra = Range::all();
259  if(frac_aer.rows() != nlay ||
260  frac_aer.cols() != number_particle()) {
261  std::stringstream err_msg;
262  err_msg << "frac_aer needs to be number_active_layer = "
263  << nlay
264  << " x number_particle = "
265  << number_particle() << ", but is currently "
266  << frac_aer.rows() << " x " << frac_aer.cols();
267  throw Exception(err_msg.str());
268  }
269  std::vector<Array<double, 3> > pf;
270  int s1 = 0;
271  int s2 = 0;
272  for(int j = 0; j < frac_aer.cols(); ++j) {
273  pf.push_back(pf_mom(wn, j).value());
274  s1 = std::max(s1, pf[j].rows());
275  s2 = std::max(s2, pf[j].depth());
276  }
277  blitz::Array<double, 3> res(s1, nlay, s2);
278  res = 0;
279  for(int j = 0; j < frac_aer.cols(); ++j) {
280  Range r1(0, pf[j].rows() - 1);
281  Range r2(0, pf[j].depth() - 1);
282  res(r1,ra,r2) += frac_aer(ra,j)(i2) * pf[j](i1, i2, i3);
283  }
284  return res;
285 }
286 
288  const ArrayAd<double, 2>& frac_aer,
289  int nummom, int numscat) const
290 {
291  FunctionTimer ft(timer.function_timer());
292  firstIndex i1; secondIndex i2; thirdIndex i3; fourthIndex i4;
293  Range ra = Range::all();
294  if(frac_aer.rows() != nlay ||
295  frac_aer.cols() != number_particle()) {
296  std::stringstream err_msg;
297  err_msg << "frac_aer needs to be number_active_layer = "
298  << nlay
299  << " x number_particle = "
300  << number_particle() << ", but is currently "
301  << frac_aer.rows() << " x " << frac_aer.cols();
302  throw Exception(err_msg.str());
303  }
304 
305  std::vector<ArrayAd<double, 3> > pf;
306  int s1 = 0;
307  int s2 = 0;
308  int nvar = frac_aer.number_variable();
309  for(int j = 0; j < frac_aer.cols(); ++j) {
310  pf.push_back(aprop[j]->phase_function_moment_each_layer(wn, nummom, numscat));
311  s1 = std::max(s1, pf[j].rows());
312  s2 = std::max(s2, pf[j].depth());
313  nvar = std::max(nvar, pf[j].number_variable());
314  if(!pf[j].is_constant() && !frac_aer.is_constant() &&
315  pf[j].number_variable() != frac_aer.number_variable())
316  throw Exception("We don't currently have the code working correctly for combining intermediates and state vector derivatives. We'll need to think through how to do this.");
317  }
318  ArrayAd<double, 3> res(s1, nlay, s2, nvar);
319  res = 0;
320  for(int j = 0; j < frac_aer.cols(); ++j) {
321  Range r1(0, pf[j].rows() - 1);
322  Range r2(0, pf[j].depth() - 1);
323  Array<double, 3> rv(res.value()(r1,ra,r2));
324  Array<double, 4> rjac(res.jacobian()(r1,ra,r2,ra));
325  Array<double, 1> fv(frac_aer.value()(ra,j));
326  Array<double, 2> fjac(frac_aer.jacobian()(ra,j, ra));
327  Array<double, 3> pv(pf[j].value());
328  Array<double, 4> pjac(pf[j].jacobian());
329  rv += fv(i2) * pv(i1, i2, i3);
330  if(pf[j].is_constant()) {
331  if(!frac_aer.is_constant())
332  rjac += fjac(i2,i4) * pv(i1, i2, i3);
333  } else {
334  if(frac_aer.is_constant())
335  rjac += fv(i2) * pjac(i1, i2, i3, i4);
336  else
337  rjac += fjac(i2,i4) * pv(i1, i2, i3) + fv(i2) * pjac(i1, i2, i3, i4);
338  }
339  }
340  return res;
341 }
342 
343 //-----------------------------------------------------------------------
348 //-----------------------------------------------------------------------
349 
352  const boost::shared_ptr<RelativeHumidity>& Rh) const
353 {
354  std::vector<boost::shared_ptr<AerosolExtinction> > aext_clone;
355  BOOST_FOREACH(const boost::shared_ptr<AerosolExtinction>& i, aext)
356  aext_clone.push_back(i->clone(Press));
357  std::vector<boost::shared_ptr<AerosolProperty> > aprop_clone;
358  BOOST_FOREACH(const boost::shared_ptr<AerosolProperty>& i, aprop)
359  aprop_clone.push_back(i->clone(Press, Rh));
360  boost::shared_ptr<Aerosol> res(new AerosolOptical(aext_clone, aprop_clone, Press, Rh));
361  return res;
362 }
363 
364 //-----------------------------------------------------------------------
370 //-----------------------------------------------------------------------
371 
373  double pmin,
374  double pmax) const
375 {
376  double res = 0.0;
377  Array<double, 1> pgrid(press->pressure_grid().convert(units::Pa).value.value());
378  for(int i = 0; i < pgrid.rows() - 1; ++i) {
379  // Three cases. First, everything is in the pmin to pmax range
380  if(pmin <= pgrid(i) && pgrid(i + 1) <= pmax)
381  res += (pgrid(i + 1) - pgrid(i)) *
382  aext[aer_idx]->extinction_for_layer(i).value();
383 
384  // second case is that pmin cuts between pgrid(i) and pgrid(i + 1)
385  else if(pmin > pgrid(i) && pmin < pgrid(i + 1) && pgrid(i + 1) <=pmax)
386  res += (pgrid(i + 1) - pmin) * aext[aer_idx]->extinction_for_layer(i).value();
387 
388  // third case is pmax cuts between pgrid(i) and pgrid(i + 1)
389  else if(pmin <= pgrid(i) && pgrid(i) < pmax && pgrid(i + 1) > pmax)
390  res += (pmax - pgrid(i)) * aext[aer_idx]->extinction_for_layer(i).value();
391  }
392  return res;
393 }
394 
395 //-----------------------------------------------------------------------
404 //-----------------------------------------------------------------------
405 
407 (double pmin, double pmax) const
408 {
409  double res = 0.0;
410  for(int j = 0; j < number_particle(); ++j)
411  res += aerosol_optical_depth(j, pmin, pmax);
412  return res;
413 }
414 
415 //-----------------------------------------------------------------------
417 //-----------------------------------------------------------------------
418 std::vector<std::string> AerosolOptical::aerosol_name() const
419 {
420  std::vector<std::string> res;
421  BOOST_FOREACH(const boost::shared_ptr<AerosolExtinction>& i, aext)
422  res.push_back(i->aerosol_name());
423  return res;
424 }
425 
426 void AerosolOptical::print(std::ostream& Os) const
427 {
428  OstreamPad opad(Os, " ");
429  Os << "AerosolOptical:";
430  for(int i = 0; i < (int) aprop.size(); ++i) {
431  Os << " Aerosol Optical Property[" << i << "]:\n";
432  opad << *aprop[i] << "\n";
433  opad.strict_sync();
434  Os << " Aerosol Extinction[" << i << "]:\n";
435  opad << *aext[i] << "\n";
436  opad.strict_sync();
437  }
438 }
void resize_number_variable(int nvar)
Definition: array_ad.h:165
#define range_check(V, Min, Max)
Range check.
Definition: fp_exception.h:140
blitz::Array< std::string, 1 > aerosol_name_arr() const
Aerosol names, plus the string "total" as the 1st entry.
int cols() const
Definition: array_ad.h:369
bool is_constant() const
Definition: array_ad.h:371
This is a AutoDerivative that also has units associated with it.
This is a filtering stream that adds a pad to the front of every line written out.
Definition: ostream_pad.h:32
AutoDerivativeWithUnit< T > convert(const Unit &R) const
Convert to the given units.
virtual void print(std::ostream &Os) const
const Unit Pa("Pa", N/(m *m))
This is the base of the exception hierarchy for Full Physics code.
Definition: fp_exception.h:16
std::vector< std::string > aerosol_name() const
Name of aerosols.
blitz::Array< T, 2 > jacobian(const blitz::Array< AutoDerivative< T >, 1 > &Ad)
Utility function to extract the Jacobian as a separate matrix from an array of AutoDerivative.
#define REGISTER_LUA_DERIVED_CLASS(X, Y)
Definition: register_lua.h:136
const blitz::Array< T, D+1 > jacobian() const
Definition: array_ad.h:307
double aerosol_optical_depth_total(double pmin=std::numeric_limits< double >::min(), double pmax=std::numeric_limits< double >::max()) const
This gives the total optical depth for each particle, plus adds the total optical depth for all parti...
double aerosol_optical_depth(int aer_idx, double pmin=std::numeric_limits< double >::min(), double pmax=std::numeric_limits< double >::max()) const
This gives the total aerosol optical depth for a given particle.
Apply value function to a blitz array.
AerosolOptical(const std::vector< boost::shared_ptr< AerosolExtinction > > &Aext, const std::vector< boost::shared_ptr< AerosolProperty > > &Aerosol_prop, const boost::shared_ptr< Pressure > &Press, const boost::shared_ptr< RelativeHumidity > &Rh, double Reference_wn=1e4/0.755)
Create an aerosol.
const blitz::Array< T, D > & value() const
Definition: array_ad.h:306
This class maintains the aerosol portion of the state.
Definition: aerosol.h:24
virtual ArrayAd< double, 2 > optical_depth_each_layer(double wn) const
This gives the optical depth for each layer, for the given wave number.
virtual boost::shared_ptr< Aerosol > clone() const
Clone a Aerosol object.
ArrayAd< T, D > copy() const
Definition: array_ad.h:374
const boost::shared_ptr< AerosolProperty > & aerosol_property(int i) const
Return aerosol property.
Implementation of Aerosol.
int number_variable() const
Number of variables in gradient.
const blitz::Array< T, 1 > & gradient() const
Gradient.
int number_variable() const
Definition: array_ad.h:376
virtual int number_particle() const
Number of aerosol particles.
virtual ArrayAd< double, 3 > pf_mom(double wn, int pindex) const
This calculates the portion of the phase function moments that come from the aerosol for a single par...
Contains classes to abstract away details in various Spurr Radiative Transfer software.
Definition: doxygen_python.h:1
#define REGISTER_LUA_END()
Definition: register_lua.h:134
const boost::shared_ptr< AerosolExtinction > & aerosol_extinction(int i) const
Return aerosol extinction.
Helper class for AccumulatedTimer.
double value(const FullPhysics::AutoDerivative< double > &Ad)
int rows() const
Definition: array_ad.h:368
virtual ArrayAd< double, 1 > ssa_each_layer(double wn, int particle_index, const ArrayAd< double, 1 > &Od) const
This gives the single scatter albedo for each layer, for the given wave number, for the given particl...

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