Isis 3 Programmer Reference
Isotropic2.cpp
1 
6 /* SPDX-License-Identifier: CC0-1.0 */
7 #include <cmath>
8 #include "AtmosModel.h"
9 #include "Isotropic2.h"
10 #include "Pvl.h"
11 #include "PvlGroup.h"
12 #include "IException.h"
13 #include "IString.h"
14 
15 using std::min;
16 using std::max;
17 
18 namespace Isis {
19  Isotropic2::Isotropic2(Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl, pmodel) {
20  }
21 
63  void Isotropic2::AtmosModelAlgorithm(double phase, double incidence,
64  double emission) {
65  double xx;
66  double fix;
67  double hpsq1;
68  double munot, munotp;
69  double mu, mup;
70  double emu, emunot;
71  double f1munot, f1mmunot, f1mmu, f1mu;
72  double xmunot, ymunot;
73  double xmu, ymu;
74  double gmu, gmunot;
75  double maxval;
76 
77  if(p_atmosTau == 0.0) {
78  p_pstd = 0.0;
79  p_trans = 1.0;
80  p_trans0 = 1.0;
81  p_sbar = 0.0;
82  p_transs = 1.0;
83  return;
84  }
85 
86  if(TauOrWhaChanged()) {
87  // preparation includes exponential integrals p_e sub 2 through 4
88  p_wha2 = 0.5 * p_atmosWha;
89  p_e1 = AtmosModel::En(1, p_atmosTau);
90  p_e1_2 = AtmosModel::En(1, 2.0 * p_atmosTau);
91  p_e2 = AtmosModel::En(2, p_atmosTau);
92  p_e3 = AtmosModel::En(3, p_atmosTau);
93  p_e4 = AtmosModel::En(4, p_atmosTau);
94 
95  // chandra's gmn functions require fm and fn at mu=-1
96  xx = -p_atmosTau;
97  if(xx < -69.0) {
98  p_em = 0.0;
99  }
100  else if(xx > 69.0) {
101  p_em = 1.0e30;
102  }
103  else {
104  p_em = exp(xx);
105  }
106  p_f1m = log(2.0) - p_em * p_e1 + p_e1_2;
107  p_f2m = -1.0 * (p_f1m + p_em * p_e2 - 1.0);
108  p_f3m = -1.0 * (p_f2m + p_em * p_e3 - 0.5);
109  p_g12 = (p_atmosTau * p_e1 * p_e2 + p_f1m + p_f2m) * 0.5;
110  p_g13 = (p_atmosTau * p_e1 * p_e3 + p_f1m + p_f3m) * (1.0 / 3.0);
111 
112  // chandra's g'mn functions require g'11 and f at mu=1
113  xx = p_atmosTau;
114  if(xx < -69.0) {
115  p_e = 0.0;
116  }
117  else if(xx > 69.0) {
118  p_e = 1.0e30;
119  }
120  else {
121  p_e = exp(xx);
122  }
123 
124  p_f1 = Eulgam() + log(p_atmosTau) + p_e * p_e1;
125  p_f2 = p_f1 + p_e * p_e2 - 1.0;
126  p_f3 = p_f2 + p_e * p_e3 - 0.5;
127  p_g11p = AtmosModel::G11Prime(p_atmosTau);
128  p_g12p = (p_atmosTau * (p_e1 - p_g11p) + p_em * (p_f1 + p_f2)) * 0.25;
129  p_g13p = (p_atmosTau * (0.5 * p_e1 - p_g12p) + p_em * (p_f1 + p_f3)) * 0.2;
130 
131  // zeroth moments of (uncorrected) x and y times characteristic fn
132  p_x0 = p_wha2 * (1.0 + p_wha2 * p_g12);
133  p_y0 = p_wha2 * (p_e2 + p_wha2 * p_g12p);
134 
135  // higher-order correction term for x and y
136  p_delta = (1.0 - (p_x0 + p_y0) - (1.0 - p_atmosWha) / (1.0 - (p_x0 - p_y0))) / (p_atmosWha * (0.5 - p_e3));
137 
138  // moments of (corrected) x and y
139  p_alpha0 = 1.0 + p_wha2 * p_g12 + p_delta * (0.5 - p_e3);
140  p_alpha1 = 0.5 + p_wha2 * p_g13 + p_delta * ((1.0 / 3.0) - p_e4);
141  p_beta0 = p_e2 + p_wha2 * p_g12p + p_delta * (0.5 - p_e3);
142  p_beta1 = p_e3 + p_wha2 * p_g13p + p_delta * ((1.0 / 3.0) - p_e4);
143 
144  // prepare to find correct mixture of x and y in conservative case
145  if(p_atmosWha == 1.0) {
146  p_e5 = AtmosModel::En(5, p_atmosTau);
147  p_f4m = -1.0 * (p_f3m + p_em * p_e4 - (1.0 / 3.0));
148  p_g14 = (p_atmosTau * p_e1 * p_e4 + p_f1m + p_f4m) * 0.25;
149  p_f4 = p_f3 + p_e * p_e4 - (1.0 / 3.0);
150  p_g14p = (p_atmosTau * (0.5 * p_e1 - p_g13p) + p_em * (p_f1 + p_f4)) * (1.0 / 6.0);
151  p_alpha2 = (1.0 / 3.0) + p_wha2 * p_g14 + p_delta * (0.25 - p_e5);
152  p_beta2 = p_e4 + p_wha2 * p_g14p + p_delta * (0.25 - p_e5);
153  p_fixcon = (p_beta0 * p_atmosTau - p_alpha1 + p_beta1) / ((p_alpha1 + p_beta1) * p_atmosTau + 2.0 * (p_alpha2 + p_beta2));
154  }
155 
156  // gamma will be a weighted sum of x and y functions
157  p_gammax = p_wha2 * p_beta0;
158  p_gammay = 1.0 - p_wha2 * p_alpha0;
159 
160  // sbar is total diffuse illumination and comes from moments
161  p_sbar = 1.0 - ((2.0 - p_atmosWha * p_alpha0) * p_alpha1 + p_atmosWha * p_beta0 * p_beta1);
162 
163  SetOldTau(p_atmosTau);
164  SetOldWha(p_atmosWha);
165  }
166 
167  // correct the path lengths for planetary curvature
168  hpsq1 = pow((1.0 + p_atmosHnorm), 2.0) - 1.0;
169  munot = cos((PI / 180.0) * incidence);
170  maxval = max(1.0e-30, hpsq1 + munot * munot);
171  munotp = p_atmosHnorm / (sqrt(maxval) - munot);
172  munotp = max(munotp, p_atmosTau / 69.0);
173  mu = cos((PI / 180.0) * emission);
174  maxval = max(1.0e-30, hpsq1 + mu * mu);
175  mup = p_atmosHnorm / (sqrt(maxval) - mu);
176  mup = max(mup, p_atmosTau / 69.0);
177 
178  // build the x and y functions of mu0 and mu
179  xx = -p_atmosTau / max(munotp, 1.0e-30);
180  if(xx < -69.0) {
181  emunot = 0.0;
182  }
183  else if(xx > 69.0) {
184  emunot = 1.0e30;
185  }
186  else {
187  emunot = exp(-p_atmosTau / munotp);
188  }
189 
190  xx = -p_atmosTau / max(mup, 1.0e-30);
191  if(xx < -69.0) {
192  emu = 0.0;
193  }
194  else if(xx > 69.0) {
195  emu = 1.0e30;
196  }
197  else {
198  emu = exp(-p_atmosTau / mup);
199  }
200 
201  // in the second approximation the x and y include the p_f1 function
202  xx = munotp;
203  if(fabs(xx - 1.0) < 1.0e-10) {
204  f1munot = p_f1;
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 if(xx > 0.0) {
209  f1munot = xx * (log(xx / (1.0 - xx)) + p_e1 / emunot +
210  AtmosModel::Ei(p_atmosTau * (1.0 / xx - 1.0)));
211  f1mmunot = xx * (log(1.0 + 1.0 / xx) - p_e1 * emunot +
212  AtmosModel::En(1, p_atmosTau * (1.0 + 1.0 / xx)));
213  }
214  else {
215  std::string msg = "Negative length of planetary curvature ";
216  msg += "encountered";
217  throw IException(IException::Unknown, msg, _FILEINFO_);
218  }
219 
220  xx = mup;
221  if(fabs(xx - 1.0) < 1.0e-10) {
222  f1mu = p_f1;
223  f1mmu = xx * (log(1.0 + 1.0 / xx) - p_e1 * emu + AtmosModel::En(1, p_atmosTau * (1.0 + 1.0 / xx)));
224  }
225  else if(xx > 0.0) {
226  f1mu = xx * (log(xx / (1.0 - xx)) + p_e1 / emu + AtmosModel::Ei(p_atmosTau * (1.0 / xx - 1.0)));
227  f1mmu = xx * (log(1.0 + 1.0 / xx) - p_e1 * emu + AtmosModel::En(1, p_atmosTau * (1.0 + 1.0 / xx)));
228  }
229  else {
230  std::string msg = "Negative length of planetary curvature encountered";
231  throw IException(IException::Unknown, msg, _FILEINFO_);
232  }
233 
234  xmunot = 1.0 + p_wha2 * f1mmunot + p_delta * munotp * (1.0 - emunot);
235  ymunot = emunot * (1.0 + p_wha2 * f1munot) + p_delta * munotp * (1.0 - emunot);
236  xmu = 1.0 + p_wha2 * f1mmu + p_delta * mup * (1.0 - emu);
237  ymu = emu * (1.0 + p_wha2 * f1mu) + p_delta * mup * (1.0 - emu);
238 
239  // mix the x and y as required in the conservative case
240  if(p_atmosWha == 1.0) {
241  fix = p_fixcon * munotp * (xmunot + ymunot);
242  xmunot = xmunot + fix;
243  ymunot = ymunot + fix;
244  fix = p_fixcon * mup * (xmu + ymu);
245  xmu = xmu + fix;
246  ymu = ymu + fix;
247  }
248 
249  // gamma1 functions come from x and y
250  gmunot = p_gammax * xmunot + p_gammay * ymunot;
251  gmu = p_gammax * xmu + p_gammay * ymu;
252 
253  // purely atmos term uses x and y, xmitted surface term uses gammas
254  p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * (xmunot * xmu - ymunot * ymu);
255  p_trans = gmunot * gmu;
256 
257  // finally, never-scattered term is given by pure attenuation
258  p_trans0 = emunot * emu;
259 
260  // Calculate the transmission of light that must be subtracted from a shadow.
261  // This includes direct flux and the scattered flux in the upsun half of the
262  // sky downwelling onto the surface, and the usual transmission upward.
263  p_transs = (emunot + 0.5 * (p_gammax * xmunot + p_gammay * ymunot - emunot)) * emu;
264  }
265 }
266 
267 extern "C" Isis::AtmosModel *Isotropic2Plugin(Isis::Pvl &pvl, Isis::PhotoModel &pmodel) {
268  return new Isis::Isotropic2(pvl, pmodel);
269 }
Isis::Isotropic2
Definition: Isotropic2.h:40
Isis::AtmosModel::TauOrWhaChanged
bool TauOrWhaChanged() const
Checks whether tau or wha have changed.
Definition: AtmosModel.cpp:954
Isis::PhotoModel
Definition: PhotoModel.h:41
Isis::PI
const double PI
The mathematical constant PI.
Definition: Constants.h:40
Isis::AtmosModel::p_pstd
double p_pstd
Pure atmospheric-scattering term.
Definition: AtmosModel.h:258
Isis::AtmosModel::En
static double En(unsigned int n, double x)
This routine evaluates the generalized exponential integral, En(x).
Definition: AtmosModel.cpp:370
Isis::IException::Unknown
@ Unknown
A type of error that cannot be classified as any of the other error types.
Definition: IException.h:118
Isis::AtmosModel
Isotropic atmos scattering model.
Definition: AtmosModel.h:60
Isis::Pvl
Container for cube-like labels.
Definition: Pvl.h:119
Isis::AtmosModel::p_trans
double p_trans
Transmission of surface reflected light through the atmosphere overall.
Definition: AtmosModel.h:259
Isis::AtmosModel::p_transs
double p_transs
Transmission of light that must be subtracted from the flat surface model to get the shadow model.
Definition: AtmosModel.h:261
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::AtmosModel::p_atmosHnorm
double p_atmosHnorm
Atmospheric shell thickness normalized to planet radius.
Definition: AtmosModel.h:267
Isis::Isotropic2::AtmosModelAlgorithm
virtual void AtmosModelAlgorithm(double phase, double incidence, double emission)
Isotropic atmospheric scattering in the first approximation The model for scattering for a general,...
Definition: Isotropic2.cpp:63
Isis::AtmosModel::Ei
static double Ei(double x)
This routine computes the exponential integral, Ei(x).
Definition: AtmosModel.cpp:229
Isis::AtmosModel::G11Prime
static double G11Prime(double tau)
Perform Chandra and Van de Hulst's series approximation for the g'11 function needed in second order ...
Definition: AtmosModel.cpp:153
Isis::AtmosModel::p_sbar
double p_sbar
Illumination of the ground by the sky.
Definition: AtmosModel.h:262
Isis::AtmosModel::p_trans0
double p_trans0
Transmission of surface reflected light through the atmosphere with no scatterings in the atmosphere.
Definition: AtmosModel.h:260
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16