Isis 3 Programmer Reference
Anisotropic1.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include <cmath>
8#include "Anisotropic1.h"
9#include "AtmosModel.h"
10#include "IException.h"
11#include "IString.h"
12
13using std::max;
14
15namespace Isis {
22 Anisotropic1::Anisotropic1(Pvl &pvl, PhotoModel &pmodel) : AtmosModel(pvl, pmodel) {
23
24 // Set default values
25 p_atmosAlpha0_0 = 0.0;
26 p_atmosAlpha1_0 = 0.0;
27 p_atmosBeta0_0 = 0.0;
28 p_atmosBeta1_0 = 0.0;
29 p_atmosDelta_0 = 0.0;
30 p_atmosDelta_1 = 0.0;
31 p_atmosDen = 0.0;
32 p_atmosE2 = 0.0;
33 p_atmosE3 = 0.0;
34 p_atmosE4 = 0.0;
35 p_atmosE5 = 0.0;
36 p_atmosFac = 0.0;
37 p_atmosP0 = 0.0;
38 p_atmosP1 = 0.0;
39 p_atmosQ0 = 0.0;
40 p_atmosQ02p02 = 0.0;
41 p_atmosQ1 = 0.0;
42 p_atmosQ12p12 = 0.0;
43 p_atmosWha2 = 0.0;
44 p_atmosWham = 0.0;
45 p_atmosX0_0 = 0.0;
46 p_atmosX0_1 = 0.0;
47 p_atmosY0_0 = 0.0;
48 p_atmosY0_1 = 0.0;
49
50 }
51
78 void Anisotropic1::AtmosModelAlgorithm(double phase, double incidence, double emission) {
79 double hpsq1;
80 double munot, munotp;
81 double maxval;
82 double mu, mup;
83 double xx;
84 double emunot, emu;
85 double gmunot, gmu;
86 double sum, prod;
87 double cosazss;
88 double xmunot_0, ymunot_0;
89 double xmu_0, ymu_0;
90 double xmunot_1, ymunot_1;
91 double xmu_1, ymu_1;
92 double cxx, cyy;
93 double xystuff;
94
95 if(p_atmosBha == 0.0) {
96 p_atmosBha = 1.0e-6;
97 }
98
99 if(p_atmosTau == 0.0) {
100 p_pstd = 0.0;
101 p_trans = 1.0;
102 p_trans0 = 1.0;
103 p_sbar = 0.0;
104 p_transs = 1.0;
105 return;
106 }
107
108 if(p_atmosWha == 1.0) {
109 QString msg = "Anisotropic conservative case not implemented yet - WHA parameter cannot be set to 1.0";
110 msg += "This will cause negative planetary curvature to occur.";
111 throw IException(IException::User, msg, _FILEINFO_);
112 }
113
114 if(TauOrWhaChanged()) {
115 // preparation includes exponential integrals e sub 2 through 5
116 p_atmosWha2 = 0.5 * p_atmosWha;
117 p_atmosWham = 1.0 - p_atmosWha;
118 p_atmosE2 = AtmosModel::En(2, p_atmosTau);
119 p_atmosE3 = AtmosModel::En(3, p_atmosTau);
120 p_atmosE4 = AtmosModel::En(4, p_atmosTau);
121 p_atmosE5 = AtmosModel::En(5, p_atmosTau);
122 // first, get the required quantities for the axisymmetric m=0 part
123 // zeroth moments of (uncorrected) x and y times characteristic fn
124 p_atmosX0_0 = p_atmosWha2 * (1.0 + (1.0 / 3.0) * p_atmosBha *
126 p_atmosY0_0 = p_atmosWha2 * (p_atmosE2 + p_atmosBha * p_atmosWham *
127 p_atmosE4);
128 // higher-order correction term for x and y
129 p_atmosDelta_0 = (1.0 - (p_atmosX0_0 + p_atmosY0_0) - (1.0 - p_atmosWha *
130 (1.0 + (1.0 / 3.0) * p_atmosBha * p_atmosWham)) / (1.0 -
131 (p_atmosX0_0 - p_atmosY0_0))) / (p_atmosWha * (0.5 - p_atmosE3 +
132 p_atmosBha * p_atmosWham * (0.25 - p_atmosE5)));
133
134 // moments of (corrected) x and y
135 p_atmosAlpha0_0 = 1.0 + p_atmosDelta_0 * (0.5 - p_atmosE3);
136 p_atmosAlpha1_0 = 0.5 + p_atmosDelta_0 * ((1.0 / 3.0) - p_atmosE4);
138 p_atmosBeta1_0 = p_atmosE3 + p_atmosDelta_0 * ((1.0 / 3.0) - p_atmosE4);
139 // gamma will be a weighted sum of m=0 x and y functions
140 // but unlike before, call the weights q1 and p1, and we also
141 // need additional weights q0 and p0
142 p_atmosFac = 2.0 - p_atmosWha * p_atmosAlpha0_0;
143 p_atmosDen = pow(p_atmosFac, 2.0) - pow(p_atmosWha * p_atmosBeta0_0, 2.0);
144 p_atmosQ0 = p_atmosBha * p_atmosWha * p_atmosWham * (p_atmosFac *
147 p_atmosP0 = p_atmosBha * p_atmosWha * p_atmosWham * (-p_atmosFac *
152 p_atmosP1 = (2.0 * p_atmosWham * p_atmosWha * p_atmosBeta0_0) /
155 // sbar is total diffuse illumination and comes from moments
156 p_sbar = 1.0 - 2.0 * (p_atmosQ1 * p_atmosAlpha1_0 + p_atmosP1 *
158 // we're not done yet! still have to calculate the m=1 portion
159 // zeroth moments of (uncorrected) x and y times characteristic fn
160 p_atmosX0_1 = 0.5 * p_atmosWha2 * p_atmosBha * (1.0 - (1.0 / 3.0));
161 p_atmosY0_1 = 0.5 * p_atmosWha2 * p_atmosBha * (p_atmosE2 - p_atmosE4);
162 // higher-order correction term for x and y
163 p_atmosDelta_1 = (1.0 - (p_atmosX0_1 + p_atmosY0_1) - (1.0 -
164 (1.0 / 3.0) * p_atmosWha * p_atmosBha) / (1.0 - (p_atmosX0_1 -
165 p_atmosY0_1))) / (p_atmosWha2 * p_atmosBha * ((0.5 - 0.25) -
166 (p_atmosE3 - p_atmosE5)));
167 // moments of (corrected) x and y are not needed for m=1, so we're done
168 SetOldTau(p_atmosTau);
169 SetOldWha(p_atmosWha);
170 }
171
172 // correct the path lengths for planetary curvature
173 hpsq1 = pow((1.0 + p_atmosHnorm), 2.0) - 1.0;
174
175 if(incidence == 90.0) {
176 munot = 0.0;
177 }
178 else {
179 munot = cos((PI / 180.0) * incidence);
180 }
181
182 maxval = max(1.0e-30, hpsq1 + munot * munot);
183 munotp = p_atmosHnorm / (sqrt(maxval) - munot);
184 munotp = max(munotp, p_atmosTau / 69.0);
185 if(emission == 90.0) {
186 mu = 0.0;
187 }
188 else {
189 mu = cos((PI / 180.0) * emission);
190 }
191
192 maxval = max(1.0e-30, hpsq1 + mu * mu);
193 mup = p_atmosHnorm / (sqrt(maxval) - mu);
194 mup = max(mup, p_atmosTau / 69.0);
195 // build the x and y functions of mu0 and mu
196 maxval = max(1.0e-30, munotp);
197 xx = -p_atmosTau / maxval;
198
199 if(xx < -69.0) {
200 emunot = 0.0;
201 }
202 else if(xx > 69.0) {
203 emunot = 1.0e30;
204 }
205 else {
206 emunot = exp(-p_atmosTau / munotp);
207 }
208
209 maxval = max(1.0e-30, mup);
210 xx = -p_atmosTau / maxval;
211
212 if(xx < -69.0) {
213 emu = 0.0;
214 }
215 else if(xx > 69.0) {
216 emu = 1.0e30;
217 }
218 else {
219 emu = exp(-p_atmosTau / mup);
220 }
221
222 // first for m=0
223 xmunot_0 = 1.0 + p_atmosDelta_0 * munotp * (1.0 - emunot);
224 ymunot_0 = emunot + p_atmosDelta_0 * munotp * (1.0 - emunot);
225 xmu_0 = 1.0 + p_atmosDelta_0 * mup * (1.0 - emu);
226 ymu_0 = emu + p_atmosDelta_0 * mup * (1.0 - emu);
227
228 // then for m=1
229 xmunot_1 = 1.0 + p_atmosDelta_1 * munotp * (1.0 - emunot);
230 ymunot_1 = emunot + p_atmosDelta_1 * munotp * (1.0 - emunot);
231 xmu_1 = 1.0 + p_atmosDelta_1 * mup * (1.0 - emu);
232 ymu_1 = emu + p_atmosDelta_1 * mup * (1.0 - emu);
233
234 // gamma1 functions come from x and y with m=0
235 gmunot = p_atmosP1 * xmunot_0 + p_atmosQ1 * ymunot_0;
236 gmu = p_atmosP1 * xmu_0 + p_atmosQ1 * ymu_0;
237
238 // purely atmos term uses x and y of both orders and is complex
239 sum = munot + mu;
240 prod = munot * mu;
241 cxx = 1.0 - p_atmosQ0 * sum + (p_atmosQ02p02 - p_atmosBha *
242 p_atmosQ12p12) * prod;
243 cyy = 1.0 + p_atmosQ0 * sum + (p_atmosQ02p02 - p_atmosBha *
244 p_atmosQ12p12) * prod;
245
246 if(phase == 90.0) {
247 cosazss = 0.0 - munot * mu;
248 }
249 else {
250 cosazss = cos((PI / 180.0) * phase) - munot * mu;
251 }
252
253 xystuff = cxx * xmunot_0 * xmu_0 - cyy * ymunot_0 *
254 ymu_0 - p_atmosP0 * sum * (xmu_0 * ymunot_0 + ymu_0 *
255 xmunot_0) + cosazss * p_atmosBha * (xmu_1 *
256 xmunot_1 - ymu_1 * ymunot_1);
257 p_pstd = 0.25 * p_atmosWha * munotp / (munotp + mup) * xystuff;
258
259 // xmitted surface term uses gammas from m=0
260 p_trans = gmunot * gmu;
261
262 // finally, never-scattered term is given by pure attenuation
263 p_trans0 = emunot * emu;
264
265 // Calculate the transmission of light that must be subtracted from a
266 // shadow. This includes direct flux and the scattered flux in the
267 // upsun half of the sky downwelling onto the surface, and the usual
268 // transmission upward. NOTE: We need to derive the analytic expression
269 // for the light from half the sky in the Legendre scattering model. Until
270 // we do so, we are setting the shadow transmission to the purely
271 // unscattered part (same as trans0). This will give a result but is
272 // not fully consistent with how the other scattering models are
273 // implemented.
275 }
276}
277
278extern "C" Isis::AtmosModel *Anisotropic1Plugin(Isis::Pvl &pvl, Isis::PhotoModel &pmodel) {
279 return new Isis::Anisotropic1(pvl, pmodel);
280}
double p_atmosQ12p12
???
double p_atmosDelta_1
???
virtual void AtmosModelAlgorithm(double phase, double incidence, double emission)
Anisotropic atmospheric scattering with P1 single-particle phase fn, in the second approximation.
double p_atmosBeta0_0
???
double p_atmosDelta_0
???
double p_atmosY0_1
???
double p_atmosBeta1_0
???
double p_atmosX0_1
???
double p_atmosQ02p02
???
double p_atmosWham
???
double p_atmosY0_0
???
double p_atmosAlpha1_0
???
double p_atmosAlpha0_0
???
double p_atmosWha2
???
double p_atmosX0_0
???
Anisotropic1(Pvl &pvl, PhotoModel &pmodel)
Constructs an Anisotropic1 object.
Isotropic atmos scattering model.
Definition AtmosModel.h:60
double p_trans
Transmission of surface reflected light through the atmosphere overall.
Definition AtmosModel.h:259
static double En(unsigned int n, double x)
This routine evaluates the generalized exponential integral, En(x).
double p_atmosHnorm
Atmospheric shell thickness normalized to planet radius.
Definition AtmosModel.h:267
double p_sbar
Illumination of the ground by the sky.
Definition AtmosModel.h:262
double p_transs
Transmission of light that must be subtracted from the flat surface model to get the shadow model.
Definition AtmosModel.h:261
double p_pstd
Pure atmospheric-scattering term.
Definition AtmosModel.h:258
double p_trans0
Transmission of surface reflected light through the atmosphere with no scatterings in the atmosphere.
Definition AtmosModel.h:260
bool TauOrWhaChanged() const
Checks whether tau or wha have changed.
Isis exception class.
Definition IException.h:91
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition IException.h:126
Container for cube-like labels.
Definition Pvl.h:119
This is free and unencumbered software released into the public domain.
Definition Apollo.h:16
const double PI
The mathematical constant PI.
Definition Constants.h:40