USGS

Isis 3.0 Object Programmers' Reference

Home

Isotropic2.cpp
1 #include <cmath>
2 #include "AtmosModel.h"
3 #include "Isotropic2.h"
4 #include "Pvl.h"
5 #include "PvlGroup.h"
6 #include "IException.h"
7 #include "IString.h"
8 
9 using std::min;
10 using std::max;
11 
12 namespace Isis {
13  Isotropic2::Isotropic2(Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl, pmodel) {
14  }
15 
57  void Isotropic2::AtmosModelAlgorithm(double phase, double incidence,
58  double emission) {
59  double xx;
60  double fix;
61  double hpsq1;
62  double munot, munotp;
63  double mu, mup;
64  double emu, emunot;
65  double f1munot, f1mmunot, f1mmu, f1mu;
66  double xmunot, ymunot;
67  double xmu, ymu;
68  double gmu, gmunot;
69  double maxval;
70 
71  if(p_atmosTau == 0.0) {
72  p_pstd = 0.0;
73  p_trans = 1.0;
74  p_trans0 = 1.0;
75  p_sbar = 0.0;
76  p_transs = 1.0;
77  return;
78  }
79 
80  if(TauOrWhaChanged()) {
81  // preparation includes exponential integrals p_e sub 2 through 4
82  p_wha2 = 0.5 * p_atmosWha;
83  p_e1 = AtmosModel::En(1, p_atmosTau);
84  p_e1_2 = AtmosModel::En(1, 2.0 * p_atmosTau);
85  p_e2 = AtmosModel::En(2, p_atmosTau);
86  p_e3 = AtmosModel::En(3, p_atmosTau);
87  p_e4 = AtmosModel::En(4, p_atmosTau);
88 
89  // chandra's gmn functions require fm and fn at mu=-1
90  xx = -p_atmosTau;
91  if(xx < -69.0) {
92  p_em = 0.0;
93  }
94  else if(xx > 69.0) {
95  p_em = 1.0e30;
96  }
97  else {
98  p_em = exp(xx);
99  }
100  p_f1m = log(2.0) - p_em * p_e1 + p_e1_2;
101  p_f2m = -1.0 * (p_f1m + p_em * p_e2 - 1.0);
102  p_f3m = -1.0 * (p_f2m + p_em * p_e3 - 0.5);
103  p_g12 = (p_atmosTau * p_e1 * p_e2 + p_f1m + p_f2m) * 0.5;
104  p_g13 = (p_atmosTau * p_e1 * p_e3 + p_f1m + p_f3m) * (1.0 / 3.0);
105 
106  // chandra's g'mn functions require g'11 and f at mu=1
107  xx = p_atmosTau;
108  if(xx < -69.0) {
109  p_e = 0.0;
110  }
111  else if(xx > 69.0) {
112  p_e = 1.0e30;
113  }
114  else {
115  p_e = exp(xx);
116  }
117 
118  p_f1 = Eulgam() + log(p_atmosTau) + p_e * p_e1;
119  p_f2 = p_f1 + p_e * p_e2 - 1.0;
120  p_f3 = p_f2 + p_e * p_e3 - 0.5;
121  p_g11p = AtmosModel::G11Prime(p_atmosTau);
122  p_g12p = (p_atmosTau * (p_e1 - p_g11p) + p_em * (p_f1 + p_f2)) * 0.25;
123  p_g13p = (p_atmosTau * (0.5 * p_e1 - p_g12p) + p_em * (p_f1 + p_f3)) * 0.2;
124 
125  // zeroth moments of (uncorrected) x and y times characteristic fn
126  p_x0 = p_wha2 * (1.0 + p_wha2 * p_g12);
127  p_y0 = p_wha2 * (p_e2 + p_wha2 * p_g12p);
128 
129  // higher-order correction term for x and y
130  p_delta = (1.0 - (p_x0 + p_y0) - (1.0 - p_atmosWha) / (1.0 - (p_x0 - p_y0))) / (p_atmosWha * (0.5 - p_e3));
131 
132  // moments of (corrected) x and y
133  p_alpha0 = 1.0 + p_wha2 * p_g12 + p_delta * (0.5 - p_e3);
134  p_alpha1 = 0.5 + p_wha2 * p_g13 + p_delta * ((1.0 / 3.0) - p_e4);
135  p_beta0 = p_e2 + p_wha2 * p_g12p + p_delta * (0.5 - p_e3);
136  p_beta1 = p_e3 + p_wha2 * p_g13p + p_delta * ((1.0 / 3.0) - p_e4);
137 
138  // prepare to find correct mixture of x and y in conservative case
139  if(p_atmosWha == 1.0) {
140  p_e5 = AtmosModel::En(5, p_atmosTau);
141  p_f4m = -1.0 * (p_f3m + p_em * p_e4 - (1.0 / 3.0));
142  p_g14 = (p_atmosTau * p_e1 * p_e4 + p_f1m + p_f4m) * 0.25;
143  p_f4 = p_f3 + p_e * p_e4 - (1.0 / 3.0);
144  p_g14p = (p_atmosTau * (0.5 * p_e1 - p_g13p) + p_em * (p_f1 + p_f4)) * (1.0 / 6.0);
145  p_alpha2 = (1.0 / 3.0) + p_wha2 * p_g14 + p_delta * (0.25 - p_e5);
146  p_beta2 = p_e4 + p_wha2 * p_g14p + p_delta * (0.25 - p_e5);
147  p_fixcon = (p_beta0 * p_atmosTau - p_alpha1 + p_beta1) / ((p_alpha1 + p_beta1) * p_atmosTau + 2.0 * (p_alpha2 + p_beta2));
148  }
149 
150  // gamma will be a weighted sum of x and y functions
151  p_gammax = p_wha2 * p_beta0;
152  p_gammay = 1.0 - p_wha2 * p_alpha0;
153 
154  // sbar is total diffuse illumination and comes from moments
155  p_sbar = 1.0 - ((2.0 - p_atmosWha * p_alpha0) * p_alpha1 + p_atmosWha * p_beta0 * p_beta1);
156 
157  SetOldTau(p_atmosTau);
158  SetOldWha(p_atmosWha);
159  }
160 
161  // correct the path lengths for planetary curvature
162  hpsq1 = pow((1.0 + p_atmosHnorm), 2.0) - 1.0;
163  munot = cos((PI / 180.0) * incidence);
164  maxval = max(1.0e-30, hpsq1 + munot * munot);
165  munotp = p_atmosHnorm / (sqrt(maxval) - munot);
166  munotp = max(munotp, p_atmosTau / 69.0);
167  mu = cos((PI / 180.0) * emission);
168  maxval = max(1.0e-30, hpsq1 + mu * mu);
169  mup = p_atmosHnorm / (sqrt(maxval) - mu);
170  mup = max(mup, p_atmosTau / 69.0);
171 
172  // build the x and y functions of mu0 and mu
173  xx = -p_atmosTau / max(munotp, 1.0e-30);
174  if(xx < -69.0) {
175  emunot = 0.0;
176  }
177  else if(xx > 69.0) {
178  emunot = 1.0e30;
179  }
180  else {
181  emunot = exp(-p_atmosTau / munotp);
182  }
183 
184  xx = -p_atmosTau / max(mup, 1.0e-30);
185  if(xx < -69.0) {
186  emu = 0.0;
187  }
188  else if(xx > 69.0) {
189  emu = 1.0e30;
190  }
191  else {
192  emu = exp(-p_atmosTau / mup);
193  }
194 
195  // in the second approximation the x and y include the p_f1 function
196  xx = munotp;
197  if(fabs(xx - 1.0) < 1.0e-10) {
198  f1munot = p_f1;
199  f1mmunot = xx * (log(1.0 + 1.0 / xx) - p_e1 * emunot +
200  AtmosModel::En(1, p_atmosTau * (1.0 + 1.0 / xx)));
201  }
202  else if(xx > 0.0) {
203  f1munot = xx * (log(xx / (1.0 - xx)) + p_e1 / emunot +
204  AtmosModel::Ei(p_atmosTau * (1.0 / xx - 1.0)));
205  f1mmunot = xx * (log(1.0 + 1.0 / xx) - p_e1 * emunot +
206  AtmosModel::En(1, p_atmosTau * (1.0 + 1.0 / xx)));
207  }
208  else {
209  std::string msg = "Negative length of planetary curvature ";
210  msg += "encountered";
212  }
213 
214  xx = mup;
215  if(fabs(xx - 1.0) < 1.0e-10) {
216  f1mu = p_f1;
217  f1mmu = xx * (log(1.0 + 1.0 / xx) - p_e1 * emu + AtmosModel::En(1, p_atmosTau * (1.0 + 1.0 / xx)));
218  }
219  else if(xx > 0.0) {
220  f1mu = xx * (log(xx / (1.0 - xx)) + p_e1 / emu + AtmosModel::Ei(p_atmosTau * (1.0 / xx - 1.0)));
221  f1mmu = xx * (log(1.0 + 1.0 / xx) - p_e1 * emu + AtmosModel::En(1, p_atmosTau * (1.0 + 1.0 / xx)));
222  }
223  else {
224  std::string msg = "Negative length of planetary curvature encountered";
226  }
227 
228  xmunot = 1.0 + p_wha2 * f1mmunot + p_delta * munotp * (1.0 - emunot);
229  ymunot = emunot * (1.0 + p_wha2 * f1munot) + p_delta * munotp * (1.0 - emunot);
230  xmu = 1.0 + p_wha2 * f1mmu + p_delta * mup * (1.0 - emu);
231  ymu = emu * (1.0 + p_wha2 * f1mu) + p_delta * mup * (1.0 - emu);
232 
233  // mix the x and y as required in the conservative case
234  if(p_atmosWha == 1.0) {
235  fix = p_fixcon * munotp * (xmunot + ymunot);
236  xmunot = xmunot + fix;
237  ymunot = ymunot + fix;
238  fix = p_fixcon * mup * (xmu + ymu);
239  xmu = xmu + fix;
240  ymu = ymu + fix;
241  }
242 
243  // gamma1 functions come from x and y
244  gmunot = p_gammax * xmunot + p_gammay * ymunot;
245  gmu = p_gammax * xmu + p_gammay * ymu;
246 
247  // purely atmos term uses x and y, xmitted surface term uses gammas
248  p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * (xmunot * xmu - ymunot * ymu);
249  p_trans = gmunot * gmu;
250 
251  // finally, never-scattered term is given by pure attenuation
252  p_trans0 = emunot * emu;
253 
254  // Calculate the transmission of light that must be subtracted from a shadow.
255  // This includes direct flux and the scattered flux in the upsun half of the
256  // sky downwelling onto the surface, and the usual transmission upward.
257  p_transs = (emunot + 0.5 * (p_gammax * xmunot + p_gammay * ymunot - emunot)) * emu;
258  }
259 }
260 
261 extern "C" Isis::AtmosModel *Isotropic2Plugin(Isis::Pvl &pvl, Isis::PhotoModel &pmodel) {
262  return new Isis::Isotropic2(pvl, pmodel);
263 }