|
Isis 3.0 Application Source Code Reference |
Home |
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