11 #include "AtmosModel.h"
12 #include "NumericalApproximation.h"
13 #include "NumericalAtmosApprox.h"
14 #include "PhotoModel.h"
16 #include "LunarLambert.h"
18 #include "IException.h"
23 #define MAX(x,y) (((x) > (y)) ? (x) : (y))
42 p_atmosAlgorithmName =
"Unknown";
45 p_atmosIncTable.resize(91);
46 p_atmosAhTable.resize(91);
47 p_atmosHahgtTable.resize(91);
48 p_atmosHahgt0Table.resize(91);
52 p_atmosEulgam = 0.5772156;
64 p_atmosWhaold = 1.0e30;
72 p_standardConditions =
false;
74 PvlGroup &algorithm = pvl.
findObject(
"AtmosphericModel").findGroup(
"Algorithm", Pvl::Traverse);
77 SetAtmosNulneg(algorithm[
"Nulneg"][0] ==
"YES");
80 p_atmosNulneg =
false;
84 SetAtmosTau(algorithm[
"Tau"]);
86 p_atmosTausave = p_atmosTau;
89 SetAtmosTauref(algorithm[
"Tauref"]);
93 SetAtmosWha(algorithm[
"Wha"]);
95 p_atmosWhasave = p_atmosWha;
98 SetAtmosHga(algorithm[
"Hga"]);
100 p_atmosHgasave = p_atmosHga;
103 SetAtmosBha(algorithm[
"Bha"]);
105 p_atmosBhasave = p_atmosBha;
108 SetAtmosInc(algorithm[
"Inc"]);
112 SetAtmosPhi(algorithm[
"Phi"]);
116 SetAtmosHnorm(algorithm[
"Hnorm"]);
120 SetAtmosIord(algorithm[
"Iord"][0] ==
"YES");
123 p_atmosAddOffset =
false;
127 SetAtmosEstTau(algorithm[
"EstTau"][0] ==
"YES");
130 p_atmosEstTau =
false;
153 double AtmosModel::G11Prime(
double tau) {
172 while(fabs(term) > fabs(sum)*tol) {
176 fac = fac * (-tau) / fi;
177 term = fac / (fi * fi);
179 elog = log(MAX(1.0e-30, tau)) + eulgam;
180 e1_2 = sum +
PI *
PI / 12.0 + 0.5 *
182 result = 2.0 * (AtmosModel::En(1, tau)
183 + elog * AtmosModel::En(2, tau)
229 double AtmosModel::Ei(
double x) {
239 double sum, fact, term, prev;
248 "AtmosModel::Ei() - Invalid argument. Definition requires x > 0.0. Entered x = "
253 result = log(x) + euler;
255 else if(x <= -log(epsilon)) {
258 for(
int k = 1; k <= maxit; k++) {
262 if(term < epsilon * sum) {
263 result = sum + log(x) + euler;
268 "AtmosModel::Ei() - Power series failed to converge in "
269 +
IString(maxit) +
" iterations. Unable to calculate exponential integral.",
275 for(
int k = 1; k <= maxit; k++) {
279 result = exp(x) * (1.0 + sum) / x;
288 result = exp(x) * (1.0 + sum) / x;
293 result = exp(x) * (1.0 + sum) / x;
370 double AtmosModel::En(
unsigned int n,
double x) {
377 double a, b, c, d, h;
389 euler = 0.5772156649;
392 if((x < 0.0) || (x == 0.0 && (n == 0 || n == 1))) {
393 IString msg =
"AtmosModel::En() - Invalid arguments. ";
394 msg +=
"Definition requires (x > 0.0 and n >=0 ) or (x >= 0.0 and n > 1). ";
395 msg +=
"Entered x = " +
IString(x) +
" and n = " +
IString((
int) n);
396 throw IException(IException::Programmer, msg, _FILEINFO_);
399 result = exp(-x) / x;
409 for(
int i = 1; i <= maxit; i++) {
412 d = 1.0 / (a * d + b);
416 if(fabs(delta - 1.0) < epsilon) {
417 result = h * exp(-x);
422 "AtmosModel::En() - Continued fraction failed to converge in "
423 +
IString(maxit) +
" iterations. Unable to calculate exponential integral.",
431 result = -log(x) - euler;
434 for(
int i = 1; i <= maxit; i++) {
435 fact = -fact * x / i;
437 delta = -fact / (i - nm1);
441 for(
int ii = 1; ii <= nm1; ii++) {
442 psi = psi + 1.0 / ii;
444 delta = fact * (-log(x) + psi);
446 result = result + delta;
447 if(fabs(delta) < fabs(result)*epsilon) {
452 "AtmosModel::En() - Series representation failed to converge in "
453 +
IString(maxit) +
" iterations. Unable to calculate exponential integral.",
475 void AtmosModel::CalcAtmEffect(
double pha,
double inc,
double ema,
476 double *pstd,
double *trans,
double *trans0,
double *sbar,
487 AtmosModelAlgorithm(pha, inc, ema);
498 void AtmosModel::SetStandardConditions(
bool standard) {
499 p_standardConditions = standard;
500 if(p_standardConditions) {
501 p_atmosTausave = p_atmosTau;
502 p_atmosTau = p_atmosTauref;
505 p_atmosTau = p_atmosTausave;
537 void AtmosModel::GenerateAhTable() {
544 sub = NumericalAtmosApprox::OuterFunction;
551 for(inccnt = 0; inccnt < p_atmosNinc; inccnt++) {
552 p_atmosInc = (double) inccnt;
553 p_atmosIncTable[inccnt] = p_atmosInc;
554 p_atmosMunot = cos((
PI / 180.0) * p_atmosInc);
555 p_atmosSini = sin((
PI / 180.0) * p_atmosInc);
557 IString phtName = p_atmosPM->AlgorithmName();
559 if(p_atmosInc == 90.0) {
560 p_atmosAhTable[inccnt] = 0.0;
562 else if(phtName ==
"LAMBERT") {
563 p_atmosAhTable[inccnt] = 1.0;
565 else if(phtName ==
"LOMMELSEELIGER") {
566 p_atmosAhTable[inccnt] = 2.0 * log((1.0 / p_atmosMunot) / p_atmosMunot);
568 else if(phtName ==
"MINNAERT") {
569 p_atmosAhTable[inccnt] = (pow(p_atmosMunot, ((
Minnaert *)p_atmosPM)->PhotoK())) / ((
Minnaert *)p_atmosPM)->PhotoK();
571 else if(phtName ==
"LUNARLAMBERT") {
572 p_atmosAhTable[inccnt] = 2.0 * ((
LunarLambert *)p_atmosPM)->PhotoL() *
573 log((1.0 + p_atmosMunot) / p_atmosMunot) + 1.0 -
579 p_atmosAtmSwitch = 0;
583 p_atmosAhTable[inccnt] = fun_temp / (90.0 * p_atmosMunot);
587 if((inccnt == 0) || (inccnt == p_atmosNinc - 1)) {
594 p_atmosAb = p_atmosAb + p_atmosAhTable[inccnt] * p_atmosMunot * p_atmosSini * factor;
597 factor = 2.0 *
PI / 180.0;
598 p_atmosAb = p_atmosAb * factor;
603 p_atmosAhSpline.Reset();
604 p_atmosAhSpline.SetInterpType(NumericalApproximation::CubicClamped);
605 p_atmosAhSpline.AddData(p_atmosIncTable, p_atmosAhTable);
606 p_atmosAhSpline.SetCubicClampedEndptDeriv(yp1, yp2);
637 void AtmosModel::GenerateHahgTables() {
645 sub = NumericalAtmosApprox::OuterFunction;
650 for(inccnt = 0; inccnt < p_atmosNinc; inccnt++) {
651 p_atmosInc = (double) inccnt;
652 p_atmosIncTable[inccnt] = p_atmosInc;
653 p_atmosMunot = cos((
PI / 180.0) * p_atmosInc);
654 p_atmosSini = sin((
PI / 180.0) * p_atmosInc);
656 p_atmosAtmSwitch = 1;
661 p_atmosHahgtTable[inccnt] = fun_temp * AtmosWha() / 360.0;
662 p_atmosAtmSwitch = 2;
666 hahgsb_temp = fun_temp * AtmosWha() / 360.0;
668 if((inccnt == 0) || (inccnt == p_atmosNinc - 1)) {
675 p_atmosHahgsb = p_atmosHahgsb + p_atmosSini * factor * hahgsb_temp;
676 if(p_atmosInc == 0.0) {
677 p_atmosHahgt0Table[inccnt] = 0.0;
680 p_atmosAtmSwitch = 3;
682 p_atmosHahgt0Table[inccnt] = fun_temp * AtmosWha() * p_atmosMunot / (360.0 * p_atmosSini);
686 factor = 2.0 *
PI / 180.0;
687 p_atmosHahgsb = p_atmosHahgsb * factor;
692 p_atmosHahgtSpline.Reset();
693 p_atmosHahgtSpline.SetInterpType(NumericalApproximation::CubicClamped);
694 p_atmosHahgtSpline.AddData(p_atmosIncTable, p_atmosHahgtTable);
695 p_atmosHahgtSpline.SetCubicClampedEndptDeriv(yp1, yp2);
697 p_atmosHahgt0Spline.Reset();
698 p_atmosHahgt0Spline.SetInterpType(NumericalApproximation::CubicClamped);
699 p_atmosHahgt0Spline.AddData(p_atmosIncTable, p_atmosHahgt0Table);
700 p_atmosHahgt0Spline.SetCubicClampedEndptDeriv(yp1, yp2);
726 void AtmosModel::GenerateHahgTablesShadow() {
734 sub = NumericalAtmosApprox::OuterFunction;
738 deltaInc = 90.0/(double)(nincl-1.0);
740 for(inccnt = 0; inccnt < nincl; inccnt++) {
741 p_atmosInc = deltaInc * (double) inccnt;
742 p_atmosMunot = cos((
PI / 180.0) * p_atmosInc);
743 p_atmosSini = sin((
PI / 180.0) * p_atmosInc);
745 p_atmosAtmSwitch = 2;
748 if (p_atmosInc >= 90.0) {
754 if((inccnt == 0) || (inccnt == nincl - 1)) {
760 p_atmosHahgsb = p_atmosHahgsb + p_atmosSini * factor * fun_temp *
764 factor = 2.0 * deltaInc *
PI / 180.0;
765 p_atmosHahgsb = p_atmosHahgsb * factor;
779 void AtmosModel::SetAtmosAtmSwitch(
const int atmswitch) {
780 if(atmswitch < 0 || atmswitch > 3) {
781 string msg =
"Invalid value of atmospheric atmswitch [" +
IString(atmswitch) +
"]";
782 throw IException(IException::User, msg, _FILEINFO_);
785 p_atmosAtmSwitch = atmswitch;
799 void AtmosModel::SetAtmosBha(
const double bha) {
800 if(bha < -1.0 || bha > 1.0) {
801 string msg =
"Invalid value of Anisotropic atmospheric bha [" +
803 throw IException(IException::User, msg, _FILEINFO_);
820 void AtmosModel::SetAtmosHga(
const double hga) {
821 if(hga <= -1.0 || hga >= 1.0) {
822 string msg =
"Invalid value of Hapke atmospheric hga [" +
IString(hga) +
"]";
823 throw IException(IException::User, msg, _FILEINFO_);
839 void AtmosModel::SetAtmosInc(
const double inc) {
840 if(inc < 0.0 || inc > 90.0) {
841 string msg =
"Invalid value of atmospheric inc [" +
IString(inc) +
"]";
842 throw IException(IException::User, msg, _FILEINFO_);
846 p_atmosMunot = cos(inc *
PI / 180.0);
847 p_atmosSini = sin(inc *
PI / 180.0);
861 void AtmosModel::SetAtmosNulneg(
const string nulneg) {
865 if(temp !=
"NO" && temp !=
"YES") {
866 string msg =
"Invalid value of Atmospheric nulneg [" + temp +
"]";
867 throw IException(IException::User, msg, _FILEINFO_);
870 SetAtmosNulneg(temp.compare(
"YES") == 0);
884 void AtmosModel::SetAtmosPhi(
const double phi) {
885 if(phi < 0.0 || phi > 360.0) {
886 string msg =
"Invalid value of atmospheric phi [" +
IString(phi) +
"]";
887 throw IException(IException::User, msg, _FILEINFO_);
891 p_atmosCosphi = cos(phi *
PI / 180.0);
903 void AtmosModel::SetAtmosTau(
const double tau) {
905 string msg =
"Invalid value of Atmospheric tau [" +
IString(tau) +
"]";
906 throw IException(IException::User, msg, _FILEINFO_);
922 void AtmosModel::SetAtmosTauref(
const double tauref) {
924 string msg =
"Invalid value of Atmospheric tauref [" +
IString(tauref) +
"]";
925 throw IException(IException::User, msg, _FILEINFO_);
928 p_atmosTauref = tauref;
941 void AtmosModel::SetAtmosWha(
const double wha) {
942 if(wha <= 0.0 || wha > 1.0) {
943 string msg =
"Invalid value of Atmospheric wha [" +
IString(wha) +
"]";
944 throw IException(IException::User, msg, _FILEINFO_);
954 bool AtmosModel::TauOrWhaChanged()
const {
955 return (AtmosTau() != p_atmosTauold) || (AtmosWha() != p_atmosWhaold);
968 void AtmosModel::SetAtmosHnorm(
const double hnorm) {
970 QString msg =
"Invalid value of Atmospheric hnorm [" +
toString(hnorm) +
"]";
971 throw IException(IException::User, msg, _FILEINFO_);
973 p_atmosHnorm = hnorm;
983 void AtmosModel::SetAtmosIord(
const string offset) {
987 if(temp !=
"NO" && temp !=
"YES") {
988 string msg =
"Invalid value of Atmospheric additive offset[" + temp +
"]";
989 throw IException(IException::User, msg, _FILEINFO_);
992 SetAtmosIord(temp.compare(
"YES") == 0);
1002 void AtmosModel::SetAtmosEstTau(
const string esttau) {
1006 if(temp !=
"NO" && temp !=
"YES") {
1007 string msg =
"Invalid value of Atmospheric optical depth estimation[" + temp +
"]";
1008 throw IException(IException::User, msg, _FILEINFO_);
1011 SetAtmosEstTau(temp.compare(
"YES") == 0);