Isis 3 Programmer Reference
Anisotropic2.cpp
1 #include <cmath>
2 #include "Anisotropic2.h"
3 #include "AtmosModel.h"
4 #include "Constants.h"
5 #include "Pvl.h"
6 #include "PvlGroup.h"
7 #include "IException.h"
8 #include "IString.h"
9 
10 using std::min;
11 using std::max;
12 
13 namespace Isis {
20  Anisotropic2::Anisotropic2(Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl, pmodel) {
21  }
22 
23 
52  void Anisotropic2::AtmosModelAlgorithm(double phase, double incidence, double emission) {
53  double xx;
54  double munot, mu;
55  double emunot, emu;
56  double munotp, mup;
57  double gmunot, gmu;
58  double hpsq1;
59  double f1munot, f2munot, f3munot;
60  double f1mmunot, f2mmunot, f3mmunot;
61  double maxval;
62  double f1mu, f2mu, f3mu;
63  double f1mmu, f2mmu, f3mmu;
64  double sum;
65  double prod;
66  double cosazss;
67  double xystuff;
68  double xmunot_0, ymunot_0;
69  double xmu_0, ymu_0;
70  double cxx, cyy;
71  double xmunot_1, ymunot_1;
72  double xmu_1, ymu_1;
73 
74  if(p_atmosBha == 0.0) {
75  p_atmosBha = 1.0e-6;
76  }
77 
78  if(p_atmosTau == 0.0) {
79  p_pstd = 0.0;
80  p_trans = 1.0;
81  p_trans0 = 1.0;
82  p_sbar = 0.0;
83  p_transs = 1.0;
84  return;
85  }
86 
87  if(p_atmosWha == 1.0) {
88  QString msg = "Anisotropic conservative case not implemented yet - WHA parameter cannot be set to 1.0.";
89  msg += "This will cause negative planetary curvature to occur.";
91  }
92 
93  if(TauOrWhaChanged()) {
94  // preparation includes exponential integrals e sub 2 through 5
95  p_wha2 = 0.5 * p_atmosWha;
96  p_wham = 1.0 - p_atmosWha;
97  p_e1 = AtmosModel::En(1, p_atmosTau);
98  p_e1_2 = AtmosModel::En(1, 2.0 * p_atmosTau);
99  p_e2 = AtmosModel::En(2, p_atmosTau);
100  p_e3 = AtmosModel::En(3, p_atmosTau);
101  p_e4 = AtmosModel::En(4, p_atmosTau);
102  p_e5 = AtmosModel::En(5, p_atmosTau);
103 
104  // chandra's gmn functions require fm and fn at mu=-1
105  xx = -p_atmosTau;
106  if(xx < -69.0) {
107  p_em = 0.0;
108  }
109  else if(xx > 69.0) {
110  p_em = 1.0e30;
111  }
112  else {
113  p_em = exp(xx);
114  }
115 
116  p_f1m = log(2.0) - p_em * p_e1 + p_e1_2;
117  p_f2m = -1.0 * (p_f1m + p_em * p_e2 - 1.0);
118  p_f3m = -1.0 * (p_f2m + p_em * p_e3 - 0.5);
119  p_f4m = -1.0 * (p_f3m + p_em * p_e4 - (1.0 / 3.0));
120  p_g12 = (p_atmosTau * p_e1 * p_e2 + p_f1m + p_f2m) * 0.5;
121  p_g13 = (p_atmosTau * p_e1 * p_e3 + p_f1m + p_f3m) * (1.0 / 3.0);
122  p_g14 = (p_atmosTau * p_e1 * p_e4 + p_f1m + p_f4m) * 0.25;
123  p_g32 = (p_atmosTau * p_e3 * p_e2 + p_f3m + p_f2m) * 0.25;
124  p_g33 = (p_atmosTau * p_e3 * p_e3 + p_f3m + p_f3m) * 0.2;
125  p_g34 = (p_atmosTau * p_e3 * p_e4 + p_f3m * p_f4m) * (1.0 / 6.0);
126 
127  // chandra's g'mn functions require g'11 and f at mu=+1
128  xx = p_atmosTau;
129  if(xx < -69.0) {
130  p_e = 0.0;
131  }
132  else if(xx > 69.0) {
133  p_e = 1.0e30;
134  }
135  else {
136  p_e = exp(xx);
137  }
138 
139  p_f1 = Eulgam() + log(p_atmosTau) + p_e * p_e1;
140  p_f2 = p_f1 + p_e * p_e2 - 1.0;
141  p_f3 = p_f2 + p_e * p_e3 - 0.5;
142  p_f4 = p_f3 + p_e * p_e4 - (1.0 / 3.0);
143  p_g11p = AtmosModel::G11Prime(p_atmosTau);
144  p_g12p = (p_atmosTau * (p_e1 - p_g11p) + p_em * (p_f1 + p_f2)) * 0.25;
145  p_g13p = (p_atmosTau * (0.5 * p_e1 - p_g12p) + p_em * (p_f1 + p_f3)) * 0.2;
146  p_g14p = (p_atmosTau * ((1.0 / 3.0) * p_e1 - p_g13p) + p_em * (p_f1 + p_f4)) * (1.0 / 6.0);
147  p_g32p = (p_atmosTau * (p_e1 - p_g13p) + p_em * (p_f3 + p_f2)) * (1.0 / 6.0);
148  p_g33p = (p_atmosTau * (0.5 * p_e1 - p_g32p) + p_em * (p_f3 + p_f3)) * 0.142857;
149  p_g34p = (p_atmosTau * ((1.0 / 3.0) * p_e1 - p_g33p) + p_em * (p_f3 + p_f4)) * 0.125;
150 
151  // first, get the required quantities for the axisymmetric m=0 part
152  // zeroth moments of (uncorrected) x and y times characteristic fn
153  p_x0_0 = p_wha2 * (1.0 + (1.0 / 3.0) * p_atmosBha * p_wham + p_wha2 * (p_g12 + p_atmosBha *
154  p_wham * (p_g14 + p_g32) + pow(p_atmosBha, 2.0) * pow(p_wham, 2.0) * p_g34));
155  p_y0_0 = p_wha2 * (p_e2 + p_atmosBha * p_wham * p_e4 + p_wha2 * (p_g12p
156  + p_atmosBha * p_wham * (p_g14p + p_g32p) +
157  pow(p_atmosBha, 2.0) * pow(p_wham, 2.0) * p_g34p));
158 
159  // higher-order correction term for x and y
160  p_delta_0 = (1.0 - (p_x0_0 + p_y0_0) - (1.0 - p_atmosWha * (1.0 + (1.0 / 3.0) * p_atmosBha *
161  p_wham)) / (1.0 - (p_x0_0 - p_y0_0))) / (p_atmosWha * (0.5 - p_e3 + p_atmosBha * p_wham * (0.25 - p_e5)));
162 
163  // moments of (corrected) x and y
164  p_alpha0_0 = 1.0 + p_wha2 * (p_g12 + p_atmosBha * p_wham * p_g32) + p_delta_0 * (0.5 - p_e3);
165  p_alpha1_0 = 0.5 + p_wha2 * (p_g13 + p_atmosBha * p_wham * p_g33) + p_delta_0 * ((1.0 / 3.0) - p_e4);
166  p_beta0_0 = p_e2 + p_wha2 * (p_g12p + p_atmosBha * p_wham * p_g32p) + p_delta_0 * (0.5 - p_e3);
167  p_beta1_0 = p_e3 + p_wha2 * (p_g13p + p_atmosBha * p_wham * p_g33p) + p_delta_0 * ((1.0 / 3.0) - p_e4);
168 
169  // gamma will be a weighted sum of m=0 x and y functions
170  // but unlike before, call the weights q1 and p1, and we also
171  // need additional weights q0 and p0
172  p_fac = 2.0 - p_atmosWha * p_alpha0_0;
173  p_den = pow(p_fac, 2.0) - pow((p_atmosWha * p_beta0_0), 2.0);
174  p_q0 = p_atmosBha * p_atmosWha * p_wham * (p_fac * p_alpha1_0 - p_atmosWha * p_beta0_0 * p_beta1_0) / p_den;
175  p_p0 = p_atmosBha * p_atmosWha * p_wham * (-p_fac * p_beta1_0 - p_atmosWha * p_beta0_0 * p_alpha1_0) / p_den;
176  p_q02p02 = p_q0 * p_q0 - p_p0 * p_p0;
177  p_q1 = (2.0 * p_wham * p_fac) / p_den;
178  p_p1 = (2.0 * p_wham * p_atmosWha * p_beta0_0) / p_den;
179  p_q12p12 = p_q1 * p_q1 - p_p1 * p_p1;
180 
181  // sbar is total diffuse illumination and comes from moments
182  p_sbar = 1.0 - 2.0 * (p_q1 * p_alpha1_0 + p_p1 * p_beta1_0);
183 
184  // we're not done yet! still have to calculate the m=1 portion
185  // zeroth moments of (uncorrected) x and y times characteristic fn
186  p_x0_1 = 0.5 * p_wha2 * p_atmosBha * (1.0 - (1.0 / 3.0) + 0.5 * p_wha2 * p_atmosBha *
187  (p_g12 - (p_g14 + p_g32) + p_g34));
188  p_y0_1 = 0.5 * p_wha2 * p_atmosBha * (p_e2 - p_e4 + 0.5 * p_wha2 * p_atmosBha *
189  (p_g12p - (p_g14p + p_g32p) + p_g34p));
190 
191  // higher-order correction term for x and y
192  p_delta_1 = (1.0 - (p_x0_1 + p_y0_1) - (1.0 - (1.0 / 3.0) * p_atmosWha * p_atmosBha) /
193  (1.0 - (p_x0_1 - p_y0_1))) / (p_wha2 * p_atmosBha *
194  ((0.5 - 0.25) - (p_e3 - p_e5)));
195 
196  // moments of (corrected) x and y are not needed for m=1, so we're done
197  SetOldTau(p_atmosTau);
198  SetOldWha(p_atmosWha);
199  }
200 
201  // correct the path lengths for planetary curvature
202  hpsq1 = pow((1.0 + p_atmosHnorm), 2.0) - 1.0;
203 
204  if(incidence == 90.0) {
205  munot = 0.0;
206  }
207  else {
208  munot = cos((PI / 180.0) * incidence);
209  }
210 
211  maxval = max(1.0e-30, hpsq1 + munot * munot);
212  munotp = p_atmosHnorm / (sqrt(maxval) - munot);
213  munotp = max(munotp, p_atmosTau / 69.0);
214 
215  if(emission == 90.0) {
216  mu = 0.0;
217  }
218  else {
219  mu = cos((PI / 180.0) * emission);
220  }
221 
222  maxval = max(1.0e-30, hpsq1 + mu * mu);
223  mup = p_atmosHnorm / (sqrt(maxval) - mu);
224  mup = max(mup, p_atmosTau / 69.0);
225 
226  // build the x and y functions of mu0 and mu
227  maxval = max(1.0e-30, munotp);
228  xx = -p_atmosTau / maxval;
229  if(xx < -69.0) {
230  emunot = 0.0;
231  }
232  else if(xx > 69.0) {
233  emunot = 1.0e30;
234  }
235  else {
236  emunot = exp(-p_atmosTau / munotp);
237  }
238 
239  maxval = max(1.0e-30, mup);
240  xx = -p_atmosTau / maxval;
241  if(xx < -69.0) {
242  emu = 0.0;
243  }
244  else if(xx > 69.0) {
245  emu = 1.0e30;
246  }
247  else {
248  emu = exp(-p_atmosTau / mup);
249  }
250 
251  // in the second approximation the x and y include the f1, f3 functions
252  xx = munotp;
253  if(fabs(xx - 1.0) < 1.0e-10) {
254  f1munot = p_f1;
255  f1mmunot = xx * (log(1.0 + 1.0 / xx) - p_e1 * emunot +
256  AtmosModel::En(1, p_atmosTau * (1.0 + 1.0 / xx)));
257  }
258  else if(xx > 0.0) {
259  f1munot = xx * (log(xx / (1.0 - xx)) + p_e1 / emunot +
260  AtmosModel::Ei(p_atmosTau * (1.0 / xx - 1.0)));
261  f1mmunot = xx * (log(1.0 + 1.0 / xx) - p_e1 * emunot +
262  AtmosModel::En(1, p_atmosTau * (1.0 + 1.0 / xx)));
263  }
264  else {
265  QString msg = "Negative length of planetary curvature encountered";
267  }
268 
269  f2munot = munotp * (f1munot + p_e2 / emunot - 1);
270  f2mmunot = -munotp * (f1mmunot + p_e2 * emunot - 1);
271  f3munot = munotp * (f2munot + p_e3 / emunot - 0.5);
272  f3mmunot = -munotp * (f2mmunot + p_e3 * emunot - 0.5);
273  xx = mup;
274 
275  if(fabs(xx - 1.0) < 1.0e-10) {
276  f1mu = p_f1;
277  f1mmu = xx * (log(1.0 + 1.0 / xx) - p_e1 * emu + AtmosModel::En(1, p_atmosTau * (1.0 + 1.0 / xx)));
278  }
279  else if(xx > 0.0) {
280  f1mu = xx * (log(xx / (1.0 - xx)) + p_e1 / emu + AtmosModel::Ei(p_atmosTau * (1.0 / xx - 1.0)));
281  f1mmu = xx * (log(1.0 + 1.0 / xx) - p_e1 * emu + AtmosModel::En(1, p_atmosTau * (1.0 + 1.0 / xx)));
282  }
283  else {
284  QString msg = "Negative length of planetary curvature encountered";
286  }
287 
288  f2mu = mup * (f1mu + p_e2 / emu - 1);
289  f2mmu = -mup * (f1mmu + p_e2 * emu - 1);
290  f3mu = mup * (f2mu + p_e3 / emu - 0.5);
291  f3mmu = -mup * (f2mmu + p_e3 * emu - 0.5);
292 
293  // first for m=0
294  xmunot_0 = 1.0 + p_wha2 * (f1mmunot + p_atmosBha * p_wham * f3mmunot) + p_delta_0 * munotp * (1.0 - emunot);
295  ymunot_0 = emunot * (1.0 + p_wha2 * (f1munot + p_atmosBha * p_wham * f3munot)) +
296  p_delta_0 * munotp * (1.0 - emunot);
297  xmu_0 = 1.0 + p_wha2 * (f1mmu + p_atmosBha * p_wham * f3mmu) + p_delta_0 * mup * (1.0 - emu);
298  ymu_0 = emu * (1.0 + p_wha2 * (f1mu + p_atmosBha * p_wham * f3mu)) + p_delta_0 * mup * (1.0 - emu);
299 
300  // then for m=1
301  xmunot_1 = 1.0 + 0.5 * p_wha2 * p_atmosBha * (f1mmunot - f3mmunot) + p_delta_1 * munotp * (1.0 - emunot);
302  ymunot_1 = emunot * (1.0 + 0.5 * p_wha2 * p_atmosBha *
303  (f1munot - f3munot)) + p_delta_1 * munotp * (1.0 - emunot);
304  xmu_1 = 1.0 + 0.5 * p_wha2 * p_atmosBha * (f1mmu - f3mmu) + p_delta_1 * mup * (1.0 - emu);
305  ymu_1 = emu * (1.0 + 0.5 * p_wha2 * p_atmosBha * (f1mu - f3mu)) + p_delta_1 * mup * (1.0 - emu);
306 
307  // gamma1 functions come from x and y with m=0
308  gmunot = p_p1 * xmunot_0 + p_q1 * ymunot_0;
309  gmu = p_p1 * xmu_0 + p_q1 * ymu_0;
310 
311  // purely atmos term uses x and y of both orders and is complex
312  sum = munot + mu;
313  prod = munot * mu;
314  cxx = 1.0 - p_q0 * sum + (p_q02p02 - p_atmosBha * p_q12p12) * prod;
315  cyy = 1.0 + p_q0 * sum + (p_q02p02 - p_atmosBha * p_q12p12) * prod;
316 
317  if(phase == 90.0) {
318  cosazss = 0.0 - munot * mu;
319  }
320  else {
321  cosazss = cos((PI / 180.0) * phase) - munot * mu;
322  }
323 
324  xystuff = cxx * xmunot_0 * xmu_0 - cyy * ymunot_0 *
325  ymu_0 - p_p0 * sum * (xmu_0 * ymunot_0 + ymu_0 * xmunot_0) + cosazss * p_atmosBha * (xmu_1 *
326  xmunot_1 - ymu_1 * ymunot_1);
327  p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * xystuff;
328 
329  // xmitted surface term uses gammas from m=0
330  p_trans = gmunot * gmu;
331 
332  // finally, never-scattered term is given by pure attenuation
333  p_trans0 = emunot * emu;
334 
335  // Calculate the transmission of light that must be subtracted from a
336  // shadow. This includes direct flux and the scattered flux in the
337  // upsun half of the sky downwelling onto the surface, and the usual
338  // transmission upward. NOTE: We need to derive the analytic expression
339  // for the light from half the sky in the Legendre scattering model. Until
340  // we do so, we are setting the shadow transmission to the purely
341  // unscattered part (same as trans0). This will give a result but is
342  // not fully consistent with how the other scattering models are
343  // implemented.
344  p_transs = p_trans0;
345  }
346 }
347 
348 
349 extern "C" Isis::AtmosModel *Anisotropic2Plugin(Isis::Pvl &pvl,
350  Isis::PhotoModel &pmodel) {
351 
352  return new Isis::Anisotropic2(pvl, pmodel);
353 }
static double G11Prime(double tau)
Perform Chandra and Van de Hulst&#39;s series approximation for the g&#39;11 function needed in second order ...
Definition: AtmosModel.cpp:147
double p_atmosHnorm
Atmospheric shell thickness normalized to planet radius.
Definition: AtmosModel.h:283
double p_g14p
???
Definition: Anisotropic2.h:97
double p_g33
???
Definition: Anisotropic2.h:88
double p_trans0
Transmission of surface reflected light through the atmosphere with no scatterings in the atmosphere...
Definition: AtmosModel.h:276
double p_q12p12
???
Definition: Anisotropic2.h:118
const double PI
The mathematical constant PI.
Definition: Constants.h:56
double p_g13
???
Definition: Anisotropic2.h:85
double p_g12
???
Definition: Anisotropic2.h:84
double p_g33p
???
Definition: Anisotropic2.h:99
double p_g12p
???
Definition: Anisotropic2.h:95
double p_g13p
???
Definition: Anisotropic2.h:96
double p_g11p
???
Definition: Anisotropic2.h:94
bool TauOrWhaChanged() const
Checks whether tau or wha have changed.
Definition: AtmosModel.cpp:948
double p_f1m
???
Definition: Anisotropic2.h:80
double p_f3m
???
Definition: Anisotropic2.h:82
double p_q02p02
???
Definition: Anisotropic2.h:117
double p_g32
???
Definition: Anisotropic2.h:87
double p_wham
???
Definition: Anisotropic2.h:71
double p_beta1_0
???
Definition: Anisotropic2.h:110
double p_delta_0
???
Definition: Anisotropic2.h:105
double p_g32p
???
Definition: Anisotropic2.h:98
double p_trans
Transmission of surface reflected light through the atmosphere overall.
Definition: AtmosModel.h:275
Isotropic atmos scattering model.
Definition: AtmosModel.h:76
double p_sbar
Illumination of the ground by the sky.
Definition: AtmosModel.h:278
static double En(unsigned int n, double x)
This routine evaluates the generalized exponential integral, En(x).
Definition: AtmosModel.cpp:364
double p_delta_1
???
Definition: Anisotropic2.h:106
double p_f4m
???
Definition: Anisotropic2.h:83
#define _FILEINFO_
Macro for the filename and line number.
Definition: IException.h:40
double p_g14
???
Definition: Anisotropic2.h:86
A type of error that could only have occurred due to a mistake on the user&#39;s part (e...
Definition: IException.h:142
Anisotropic2(Pvl &pvl, PhotoModel &pmodel)
Empty constructor.
A type of error that cannot be classified as any of the other error types.
Definition: IException.h:134
double p_alpha1_0
???
Definition: Anisotropic2.h:108
Container for cube-like labels.
Definition: Pvl.h:135
static double Ei(double x)
This routine computes the exponential integral, Ei(x).
Definition: AtmosModel.cpp:223
double p_transs
Transmission of light that must be subtracted from the flat surface model to get the shadow model...
Definition: AtmosModel.h:277
double p_alpha0_0
???
Definition: Anisotropic2.h:107
double p_g34
???
Definition: Anisotropic2.h:89
double p_pstd
Pure atmospheric-scattering term.
Definition: AtmosModel.h:274
double p_f2m
???
Definition: Anisotropic2.h:81
double p_e1_2
???
Definition: Anisotropic2.h:73
Isis exception class.
Definition: IException.h:107
Namespace for ISIS/Bullet specific routines.
Definition: Apollo.h:31
double p_beta0_0
???
Definition: Anisotropic2.h:109
double p_wha2
???
Definition: Anisotropic2.h:70
virtual void AtmosModelAlgorithm(double phase, double incidence, double emission)
Anisotropic atmospheric scattering with P1 single-particle phase fn, in the second approximation...