7 #include <boost/lexical_cast.hpp> 8 #include <boost/bind.hpp> 10 using namespace blitz;
11 inline double sqr(
double x) {
return x * x;}
44 return vmr_func(Species_index, P) * c->avogadro_constant() /
45 (gravity_func(Spec_index, P) *
46 (1 + h2o_vmr_func(P) * c->molar_weight_water() /
47 c->molar_weight_dry_air()) * c->molar_weight_dry_air());
56 (
double wn,
double P,
int Spec_index,
int Species_index)
const 61 integrand_independent_wn(Spec_index, Species_index,
62 punit).convert(
Unit(
"cm^-2 / Pa")).value.value();
67 if(gas_absorption[Species_index]->have_data(wn)) {
68 DoubleWithUnit cross_sec = gas_absorption[Species_index]->absorption_cross_section(wn, punit, t, bvmr);
69 return v1 * cross_sec.
value;
84 double wn,
int Spec_index,
int Species_index,
int Layer_index,
85 double eps_abs,
double eps_rel)
const 90 if(!gas_absorption[Species_index]->have_data(wn))
92 boost::function<double (double)> f;
96 std::vector<double> bp;
97 Array<double, 1> imp =
99 for(
int i = 0; i < imp.rows(); ++i)
100 bp.push_back(imp(i));
101 return intg.integrate(f, pgrid.value.value()(Layer_index),
102 pgrid.value.value()(Layer_index + 1),
112 blitz::Array<double, 2>
114 (
double wn,
int Spec_index,
double eps_abs,
double eps_rel)
const 116 blitz::Array<double, 2> res(press->number_layer(), number_species());
117 for(
int i = 0; i < res.rows(); ++i)
118 for(
int j = 0; j < res.cols(); ++j)
119 res(i, j) = optical_depth_each_layer_direct_integrate
120 (wn, Spec_index, j, i, eps_abs, eps_rel);
148 void AbsorberAbsco::create_sublayer()
const 160 pgrid.reference(press->pressure_grid().convert(
units::Pa));
169 int npoint = nsub / 2;
171 Array<double, 1> sublay_fac(npoint);
172 sublay_fac = (i1 + 1.0) / (npoint);
176 Array<double, 1> pimp_arr =
177 temp->important_pressure_level().convert(
units::Pa).value;
179 std::list<double> pimp;
180 for(
int i = 0; i < pimp_arr.rows(); ++i)
181 pimp.push_back(pimp_arr(i));
190 std::vector<double> psub_vec;
191 psub_vec.push_back(pgrid.value.value()(0));
194 while(pimp.size() > 0 && pimp.front() <= psub_vec.front())
214 for(
int i = 0; i < press->number_layer(); ++i) {
215 for(
int j = 0; j < sublay_fac.rows(); ++j) {
216 double pv = pgrid.value.value()(i) * (1 - sublay_fac(j)) +
217 pgrid.value.value()(i + 1) * sublay_fac(j);
218 while(pimp.size() > 0 && pimp.front() < pv) {
219 double midpoint = (psub_vec.back() + pimp.front()) / 2.0;
220 psub_vec.push_back(midpoint);
221 psub_vec.push_back(pimp.front());
226 while(pimp.size() > 0 && pimp.front() == pv)
229 double midpoint = (psub_vec.back() + pv) / 2.0;
230 psub_vec.push_back(midpoint);
231 psub_vec.push_back(pv);
233 int end = ((int) psub_vec.size()) - 1;
234 layer_range.push_back(Range(start, end));
240 psub.units = pgrid.units;
241 psub.value.resize((
int) psub_vec.size());
242 for(
int i = 0; i < psub.rows(); ++i)
243 psub.value(i) = psub_vec[i];
249 weight.resize(layer_range.size());
250 for(
int i = 0; i < (int) weight.size(); ++i) {
251 Array<double, 1> play(psub.value(layer_range[i]));
252 weight[i].value.resize(play.shape());
255 for(
int j = 0; j < play.rows() - 1; j += 2) {
256 double delta = play(j + 2) - play(j);
257 weight[i].value(j) += delta / 6.0;
258 weight[i].value(j + 1) += 4 * delta / 6.0;
259 weight[i].value(j + 2) += delta / 6.0;
264 pressure_nonzero_column.clear();
267 for(
int i = 0; i < number_layer(); ++i) {
268 Array<double, 1> p1g = pgrid.value(i + 1).gradient();
269 Array<double, 1> p2g = pgrid.value(i).gradient();
270 std::vector<int> nzero_col;
271 for(
int j = 0; j < p1g.rows(); ++j)
272 if(abs(p1g(j)) > 1e-20 ||
274 nzero_col.push_back(j);
275 Array<double, 1> p1g_sparse((
int) nzero_col.size());
276 Array<double, 1> p2g_sparse(p1g_sparse.shape());
278 BOOST_FOREACH(
int j, nzero_col) {
279 p1g_sparse(k) = p1g(j);
280 p2g_sparse(k) = p2g(j);
283 pressure_nonzero_column.push_back(nzero_col);
284 p1_grad.push_back(p1g_sparse);
285 p2_grad.push_back(p2g_sparse);
296 void AbsorberAbsco::fill_tau_gas_cache()
const 298 if(!cache_tau_gas_stale)
301 firstIndex i1; secondIndex i2; thirdIndex i3;
302 Range ra(Range::all());
310 Array<AutoDerivative<double>, 3>
311 integrand_independent_wn_sub_t(number_spectrometer(), number_species(),
313 for(
int i = 0; i < integrand_independent_wn_sub_t.rows(); ++i)
314 for(
int j = 0; j < integrand_independent_wn_sub_t.cols(); ++j)
315 for(
int k = 0; k < integrand_independent_wn_sub_t.depth(); ++k)
316 integrand_independent_wn_sub_t(i, j, k) =
317 integrand_independent_wn(i, j, psub(k)).
318 convert(
Unit(
"cm^-2 / Pa")).value;
319 integrand_independent_wn_sub.units =
Unit(
"cm^-2 / Pa");
320 integrand_independent_wn_sub.value.
325 integrand_nonzero_column.clear();
326 integrand_jac.clear();
327 for(
int i = 0; i < number_layer(); ++i) {
328 Range r = layer_range[i];
330 Array<double, 4> jac = piv.
jacobian();
332 for(
int j = 0; j < piv.number_variable(); ++j) {
333 double mv = max(abs(jac(ra, ra, ra, j)));
338 Array<double, 4> ijac(jac.
rows(), jac.
cols(), jac.
depth(), (int) nz.size());
339 BOOST_FOREACH(
int m, nz) {
340 ijac(ra, ra, ra, k) = jac(ra,ra,ra,m);
343 integrand_nonzero_column.push_back(nz);
344 integrand_jac.push_back(ijac);
348 Array<AutoDerivative<double>, 1> tsub_t(psub.rows());
349 Array<AutoDerivative<double>, 1> h2o_vmr_t(psub.rows());
350 for(
int i = 0; i < psub.rows(); ++i) {
351 tsub_t(i) = temp_func(psub(i)).convert(
units::K).value;
352 h2o_vmr_t(i) = h2o_vmr_func(psub(i)).value;
360 absco_nonzero_column.clear();
374 if(mv1 > 1e-20 || mv2 > 1e-20)
375 absco_nonzero_column.push_back(i);
377 Array<double, 2> tsub_sjac(tsub.
value.
rows(),
378 (int) absco_nonzero_column.size());
379 Array<double, 2> h2o_vmr_sjac(tsub_sjac.shape());
383 BOOST_FOREACH(
int m, absco_nonzero_column) {
397 absco_interp.resize(gas_absorption.size());
398 for(
int i = 0; i < (int) absco_interp.size(); ++i) {
400 boost::dynamic_pointer_cast<
Absco>(gas_absorption[i]);
402 throw Exception(
"AbsorberAbsco requires Absco, not just any GasAbsorption object");
407 taug.resize((
int) layer_range.size(), number_species(),
408 std::max(integrand_independent_wn_sub.number_variable(),
411 cache_tau_gas_stale =
false;
422 AbsorberAbsco::tau_gas_nder(
double wn,
int spec_index)
const 424 firstIndex i1; secondIndex i2; thirdIndex i3;
425 Range ra(Range::all());
426 fill_tau_gas_cache();
444 for(
int i = 0; i < taug.cols(); ++i)
445 if(gas_absorption[i]->have_data(wn)) {
446 Array<double, 1> abcsub =
447 absco_interp[i]->absorption_cross_section_noderiv(wn);
448 for(
int j = 0; j < taug.rows(); ++j) {
449 Range r = layer_range[j];
450 Array<double, 1> av(abcsub(r));
451 Array<double, 1> piv(integrand_independent_wn_sub.value.value()(spec_index,i,r));
452 taug.value()(j, i) = sum(av * piv * weight[j].
value);
455 for(
int j =0; j < taug.rows(); ++j) {
456 taug.value()(j, i) = 0;
469 AbsorberAbsco::tau_gas_der(
double wn,
int spec_index)
const 471 firstIndex i1; secondIndex i2; thirdIndex i3;
472 Range ra(Range::all());
473 fill_tau_gas_cache();
494 for(
int i = 0; i < taug.cols(); ++i)
495 if(gas_absorption[i]->have_data(wn)) {
497 absco_interp[i]->absorption_cross_section_deriv(wn);
498 for(
int j = 0; j < taug.rows(); ++j) {
499 Range r = layer_range[j];
501 Array<double, 1> piv(integrand_independent_wn_sub.value(spec_index,i,r).value());
502 Array<double, 1> jacv(taug.jacobian()(j, i, Range::all()));
503 taug.value()(j, i) = sum(av.
value() * piv * weight[j].value);
507 BOOST_FOREACH(
int m, pressure_nonzero_column[j])
510 BOOST_FOREACH(
int m, absco_nonzero_column)
520 BOOST_FOREACH(
int m, integrand_nonzero_column[j]) {
521 Array<double, 1> intjac(integrand_jac[j](spec_index, i, ra, k));
522 jacv(m) = sum(av.
value() * intjac * weight[j].value);
527 BOOST_FOREACH(
int m, absco_nonzero_column) {
528 Array<double, 1> avjac(av.
jacobian()(ra, k));
529 jacv(m) += sum(avjac * piv * weight[j].
value);
542 int i1 = av.
rows() - 1;
545 BOOST_FOREACH(
int m, pressure_nonzero_column[j]) {
546 jacv(m) += av.
value()(i1) * piv(i1) * p1_grad[j](k) -
547 av.
value()(i2) * piv(i2) * p2_grad[j](k);
552 for(
int j =0; j < taug.rows(); ++j) {
553 taug.value()(j, i) = 0;
554 taug.jacobian()(j, i, Range::all()) = 0;
571 : press(Press), temp(Temp), alt(Alt), vmr(Vmr),
572 gas_absorption(Gas_absorption), c(C), nsub(Nsub),
573 cache_tau_gas_stale(
true)
575 Range ra(Range::all());
576 press->add_observer(*
this);
577 temp->add_observer(*
this);
579 a->add_observer(*
this);
581 a->add_observer(*
this);
582 h2o_index = gas_index(
"H2O");
585 if(ga->broadener_name() !=
"" &&
586 ga->broadener_name() !=
"h2o") {
588 e <<
"Right now, we only support H2O as a broadener. " 589 <<
"The GasAbsorption has a broadener of \"" 590 << ga->broadener_name() <<
"\"";
600 return tau_gas_der(wn,spec_index);
607 return tau_gas_nder(wn,spec_index);
615 temp->clone(pressure_clone);
616 std::vector<boost::shared_ptr<Altitude> > alt_clone;
618 alt_clone.push_back(a->clone(pressure_clone, temperature_clone));
619 return clone(pressure_clone, temperature_clone, alt_clone);
628 std::vector<boost::shared_ptr<AbsorberVmr> > vmr_clone;
630 vmr_clone.push_back(a->clone(Press));
633 gas_absorption, c, nsub));
646 Array<AutoDerivative<double>, 1> spec_hum_t(pgrid.rows() - 1);
647 DoubleWithUnit epsilon = c->molar_weight_water() / c->molar_weight_dry_air();
648 for(
int i = 0; i < spec_hum_t.rows(); ++i) {
652 ((h2o_index < 0 ? 0 : vmr[h2o_index]->volume_mixing_ratio(play.
value)),
654 spec_hum_t(i) = (h2o_lay / (1.0 / epsilon + h2o_lay)).
655 convert(spec_hum.
units).value;
679 Array<AutoDerivative<double>, 1> mol_dens_t(pgrid.rows() - 1);
680 for(
int i = 0; i < mol_dens_t.rows(); ++i) {
684 mol_dens_t(i) = (dp / (c->molar_weight_dry_air() * grav_lay) *
685 c->avogadro_constant()).convert(mol_dens.
units).
value;
702 Array<AutoDerivative<double>, 1> dry_am_t(mol_dens.
rows());
703 for(
int i = 0; i < dry_am_t.rows(); ++i)
704 dry_am_t(i) = (mol_dens(i) * (1 - spec_hum(i))).convert(dry_am.
units).value;
719 DoubleWithUnit epsilon = c->molar_weight_water() / c->molar_weight_dry_air();
722 Array<AutoDerivative<double>, 1> wet_am_t(mol_dens.
rows());
723 for(
int i = 0; i < wet_am_t.rows(); ++i)
725 (mol_dens(i) * (1 + spec_hum(i) * (1 - epsilon) / epsilon)).
726 convert(wet_am.
units).value;
738 Array<AutoDerivative<double>, 1> dry_am(dry_air_column_thickness_layer().
740 Array<AutoDerivative<double>, 1> pwf(dry_am.rows());
741 pwf = dry_am / sum(dry_am);
755 int nactive = press->number_level();
756 Array<AutoDerivative<double>, 1> pwlev(nactive);
757 pwlev(0) = pwlay(0) / 2;
758 for(
int i = 1; i < nactive - 1; ++i)
759 pwlev(i) = (pwlay(i-1) + pwlay(i)) / 2;
760 pwlev(nactive - 1) = pwlay(nactive - 2) / 2;
776 Array<AutoDerivative<double>, 1> gas_thickness_t(dry_am.
rows());
777 for(
int i = 0; i < gas_thickness_t.rows(); ++i) {
781 (dry_am(i) * absorber_vmr(Gas_name)->volume_mixing_ratio(play.
convert(
units::Pa).value)).
785 return gas_thickness;
796 gas_column_thickness_layer(Gas_name);
798 gas_thickness.
units);
807 res = pwf(0) * absorber_vmr(Gas_name)->volume_mixing_ratio(pgrid(0).convert(
units::Pa).
value);
808 for(
int i = 1; i < pwf.
rows(); ++i)
809 res += pwf(i) * absorber_vmr(Gas_name)->volume_mixing_ratio(pgrid(i).convert(
units::Pa).value);
822 for(
int i = 1; i < press->number_level(); ++i) {
823 avg_vmr += absorber_vmr(Gas_name)->volume_mixing_ratio(pgrid(i).convert(
units::Pa).value);
825 return avg_vmr / press->number_level();
831 Os <<
"AbsorberAbsco:\n";
832 for(
int i = 0; i < (int) gas_absorption.size(); ++i) {
833 Os <<
" Gas Absorber[" << i <<
"]:\n";
834 opad << *gas_absorption[i] <<
"\n";
836 Os <<
" Absorber VMR[" << i <<
"]:\n";
837 opad << *vmr[i] <<
"\n";
849 fill_tau_gas_cache();
851 blitz::Array<AutoDerivative<double>, 1> gsub(psub.rows());
852 for(
int i = 0; i < gsub.rows(); ++i)
853 gsub(i) = gravity_func(Spec_index, psub(i)).convert(
Unit(
"m/s^2")).value;
865 fill_tau_gas_cache();
866 int j = gas_index(Gas_name);
869 err <<
"Gas named " << Gas_name <<
" not present in vmr list";
872 Array<AutoDerivative<double>, 1> vmrsub(psub.rows());
873 for(
int i = 0; i < psub.rows(); ++i)
874 vmrsub(i) = vmr_func(j, psub(i)).value;
882 int i = gas_index(Gas_name);
885 err <<
"Gas named " << Gas_name <<
" not present in vmr list";
896 (
const std::string& Gas_name)
const 898 int i = gas_index(Gas_name);
901 err <<
"Gas named " << Gas_name <<
" not present in vmr list";
904 return gas_absorption[i];
914 fill_tau_gas_cache();
915 Array<AutoDerivative<double>, 1> tsub_t(psub.rows());
916 for(
int i = 0; i < psub.rows(); ++i)
917 tsub_t(i) = temp_func(psub(i)).convert(
units::K).value;
929 fill_tau_gas_cache();
930 Array<AutoDerivative<double>, 1> h2o_vmr_t(psub.rows());
931 for(
int i = 0; i < psub.rows(); ++i)
932 h2o_vmr_t(i) = h2o_vmr_func(psub(i)).value;
This class is used to read the absco tables.
#define range_check(V, Min, Max)
Range check.
This class maintains the absorber portion of the state.
ArrayAd< double, 1 > pressure_weighting_function_grid() const
This is the pressure weighting function by grid level.
This is a AutoDerivative that also has units associated with it.
virtual boost::shared_ptr< Absorber > clone() const
Clone an Absorber object.
ArrayAdWithUnit< double, 1 > h2o_vmr_sublayer() const
Return the H2O volume mixing ratio we use for each sublayer.
This is a filtering stream that adds a pad to the front of every line written out.
AutoDerivativeWithUnit< T > convert(const Unit &R) const
Convert to the given units.
double integrand(double wn, double p, int Spec_index, int Species_index) const
Integrand used in the absorption calculation.
AbsorberAbsco(const std::vector< boost::shared_ptr< AbsorberVmr > > Vmr, const boost::shared_ptr< Pressure > &Press, const boost::shared_ptr< Temperature > &Temp, const std::vector< boost::shared_ptr< Altitude > > &Alt, const std::vector< boost::shared_ptr< GasAbsorption > > &Gas_absorption, const boost::shared_ptr< Constant > &C, int Nsub=10)
Create an absorber.
ArrayAdWithUnit< double, 1 > dry_air_molecular_density_layer() const
This is a helper function to compute the common part of the dry air mass and wet air mass routines...
const Unit dimensionless("dimensionless", 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
virtual void print(std::ostream &Os) const
virtual boost::shared_ptr< AbsorberVmr > absorber_vmr(const std::string &Gas_name) const
Returns the AbsorberVmr object for a given species index.
const Unit Pa("Pa", N/(m *m))
virtual blitz::Array< double, 2 > optical_depth_each_layer_nder(double wn, int spec_index) const
This is the base of the exception hierarchy for Full Physics code.
#define REGISTER_LUA_DERIVED_CLASS(X, Y)
const blitz::Array< T, D+1 > jacobian() const
AutoDerivative< double > average_vmr(const std::string &Gas_name) const
Returns the simple average volume mixing ratio for a gas.
ArrayAdWithUnit< double, 1 > wet_air_column_thickness_layer() const
This is the wet air column thickness by layer.
blitz::Array< AutoDerivative< T >, D > to_array() const
AutoDerivativeWithUnit< double > integrand_independent_wn(int Spec_index, int Species_index, const DoubleWithUnit &P) const
This is the portion of the optical depth calculation integrand that is independent on the wave number...
Apply value function to a blitz array.
ArrayAd< double, 1 > pressure_weighting_function_layer() const
This is the pressure weighting function by layer.
const blitz::Array< T, D > & value() const
The AutoDerivative<T> works well, and it works with blitz if you create a blitz::Array<AutoDerivative...
int number_variable() const
const Unit K("K", 1.0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)
This is a helper class that calculates the absorption cross section for a fixed set of Pressure...
const Unit m("m", 1.0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
virtual ArrayAd< double, 2 > optical_depth_each_layer(double wn, int spec_index) const
This gives the optical depth for each layer, for the given wave number.
We frequently have a double with units associated with it.
double optical_depth_each_layer_direct_integrate(double wn, int Spec_index, int Species_index, int Layer_index, double eps_abs=0, double eps_rel=1e-3) const
Find the optical depth for a layer by directly integrating the integrand function.
int number_variable() const
ArrayAdWithUnit< double, 1 > vmr_sublayer(const std::string &Gas_name) const
Return the volume mixing ratio we use for each sublayer.
void reference(const ArrayAd< T, D > &V)
Libraries such as boost::units allow unit handling where we know the units at compile time...
Contains classes to abstract away details in various Spurr Radiative Transfer software.
const T & value() const
Convert to type T.
#define REGISTER_LUA_END()
ArrayAdWithUnit< double, 1 > specific_humidity_layer() const
Returns specific humidity by layer.
ArrayAdWithUnit< double, 1 > gravity_sublayer(int Spec_index) const
Return the gravity we use for each sublayer.
AutoDerivative< T > value
This class maintains the absorber portion of the state.
Helper class for AccumulatedTimer.
ArrayAdWithUnit< double, 1 > gas_column_thickness_layer(const std::string &Gas_name) const
This is the column thickness of a gas by layer.
ArrayAdWithUnit< double, 1 > temperature_sublayer() const
Return the temperature we use for each sublayer.
double value(const FullPhysics::AutoDerivative< double > &Ad)
virtual AutoDerivative< double > xgas(const std::string &Gas_name) const
This calculates the gas column, e.g., XCO2.
AutoDerivativeWithUnit< double > gas_total_column_thickness(const std::string &Gas_name) const
This is the total column thickness of a gas.
ArrayAdWithUnit< double, 1 > dry_air_column_thickness_layer() const
This is the dry air column thickness by layer.
boost::shared_ptr< GasAbsorption > gas_absorption_ptr(const std::string &Gas_name) const
Return GasAbsorption as a pointer.