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
15using std::min;
16using std::max;
17
18namespace 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
267extern "C" Isis::AtmosModel *Isotropic2Plugin(Isis::Pvl &pvl, Isis::PhotoModel &pmodel) {
268 return new Isis::Isotropic2(pvl, pmodel);
269}
Isotropic atmos scattering model.
Definition AtmosModel.h:60
Isis exception class.
Definition IException.h:91
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