casa  $Rev:20696$
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines
UnitVal.h
Go to the documentation of this file.
00001 //# UnitVal.h: defines the class describing a unit as a value and a dimension
00002 //# Copyright (C) 1994-1999,2000,2001,2004
00003 //# Associated Universities, Inc. Washington DC, USA.
00004 //#
00005 //# This library is free software; you can redistribute it and/or modify it
00006 //# under the terms of the GNU Library General Public License as published by
00007 //# the Free Software Foundation; either version 2 of the License, or (at your
00008 //# option) any later version.
00009 //#
00010 //# This library is distributed in the hope that it will be useful, but WITHOUT
00011 //# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
00012 //# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
00013 //# License for more details.
00014 //#
00015 //# You should have received a copy of the GNU Library General Public License
00016 //# along with this library; if not, write to the Free Software Foundation,
00017 //# Inc., 675 Massachusetts Ave, Cambridge, MA 02139, USA.
00018 //#
00019 //# Correspondence concerning AIPS++ should be addressed as follows:
00020 //#        Internet email: aips2-request@nrao.edu.
00021 //#        Postal address: AIPS++ Project Office
00022 //#                        National Radio Astronomy Observatory
00023 //#                        520 Edgemont Road
00024 //#                        Charlottesville, VA 22903-2475 USA
00025 //#
00026 //# $Id: UnitVal.h 20551 2009-03-25 00:11:33Z Malte.Marquarding $
00027 
00028 #ifndef CASA_UNITVAL_H
00029 #define CASA_UNITVAL_H
00030 
00031 
00032 //# Includes
00033 #include <casa/aips.h>
00034 #include <casa/Quanta/UnitDim.h>
00035 #include <casa/iosfwd.h>
00036 
00037 namespace casa { //# NAMESPACE CASA - BEGIN
00038 
00039 //# Forward Declarations
00040 class String;
00041 class MUString;
00042 class UnitMap;
00043 
00044 // 
00045 // <summary>
00046 // describes any valid unit as a factor and a dimenion of SI units
00047 // </summary>
00048 
00049 // <use visibility=export>
00050 
00051 // <reviewed reviewer="UNKNOWN" date="before2004/08/25" tests="tUnit">
00052 //
00053 // <prerequisite>
00054 // You should have at least a preliminary understanding of these classes:
00055 //   <li> <linkto class=Unit>Unit</linkto>
00056 // </prerequisite>
00057 //
00058 // <etymology>
00059 // The class name derives from Units and gives a Value for a unit string
00060 // </etymology>
00061 //
00062 // <synopsis> 
00063 // Physical units are strings consisting of one or more names of known
00064 // basic units, separated by '.' or ' ' (for multiplication) or '/' (for
00065 // division). Each name can optionally be preceded by a standard decimal 
00066 // prefix, and/or followed by an (optionally signed) exponent.
00067 // Example:
00068 //      km/s/(Mpc.s)2  is identical to km.s-1.Mpc-2.s-2
00069 //
00070 // See the <linkto class="Unit">Unit</linkto> class for more details.
00071 //
00072 // The UnitVal class maps a Unit string to a factor and a dimension of SI
00073 // defining units. E.g 'km/s' will be 1000 m.s-1 .
00074 // This class is only of interest if the manipulation of units is of
00075 // direct interest. Normally units will be used as Quantities and Quantums
00076 // (see the <linkto class=Quantum>Quantum</linkto> class) only,
00077 // i.e. as a physical quantity having a value and unit.
00078 // The class can also be used to check the validity of a unit string.
00079 //
00080 //  <h3> Constructing UnitVal values </h3>
00081 //
00082 // UnitVal has the following constructors:
00083 // <ul>
00084 //   <li> UnitVal()             creates an (non-dimensioned) value 1.
00085 //   <li> UnitVal(Double f)     creates an (non-dimensioned) value f.
00086 //   <li> UnitVal(Double f, String s) creates value f with unit s
00087 //   <li> UnitVal(Double f, Int i) (private) creates value f with unit
00088 //                              at position i in dimension vector
00089 // </ul>
00090 // 
00091 //
00092 //  <h3> Manipulating unit values </h3>
00093 //
00094 // The UnitVal can be manipulated by the following operators and functions:
00095 // <ul>
00096 //   <li> *, /  generates combined UnitVal (e.g. 1 yd * 1 m = 0.9 m2)
00097 //   <li> pow(Int)      UnitVal(2,"km")->pow(2) = 4000000 m2
00098 //   <li> root(Int)     UnitVal(4000000,"m2")->root(2) = 2 km
00099 //   <li> ==, !=        compares dimensions only: 1 yd == 5 ly: True
00100 //   <li> getFac()      will return the factor (Double)
00101 //   <li> getDim()      will return the dimensions (as UnitDim)
00102 //   <li> <<            will output formatted unit (factor and dimension)
00103 // </ul>
00104 // To aid in checking the dimensionality of units, the following constants
00105 // are available:
00106 // <ul>
00107 //   <li> UnitVal::NODIM
00108 //   <li> UnitVal::UNDIM
00109 //   <li> UnitVal::LENGTH
00110 //   <li> UnitVal::MASS
00111 //   <li> UnitVal::ANGLE
00112 //   <li> UnitVal::SOLIDANGLE
00113 //   <li> UnitVal::MOLAR
00114 //   <li> UnitVal::CURRENT
00115 //   <li> UnitVal::TIME
00116 //   <li> UnitVal::TEMPERATURE
00117 //   <li> UnitVal::INTENSITY
00118 // </ul>
00119 // <note role=tip>
00120 // Any other dimension can be checked by a combination. To check e.g. if
00121 // a unit is an acceleration, use: UnitVal::LENGTH/UnitVal::TIME/UnitVal::TIME
00122 // </note>
00123 //
00124 //  <h3> Checking for valid unit strings </h3>
00125 //
00126 // The validity of a unit string can be checked by:
00127 // <srcblock>
00128 // // Check if the given String is a valid unit representation. The String
00129 // // will be cached in the unit maps for later reference if True
00130 // if ( UnitVal::check( "km/s/Mpc") ) {...}
00131 // </srcblock>
00132 //
00133 // </synopsis> 
00134 //
00135 // <example>
00136 // An observation contains values in Janskys and in Westerbork Units. The
00137 // data can be combined by the following code:
00138 // <srcblock>
00139 // // The Fits tape gave JY, we check if defined, else we define them
00140 //   if ( !UnitVal::check( "JY")) {
00141 //      UnitMap::putUser("JY", UnitVal(1.,"Jy"), "FITS way to write Jy");
00142 //   }
00143 // // The Fits tape gave WU (which are defined):
00144 // // We check if JY and WU are of the same dimension:
00145 //   if (UnitVal(1.,"JY") != UnitVal(1.,"WU")) {
00146 //      cerr << "Wrong dimension for either JY ( " << 
00147 //              UnitVal(1.,"JY")->getDim() <<
00148 //              ") or WU ( " <<
00149 //              UnitVal(1.,"WU")->getDim() << ")" << endl;
00150 //   }
00151 // // And output the relation between WU and JY, and the WU value:
00152 //   cout << "1 WU = " << ( UnitVal(1.,"WU")/UnitVal(1.,"Jy") )->getVal() <<
00153 //           " JY with 1 WU = " << UnitVal(1.,"WU") << endl;
00154 // </srcblock>
00155 // </example>
00156 
00157 // <motivation>
00158 // To separate the actual manipulation of unit values from the related
00159 // quantity
00160 // </motivation>
00161 //
00162 // <todo asof="941110">
00163 //   <li> Some inlining (did not work first go)
00164 // </todo>
00165 
00166 class UnitVal {
00167   //# Friends
00168   // Multiply
00169   friend UnitVal operator*(const UnitVal &in, const UnitVal &other);
00170   // Divide
00171   friend UnitVal operator/(const UnitVal &in, const UnitVal &other);
00172   // Output a unit as a value and a string of SI defining units
00173   friend ostream& operator<<(ostream &os, const UnitVal &ku);
00174   // ensure that statics are initialized
00175   friend class UnitVal_static_initializer;
00176 
00177  public:
00178   //# Constructors
00179   // Construct an non-dimensioned value of 1
00180   UnitVal();
00181   // Copy constructor
00182   UnitVal(const UnitVal &other);
00183   
00184   // Construct an non-dimensioned value
00185   UnitVal(Double factor) { init(factor); }
00186   
00187   // Construct a fully dimensioned value
00188   // <thrown>
00189   //   <li> AipsError
00190   // </thrown>
00191   UnitVal(Double factor, const String &s);
00192   
00193   // Construct a value with a single unit at position specified
00194   UnitVal(Double factor, Int pos) { init(factor, pos); }
00195   
00196   // Destructor
00197   ~UnitVal();
00198   
00199   //# Operators
00200   // Assignment (copy semantics)
00201   UnitVal &operator=(const UnitVal &other);
00202   
00203   // Manipulate units
00204   // <group name="manipulate">
00205   // Multiply different units
00206   UnitVal &operator*=(const UnitVal &other);
00207   
00208   // Divide different units
00209   UnitVal &operator/=(const UnitVal &other);
00210   
00211   // Compare the dimensionality of different units
00212   Bool operator==(const UnitVal &other) const;
00213   Bool operator!=(const UnitVal &other) const;
00214   // </group>
00215   
00216   //# General member functions
00217   
00218   // Raise a unit to an integer power
00219   UnitVal pow(Int p);
00220 
00221   // Take integer root
00222   // <thrown>
00223   // <li> AipsError if power equals zero
00224   // <li> AipsError if unit dimensions not multiple of power
00225   // </thrown>
00226   // <group>
00227   UnitVal root(Int p) const;
00228   UnitVal sqrt() const;
00229   // </group>
00230   
00231   // Get the data parts of the unit value definition
00232   // <group name="get data">
00233   // Get the dimensions in the defining SI units
00234   const UnitDim &getDim() const;
00235   
00236   // Get the factor of the unit (as compared to pure SI units)
00237   Double getFac() const;
00238   // </group>
00239   
00240   //# Helper functions
00241   // Convert a unit string to a proper unit value and cache the result. The
00242   // function will return False if invalid string specified
00243   static Bool check(const String &s);
00244   
00245   // Convert a unit string to a proper unit value, cache the result and compare
00246   // the dimension with the specified unit value. False if any of the steps fails
00247   static Bool check(const String &s, UnitVal &loc);
00248   
00249   
00250   //# Data members
00251   // Some constants to check type of units
00252   // <group name="unit kinds">
00253   static UnitVal NODIM;
00254   static UnitVal UNDIM;
00255   static UnitVal LENGTH;
00256   static UnitVal MASS;
00257   static UnitVal TIME;
00258   static UnitVal CURRENT;
00259   static UnitVal TEMPERATURE;
00260   static UnitVal INTENSITY;
00261   static UnitVal MOLAR;
00262   static UnitVal ANGLE;
00263   static UnitVal SOLIDANGLE;
00264   // </group>
00265 
00266  protected:
00267   // alternate initialization
00268   void init(Double factor);
00269   void init(Double factor, Int pos);
00270 
00271  private:
00272   //# Data members
00273   // The factor necessary to express the specified unit in the defining SI units
00274   Double kindFactor;
00275   
00276   // The dimensions of the unit in the defining SI units
00277   UnitDim kindDim;
00278   
00279   // Convert (and check) a unit string to an SI value representation
00280   // <group>
00281   static Bool create(const String &s, UnitVal &res);
00282   static Bool create(MUString &str, UnitVal &res);
00283   // </group>
00284   
00285   // Determine sign of unit power (i.e. if '.' or '/')
00286   static Int psign(MUString &str);
00287   
00288   // Determine exponent of unit symbol
00289   static Int power(MUString &str);
00290   
00291   // Determine symbol name in unit string
00292   static Bool field(MUString &str, UnitVal &res);
00293   
00294 };
00295 
00296 //# Inline Implementations
00297 
00298 //# Global functions
00299 // <summary> Global output function </summary>
00300 // <group name=output>
00301 // Output
00302 ostream& operator<<(ostream &os, const UnitVal &ku);
00303 // </group>
00304 
00305 // <summary> Static initialisation of UnitVal constants </summary>
00306 static class UnitVal_static_initializer {
00307   public:
00308     UnitVal_static_initializer( ) {
00309       if ( ! initialized ) {
00310         UnitVal::NODIM.init(       1.);
00311         UnitVal::UNDIM.init(       1., UnitDim::Dnon);
00312         UnitVal::LENGTH.init(      1., UnitDim::Dm);
00313         UnitVal::MASS.init(        1., UnitDim::Dkg);
00314         UnitVal::TIME.init(        1., UnitDim::Ds);
00315         UnitVal::CURRENT.init(     1., UnitDim::DA);
00316         UnitVal::TEMPERATURE.init( 1., UnitDim::DK);
00317         UnitVal::INTENSITY.init(   1., UnitDim::Dcd);
00318         UnitVal::MOLAR.init(       1., UnitDim::Dmol);
00319         UnitVal::ANGLE.init(       1., UnitDim::Drad);
00320         UnitVal::SOLIDANGLE.init(  1., UnitDim::Dsr);
00321         initialized = 1;
00322       }
00323     }
00324  private:
00325     static int initialized;
00326 } unitval_static_initializer;
00327 
00328 
00329 } //# NAMESPACE CASA - END
00330 
00331 #endif
00332