00001 /* 00002 ------------------------------------------------------------------- 00003 00004 Copyright (C) 2008, 2009, Andrew W. Steiner 00005 00006 This file is part of O2scl. 00007 00008 O2scl is free software; you can redistribute it and/or modify 00009 it under the terms of the GNU General Public License as published by 00010 the Free Software Foundation; either version 3 of the License, or 00011 (at your option) any later version. 00012 00013 O2scl is distributed in the hope that it will be useful, 00014 but WITHOUT ANY WARRANTY; without even the implied warranty of 00015 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00016 GNU General Public License for more details. 00017 00018 You should have received a copy of the GNU General Public License 00019 along with O2scl. If not, see <http://www.gnu.org/licenses/>. 00020 00021 ------------------------------------------------------------------- 00022 */ 00023 #ifndef O2SCL_CONVERT_UNITS_H 00024 #define O2SCL_CONVERT_UNITS_H 00025 00026 #include <cstdio> 00027 #include <cstdlib> 00028 #include <iostream> 00029 #include <map> 00030 #include <o2scl/err_hnd.h> 00031 #include <o2scl/file_format.h> 00032 #include <o2scl/misc.h> 00033 #include <o2scl/constants.h> 00034 00035 #ifndef DOXYGENP 00036 namespace o2scl { 00037 #endif 00038 00039 /** 00040 \brief Convert units 00041 00042 Allow the user to convert between two different units after 00043 specifying a conversion factor. This class will also 00044 automatically combine two conversion factors to create a new 00045 unit conversion. 00046 00047 Conversions are performed by the \ref convert() function and 00048 the conversion factors must be specified beforehand using the 00049 \ref insert_cache() function. 00050 00051 Example: 00052 \code 00053 convert_units cu; 00054 cu.insert_cache("in","cm",2.54); 00055 cout << "12 in is " << cu.convert("in","cm",12.0) << " cm. " << endl; 00056 \endcode 00057 00058 \future Ideally, a real C++ API for the GNU units command, 00059 or some interface to the Boost units library would 00060 probably be better. 00061 */ 00062 class convert_units { 00063 00064 #ifndef DOXYGEN_INTERNAL 00065 00066 protected: 00067 00068 /// The type for caching unit conversions 00069 typedef struct { 00070 /// The input unit 00071 std::string f; 00072 /// The output unit 00073 std::string t; 00074 /// The conversion factor 00075 double c; 00076 } unit_t; 00077 00078 /// The cache where unit conversions are stored 00079 std::map<std::string,unit_t,string_comp> mcache; 00080 00081 /// The iterator type 00082 typedef std::map<std::string,unit_t,string_comp>::iterator miter; 00083 00084 #endif 00085 00086 public: 00087 00088 /// Verbosity (default 0) 00089 int verbose; 00090 00091 convert_units() { 00092 verbose=0; 00093 } 00094 00095 virtual ~convert_units() {} 00096 00097 /** \brief Return the value \c val after converting using units \c 00098 from and \c to 00099 */ 00100 virtual double convert(std::string from, std::string to, double val) { 00101 00102 // Look in cache for conversion 00103 std::string both=from+","+to; 00104 miter m3=mcache.find(both); 00105 if (m3!=mcache.end()) { 00106 return val*m3->second.c; 00107 } 00108 00109 // Look in cache for reverse conversion 00110 std::string both2=to+","+from; 00111 m3=mcache.find(both2); 00112 if (m3!=mcache.end()) { 00113 return val/m3->second.c; 00114 } 00115 00116 // Look for combined conversions 00117 for(miter m=mcache.begin();m!=mcache.end();m++) { 00118 if (m->second.f==from) { 00119 std::string b=m->second.t+","+to; 00120 miter m2=mcache.find(b); 00121 if (m2!=mcache.end()) { 00122 if (verbose>0) { 00123 std::cout << "Using conversions: " << m->second.f << " , " 00124 << m->second.t << std::endl; 00125 std::cout << " (1) and: " << m2->second.f << " , " 00126 << m2->second.t << std::endl; 00127 } 00128 return val*m->second.c*m2->second.c; 00129 } 00130 std::string b2=to+","+m->second.t; 00131 miter m4=mcache.find(b2); 00132 if (m4!=mcache.end()) { 00133 if (verbose>0) { 00134 std::cout << "Using conversions: " << m->second.f << " , " 00135 << m->second.t << std::endl; 00136 std::cout << " (2) and: " << m4->second.f << " , " 00137 << m4->second.t << std::endl; 00138 } 00139 return val*m->second.c/m4->second.c; 00140 } 00141 } else if (m->second.t==from) { 00142 std::string b=m->second.f+","+to; 00143 miter m2=mcache.find(b); 00144 if (m2!=mcache.end()) { 00145 if (verbose>0) { 00146 std::cout << "Using conversions: " << m->second.f << " , " 00147 << m->second.t << std::endl; 00148 std::cout << " (3) and: " << m2->second.f << " , " 00149 << m2->second.t << std::endl; 00150 } 00151 return val/m->second.c*m2->second.c; 00152 } 00153 } else if (m->second.f==to) { 00154 std::string b=m->second.t+","+from; 00155 miter m2=mcache.find(b); 00156 if (m2!=mcache.end()) { 00157 if (verbose>0) { 00158 std::cout << "Using conversions: " << m->second.f << " , " 00159 << m->second.t << std::endl; 00160 std::cout << " (4) and: " << m2->second.f << " , " 00161 << m2->second.t << std::endl; 00162 } 00163 return val/m->second.c/m2->second.c; 00164 } 00165 std::string b2=from+","+m->second.t; 00166 miter m4=mcache.find(b2); 00167 if (m4!=mcache.end()) { 00168 if (verbose>0) { 00169 std::cout << "Using conversions: " << m->second.f << " , " 00170 << m->second.t << std::endl; 00171 std::cout << " (5) and: " << m4->second.f << " , " 00172 << m4->second.t << std::endl; 00173 } 00174 return val/m->second.c*m4->second.c; 00175 } 00176 } else if (m->second.t==to) { 00177 std::string b=m->second.f+","+from; 00178 miter m2=mcache.find(b); 00179 if (m2!=mcache.end()) { 00180 if (verbose>0) { 00181 std::cout << "Using conversions: " << m->second.f << " , " 00182 << m->second.t << std::endl; 00183 std::cout << " (6) and: " << m2->second.f << " , " 00184 << m2->second.t << std::endl; 00185 } 00186 return val*m->second.c/m2->second.c; 00187 } 00188 } 00189 } 00190 00191 O2SCL_ERR("Conversion not found in convert_units::convert().", 00192 gsl_efailed); 00193 00194 return 0.0; 00195 } 00196 00197 /// Manually insert a unit conversion into the cache 00198 int insert_cache(std::string from, std::string to, double conv) { 00199 unit_t ut; 00200 ut.f=from; 00201 ut.t=to; 00202 ut.c=conv; 00203 std::string both=from+","+to; 00204 mcache.insert(make_pair(both,ut)); 00205 return 0; 00206 } 00207 00208 /// Print the present unit cache 00209 int print_cache() { 00210 miter m; 00211 std::cout << "Unit cache: " << std::endl; 00212 for (m=mcache.begin();m!=mcache.end();m++) { 00213 std::cout.setf(std::ios::left); 00214 std::cout.width(20); 00215 std::cout << m->second.f << " "; 00216 std::cout.width(20); 00217 std::cout << m->second.t << " "; 00218 std::cout.unsetf(std::ios::left); 00219 std::cout.precision(10); 00220 std::cout << m->second.c << std::endl; 00221 } 00222 return 0; 00223 } 00224 00225 /// Add conversion factors for energy equivalents 00226 int energy_conv() { 00227 00228 // Entries derived from http://physics.nist.gov/cuu/Constants. 00229 // The NIST website uses 'h' to convert instead of hbar, 00230 // so we have to add a lot of factors of 2 pi 00231 00232 insert_cache("J","m^-1",5.03411747e24*2.0*o2scl_const::pi); 00233 insert_cache("J","km^-1",5.03411747e27*2.0*o2scl_const::pi); 00234 insert_cache("J","cm^-1",5.03411747e22*2.0*o2scl_const::pi); 00235 insert_cache("J","fm^-1",5.03411747e9*2.0*o2scl_const::pi); 00236 insert_cache("J","s^-1",1.509190450e33*2.0*o2scl_const::pi); 00237 insert_cache("J","K",1.0e7/gsl_cgs::boltzmann); 00238 insert_cache("J","eV",6.24150965e18); 00239 insert_cache("J","MeV",6.24150965e12); 00240 insert_cache("J","u",6.70053641e9); 00241 insert_cache("J","erg",1.0e7); 00242 insert_cache("J","kg",1.0/gsl_mks::speed_of_light/ 00243 gsl_mks::speed_of_light); 00244 insert_cache("J","g",1.0e3/gsl_mks::speed_of_light/ 00245 gsl_mks::speed_of_light); 00246 00247 return 0; 00248 } 00249 00250 }; 00251 00252 #ifndef DOXYGENP 00253 } 00254 #endif 00255 00256 #endif
Documentation generated with Doxygen and provided under the GNU Free Documentation License. See License Information for details.
Project hosting provided by
,
O2scl Sourceforge Project Page