6 #include "NumericalApproximation.h" 17 #define MAX(x,y) (((x) > (y)) ? (x) : (y)) 36 p_atmosAlgorithmName =
"Unknown";
39 p_atmosIncTable.resize(91);
40 p_atmosAhTable.resize(91);
41 p_atmosHahgtTable.resize(91);
42 p_atmosHahgt0Table.resize(91);
46 p_atmosEulgam = 0.5772156;
58 p_atmosWhaold = 1.0e30;
66 p_standardConditions =
false;
68 PvlGroup &algorithm = pvl.
findObject(
"AtmosphericModel").findGroup(
"Algorithm", Pvl::Traverse);
71 SetAtmosNulneg(algorithm[
"Nulneg"][0] ==
"YES");
74 p_atmosNulneg =
false;
78 SetAtmosTau(algorithm[
"Tau"]);
80 p_atmosTausave = p_atmosTau;
83 SetAtmosTauref(algorithm[
"Tauref"]);
87 SetAtmosWha(algorithm[
"Wha"]);
89 p_atmosWhasave = p_atmosWha;
92 SetAtmosHga(algorithm[
"Hga"]);
94 p_atmosHgasave = p_atmosHga;
97 SetAtmosBha(algorithm[
"Bha"]);
99 p_atmosBhasave = p_atmosBha;
102 SetAtmosInc(algorithm[
"Inc"]);
106 SetAtmosPhi(algorithm[
"Phi"]);
110 SetAtmosHnorm(algorithm[
"Hnorm"]);
114 SetAtmosIord(algorithm[
"Iord"][0] ==
"YES");
117 p_atmosAddOffset =
false;
121 SetAtmosEstTau(algorithm[
"EstTau"][0] ==
"YES");
124 p_atmosEstTau =
false;
147 double AtmosModel::G11Prime(
double tau) {
166 while(fabs(term) > fabs(sum)*tol) {
170 fac = fac * (-tau) / fi;
171 term = fac / (fi * fi);
173 elog = log(MAX(1.0e-30, tau)) + eulgam;
174 e1_2 = sum +
PI *
PI / 12.0 + 0.5 *
176 result = 2.0 * (AtmosModel::En(1, tau)
177 + elog * AtmosModel::En(2, tau)
223 double AtmosModel::Ei(
double x) {
233 double sum, fact, term, prev;
242 "AtmosModel::Ei() - Invalid argument. Definition requires x > 0.0. Entered x = " 247 result = log(x) + euler;
249 else if(x <= -log(epsilon)) {
252 for(
int k = 1; k <= maxit; k++) {
256 if(term < epsilon * sum) {
257 result = sum + log(x) + euler;
262 "AtmosModel::Ei() - Power series failed to converge in " 263 +
IString(maxit) +
" iterations. Unable to calculate exponential integral.",
269 for(
int k = 1; k <= maxit; k++) {
273 result = exp(x) * (1.0 + sum) / x;
282 result = exp(x) * (1.0 + sum) / x;
287 result = exp(x) * (1.0 + sum) / x;
364 double AtmosModel::En(
unsigned int n,
double x) {
371 double a, b, c, d, h;
383 euler = 0.5772156649;
386 if((x < 0.0) || (x == 0.0 && (n == 0 || n == 1))) {
387 IString msg =
"AtmosModel::En() - Invalid arguments. ";
388 msg +=
"Definition requires (x > 0.0 and n >=0 ) or (x >= 0.0 and n > 1). ";
389 msg +=
"Entered x = " +
IString(x) +
" and n = " +
IString((
int) n);
393 result = exp(-x) / x;
403 for(
int i = 1; i <= maxit; i++) {
406 d = 1.0 / (a * d + b);
410 if(fabs(delta - 1.0) < epsilon) {
411 result = h * exp(-x);
416 "AtmosModel::En() - Continued fraction failed to converge in " 417 +
IString(maxit) +
" iterations. Unable to calculate exponential integral.",
425 result = -log(x) - euler;
428 for(
int i = 1; i <= maxit; i++) {
429 fact = -fact * x / i;
431 delta = -fact / (i - nm1);
435 for(
int ii = 1; ii <= nm1; ii++) {
436 psi = psi + 1.0 / ii;
438 delta = fact * (-log(x) + psi);
440 result = result + delta;
441 if(fabs(delta) < fabs(result)*epsilon) {
446 "AtmosModel::En() - Series representation failed to converge in " 447 +
IString(maxit) +
" iterations. Unable to calculate exponential integral.",
469 void AtmosModel::CalcAtmEffect(
double pha,
double inc,
double ema,
470 double *pstd,
double *trans,
double *trans0,
double *sbar,
481 AtmosModelAlgorithm(pha, inc, ema);
492 void AtmosModel::SetStandardConditions(
bool standard) {
493 p_standardConditions = standard;
494 if(p_standardConditions) {
495 p_atmosTausave = p_atmosTau;
496 p_atmosTau = p_atmosTauref;
499 p_atmosTau = p_atmosTausave;
531 void AtmosModel::GenerateAhTable() {
538 sub = NumericalAtmosApprox::OuterFunction;
545 for(inccnt = 0; inccnt < p_atmosNinc; inccnt++) {
546 p_atmosInc = (double) inccnt;
547 p_atmosIncTable[inccnt] = p_atmosInc;
548 p_atmosMunot = cos((
PI / 180.0) * p_atmosInc);
549 p_atmosSini = sin((
PI / 180.0) * p_atmosInc);
551 IString phtName = p_atmosPM->AlgorithmName();
553 if(p_atmosInc == 90.0) {
554 p_atmosAhTable[inccnt] = 0.0;
556 else if(phtName ==
"LAMBERT") {
557 p_atmosAhTable[inccnt] = 1.0;
559 else if(phtName ==
"LOMMELSEELIGER") {
560 p_atmosAhTable[inccnt] = 2.0 * log((1.0 / p_atmosMunot) / p_atmosMunot);
562 else if(phtName ==
"MINNAERT") {
563 p_atmosAhTable[inccnt] = (pow(p_atmosMunot, ((
Minnaert *)p_atmosPM)->PhotoK())) / ((
Minnaert *)p_atmosPM)->PhotoK();
565 else if(phtName ==
"LUNARLAMBERT") {
566 p_atmosAhTable[inccnt] = 2.0 * ((
LunarLambert *)p_atmosPM)->PhotoL() *
567 log((1.0 + p_atmosMunot) / p_atmosMunot) + 1.0 -
573 p_atmosAtmSwitch = 0;
577 p_atmosAhTable[inccnt] = fun_temp / (90.0 * p_atmosMunot);
581 if((inccnt == 0) || (inccnt == p_atmosNinc - 1)) {
588 p_atmosAb = p_atmosAb + p_atmosAhTable[inccnt] * p_atmosMunot * p_atmosSini * factor;
591 factor = 2.0 *
PI / 180.0;
592 p_atmosAb = p_atmosAb * factor;
597 p_atmosAhSpline.Reset();
598 p_atmosAhSpline.SetInterpType(NumericalApproximation::CubicClamped);
599 p_atmosAhSpline.AddData(p_atmosIncTable, p_atmosAhTable);
600 p_atmosAhSpline.SetCubicClampedEndptDeriv(yp1, yp2);
631 void AtmosModel::GenerateHahgTables() {
639 sub = NumericalAtmosApprox::OuterFunction;
644 for(inccnt = 0; inccnt < p_atmosNinc; inccnt++) {
645 p_atmosInc = (double) inccnt;
646 p_atmosIncTable[inccnt] = p_atmosInc;
647 p_atmosMunot = cos((
PI / 180.0) * p_atmosInc);
648 p_atmosSini = sin((
PI / 180.0) * p_atmosInc);
650 p_atmosAtmSwitch = 1;
655 p_atmosHahgtTable[inccnt] = fun_temp * AtmosWha() / 360.0;
656 p_atmosAtmSwitch = 2;
660 hahgsb_temp = fun_temp * AtmosWha() / 360.0;
662 if((inccnt == 0) || (inccnt == p_atmosNinc - 1)) {
669 p_atmosHahgsb = p_atmosHahgsb + p_atmosSini * factor * hahgsb_temp;
670 if(p_atmosInc == 0.0) {
671 p_atmosHahgt0Table[inccnt] = 0.0;
674 p_atmosAtmSwitch = 3;
676 p_atmosHahgt0Table[inccnt] = fun_temp * AtmosWha() * p_atmosMunot / (360.0 * p_atmosSini);
680 factor = 2.0 *
PI / 180.0;
681 p_atmosHahgsb = p_atmosHahgsb * factor;
686 p_atmosHahgtSpline.Reset();
687 p_atmosHahgtSpline.SetInterpType(NumericalApproximation::CubicClamped);
688 p_atmosHahgtSpline.AddData(p_atmosIncTable, p_atmosHahgtTable);
689 p_atmosHahgtSpline.SetCubicClampedEndptDeriv(yp1, yp2);
691 p_atmosHahgt0Spline.Reset();
692 p_atmosHahgt0Spline.SetInterpType(NumericalApproximation::CubicClamped);
693 p_atmosHahgt0Spline.AddData(p_atmosIncTable, p_atmosHahgt0Table);
694 p_atmosHahgt0Spline.SetCubicClampedEndptDeriv(yp1, yp2);
720 void AtmosModel::GenerateHahgTablesShadow() {
728 sub = NumericalAtmosApprox::OuterFunction;
732 deltaInc = 90.0/(double)(nincl-1.0);
734 for(inccnt = 0; inccnt < nincl; inccnt++) {
735 p_atmosInc = deltaInc * (double) inccnt;
736 p_atmosMunot = cos((
PI / 180.0) * p_atmosInc);
737 p_atmosSini = sin((
PI / 180.0) * p_atmosInc);
739 p_atmosAtmSwitch = 2;
742 if (p_atmosInc >= 90.0) {
748 if((inccnt == 0) || (inccnt == nincl - 1)) {
754 p_atmosHahgsb = p_atmosHahgsb + p_atmosSini * factor * fun_temp *
758 factor = 2.0 * deltaInc *
PI / 180.0;
759 p_atmosHahgsb = p_atmosHahgsb * factor;
773 void AtmosModel::SetAtmosAtmSwitch(
const int atmswitch) {
774 if(atmswitch < 0 || atmswitch > 3) {
775 string msg =
"Invalid value of atmospheric atmswitch [" +
IString(atmswitch) +
"]";
779 p_atmosAtmSwitch = atmswitch;
793 void AtmosModel::SetAtmosBha(
const double bha) {
794 if(bha < -1.0 || bha > 1.0) {
795 string msg =
"Invalid value of Anisotropic atmospheric bha [" +
814 void AtmosModel::SetAtmosHga(
const double hga) {
815 if(hga <= -1.0 || hga >= 1.0) {
816 string msg =
"Invalid value of Hapke atmospheric hga [" +
IString(hga) +
"]";
833 void AtmosModel::SetAtmosInc(
const double inc) {
834 if(inc < 0.0 || inc > 90.0) {
835 string msg =
"Invalid value of atmospheric inc [" +
IString(inc) +
"]";
840 p_atmosMunot = cos(inc *
PI / 180.0);
841 p_atmosSini = sin(inc *
PI / 180.0);
855 void AtmosModel::SetAtmosNulneg(
const string nulneg) {
859 if(temp !=
"NO" && temp !=
"YES") {
860 string msg =
"Invalid value of Atmospheric nulneg [" + temp +
"]";
864 SetAtmosNulneg(temp.compare(
"YES") == 0);
878 void AtmosModel::SetAtmosPhi(
const double phi) {
879 if(phi < 0.0 || phi > 360.0) {
880 string msg =
"Invalid value of atmospheric phi [" +
IString(phi) +
"]";
885 p_atmosCosphi = cos(phi *
PI / 180.0);
897 void AtmosModel::SetAtmosTau(
const double tau) {
899 string msg =
"Invalid value of Atmospheric tau [" +
IString(tau) +
"]";
916 void AtmosModel::SetAtmosTauref(
const double tauref) {
918 string msg =
"Invalid value of Atmospheric tauref [" +
IString(tauref) +
"]";
922 p_atmosTauref = tauref;
935 void AtmosModel::SetAtmosWha(
const double wha) {
936 if(wha <= 0.0 || wha > 1.0) {
937 string msg =
"Invalid value of Atmospheric wha [" +
IString(wha) +
"]";
948 bool AtmosModel::TauOrWhaChanged()
const {
949 return (AtmosTau() != p_atmosTauold) || (AtmosWha() != p_atmosWhaold);
962 void AtmosModel::SetAtmosHnorm(
const double hnorm) {
964 QString msg =
"Invalid value of Atmospheric hnorm [" +
toString(hnorm) +
"]";
967 p_atmosHnorm = hnorm;
977 void AtmosModel::SetAtmosIord(
const string offset) {
981 if(temp !=
"NO" && temp !=
"YES") {
982 string msg =
"Invalid value of Atmospheric additive offset[" + temp +
"]";
986 SetAtmosIord(temp.compare(
"YES") == 0);
996 void AtmosModel::SetAtmosEstTau(
const string esttau) {
1000 if(temp !=
"NO" && temp !=
"YES") {
1001 string msg =
"Invalid value of Atmospheric optical depth estimation[" + temp +
"]";
1005 SetAtmosEstTau(temp.compare(
"YES") == 0);
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
const double PI
The mathematical constant PI.
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
Namespace for the standard library.
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
double RombergsMethod(AtmosModel *am, IntegFunc sub, double a, double b)
This variation on the NumericalApproximation method integrates a specified AtmosModel function rather...
void Reset()
Resets the state of the object.
Contains multiple PvlContainers.
#define _FILEINFO_
Macro for the filename and line number.
Container for cube-like labels.
Minnaert photometric model Derive model albedo using Minnaert equation.
IntegFunc
This enum defines function to be integrated by Romberg's method.
Adds specific functionality to C++ strings.
Namespace for ISIS/Bullet specific routines.
Lunar (Lommel-Seeliger)-Lambert law photometric model Derive model albedo for Lunar (Lommel-Seeliger)...
IString UpCase()
Converst any lower case characters in the object IString with uppercase characters.
This class extends Isis::NumericalApproximation.