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;
549 NumericalAtmosApprox qromb;
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;
648 NumericalAtmosApprox qromb;
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;
737 NumericalAtmosApprox qromb;
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;
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);
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) +
"]";
987 if(temp !=
"NO" && temp !=
"YES") {
988 string msg =
"Invalid value of Atmospheric additive offset[" + temp +
"]";
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.
IString UpCase()
Converst any lower case characters in the object IString with uppercase characters.
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()
bool hasKeyword(const QString &name) const
Check to see if a keyword exists.
Contains multiple PvlContainers.
Container for cube-like labels.
PvlObjectIterator findObject(const QString &name, PvlObjectIterator beg, PvlObjectIterator end)
Find the index of object with a specified name, between two indexes.
@ 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.