Isis 3 Programmer Reference
Hapke.cpp
1
6/* SPDX-License-Identifier: CC0-1.0 */
7#include <cmath>
8#include "Constants.h"
9#include "Hapke.h"
10#include "Pvl.h"
11#include "PvlGroup.h"
12#include "IException.h"
13#include "IString.h"
14
15using namespace std;
16
17namespace Isis {
18
19 Hapke::Hapke(Pvl &pvl) : PhotoModel(pvl) {
20 p_photoHh = 0.0;
21 p_photoB0 = 0.0;
22 p_photoTheta = 0.0;
23 p_photoWh = 0.5;
24 p_photoThetaold = -999.0;
25
26 p_photoHg1 = 0.0;
27 p_photoHg2 = 0.0;
28
29 PvlGroup &algorithm = pvl.findObject("PhotometricModel").findGroup("Algorithm", Pvl::Traverse);
30
31 p_algName = AlgorithmName().toUpper();
32
33 if(algorithm.hasKeyword("Hg1")) {
34 SetPhotoHg1(algorithm["Hg1"]);
35 }
36
37 if(algorithm.hasKeyword("Hg2")) {
38 SetPhotoHg2(algorithm["Hg2"]);
39 }
40
41 if(algorithm.hasKeyword("Bh")) {
42 SetPhotoBh(algorithm["Bh"]);
43 }
44
45 if(algorithm.hasKeyword("Ch")) {
46 SetPhotoCh(algorithm["Ch"]);
47 }
48
49 if(algorithm.hasKeyword("ZeroB0Standard")) {
50 SetPhoto0B0Standard(algorithm["ZeroB0Standard"][0]);
51 } else if (algorithm.hasKeyword("ZeroB0St")) {
52 SetPhoto0B0Standard(algorithm["ZeroB0St"][0]);
53 } else {
54 SetPhoto0B0Standard("TRUE");
55 }
56
57 if(algorithm.hasKeyword("Wh")) {
58 SetPhotoWh(algorithm["Wh"]);
59 }
60
61 if(algorithm.hasKeyword("Hh")) {
62 SetPhotoHh(algorithm["Hh"]);
63 }
64
65 if(algorithm.hasKeyword("B0")) {
66 SetPhotoB0(algorithm["B0"]);
67 }
68
69 p_photoB0save = p_photoB0;
70
71 if(algorithm.hasKeyword("Theta")) {
72 SetPhotoTheta(algorithm["Theta"]);
73 }
74 }
75
76 /*
77 * Computes normal albedo mult factor w/o opp surge from
78 * Hapke input parameters: W,H,BO,HG,THETA.
79 * Full-up Hapke's Law with macroscopic roughness. The photometric
80 * function multiplied back in will be modified to take out oppos-
81 * ition effect. This requires saving the actual value of B0 while
82 * temporarily setting it to zero in the common block to compute
83 * the overall normalization.
84 *
85 * @param phase Value of phase angle, in degrees.
86 * @param incidence Value of incidence angle, in degrees.
87 * @param emission Value of emission angle, in degrees.
88 * @returns <b>double</b>
89 *
90 *
91 * @history 1989-08-02 Unknown author in Isis2 under name pht_hapke
92 * @history 1991-08-07 Tammy Becker relinked hapke to new photompr
93 * @history 1997-02-16 James M Anderson - changed nonstandard degree trig
94 * to use radians
95 * @history 1999-01-11 KTT - Remove mu,munot,and alpha from the argument
96 * list and pass in only ema,inc, and phase. Remove
97 * lat and lon from argument list because they aren't
98 * used.
99 * @history 1999-03-01 K Teal Thompson Implement 1999-01-08 Randy Kirk
100 * Original Specs & Code. Declare vars, add implicit none.
101 * @history 1999-11-18 Randy Kirk - fixed minor typos, implemented return with
102 * smooth Hapke (Theta=0) result before doing rough Hapke
103 * calculations, allow single-particle-phase params = 0
104 * @history 2008-01-14 Janet Barrett - Imported into Isis3. Changed name from pht_hapke to PhotoModelAlgorithm()
105 * @history 2008-11-05 Jeannie Walldren - Added documentation
106 * from Isis2 files. Replaced Isis::PI with PI since this is in Isis namespace.
107 *
108 */
109 double Hapke::PhotoModelAlgorithm(double phase, double incidence,
110 double emission) {
111 static double pht_hapke;
112 double pharad; //phase angle in radians
113 double incrad; // incidence angle in radians
114 double emarad; // emission angle in radians
115 double munot;
116 double mu;
117 double cost;
118 double sint;
119 double tan2t;
120 double gamma;
121 double hgs;
122 double cosg;
123 double tang2;
124 double bg;
125 double pg;
126 double pg1;
127 double pg2;
128 double sini;
129 double coti;
130 double cot2i;
131 double ecoti;
132 double ecot2i;
133 double u0p0;
134 double sine;
135 double cote;
136 double cot2e;
137 double cosei;
138 double sinei;
139 double caz;
140 double az;
141 double az2;
142 double faz;
143 double tanaz2;
144 double sin2a2;
145 double api;
146 double ecote;
147 double ecot2e;
148 double up0;
149 double q;
150 double ecei;
151 double s2ei;
152 double u0p;
153 double up;
154 double ecee;
155 double s2ee;
156 double rr1;
157 double rr2;
158
159 static double old_phase = -9999;
160 static double old_incidence = -9999;
161 static double old_emission= -9999;
162
163 if (old_phase == phase && old_incidence == incidence && old_emission == emission) {
164 return pht_hapke;
165 }
166
167 old_phase = phase;
168 old_incidence = incidence;
169 old_emission = emission;
170
171 pharad = phase * PI / 180.0;
172 incrad = incidence * PI / 180.0;
173 emarad = emission * PI / 180.0;
174 munot = cos(incrad);
175 mu = cos(emarad);
176
177 if(p_photoTheta != p_photoThetaold) {
178 cost = cos(p_photoTheta * PI / 180.0);
179 sint = sin(p_photoTheta * PI / 180.0);
180 p_photoCott = cost / max(1.0e-10, sint);
181 p_photoCot2t = p_photoCott * p_photoCott;
182 p_photoTant = sint / cost;
183 tan2t = p_photoTant * p_photoTant;
184 p_photoSr = sqrt(1.0 + PI * tan2t);
185 p_photoOsr = 1.0 / p_photoSr;
186 SetOldTheta(p_photoTheta);
187 }
188
189 if(incidence >= 90.0) {
190 pht_hapke = 0.0;
191 return pht_hapke;
192 }
193
194 gamma = sqrt(1.0 - p_photoWh);
195 hgs = p_photoHg1 * p_photoHg1;
196
197 cosg = cos(pharad);
198 tang2 = tan(pharad/2.0);
199
200 if(p_photoHh == 0.0) {
201 bg = 0.0;
202 }
203 else {
204 bg = p_photoB0 / (1.0 + tang2 / p_photoHh);
205 }
206
207 if (p_algName == "HAPKEHEN") {
208 pg1 = (1.0 - p_photoHg2) * (1.0 - hgs) / pow((1.0 + hgs + 2.0 *
209 p_photoHg1 * cosg), 1.5);
210 pg2 = p_photoHg2 * (1.0 - hgs) / pow((1.0 + hgs - 2.0 *
211 p_photoHg1 * cosg), 1.5);
212 pg = pg1 + pg2;
213 } else { // Hapke Legendre
214 pg = 1.0 + p_photoBh * cosg + p_photoCh * (1.5 * pow(cosg, 2.0) - .5);
215 }
216
217 // If smooth Hapke is wanted then set Theta<=0.0
218 if(p_photoTheta <= 0.0) {
219 pht_hapke = p_photoWh / 4.0 * munot / (munot + mu) * ((1.0 + bg) *
220 pg - 1.0 + Hfunc(munot, gamma) * Hfunc(mu, gamma));
221 return pht_hapke;
222 }
223
224 sini = sin(incrad);
225 coti = munot / max(1.0e-10, sini);
226 cot2i = coti * coti;
227 ecoti = exp(min(-p_photoCot2t * cot2i / PI , 23.0));
228 ecot2i = exp(min(-2.0 * p_photoCott * coti / PI, 23.0));
229 u0p0 = p_photoOsr * (munot + sini * p_photoTant * ecoti / (2.0 - ecot2i));
230
231 sine = sin(emarad);
232 cote = mu / max(1.0e-10, sine);
233 cot2e = cote * cote;
234
235 cosei = mu * munot;
236 sinei = sine * sini;
237
238 if(sinei == 0.0) {
239 caz = 1.0;
240 az = 0.0;
241 }
242 else {
243 caz = (cosg - cosei) / sinei;
244 if(caz <= -1.0) {
245 az = 180.0;
246 }
247 else if(caz > 1.0) {
248 az = 0.0;
249 }
250 else {
251 az = acos(caz) * 180.0 / PI;
252 }
253 }
254
255 az2 = az / 2.0;
256 if(az2 >= 90.0) {
257 faz = 0.0;
258 }
259 else {
260 tanaz2 = tan(az2 * PI / 180.0);
261 faz = exp(min(-2.0 * tanaz2, 23.0));
262 }
263
264 sin2a2 = pow(sin(az2 * PI / 180.0), 2.0);
265 api = az / 180.0;
266
267 ecote = exp(min(-p_photoCot2t * cot2e / PI, 23.0));
268 ecot2e = exp(min(-2.0 * p_photoCott * cote / PI, 23.0));
269 up0 = p_photoOsr * (mu + sine * p_photoTant * ecote / (2.0 - ecot2e));
270
271 if(incidence <= emission) {
272 q = p_photoOsr * munot / u0p0;
273 }
274 else {
275 q = p_photoOsr * mu / up0;
276 }
277
278 if(incidence <= emission) {
279 ecei = (2.0 - ecot2e - api * ecot2i);
280 s2ei = sin2a2 * ecoti;
281 u0p = p_photoOsr * (munot + sini * p_photoTant * (caz * ecote + s2ei) / ecei);
282 up = p_photoOsr * (mu + sine * p_photoTant * (ecote - s2ei) / ecei);
283 }
284 else {
285 ecee = (2.0 - ecot2i - api * ecot2e);
286 s2ee = sin2a2 * ecote;
287 u0p = p_photoOsr * (munot + sini * p_photoTant * (ecoti - s2ee) / ecee);
288 up = p_photoOsr * (mu + sine * p_photoTant * (caz * ecoti + s2ee) / ecee);
289 }
290
291 rr1 = p_photoWh / 4.0 * u0p / (u0p + up) * ((1.0 + bg) * pg -
292 1.0 + Hfunc(u0p, gamma) * Hfunc(up, gamma));
293 rr2 = up * munot / (up0 * u0p0 * p_photoSr * (1.0 - faz + faz * q));
294 pht_hapke = rr1 * rr2;
295
296 return pht_hapke;
297 }
298
307 void Hapke::SetPhotoHg1(const double hg1) {
308 if(hg1 <= -1.0 || hg1 >= 1.0) {
309 string msg = "Invalid value of Hapke Henyey Greenstein hg1 [" +
310 IString(hg1) + "]";
311 throw IException(IException::User, msg, _FILEINFO_);
312 }
313 p_photoHg1 = hg1;
314 }
315
324 void Hapke::SetPhotoHg2(const double hg2) {
325 if(hg2 < 0.0 || hg2 > 1.0) {
326 string msg = "Invalid value of Hapke Henyey Greenstein hg2 [" +
327 IString(hg2) + "]";
328 throw IException(IException::User, msg, _FILEINFO_);
329 }
330 p_photoHg2 = hg2;
331 }
332
341 void Hapke::SetPhotoBh(const double bh) {
342 if(bh < -1.0 || bh > 1.0) {
343 string msg = "Invalid value of Hapke Legendre bh [" +
344 IString(bh) + "]";
345 throw IException(IException::User, msg, _FILEINFO_);
346 }
347 p_photoBh = bh;
348 }
349
358 void Hapke::SetPhotoCh(const double ch) {
359 if(ch < -1.0 || ch > 1.0) {
360 string msg = "Invalid value of Hapke Legendre ch [" +
361 IString(ch) + "]";
362 throw IException(IException::User, msg, _FILEINFO_);
363 }
364 p_photoCh = ch;
365 }
366
374 void Hapke::SetPhotoWh(const double wh) {
375 if(wh <= 0.0 || wh > 1.0) {
376 string msg = "Invalid value of Hapke wh [" +
377 IString(wh) + "]";
378 throw IException(IException::User, msg, _FILEINFO_);
379 }
380 p_photoWh = wh;
381 }
382
390 void Hapke::SetPhotoHh(const double hh) {
391 if(hh < 0.0) {
392 string msg = "Invalid value of Hapke hh [" +
393 IString(hh) + "]";
394 throw IException(IException::User, msg, _FILEINFO_);
395 }
396 p_photoHh = hh;
397 }
398
406 void Hapke::SetPhotoB0(const double b0) {
407 if(b0 < 0.0) {
408 string msg = "Invalid value of Hapke b0 [" +
409 IString(b0) + "]";
410 throw IException(IException::User, msg, _FILEINFO_);
411 }
412 p_photoB0 = b0;
413 }
414
415
423 void Hapke::SetPhoto0B0Standard(const QString &b0standard) {
424 IString temp(b0standard);
425 temp = temp.UpCase();
426
427 if(temp != "NO" && temp != "YES" && temp != "FALSE" && temp != "TRUE") {
428 string msg = "Invalid value of Hapke ZeroB0Standard [" +
429 temp + "]";
430 throw IException(IException::User, msg, _FILEINFO_);
431 }
432
433 if (temp == "NO" || temp == "FALSE") p_photo0B0Standard = "FALSE";
434 if (temp == "YES" || temp == "TRUE") p_photo0B0Standard = "TRUE";
435 }
436
437
444 void Hapke::SetPhotoTheta(const double theta) {
445 if(theta < 0.0 || theta > 90.0) {
446 string msg = "Invalid value of Hapke theta [" +
447 IString(theta) + "]";
448 throw IException(IException::User, msg, _FILEINFO_);
449 }
450 p_photoTheta = theta;
451 }
452
453
454 void Hapke::SetStandardConditions(bool standard) {
455 PhotoModel::SetStandardConditions(standard);
456
457 if(standard) {
458 p_photoB0save = p_photoB0;
459 if (p_photo0B0Standard == "TRUE") p_photoB0 = 0.0;
460 }
461 else {
462 p_photoB0 = p_photoB0save;
463 }
464 }
465}
466
467extern "C" Isis::PhotoModel *HapkePlugin(Isis::Pvl &pvl) {
468 return new Isis::Hapke(pvl);
469}
Hapke-Henyey-Greenstein photometric model.
Definition Hapke.h:47
Isis exception class.
Definition IException.h:91
Adds specific functionality to C++ strings.
Definition IString.h:165
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
Namespace for the standard library.