ReFRACtor
lidort_driver.cc
Go to the documentation of this file.
1 #include "lidort_driver.h"
2 #include "fp_exception.h"
3 #include "linear_algebra.h"
4 #include "old_constant.h"
5 #include "wgs84_constant.h"
6 #include "ground.h"
7 #include "ostream_pad.h"
8 #include "fe_disable_exception.h"
9 
10 #include "spurr_brdf_types.h"
11 
12 using namespace FullPhysics;
13 using namespace blitz;
14 
15 //=======================================================================
16 // LidortBrdfInterface
17 //=======================================================================
18 
19 //-----------------------------------------------------------------------
21 //-----------------------------------------------------------------------
22 
23 LidortBrdfDriver::LidortBrdfDriver(int nstream, int nmoment) : nmoment_(nmoment)
24 {
25  brdf_interface_.reset( new Brdf_Linsup_Masters() );
26 
27  Brdf_Sup_Inputs& brdf_inputs = brdf_interface_->brdf_sup_in();
28 
29  // Only use 1 beam meaning only one set of sza, azm
30  brdf_inputs.bs_nbeams(1);
31  brdf_inputs.bs_n_user_streams(1);
32  brdf_inputs.bs_n_user_relazms(1);
33 
34  // This MUST be consistent with streams used for
35  // LIDORT RT calculation
36  brdf_inputs.bs_nstreams(nstream);
37 
38  // Recommended value from LIDORT manual
39  // Number of quadtrature streams for BRDF calculation
40  brdf_inputs.bs_nstreams_brdf(50);
41 
42  brdf_params.reference( brdf_inputs.bs_brdf_parameters() );
43  brdf_factors.reference( brdf_inputs.bs_brdf_factors() );
44 }
45 
46 void LidortBrdfDriver::setup_geometry(double sza, double azm, double zen) const
47 {
48 
49  Brdf_Sup_Inputs& brdf_inputs = brdf_interface_->brdf_sup_in();
50 
51  // Solar zenith angles (degrees) [0,90]
52  Array<double, 1> brdf_sza( brdf_inputs.bs_beam_szas() );
53  brdf_sza(0) = sza;
54 
55  // User-defined relative angles (in degrees) for
56  // off-quadrature output.
57  Array<double, 1> brdf_azm( brdf_inputs.bs_user_relazms() );
58  brdf_azm(0) = azm;
59 
60  // User-defined viewing zenith angles (in degrees) for
61  // off quadrature output.
62  Array<double, 1> brdf_zen( brdf_inputs.bs_user_angles_input() );
63  brdf_zen(0) = zen;
64 }
65 
67 {
68  // Lidort may cause floating point exceptions when doing setup. This
69  // is because it may copy garbage value, which are never used. By
70  // chance the garbage values may cause a overflow. We
71  // suspend floating point exceptions when doing setup
72  FeDisableException disable_fp;
73 
74  // Process BRDF inputs
75  bool do_debug_restoration = false;
76  brdf_interface_->run(do_debug_restoration, nmoment_);
77 }
78 
80 {
81  return brdf_interface_->brdf_sup_in().bs_n_brdf_kernels();
82 }
83 
84 void LidortBrdfDriver::n_brdf_kernels(const int n_kernels)
85 {
86  brdf_interface_->brdf_sup_in().bs_n_brdf_kernels(n_kernels);
87 }
88 
90  return brdf_interface_->brdf_linsup_in().bs_n_kernel_factor_wfs();
91 }
92 
93 void LidortBrdfDriver::n_kernel_factor_wfs(const int n_factors) {
94  brdf_interface_->brdf_linsup_in().bs_n_kernel_factor_wfs(n_factors);
95 }
96 
98  return brdf_interface_->brdf_linsup_in().bs_n_kernel_params_wfs();
99 }
100 
101 void LidortBrdfDriver::n_kernel_params_wfs(const int n_params) {
102  brdf_interface_->brdf_linsup_in().bs_n_kernel_params_wfs(n_params);
103 }
104 
106  return brdf_interface_->brdf_linsup_in().bs_n_surface_wfs();
107 }
108 
109 void LidortBrdfDriver::n_surface_wfs(const int n_wfs) {
110  brdf_interface_->brdf_linsup_in().bs_n_surface_wfs(n_wfs);
111 }
112 
113 bool LidortBrdfDriver::do_kparams_derivs(const int kernel_index) const
114 {
115  return brdf_interface_->brdf_linsup_in().bs_do_kparams_derivs()(kernel_index);
116 }
117 
118 void LidortBrdfDriver::do_kparams_derivs(const int kernel_index, const bool do_kparams)
119 {
120  Brdf_Linsup_Inputs& brdf_lin_inputs = brdf_interface_->brdf_linsup_in();
121  Array<bool, 1> do_kparams_derivs( brdf_lin_inputs.bs_do_kparams_derivs() );
122  do_kparams_derivs(kernel_index) = do_kparams;
123  brdf_lin_inputs.bs_do_kparams_derivs(do_kparams_derivs);
124 }
125 
127  return brdf_interface_->brdf_sup_in().bs_do_shadow_effect();
128 }
129 
130 void LidortBrdfDriver::do_shadow_effect(const bool do_shadow) const {
131  brdf_interface_->brdf_sup_in().bs_do_shadow_effect(do_shadow);
132 }
133 
135  const int which_brdf,
136  const bool lambertian_flag,
137  const int n_brdf_parameters,
138  const bool do_factor_wfs,
139  const blitz::Array<bool, 1>& do_params_wfs)
140 {
141  Brdf_Sup_Inputs& brdf_inputs = brdf_interface_->brdf_sup_in();
142  Brdf_Linsup_Inputs& brdf_lin_inputs = brdf_interface_->brdf_linsup_in();
143 
144  Array<int, 1> bs_which_brdf( brdf_inputs.bs_which_brdf() );
145  bs_which_brdf(kernel_index) = which_brdf;
146 
147  Array<bool, 1> bs_lambertian_flag = brdf_inputs.bs_lambertian_kernel_flag();
148  bs_lambertian_flag(kernel_index) = lambertian_flag;
149  brdf_inputs.bs_lambertian_kernel_flag(bs_lambertian_flag);
150 
151  Array<int, 1> bs_n_brdf_parameters( brdf_inputs.bs_n_brdf_parameters() );
152  bs_n_brdf_parameters(kernel_index) = n_brdf_parameters;
153 
154  Array<bool, 1> bs_do_factor_wfs( brdf_lin_inputs.bs_do_kernel_factor_wfs() );
155  bs_do_factor_wfs(kernel_index) = do_factor_wfs;
156  brdf_lin_inputs.bs_do_kernel_factor_wfs(bs_do_factor_wfs);
157 
158  Array<bool, 2> bs_do_params_wfs( brdf_lin_inputs.bs_do_kernel_params_wfs() );
159  bs_do_params_wfs(kernel_index, Range(0, do_params_wfs.rows()-1)) = do_params_wfs;
160  brdf_lin_inputs.bs_do_kernel_params_wfs(bs_do_params_wfs);
161 }
162 
163 //=======================================================================
164 // LidortRtDriver
165 //=======================================================================
166 
167 LidortRtDriver::LidortRtDriver(int nstream, int nmoment, bool do_multi_scatt_only,
168  int surface_type, const blitz::Array<double, 1>& zen, bool pure_nadir,
169  bool do_solar, bool do_thermal)
170  : nstream_(nstream), nmoment_(nmoment), do_multi_scatt_only_(do_multi_scatt_only), surface_type_(surface_type), pure_nadir_(pure_nadir),
171  SpurrRtDriver(do_solar, do_thermal)
172 {
173  brdf_driver_.reset( new LidortBrdfDriver(nstream, nmoment) );
174  lidort_interface_.reset( new Lidort_Lps_Masters() );
175 
176  // Check inputs against sizes allowed by LIDORT
177  Lidort_Pars lid_pars = Lidort_Pars::instance();
178  range_check(nstream, 1, lid_pars.maxstreams+1);
179  range_check(nmoment, 3, lid_pars.maxmoments_input+1);
180 
181  // Initialize BRDF data structure
182  brdf_driver()->initialize_brdf_inputs(surface_type_);
183 
184  initialize_rt();
185 
186  // Set up scatting mode based on viewing zenith angle
187  setup_sphericity(max(zen));
188 }
189 
191 {
192  if (!lidort_interface_) {
193  throw Exception("Lidort Interface not initialized");
194  }
195  return lidort_interface_->lidort_modin().mcont().ts_nmoments_input();
196 }
197 
199 {
200  if (!lidort_interface_) {
201  throw Exception("Lidort Interface not initialized");
202  }
203  return lidort_interface_->lidort_fixin().cont().ts_nstreams();
204 }
205 
207 {
208  // Set up these references for convienence
209  Lidort_Fixed_Boolean& fboolean_inputs = lidort_interface_->lidort_fixin().f_bool();
210  Lidort_Modified_Control& mcontrol_inputs = lidort_interface_->lidort_modin().mcont();
211  Lidort_Modified_Boolean& mboolean_inputs = lidort_interface_->lidort_modin().mbool();
212 
213  Lidort_Fixed_Control& fcontrol_inputs = lidort_interface_->lidort_fixin().cont();
214  Lidort_Fixed_Sunrays& fbeam_inputs = lidort_interface_->lidort_fixin().sunrays();
215  Lidort_Modified_Sunrays& mbeam_inputs = lidort_interface_->lidort_modin().msunrays();
216  Lidort_Modified_Chapman& mchapman_inputs = lidort_interface_->lidort_modin().mchapman();
217 
218  Lidort_Modified_Uservalues& muser_inputs = lidort_interface_->lidort_modin().muserval();
219  Lidort_Fixed_Uservalues& fuser_inputs = lidort_interface_->lidort_fixin().userval();
220 
221  Lidort_Fixed_Lincontrol& lincontrol = lidort_interface_->lidort_linfixin().cont();
222 
223  // Set values used for all calculations
224  // Number of quadtature streams in the cosine half space
225  fcontrol_inputs.ts_nstreams(nstream_);
226 
227  // Number of Legendre expansion coefficients for the phase function
228  mcontrol_inputs.ts_nmoments_input(nmoment_);
229 
230  // Always use BRDF supplement, don't use specialized lambertian_albedo mode
231  brdf_interface()->brdf_sup_in().bs_do_brdf_surface(true);
232  fboolean_inputs.ts_do_brdf_surface(true);
233 
234  // Flags for viewing mode
235  fboolean_inputs.ts_do_upwelling(true);
236  fboolean_inputs.ts_do_dnwelling(false);
237 
238  // Fourier azimuth series is examined twice for convergence
239  mboolean_inputs.ts_do_double_convtest(true);
240 
241  // Do internal calculation of slanth path optical depths
242  mboolean_inputs.ts_do_chapman_function(true);
243 
244  // In most instances this flag for delta-m scaling should be set
245  mboolean_inputs.ts_do_deltam_scaling(true);
246 
247  // There will be output at a number of off-quadrature
248  // zenith angles specified by the user, this is the normal case
249  mboolean_inputs.ts_do_user_streams(true);
250  brdf_interface()->brdf_sup_in().bs_do_user_streams(true);
251 
252  // Accuracy criterion for convergence of Fourier series in
253  // relative azimuth. Set to recommended value.
254  fcontrol_inputs.ts_lidort_accuracy(1e-8);
255 
256  // Beam source flux, same value used for all solar angles
257  // Normally set to 1 for "sun-normalized" output
258  fbeam_inputs.ts_flux_factor(1.0);
259 
260  // Enable solar sources calculations
261  if (do_solar_sources) {
262  // Needed for atmospheric scattering of sunlight
263  mboolean_inputs.ts_do_solar_sources(true);
264 
265  // Enable solar sources in the BRDF driver
266  brdf_interface()->brdf_sup_in().bs_do_solar_sources(true);
267  }
268 
269  // Enable thermal emission calculation
270  if (do_thermal_emission) {
271  fboolean_inputs.ts_do_thermal_emission(true);
272  fboolean_inputs.ts_do_surface_emission(true);
273 
274  // Number of coefficients used in treatment of blackbody emissions in a layer
275  // 1 implies constant within a layer
276  // 2 implies a lineaer treatment
277  fcontrol_inputs.ts_n_thermal_coeffs(2);
278 
279  // Enable solar sources in the BRDF driver
280  brdf_interface()->brdf_sup_in().bs_do_surface_emission(true);
281  }
282 
283  // Number of solar beams
284  mbeam_inputs.ts_nbeams(1);
285 
286  // Earth's radius in km
287  mchapman_inputs.ts_earth_radius( OldConstant::wgs84_a.
288  convert(units::km).value);
289 
290  // Number of user-defined relative azimuth angles
291  muser_inputs.ts_n_user_relazms(1);
292 
293  // Number of user-defined viewing zenith angles
294  muser_inputs.ts_n_user_streams(1);
295 
296  // Number of vertical output levels
297  fuser_inputs.ts_n_user_levels(1);
298 
299  // Flag for calculating profile Jacobians in layer n
300  // Calculate jacobians for all layers
301  Array<bool, 1> layer_jac_flag(lincontrol.ts_layer_vary_flag());
302  layer_jac_flag = true;
303  lincontrol.ts_layer_vary_flag(layer_jac_flag);
304 
305  // Needs to match the number set in the BRDF structure
306  lincontrol.ts_n_surface_wfs(brdf_interface()->brdf_linsup_in().bs_n_surface_wfs());
307 }
308 
311 void LidortRtDriver::setup_sphericity(double zen) const
312 {
313 
314  Lidort_Fixed_Boolean& fboolean_inputs = lidort_interface_->lidort_fixin().f_bool();
315  Lidort_Modified_Boolean& mboolean_inputs = lidort_interface_->lidort_modin().mbool();
316  Lidort_Fixed_Control& fcontrol_inputs = lidort_interface_->lidort_fixin().cont();
317 
319  // Do not do full reflectance calculation if only multiple scattering needed
320  // These flags should already be false, but just in case..
321 
322  // Only return diffuse multiple scattering component
323  fboolean_inputs.ts_do_fullrad_mode(false);
324  fboolean_inputs.ts_do_ssfull(false);
325 
326  // Also SS corr and plane-parallel flags are false
327  mboolean_inputs.ts_do_sscorr_nadir(false);
328  mboolean_inputs.ts_do_sscorr_outgoing(false);
329 
330  } else { // if not do multi_scatt_only
331  // Do full SS + MS calculation and use LOS correction
332 
333  // Do a full reflectance calculation
334  fboolean_inputs.ts_do_fullrad_mode(true);
335  fboolean_inputs.ts_do_ssfull(false);
336 
337  // Pseudo-spherical + Line of Sight correction
338  mboolean_inputs.ts_do_sscorr_nadir(false);
339  mboolean_inputs.ts_do_sscorr_outgoing(true);
340 
341  // Number of fine layers subdividing coarse layering
342  // Only used during LOS correction
343  fcontrol_inputs.ts_nfinelayers(4);
344  }
345 
346  // Flag for controlling azimuth dependence in the output
347  // LIDORT will complain if user zenith is 0 and this is not
348  // set, when not using ss correction mode
349  if( pure_nadir_ ) {
350  mboolean_inputs.ts_do_no_azimuth(true);
351  if (mboolean_inputs.ts_do_sscorr_outgoing()) {
352  // Use Pseudo-spherical correction instead for these small viewing zenith angles
353  mboolean_inputs.ts_do_sscorr_outgoing(false);
354  mboolean_inputs.ts_do_sscorr_nadir(true);
355  }
356  }
357 }
358 
361 {
362  Lidort_Modified_Boolean& mboolean_inputs = lidort_interface_->lidort_modin().mbool();
363  Lidort_Fixed_Boolean& fboolean_inputs = lidort_interface_->lidort_fixin().f_bool();
364 
365  mboolean_inputs.ts_do_sscorr_outgoing(false);
366  mboolean_inputs.ts_do_sscorr_nadir(false);
367  fboolean_inputs.ts_do_plane_parallel(true);
368  mboolean_inputs.ts_do_no_azimuth(true);
369 }
370 
373 {
374  // Lidort may cause floating point exceptions when doing setup. This
375  // is because it may copy garbage value, which are never used. By
376  // chance the garbage values may cause a overflow. We
377  // suspend floating point exceptions when doing setup
378  FeDisableException disable_fp;
379 
380  Lidort_Modified_Boolean& mboolean_inputs = lidort_interface_->lidort_modin().mbool();
381  Lidort_Fixed_Boolean& fboolean_inputs = lidort_interface_->lidort_fixin().f_bool();
382 
383  mboolean_inputs.ts_do_sscorr_outgoing(false);
384  mboolean_inputs.ts_do_sscorr_nadir(true);
385  fboolean_inputs.ts_do_plane_parallel(false);
386  mboolean_inputs.ts_do_no_azimuth(false);
387 }
388 
391 {
392  Lidort_Modified_Boolean& mboolean_inputs = lidort_interface_->lidort_modin().mbool();
393  Lidort_Fixed_Boolean& fboolean_inputs = lidort_interface_->lidort_fixin().f_bool();
394 
395  mboolean_inputs.ts_do_sscorr_outgoing(false);
396  mboolean_inputs.ts_do_sscorr_nadir(true);
397  fboolean_inputs.ts_do_plane_parallel(true);
398  mboolean_inputs.ts_do_no_azimuth(false);
399 }
400 
403 {
404  Lidort_Modified_Boolean& mboolean_inputs = lidort_interface_->lidort_modin().mbool();
405  Lidort_Fixed_Boolean& fboolean_inputs = lidort_interface_->lidort_fixin().f_bool();
406 
407  mboolean_inputs.ts_do_sscorr_outgoing(true);
408  mboolean_inputs.ts_do_sscorr_nadir(false);
409  fboolean_inputs.ts_do_plane_parallel(false);
410  mboolean_inputs.ts_do_no_azimuth(false);
411 }
412 
413 void LidortRtDriver::setup_height_grid(const blitz::Array<double, 1>& in_height_grid) const
414 {
415 
416  Lidort_Fixed_Chapman& fchapman_inputs = lidort_interface_->lidort_fixin().chapman();
417  Lidort_Modified_Uservalues& muser_inputs = lidort_interface_->lidort_modin().muserval();
418 
419  Array<double, 1> lidort_height_grid( fchapman_inputs.ts_height_grid() );
420  int nlayer = in_height_grid.extent(firstDim) - 1;
421  Range lay_range = Range(0,nlayer);
422  lidort_height_grid(lay_range) = in_height_grid;
423 
424  // Set GEOMETRY_SPECHEIGHT = HEIGHT_GRID(NLAYERS)
425  muser_inputs.ts_geometry_specheight( lidort_height_grid(nlayer) );
426 
427  // Tell LIDORT number of layers
428  lidort_interface_->lidort_fixin().cont().ts_nlayers(nlayer);
429 }
430 
431 void LidortRtDriver::setup_geometry(double sza, double azm, double zen) const
432 {
433 
434  Lidort_Modified_Sunrays& mbeam_inputs = lidort_interface_->lidort_modin().msunrays();
435  Lidort_Modified_Uservalues& muser_inputs = lidort_interface_->lidort_modin().muserval();
436 
437  // Solar zenith angles (degrees) [0,90]
438  Array<double, 1> ld_sza( mbeam_inputs.ts_beam_szas() );
439  ld_sza(0) = sza;
440 
441  // User-defined relative angles (in degrees) for
442  // off-quadrature output.
443  Array<double, 1> ld_azm( muser_inputs.ts_user_relazms() );
444  ld_azm(0) = azm;
445 
446  // User-defined viewing zenith angles (in degrees) for
447  // off quadrature output.
448  Array<double, 1> ld_zen( muser_inputs.ts_user_angles_input() );
449  ld_zen(0) = zen;
450 }
451 
452 void LidortRtDriver::setup_thermal_inputs(double surface_bb, const blitz::Array<double, 1> atmosphere_bb) const
453 {
454  Lidort_Fixed_Optical& foptical_inputs = lidort_interface_->lidort_fixin().optical();
455 
456  foptical_inputs.ts_surface_bb_input(surface_bb);
457 
458  // Thermal black body atmosphere inputs will be on levels instead of layers
459  Range rlev(0, atmosphere_bb.extent(firstDim) - 1);
460  Array<double, 1> thermal_bb_input( foptical_inputs.ts_thermal_bb_input() );
461  thermal_bb_input(rlev) = atmosphere_bb;
462 }
463 
464 void LidortRtDriver::setup_optical_inputs(const blitz::Array<double, 1>& od,
465  const blitz::Array<double, 1>& ssa,
466  const blitz::Array<double, 2>& pf) const
467 {
468 
469  // Ranges for copying inputs to method
470  Range rlay(0, od.extent(firstDim) - 1);
471  Range rmom(0, pf.extent(firstDim) - 1);
472 
473  // Convienence references
474  Lidort_Fixed_Optical& foptical_inputs = lidort_interface_->lidort_fixin().optical();
475  Lidort_Modified_Optical& moptical_inputs = lidort_interface_->lidort_modin().moptical();
476 
477  // Vertical optical depth thicness values for all layers and threads
478  Array<double, 1> deltau( foptical_inputs.ts_deltau_vert_input() );
479  deltau(rlay) = od;
480 
481  // Single scattering albedos for all layers and threads
482  Array<double, 1> omega( moptical_inputs.ts_omega_total_input() );
483  omega(rlay) = where(ssa > 0.999, 0.999999, ssa);
484 
485  // For all layers n and threads t, Legrenre moments of
486  // the phase function expansion multiplied by (2L+1);
487  // initial value (L=0) should always be 1
488  // phasmoms_total_input(n, L, t)
489  // n = moments, L = layers, t = threads
490  Array<double, 2> phasmoms( foptical_inputs.ts_phasmoms_total_input() );
491  phasmoms(rmom, rlay) = where(abs(pf) > 1e-11, pf, 1e-11);
492 }
493 
495 {
496  Lidort_Fixed_Lincontrol& lincontrol = lidort_interface_->lidort_linfixin().cont();
497 
498  // Flag for output of profile Jacobians
499  lincontrol.ts_do_profile_linearization(false);
500 
501  // Flag for output of surface Jacobians
502  lincontrol.ts_do_surface_linearization(false);
503 }
504 
506  const ArrayAd<double, 1>& ssa,
507  const ArrayAd<double, 2>& pf,
508  bool do_surface_linearization) const
509 {
510 
512  Exception err;
513  err << "LIDORT has been compiled to allow a maximum of " << Lidort_Pars::instance().max_atmoswfs
514  << " atmosphere derivatives to be calculated. We are trying to calculate "
515  << od.number_variable() << " atmosphere derivatives";
516  throw err;
517  }
518 
519  Lidort_Fixed_Lincontrol& lincontrol = lidort_interface_->lidort_linfixin().cont();
520  Lidort_Fixed_Linoptical& linoptical = lidort_interface_->lidort_linfixin().optical();
521 
522  // Number of profile weighting functions in layer n
523  int natm_jac = od.number_variable();
524  Array<int, 1> layer_jac_number( lincontrol.ts_layer_vary_number() );
525  layer_jac_number = natm_jac;
526 
527  // Ranges for copying inputs to method
528  Range ra(Range::all());
529  Range rlay(0, od.rows() - 1); // number of layers
530  Range rjac(0, natm_jac - 1);
531 
532  Range rmom(0, pf.rows() - 1); // number phase function moments
533  Range all(Range::all());
534 
535  // Flag for output of profile Jacobians
536  // Unlikely we won't need these
537  lincontrol.ts_do_profile_linearization(true);
538 
539  // Flag for output of surface Jacobians
540  // Certainly wouldn't need this if not retrieving ground
541  lincontrol.ts_do_surface_linearization(do_surface_linearization);
542 
543  // Check that we fit within the LIDORT configuration
544  if(linoptical.ts_l_deltau_vert_input().cols() < od.rows()) {
545  Exception e;
546  e << "The number of layers you are using exceeds the maximum allowed by\n"
547  << "the current build of Lidort. The number requested is "
548  << od.rows() << "\nand the maximum allowed is "
549  << linoptical.ts_l_deltau_vert_input().cols() << "\n"
550  << "\n"
551  << "You might try rebuilding with a larger value given to the configure\n"
552  << "option --with-lidort-maxlayer=value set to a larger value.\n";
553  throw e;
554  }
555  if(linoptical.ts_l_deltau_vert_input().rows() < natm_jac) {
556  Exception e;
557  e << "The number of jacobians you are using exceeds the maximum allowed by\n"
558  << "the current build of Lidort. The number requested is "
559  << natm_jac << "\nand the maximum allowed is "
560  << linoptical.ts_l_deltau_vert_input().rows() << "\n"
561  << "\n"
562  << "This number of jacobians is a function of the number of aerosols\n"
563  << "in your state vector, so you can reduce the number of aerosols\n"
564  << "\n"
565  << "You might also try rebuilding with a larger value given to the configure\n"
566  << "option --with-lidort-maxatmoswfs=value set to a larger value.\n";
567  throw e;
568  }
569 
570  // Setup optical linear inputs
571  // LIDORT expects the following:
572  // l_deltau = xi/tau * dtau/dxi
573  // l_omega = xi/omega * domega/dxi
574  // ... etc
575  // The driver is handed dtau/dxi, domega/dxi ... etc
576  // Where it is normally set up for xi being taug, taur, taua[0], taua[1]...
577  //
578  // LIDORT returns to us:
579  // xi * dI/dxi
580  // Therefore you will notice that by not multiplying dtau/dxi by xi and only
581  // dividing by xi, we are cancelling out the xi in the result and hence
582  // the driver really return dI/dxi
583  Array<double, 2> l_deltau( linoptical.ts_l_deltau_vert_input()(rjac,rlay) );
584  Array<double, 2> l_omega( linoptical.ts_l_omega_total_input()(rjac,rlay) );
585  Array<double, 3> l_phasmoms( linoptical.ts_l_phasmoms_total_input()(rjac,rmom,rlay) );
586 
587  // Transpose these to match dimensions used internally
588  l_deltau.transposeSelf(secondDim, firstDim);
589  l_omega.transposeSelf(secondDim, firstDim);
590 
591  // Note that LIDORT does *not* take l_deltau etc. Rather it takes
592  // what it calls "normalized derivative inputs". So for an optical
593  // quantity like taug wrt to tau, this would be taug / tau *
594  // dtau/dtaug.
595  //
596  // It then returns a normalized jacobian, which for taug would be
597  // taug * d I /dtaug.
598  //
599  // Note that we actually leave out one of these factors, because it
600  // effectively cancels out. We pass in 1 / tau * dtau / dtaug and
601  // get back d I / dtaug.
602 
603  firstIndex i1; secondIndex i2;
604  l_deltau = where(od.value()(i1) != 0, od.jacobian() / od.value()(i1), 0.0);
605 
606  Array<double, 1> ssa_limit(ssa.rows());
607  ssa_limit = where(ssa.value() > 0.999, 0.999999, ssa.value());
608  l_omega = where(ssa_limit(i1) != 0, ssa.jacobian() / ssa_limit(i1), 0.0);
609 
610  if(pf.is_constant())
611  l_phasmoms(rjac, rmom, rlay) = 0.0;
612  else {
613  blitz::Array<double, 2> pf_in( where(abs(pf.value()) > 1e-11, pf.value(), 1e-11) );
614 
615  // We need this loop since l_phasmoms and pf variables have jacobian data in different dimensions
616  for (int jidx = 0; jidx < pf.number_variable(); jidx++)
617  l_phasmoms(jidx, rmom, rlay) = pf.jacobian()(rmom, rlay, jidx) / pf_in(rmom, rlay)(i1,i2);
618  }
619 }
620 
623 
624  // Copy BRDF outputs to LIDORT's BRDF inputs
625  Brdf_Sup_Outputs& brdf_outputs = brdf_interface()->brdf_sup_out();
626  Brdf_Linsup_Outputs& brdf_lin_outputs = brdf_interface()->brdf_linsup_out();
627 
628  Lidort_Sup_Brdf& lid_brdf = lidort_interface_->lidort_sup().brdf();
629  Lidort_Linsup_Brdf& lid_lin_brdf = lidort_interface_->lidort_linsup().brdf();
630 
631  lid_brdf.copy_from_sup( brdf_outputs );
632  lid_lin_brdf.copy_from_sup( brdf_lin_outputs );
633 }
634 
636 {
637  // Must copy current BRDF supplement outputs into datastructures used by LIDORT
639 
640  // Call LIDORT for calculations
641  lidort_interface_->run();
642 }
643 
645 {
646  // So we know index of intensity
647  Lidort_Pars lid_pars = Lidort_Pars::instance();
648 
649  // Total Intensity I(t,v,d,T) at output level t, output geometry v,
650  // direction d, thread T
651  return lidort_interface_->lidort_out().main().ts_intensity()(0,0,lid_pars.upidx-1);
652 }
653 
654 void LidortRtDriver::copy_jacobians(blitz::Array<double, 2>& jac_atm, blitz::Array<double, 1>& jac_surf) const
655 {
656  Lidort_Pars lid_pars = Lidort_Pars::instance();
657 
658  Lidort_Linatmos& lpoutputs = lidort_interface_->lidort_linout().atmos();
659  Lidort_Linsurf& lsoutputs = lidort_interface_->lidort_linout().surf();
660 
661  Range ra(Range::all());
662 
663  // Surface Jacobians KR(r,t,v,d) with respect to surface variable r
664  // at output level t, geometry v, direction
665  jac_surf.reference( lsoutputs.ts_surfacewf()(ra, 0, 0, lid_pars.upidx-1).copy() );
666 
667  // Get profile jacobians
668  // Jacobians K(q,n,t,v,d) with respect to profile atmospheric variable
669  // q in layer n, at output level t, geometry v, direction d
670  jac_atm.reference( lpoutputs.ts_profilewf()(ra, ra, 0, 0, lid_pars.upidx-1).copy() );
671 }
const boost::shared_ptr< Brdf_Linsup_Masters > brdf_interface() const
Definition: lidort_driver.h:81
void setup_thermal_inputs(double surface_bb, const blitz::Array< double, 1 > atmosphere_bb) const
Set up thermal emission inputs.
const blitz::Array< double, 1 > & ts_height_grid() const
#define range_check(V, Min, Max)
Range check.
Definition: fp_exception.h:140
const blitz::Array< int, 1 > & ts_layer_vary_number() const
static Lidort_Pars & instance()
const blitz::Array< bool, 1 > ts_layer_vary_flag() const
bool is_constant() const
Definition: array_ad.h:371
void set_line_of_sight() const
Set line of sight mode.
virtual int n_kernel_params_wfs() const
const blitz::Array< double, 1 > & ts_beam_szas() const
const blitz::Array< double, 2 > & ts_l_deltau_vert_input() const
LidortBrdfDriver(int nstream, int nmoment)
Initialize Lidort BRDF interface.
const DoubleWithUnit wgs84_a(6378137.0000, units::m)
Equatorial radius.
const boost::shared_ptr< SpurrBrdfDriver > brdf_driver() const
Access to BRDF driver.
Definition: spurr_driver.h:123
const blitz::Array< double, 4 > & ts_surfacewf() const
const blitz::Array< double, 5 > & ts_profilewf() const
void clear_linear_inputs() const
Mark that we are not retrieving weighting functions.
const blitz::Array< double, 1 > & ts_user_angles_input() const
void copy_brdf_sup_outputs() const
Copy outputs from BRDF supplement into LIDORT Sup inputs types.
void copy_jacobians(blitz::Array< double, 2 > &jac_atm, blitz::Array< double, 1 > &jac_surf) const
Copy jacobians out of internal xdata structures.
boost::shared_ptr< Brdf_Linsup_Masters > brdf_interface_
Definition: lidort_driver.h:51
boost::shared_ptr< Lidort_Lps_Masters > lidort_interface_
This is the base of the exception hierarchy for Full Physics code.
Definition: fp_exception.h:16
const blitz::Array< double, 1 > & bs_beam_szas() const
To detect things like divide by zero, we may turn on floating point exceptions.
void setup_optical_inputs(const blitz::Array< double, 1 > &od, const blitz::Array< double, 1 > &ssa, const blitz::Array< double, 2 > &pf) const
Set up optical depth, single scattering albedo and phase function Should be called per spectral point...
const blitz::Array< T, D+1 > jacobian() const
Definition: array_ad.h:307
const blitz::Array< int, 1 > & bs_n_brdf_parameters() const
LidortRtDriver(int nstream, int nmoment, bool do_multi_scatt_only, int surface_type, const blitz::Array< double, 1 > &zen, bool pure_nadir, bool do_solar=true, bool do_thermal=false)
const blitz::Array< double, 2 > & ts_l_omega_total_input() const
virtual int n_kernel_factor_wfs() const
virtual int n_brdf_kernels() const
const blitz::Array< double, 2 > & bs_brdf_parameters() const
Apply value function to a blitz array.
virtual bool do_kparams_derivs(const int kernel_index) const
const blitz::Array< bool, 1 > bs_do_kparams_derivs() const
const blitz::Array< T, D > & value() const
Definition: array_ad.h:306
const blitz::Array< double, 1 > & bs_brdf_factors() const
const blitz::Array< double, 3 > & ts_l_phasmoms_total_input() const
virtual void initialize_kernel_parameters(const int kernel_index, const int which_brdf, const bool lambertian_flag, const int n_brdf_parameters, const bool do_factor_wfs, const blitz::Array< bool, 1 > &do_params_wfs)
const blitz::Array< bool, 1 > bs_lambertian_kernel_flag() const
const blitz::Array< bool, 1 > bs_do_kernel_factor_wfs() const
void set_plane_parallel() const
Set plane parallel sphericity.
void setup_height_grid(const blitz::Array< double, 1 > &height_grid) const
Setup height grid, should only be called once per instance or if the height grid changes.
double get_intensity() const
Retrieve the intensity value calculated.
const blitz::Array< double, 1 > & bs_user_relazms() const
void set_plane_parallel_plus_ss_correction() const
Set plane parallel plus single scattering correction.
int number_variable() const
Definition: array_ad.h:376
blitz::Array< double, 1 > brdf_factors
Definition: spurr_driver.h:78
void calculate_rt() const
Perform radiative transfer calculation with the values setup by setup_optical_inputs and setup_linear...
const blitz::Array< double, 1 > & bs_user_angles_input() const
void copy_from_sup(Brdf_Sup_Outputs &supp_obj)
void set_pseudo_spherical() const
Set pseudo spherical sphericity.
const blitz::Array< double, 1 > & ts_omega_total_input() const
Abstracts away set up of Radiative Transfer software from Rob Spurr into a simpler common inteface us...
Definition: spurr_driver.h:90
const blitz::Array< int, 1 > & bs_which_brdf() const
virtual void setup_geometry(double sza, double azm, double zen) const
Contains classes to abstract away details in various Spurr Radiative Transfer software.
Definition: doxygen_python.h:1
LIDORT specific BRDF driver implementation.
Definition: lidort_driver.h:13
virtual void calculate_brdf() const
virtual int n_surface_wfs() const
const blitz::Array< bool, 2 > bs_do_kernel_params_wfs() const
void setup_geometry(double sza, double azm, double zen) const
Setup viewing geometry, should only be called once per instance or if the viewing geometry changes...
const Unit km("km", 1e3 *m)
double value(const FullPhysics::AutoDerivative< double > &Ad)
virtual bool do_shadow_effect() const
void copy_from_sup(Brdf_Linsup_Outputs &supp_obj)
void setup_linear_inputs(const ArrayAd< double, 1 > &od, const ArrayAd< double, 1 > &ssa, const ArrayAd< double, 2 > &pf, bool do_surface_linearization) const
Set up linearization, weighting functions.
boost::shared_ptr< SpurrBrdfDriver > brdf_driver_
Spurr BRDF class interface class to use.
Definition: spurr_driver.h:169
const blitz::Array< double, 1 > & ts_user_relazms() const
blitz::Array< double, 2 > brdf_params
Definition: spurr_driver.h:79
void setup_sphericity(double zen) const
Set up/reset sphericity mode which may be affected by the current zenith viewing angle.
const blitz::Array< double, 1 > & ts_thermal_bb_input() const
int rows() const
Definition: array_ad.h:368
void initialize_rt()
Initializes radiative transfer data structures.

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