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 
15 using namespace std;
16 
17 namespace 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) {
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 
467 extern "C" Isis::PhotoModel *HapkePlugin(Isis::Pvl &pvl) {
468  return new Isis::Hapke(pvl);
469 }
Isis::Hapke::SetPhotoHh
void SetPhotoHh(const double hh)
Return photometric Wh value.
Definition: Hapke.cpp:390
Isis::PhotoModel
Definition: PhotoModel.h:41
Isis::PI
const double PI
The mathematical constant PI.
Definition: Constants.h:40
Isis::Hapke
Hapke-Henyey-Greenstein photometric model.
Definition: Hapke.h:47
Isis::Pvl
Container for cube-like labels.
Definition: Pvl.h:119
Isis::Hapke::SetPhoto0B0Standard
void SetPhoto0B0Standard(const QString &b0standard)
Determine if the Hapke opposition surge component is initialized to zero during the SetStandardCondit...
Definition: Hapke.cpp:423
Isis::Hapke::SetStandardConditions
void SetStandardConditions(bool standard)
Sets whether standard conditions will be used.
Definition: Hapke.cpp:454
Isis::PvlObject::Traverse
@ Traverse
Search child objects.
Definition: PvlObject.h:158
Isis::IString::UpCase
IString UpCase()
Converst any lower case characters in the object IString with uppercase characters.
Definition: IString.cpp:617
Isis::Hapke::SetPhotoTheta
void SetPhotoTheta(const double theta)
Return photometric B0 value.
Definition: Hapke.cpp:444
Isis::IException
Isis exception class.
Definition: IException.h:91
Isis::Hapke::SetPhotoHg2
void SetPhotoHg2(const double hg2)
Return photometric Hg1 value.
Definition: Hapke.cpp:324
Isis::PhotoModel::SetStandardConditions
virtual void SetStandardConditions(bool standard)
Sets whether standard conditions will be used.
Definition: PhotoModel.cpp:50
std
Namespace for the standard library.
Isis::Hapke::SetPhotoWh
void SetPhotoWh(const double wh)
Return photometric Ch value.
Definition: Hapke.cpp:374
Isis::PhotoModel::Hfunc
double Hfunc(double u, double gamma)
Hapke's approximation to Chandra's H function.
Definition: PhotoModel.h:168
Isis::IString
Adds specific functionality to C++ strings.
Definition: IString.h:165
Isis::Hapke::SetPhotoB0
void SetPhotoB0(const double b0)
Return photometric Hh value.
Definition: Hapke.cpp:406
Isis::Hapke::SetPhotoCh
void SetPhotoCh(const double ch)
Return photometric Bh value.
Definition: Hapke.cpp:358
Isis::Hapke::SetOldTheta
void SetOldTheta(double theta)
Return photometric Theta value.
Definition: Hapke.h:100
Isis::Hapke::SetPhotoHg1
void SetPhotoHg1(const double hg1)
Set the Hapke Henyey Greenstein coefficient for the single particle phase function.
Definition: Hapke.cpp:307
Isis
This is free and unencumbered software released into the public domain.
Definition: Apollo.h:16
Isis::IException::User
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
Definition: IException.h:126
Isis::Hapke::SetPhotoBh
void SetPhotoBh(const double bh)
Return photometric Hg2 value.
Definition: Hapke.cpp:341