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;
80 p_atmosNulneg =
false;
86 p_atmosTausave = p_atmosTau;
95 p_atmosWhasave = p_atmosWha;
100 p_atmosHgasave = p_atmosHga;
105 p_atmosBhasave = p_atmosBha;
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 *
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;
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);
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.",
476 double *pstd,
double *trans,
double *trans0,
double *sbar,
487 AtmosModelAlgorithm(pha, inc, ema);
499 p_standardConditions = standard;
500 if(p_standardConditions) {
501 p_atmosTausave = p_atmosTau;
502 p_atmosTau = p_atmosTauref;
505 p_atmosTau = p_atmosTausave;
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);
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;
581 fun_temp = qromb.RombergsMethod(
this, sub, 0, 180);
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;
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;
659 fun_temp = qromb.RombergsMethod(
this, sub, 0, 180);
661 p_atmosHahgtTable[inccnt] = fun_temp *
AtmosWha() / 360.0;
662 p_atmosAtmSwitch = 2;
664 fun_temp = qromb.RombergsMethod(
this, sub, 0, 180);
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;
681 fun_temp = qromb.RombergsMethod(
this, sub, 0, 180);
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;
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) {
751 fun_temp = qromb.RombergsMethod(
this, sub, 0, 180);
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;
780 if(atmswitch < 0 || atmswitch > 3) {
781 string msg =
"Invalid value of atmospheric atmswitch [" +
IString(atmswitch) +
"]";
785 p_atmosAtmSwitch = atmswitch;
800 if(bha < -1.0 || bha > 1.0) {
801 string msg =
"Invalid value of Anisotropic atmospheric bha [" +
821 if(hga <= -1.0 || hga >= 1.0) {
822 string msg =
"Invalid value of Hapke atmospheric hga [" +
IString(hga) +
"]";
840 if(inc < 0.0 || inc > 90.0) {
841 string msg =
"Invalid value of atmospheric inc [" +
IString(inc) +
"]";
846 p_atmosMunot = cos(inc *
PI / 180.0);
847 p_atmosSini = sin(inc *
PI / 180.0);
863 temp = temp.UpCase();
865 if(temp !=
"NO" && temp !=
"YES") {
866 string msg =
"Invalid value of Atmospheric nulneg [" + temp +
"]";
885 if(phi < 0.0 || phi > 360.0) {
886 string msg =
"Invalid value of atmospheric phi [" +
IString(phi) +
"]";
891 p_atmosCosphi = cos(phi *
PI / 180.0);
905 string msg =
"Invalid value of Atmospheric tau [" +
IString(tau) +
"]";
924 string msg =
"Invalid value of Atmospheric tauref [" +
IString(tauref) +
"]";
928 p_atmosTauref = tauref;
942 if(wha <= 0.0 || wha > 1.0) {
943 string msg =
"Invalid value of Atmospheric wha [" +
IString(wha) +
"]";
970 QString msg =
"Invalid value of Atmospheric hnorm [" +
toString(hnorm) +
"]";
985 temp = temp.UpCase();
987 if(temp !=
"NO" && temp !=
"YES") {
988 string msg =
"Invalid value of Atmospheric additive offset[" + temp +
"]";
1004 temp = temp.UpCase();
1006 if(temp !=
"NO" && temp !=
"YES") {
1007 string msg =
"Invalid value of Atmospheric optical depth estimation[" + temp +
"]";
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.
@ Unknown
A type of error that cannot be classified as any of the other error types.
@ User
A type of error that could only have occurred due to a mistake on the user's part (e....
@ Programmer
This error is for when a programmer made an API call that was illegal.
Adds specific functionality to C++ strings.
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 SetInterpType(NumericalApproximation::InterpType itype)
Sets interpolation type.
void Reset()
Resets the state of the object.
void SetCubicClampedEndptDeriv(const double yp1, const double ypn)
Sets the values for the first derivatives of the endpoints of the data set.
void AddData(const double x, const double y)
Add a datapoint to the set.
This class extends Isis::NumericalApproximation.
IntegFunc
This enum defines function to be integrated by Romberg's method.
@ OuterFunction
Indicates that Romberg's method will integrate the function OutrFunc2Bint()
QString AlgorithmName() const
Return algorithm name found in Pvl file from constructor.
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
Contains multiple PvlContainers.
Container for cube-like labels.
@ Traverse
Search child objects.
This is free and unencumbered software released into the public domain.
QString toString(bool boolToConvert)
Global function to convert a boolean to a string.
const double PI
The mathematical constant PI.
Namespace for the standard library.