USGS

Isis 3.0 Application Source Code Reference

Home

Exponential.cpp

Go to the documentation of this file.
00001 /**
00002  * @file
00003  * $Revision$
00004  * $Date$
00005  *
00006  *   Unless noted otherwise, the portions of Isis written by the USGS are
00007  *   public domain. See individual third-party library and package descriptions
00008  *   for intellectual property information, user agreements, and related
00009  *   information.
00010  *
00011  *   Although Isis has been used by the USGS, no warranty, expressed or
00012  *   implied, is made by the USGS as to the accuracy and functioning of such
00013  *   software and related material nor shall the fact of distribution
00014  *   constitute any such warranty, and no responsibility is assumed by the
00015  *   USGS in connection therewith.
00016  *
00017  *   For additional information, launch
00018  *   $ISISROOT/doc//documents/Disclaimers/Disclaimers.html
00019  *   in a browser or see the Privacy & Disclaimers page on the Isis website,
00020  *   http://isis.astrogeology.usgs.gov, and the USGS privacy and disclaimers on
00021  *   http://www.usgs.gov/privacy.html.
00022  */
00023 #include <memory>
00024 #include <cmath>
00025 #include <cstdlib>
00026 #include <iostream>
00027 #include <iomanip>
00028 #include <sstream>
00029 
00030 #include "Camera.h"
00031 #include "Exponential.h"
00032 #include "DbProfile.h"
00033 #include "PvlObject.h"
00034 #include "naif/SpiceUsr.h"
00035 #include "naif/SpiceZfc.h"
00036 #include "naif/SpiceZmc.h"
00037 
00038 using namespace std;
00039 
00040 namespace Isis {
00041 
00042     /**
00043      * @brief Method to get photometric property given angles
00044      *
00045      * This routine computes the photometric property at the given
00046      * cube location after ensuring a proper parameter container is
00047      * found for the specified band.
00048      *
00049      * @author Kris Becker - 2/21/2010
00050      *
00051      * @param i     Incidence angle at cube location
00052      * @param e     Emission angle at cube location
00053      * @param g     Phase angle at cube location
00054      * @param band  Band number in cube (actually is band index) for
00055      *              lookup purposes
00056      *
00057      * @return double Returns photometric correction using
00058      *         parameters
00059      */
00060     double Exponential::photometry ( double i, double e, double g, int band ) const {
00061         // Test for valid band
00062         if ((band <= 0) || (band > (int) _bandpho.size())) {
00063             std::string mess = "Provided band " + IString(band) + " out of range.";
00064             throw IException(IException::Programmer, mess, _FILEINFO_);
00065         }
00066         double ph = photometry(_bandpho[band - 1], i, e, g);
00067         return (_bandpho[band - 1].phoStd / ph);
00068     }
00069 
00070     /**
00071      * @brief Performs actual photometric correction calculations
00072      *
00073      * This routine computes photometric correction using parameters
00074      * for the Exponential-Buratti-Hill equation.
00075      *
00076      * @author Kris Becker - 2/21/2010
00077      *
00078      * @param parms Container of band-specific Exponential parameters
00079      * @param i     Incidence angle in degrees
00080      * @param e     Emission angle in degrees
00081      * @param g     Phase angle in degrees
00082      *
00083      * @return double Photometric correction parameter
00084      */
00085     double Exponential::photometry ( const Parameters &parms, double i, double e, double g ) const {
00086 
00087         //  Ensure problematic values are adjusted
00088         if (i == 0.0)
00089             i = 10.E-12;
00090         if (e == 0.0)
00091             e = 10.E-12;
00092 
00093         // Convert to radians
00094         i *= rpd_c();
00095         e *= rpd_c();
00096         g *= parms.phaUnit; //  Apply unit normalizer
00097 
00098         // Compute Lommel-Seeliger components
00099         double mu = cos(e);
00100         double mu0 = cos(i);
00101 
00102         double alpha = g;
00103 
00104         // Simple Exponential photometric polynomial equation with exponential opposition
00105         //  surge term.
00106         double rcal = 0.0;
00107         for (unsigned int i = 0; i < parms.aTerms.size(); i++) {
00108             rcal += parms.aTerms[i] * exp(parms.bTerms[i] * alpha);
00109         }
00110 
00111         return ((mu0 / (mu + mu0)) * rcal);
00112     }
00113 
00114     /**
00115      * @brief Return parameters used for all bands
00116      *
00117      * Method creates keyword vectors of band specific parameters
00118      * used in the photometric correction.
00119      *
00120      * @author Kris Becker - 2/22/2010
00121      *
00122      * @param pvl Output PVL container write keywords
00123      */
00124     void Exponential::Report ( PvlContainer &pvl ) {
00125         pvl.AddComment("I/F = mu0/(mu0+mu) * F(phase)");
00126         pvl.AddComment("where:");
00127         pvl.AddComment("  mu0 = cos(incidence)");
00128         pvl.AddComment("  mu = cos(incidence)");
00129         pvl.AddComment("  F(phase) =  A0*exp(B0*phase) + A1*exp(B1*phase) + ... + An*exp(Bn*phase)");
00130 
00131         pvl += PvlKeyword("Algorithm", "Exponential");
00132         pvl += PvlKeyword("IncRef", toString(_iRef), "degrees");
00133         pvl += PvlKeyword("EmaRef", toString(_eRef), "degrees");
00134         pvl += PvlKeyword("PhaRef", toString(_gRef), "degrees");
00135         PvlKeyword units("ExponentialUnits");
00136         PvlKeyword phostd("PhotometricStandard");
00137         PvlKeyword bbc("BandBinCenter");
00138         PvlKeyword bbct("BandBinCenterTolerance");
00139         PvlKeyword bbn("BandNumber");
00140 
00141         std::vector < PvlKeyword > aTermKeywords;
00142         std::vector < PvlKeyword > bTermKeywords;
00143         for (unsigned int i = 0; i < _bandpho[0].aTerms.size(); i++)
00144             aTermKeywords.push_back(PvlKeyword("A" + toString((int) i)));
00145         for (unsigned int i = 0; i < _bandpho[0].bTerms.size(); i++)
00146             bTermKeywords.push_back(PvlKeyword("B" + toString((int) i)));
00147 
00148         for (unsigned int i = 0; i < _bandpho.size(); i++) {
00149             Parameters &p = _bandpho[i];
00150             units.AddValue(p.units);
00151             phostd.AddValue(toString(p.phoStd));
00152             bbc.AddValue(toString(p.wavelength));
00153             bbct.AddValue(toString(p.tolerance));
00154             bbn.AddValue(toString(p.band));
00155             for (unsigned int j = 0; j < aTermKeywords.size(); j++)
00156                 aTermKeywords[j].AddValue(toString(p.aTerms[j]));
00157             for (unsigned int j = 0; j < bTermKeywords.size(); j++)
00158                 bTermKeywords[j].AddValue(toString(p.bTerms[j]));
00159         }
00160         pvl += units;
00161         pvl += phostd;
00162         pvl += bbc;
00163         pvl += bbct;
00164         pvl += bbn;
00165         for (unsigned int i = 0; i < aTermKeywords.size(); i++)
00166             pvl += aTermKeywords[i];
00167 
00168         for (unsigned int i = 0; i < bTermKeywords.size(); i++)
00169             pvl += bTermKeywords[i];
00170 
00171         return;
00172     }
00173 
00174     /**
00175      * @brief Determine Exponential parameters given a wavelength
00176      *
00177      * This method determines the set of Exponential parameters to use
00178      * for a given wavelength.  It iterates through all band
00179      * profiles as read from the PVL file and computes the
00180      * difference between the "wavelength" parameter and the
00181      * BandBinCenter keyword.  The absolute value of this value is
00182      * checked against the BandBinCenterTolerance paramter and if it
00183      * is less than or equal to it, a Parameter container is
00184      * returned.
00185      *
00186      * @author Kris Becker - 2/22/2010
00187      *
00188      * @param wavelength Wavelength used to find parameter set
00189      *
00190      * @return Exponential::Parameters Container of valid values.  If
00191      *         not found, a value of iProfile = -1 is returned.
00192      */
00193     Exponential::Parameters Exponential::findParameters ( const double wavelength ) const {
00194         for (unsigned int i = 0; i < _profiles.size(); i++) {
00195             const DbProfile &p = _profiles[i];
00196             if (p.exists("BandBinCenter")) {
00197                 double p_center = toDouble(ConfKey(p, "BandBinCenter", toString(Null)));
00198                 double tolerance = toDouble(ConfKey(p, "BandBinCenterTolerance", toString(1.0E-6)));
00199                 if (fabs(wavelength - p_center) <= fabs(tolerance)) {
00200                     Parameters pars = extract(p);
00201                     pars.iProfile = i;
00202                     pars.wavelength = wavelength;
00203                     pars.tolerance = tolerance;
00204                     return (pars);
00205                 }
00206             }
00207         }
00208 
00209         // Not found if we reach here
00210         return (Parameters());
00211     }
00212 
00213     /**
00214      * @brief Extracts necessary Exponential parameters from profile
00215      *
00216      * Given a profile read from the input PVL file, this method
00217      * extracts needed parameters (from Keywords) in the PVL profile
00218      * and creates a container of the converted values.
00219      *
00220      * @author Kris Becker - 2/22/2010
00221      *
00222      * @param p Profile to extract/convert
00223      *
00224      * @return Exponential::Parameters Container of extracted values
00225      */
00226     Exponential::Parameters Exponential::extract ( const DbProfile &p ) const {
00227         Parameters pars;
00228 
00229         for (int i = 0; i < p.size(); i++) {
00230             if (p.exists("A" + toString(i)) || p.exists("B" + toString(i))) {
00231                 pars.aTerms.push_back(toDouble(ConfKey(p, "A" + toString(i), (QString)"1.0")));
00232                 pars.bTerms.push_back(toDouble(ConfKey(p, "B" + toString(i), (QString)"0.0")));
00233             }
00234         }
00235 
00236         pars.wavelength = toDouble(ConfKey(p, "BandBinCenter", toString(Null)));
00237         pars.tolerance = toDouble(ConfKey(p, "BandBinCenterTolerance", toString(Null)));
00238         //  Determine equation units - defaults to Radians
00239         pars.units = ConfKey(p, "ExponentialUnits", toString("Radians"));
00240         pars.phaUnit = (pars.units.toLower() == "degrees") ? 1.0 : rpd_c();
00241         return (pars);
00242     }
00243 
00244     /**
00245      * @brief Initialize class from input PVL and Cube files
00246      *
00247      * This method is typically called at class instantiation time,
00248      * but is reentrant.  It reads the parameter PVL file and
00249      * extracts Photometric model and Normalization models from it.
00250      * The cube is needed to match all potential profiles for each
00251      * band.
00252      *
00253      * @author Kris Becker - 2/22/2010
00254      *
00255      * @param pvl  Input PVL parameter files
00256      * @param cube Input cube file to correct
00257      */
00258     void Exponential::init ( PvlObject &pvl, Cube &cube ) {
00259 
00260         //  Make it reentrant
00261         _profiles.clear();
00262         _bandpho.clear();
00263 
00264         //  Interate over all Photometric groups
00265         _normProf = DbProfile(pvl.FindObject("NormalizationModel").FindGroup("Algorithm", Pvl::Traverse));
00266         _iRef = toDouble(ConfKey(_normProf, "IncRef", toString(30.0)));
00267         _eRef = toDouble(ConfKey(_normProf, "EmaRef", toString(0.0)));
00268         _gRef = toDouble(ConfKey(_normProf, "PhaRef", toString(_iRef)));
00269 
00270         PvlObject &phoObj = pvl.FindObject("PhotometricModel");
00271         DbProfile phoProf = DbProfile(phoObj);
00272         PvlObject::PvlGroupIterator algo = phoObj.BeginGroup();
00273         while (algo != phoObj.EndGroup()) {
00274             if (algo->Name().toLower() == "algorithm") {
00275                 _profiles.push_back(DbProfile(phoProf, DbProfile(*algo)));
00276             }
00277             ++algo;
00278         }
00279 
00280         Pvl *label = cube.label();
00281         PvlKeyword center = label->FindGroup("BandBin", Pvl::Traverse)["Center"];
00282         QString errs("");
00283         for (int i = 0; i < cube.bandCount(); i++) {
00284             Parameters parms = findParameters(toDouble(center[i]));
00285             if (parms.IsValid()) {
00286                 parms.band = i + 1;
00287                 //_camera->SetBand(i + 1);
00288                 parms.phoStd = photometry(parms, _iRef, _eRef, _gRef);
00289                 _bandpho.push_back(parms);
00290             }
00291             else { // Appropriate photometric parameters not found
00292                 ostringstream mess;
00293                 mess << "Band " << i + 1 << " with wavelength Center = " << center[i]
00294                         << " does not have PhotometricModel Algorithm group/profile";
00295                 IException e(IException::User, mess.str(), _FILEINFO_);
00296                 errs += e.toString() + "\n";
00297             }
00298         }
00299 
00300         // Check for errors and throw them all at the same time
00301         if (!errs.isEmpty()) {
00302             errs += " --> Errors in the input PVL file \"" + pvl.FileName() + "\"";
00303             throw IException(IException::User, errs, _FILEINFO_);
00304         }
00305 
00306         return;
00307     }
00308 
00309 } // namespace Isis
00310 
00311