11#include "AtmosModel.h"
12#include "NumericalApproximation.h"
13#include "NumericalAtmosApprox.h"
14#include "PhotoModel.h"
16#include "LunarLambert.h"
18#include "IException.h"
41 p_atmosAlgorithmName =
"Unknown";
44 p_atmosIncTable.resize(91);
45 p_atmosAhTable.resize(91);
46 p_atmosHahgtTable.resize(91);
47 p_atmosHahgt0Table.resize(91);
51 p_atmosEulgam = 0.5772156;
63 p_atmosWhaold = 1.0e30;
71 p_standardConditions =
false;
73 PvlGroup &algorithm = pvl.findObject(
"AtmosphericModel").findGroup(
"Algorithm", Pvl::Traverse);
75 if(algorithm.hasKeyword(
"Nulneg")) {
79 p_atmosNulneg =
false;
82 if(algorithm.hasKeyword(
"Tau")) {
85 p_atmosTausave = p_atmosTau;
87 if(algorithm.hasKeyword(
"Tauref")) {
91 if(algorithm.hasKeyword(
"Wha")) {
94 p_atmosWhasave = p_atmosWha;
96 if(algorithm.hasKeyword(
"Hga")) {
99 p_atmosHgasave = p_atmosHga;
101 if(algorithm.hasKeyword(
"Bha")) {
104 p_atmosBhasave = p_atmosBha;
106 if(algorithm.hasKeyword(
"Inc")) {
110 if(algorithm.hasKeyword(
"Phi")) {
114 if(algorithm.hasKeyword(
"Hnorm")) {
118 if(algorithm.hasKeyword(
"Iord")) {
125 if(algorithm.hasKeyword(
"EstTau")) {
171 while(fabs(term) > fabs(sum)*tol) {
175 fac = fac * (-tau) / fi;
176 term = fac / (fi * fi);
178 elog = log(std::max(1.0e-30, tau)) + eulgam;
179 e1_2 = sum + PI * PI / 12.0 + 0.5 *
238 double sum, fact, term, prev;
246 throw IException(IException::Programmer,
247 "AtmosModel::Ei() - Invalid argument. Definition requires x > 0.0. Entered x = "
252 result = log(x) + euler;
254 else if(x <= -log(epsilon)) {
257 for(
int k = 1; k <= maxit; k++) {
261 if(term < epsilon * sum) {
262 result = sum + log(x) + euler;
266 throw IException(IException::Unknown,
267 "AtmosModel::Ei() - Power series failed to converge in "
268 + IString(maxit) +
" iterations. Unable to calculate exponential integral.",
274 for(
int k = 1; k <= maxit; k++) {
278 result = exp(x) * (1.0 + sum) / x;
287 result = exp(x) * (1.0 + sum) / x;
292 result = exp(x) * (1.0 + sum) / x;
376 double a, b, c, d, h;
388 euler = 0.5772156649;
391 if((x < 0.0) || (x == 0.0 && (n == 0 || n == 1))) {
392 IString msg =
"AtmosModel::En() - Invalid arguments. ";
393 msg +=
"Definition requires (x > 0.0 and n >=0 ) or (x >= 0.0 and n > 1). ";
394 msg +=
"Entered x = " + IString(x) +
" and n = " + IString((
int) n);
395 throw IException(IException::Programmer, msg, _FILEINFO_);
398 result = exp(-x) / x;
408 for(
int i = 1; i <= maxit; i++) {
411 d = 1.0 / (a * d + b);
415 if(fabs(delta - 1.0) < epsilon) {
416 result = h * exp(-x);
420 throw IException(IException::Unknown,
421 "AtmosModel::En() - Continued fraction failed to converge in "
422 + IString(maxit) +
" iterations. Unable to calculate exponential integral.",
430 result = -log(x) - euler;
433 for(
int i = 1; i <= maxit; i++) {
434 fact = -fact * x / i;
436 delta = -fact / (i - nm1);
440 for(
int ii = 1; ii <= nm1; ii++) {
441 psi = psi + 1.0 / ii;
443 delta = fact * (-log(x) + psi);
445 result = result + delta;
446 if(fabs(delta) < fabs(result)*epsilon) {
450 throw IException(IException::Unknown,
451 "AtmosModel::En() - Series representation failed to converge in "
452 + IString(maxit) +
" iterations. Unable to calculate exponential integral.",
475 double *pstd,
double *trans,
double *trans0,
double *sbar,
486 AtmosModelAlgorithm(pha, inc, ema);
498 p_standardConditions = standard;
499 if(p_standardConditions) {
500 p_atmosTausave = p_atmosTau;
501 p_atmosTau = p_atmosTauref;
504 p_atmosTau = p_atmosTausave;
548 NumericalAtmosApprox qromb;
550 for(inccnt = 0; inccnt < p_atmosNinc; inccnt++) {
551 p_atmosInc = (double) inccnt;
552 p_atmosIncTable[inccnt] = p_atmosInc;
553 p_atmosMunot = cos((PI / 180.0) * p_atmosInc);
554 p_atmosSini = sin((PI / 180.0) * p_atmosInc);
556 IString phtName = p_atmosPM->AlgorithmName();
558 if(p_atmosInc == 90.0) {
559 p_atmosAhTable[inccnt] = 0.0;
561 else if(phtName ==
"LAMBERT") {
562 p_atmosAhTable[inccnt] = 1.0;
564 else if(phtName ==
"LOMMELSEELIGER") {
565 p_atmosAhTable[inccnt] = 2.0 * log((1.0 / p_atmosMunot) / p_atmosMunot);
567 else if(phtName ==
"MINNAERT") {
568 p_atmosAhTable[inccnt] = (pow(p_atmosMunot, ((
Minnaert *)p_atmosPM)->PhotoK())) / ((
Minnaert *)p_atmosPM)->PhotoK();
570 else if(phtName ==
"LUNARLAMBERT") {
571 p_atmosAhTable[inccnt] = 2.0 * ((
LunarLambert *)p_atmosPM)->PhotoL() *
572 log((1.0 + p_atmosMunot) / p_atmosMunot) + 1.0 -
578 p_atmosAtmSwitch = 0;
582 p_atmosAhTable[inccnt] = fun_temp / (90.0 * p_atmosMunot);
586 if((inccnt == 0) || (inccnt == p_atmosNinc - 1)) {
593 p_atmosAb = p_atmosAb + p_atmosAhTable[inccnt] * p_atmosMunot * p_atmosSini * factor;
596 factor = 2.0 * PI / 180.0;
597 p_atmosAb = p_atmosAb * factor;
647 NumericalAtmosApprox qromb;
649 for(inccnt = 0; inccnt < p_atmosNinc; inccnt++) {
650 p_atmosInc = (double) inccnt;
651 p_atmosIncTable[inccnt] = p_atmosInc;
652 p_atmosMunot = cos((PI / 180.0) * p_atmosInc);
653 p_atmosSini = sin((PI / 180.0) * p_atmosInc);
655 p_atmosAtmSwitch = 1;
660 p_atmosHahgtTable[inccnt] = fun_temp *
AtmosWha() / 360.0;
661 p_atmosAtmSwitch = 2;
665 hahgsb_temp = fun_temp *
AtmosWha() / 360.0;
667 if((inccnt == 0) || (inccnt == p_atmosNinc - 1)) {
674 p_atmosHahgsb = p_atmosHahgsb + p_atmosSini * factor * hahgsb_temp;
675 if(p_atmosInc == 0.0) {
676 p_atmosHahgt0Table[inccnt] = 0.0;
679 p_atmosAtmSwitch = 3;
681 p_atmosHahgt0Table[inccnt] = fun_temp *
AtmosWha() * p_atmosMunot / (360.0 * p_atmosSini);
685 factor = 2.0 * PI / 180.0;
686 p_atmosHahgsb = p_atmosHahgsb * factor;
736 NumericalAtmosApprox qromb;
737 deltaInc = 90.0/(double)(nincl-1.0);
739 for(inccnt = 0; inccnt < nincl; inccnt++) {
740 p_atmosInc = deltaInc * (double) inccnt;
741 p_atmosMunot = cos((PI / 180.0) * p_atmosInc);
742 p_atmosSini = sin((PI / 180.0) * p_atmosInc);
744 p_atmosAtmSwitch = 2;
747 if (p_atmosInc >= 90.0) {
753 if((inccnt == 0) || (inccnt == nincl - 1)) {
759 p_atmosHahgsb = p_atmosHahgsb + p_atmosSini * factor * fun_temp *
763 factor = 2.0 * deltaInc * PI / 180.0;
764 p_atmosHahgsb = p_atmosHahgsb * factor;
779 if(atmswitch < 0 || atmswitch > 3) {
780 string msg =
"Invalid value of atmospheric atmswitch [" + IString(atmswitch) +
"]";
781 throw IException(IException::User, msg, _FILEINFO_);
784 p_atmosAtmSwitch = atmswitch;
799 if(bha < -1.0 || bha > 1.0) {
800 string msg =
"Invalid value of Anisotropic atmospheric bha [" +
802 throw IException(IException::User, msg, _FILEINFO_);
820 if(hga <= -1.0 || hga >= 1.0) {
821 string msg =
"Invalid value of Hapke atmospheric hga [" + IString(hga) +
"]";
822 throw IException(IException::User, msg, _FILEINFO_);
839 if(inc < 0.0 || inc > 90.0) {
840 string msg =
"Invalid value of atmospheric inc [" + IString(inc) +
"]";
841 throw IException(IException::User, msg, _FILEINFO_);
845 p_atmosMunot = cos(inc * PI / 180.0);
846 p_atmosSini = sin(inc * PI / 180.0);
861 IString temp(nulneg);
862 temp = temp.UpCase();
864 if(temp !=
"NO" && temp !=
"YES") {
865 string msg =
"Invalid value of Atmospheric nulneg [" + temp +
"]";
866 throw IException(IException::User, msg, _FILEINFO_);
884 if(phi < 0.0 || phi > 360.0) {
885 string msg =
"Invalid value of atmospheric phi [" + IString(phi) +
"]";
886 throw IException(IException::User, msg, _FILEINFO_);
890 p_atmosCosphi = cos(phi * PI / 180.0);
904 string msg =
"Invalid value of Atmospheric tau [" + IString(tau) +
"]";
905 throw IException(IException::User, msg, _FILEINFO_);
923 string msg =
"Invalid value of Atmospheric tauref [" + IString(tauref) +
"]";
924 throw IException(IException::User, msg, _FILEINFO_);
927 p_atmosTauref = tauref;
941 if(wha <= 0.0 || wha > 1.0) {
942 string msg =
"Invalid value of Atmospheric wha [" + IString(wha) +
"]";
943 throw IException(IException::User, msg, _FILEINFO_);
969 QString msg =
"Invalid value of Atmospheric hnorm [" +
toString(hnorm) +
"]";
970 throw IException(IException::User, msg, _FILEINFO_);
983 IString temp(offset);
984 temp = temp.UpCase();
986 if(temp !=
"NO" && temp !=
"YES") {
987 string msg =
"Invalid value of Atmospheric additive offset[" + temp +
"]";
988 throw IException(IException::User, msg, _FILEINFO_);
1002 IString temp(esttau);
1003 temp = temp.UpCase();
1005 if(temp !=
"NO" && temp !=
"YES") {
1006 string msg =
"Invalid value of Atmospheric optical depth estimation[" + temp +
"]";
1007 throw IException(IException::User, msg, _FILEINFO_);
double p_trans
Transmission of surface reflected light through the atmosphere overall.
static double En(unsigned int n, double x)
This routine evaluates the generalized exponential integral, En(x).
void SetAtmosHga(const double hga)
Set the Hapke atmospheric function parameter.
double p_atmosHnorm
Atmospheric shell thickness normalized to planet radius.
double p_sbar
Illumination of the ground by the sky.
bool p_atmosEstTau
Estimate optical depth tau using shadows.
void SetAtmosInc(const double inc)
Set the incidence angle.
void SetAtmosEstTau(const string esttau)
Estimate the optical depth tau using shadows.
NumericalApproximation p_atmosAhSpline
Spline object for the atmospheric Ah Table. Properties are set in GenerateAhTable().
double AtmosTau() const
Return atmospheric Tau value.
static double G11Prime(double tau)
Perform Chandra and Van de Hulst's series approximation for the g'11 function needed in second order ...
void SetAtmosWha(const double wha)
Set the Atmospheric function parameter.
bool p_atmosAddOffset
Allow additive offset in fit.
void SetAtmosTau(const double tau)
Set the Atmospheric function parameter.
void SetAtmosBha(const double bha)
Set the Anisotropic Atmospheric function parameter.
double p_transs
Transmission of light that must be subtracted from the flat surface model to get the shadow model.
NumericalApproximation p_atmosHahgt0Spline
Spline object for the atmospheric Hahg0 Table. Properties are set in GenerateHahgTables().
static double Ei(double x)
This routine computes the exponential integral, Ei(x).
void SetAtmosIord(const string offset)
Set additive offset in fit.
void GenerateAhTable()
This method computes the values of the atmospheric Ah table and sets the properties of the atmospheri...
void SetAtmosHnorm(const double hnorm)
Set the Atmospheric function parameter.
void SetAtmosAtmSwitch(const int atmswitch)
Set the switch that controls the function that will be integrated.
virtual void SetStandardConditions(bool standard)
Used to calculate atmosphere at standard conditions.
void GenerateHahgTablesShadow()
This method is a modified version of the GenerateHahgTables method and is used solely for shadow mode...
AtmosModel(Pvl &pvl, PhotoModel &pmodel)
Create an AtmosModel object.
double p_pstd
Pure atmospheric-scattering term.
void SetAtmosPhi(const double phi)
Set the azimuth angle.
void SetAtmosNulneg(const string nulneg)
Set the Atmospheric function parameter.
double p_trans0
Transmission of surface reflected light through the atmosphere with no scatterings in the atmosphere.
void CalcAtmEffect(double pha, double inc, double ema, double *pstd, double *trans, double *trans0, double *sbar, double *transs)
Calculate the atmospheric scattering effect using photometric angle information.
NumericalApproximation p_atmosHahgtSpline
Spline object for the atmospheric Hahg Table. Properties are set in GenerateHahgTables().
double AtmosWha() const
Return atmospheric Wha value.
void GenerateHahgTables()
This method computes the values of the atmospheric Hahg and Hahg0 tables and sets the properties of t...
void SetAtmosTauref(const double tauref)
Set the Atmospheric function parameter.
bool TauOrWhaChanged() const
Checks whether tau or wha have changed.
Lunar (Lommel-Seeliger)-Lambert law photometric model Derive model albedo for Lunar (Lommel-Seeliger)...
Minnaert photometric model Derive model albedo using Minnaert equation.
@ CubicClamped
Cubic Spline interpolation with clamped boundary conditions.
void Reset()
Resets the state of the object.
double RombergsMethod(AtmosModel *am, IntegFunc sub, double a, double b)
This variation on the NumericalApproximation method integrates a specified AtmosModel function rather...
IntegFunc
This enum defines function to be integrated by Romberg's method.
@ OuterFunction
Indicates that Romberg's method will integrate the function OutrFunc2Bint()
This is free and unencumbered software released into the public domain.
QString toString(const LinearAlgebra::Vector &vector, int precision)
A global function to format LinearAlgebra::Vector as a QString with the given precision.
Namespace for the standard library.