Back to index

salome-med  6.5.0
InterpKernelUnit.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D
00002 //
00003 // This library is free software; you can redistribute it and/or
00004 // modify it under the terms of the GNU Lesser General Public
00005 // License as published by the Free Software Foundation; either
00006 // version 2.1 of the License.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // Lesser General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU Lesser General Public
00014 // License along with this library; if not, write to the Free Software
00015 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00016 //
00017 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00018 //
00019 
00020 #include "InterpKernelUnit.hxx"
00021 #include "InterpKernelExprParser.hxx"
00022 
00023 #include <cmath>
00024 #include <sstream>
00025 #include <iomanip>
00026 #include <limits>
00027 
00028 using namespace INTERP_KERNEL;
00029 
00030 UnitDataBase UnitDataBase::_uniqueMapForExpr;
00031 
00032 static const char InterpKernelMuAscii[2]={-0x4B,0x0};
00033 
00034 static const char InterpKernelMuUnicode[3]={-0x3E,-0x4B,0x0};
00035 
00036 const char *UnitDataBase::PREF_POW10[NB_OF_PREF_POW10]={"y","z","a","f","p","n",InterpKernelMuAscii,InterpKernelMuUnicode,"u","m","c","d",
00037                                                         "da","h","k","M","G","T","P","E","Z","Y"};
00038 
00039 const double UnitDataBase::POW10[NB_OF_PREF_POW10]={1e-24,1e-21,1e-18,1e-15,1e-12,1e-9,1e-6,1e-6,1e-6,1e-3,1e-2,1e-1,
00040                                                   1e1,1e2,1e3,1e6,1e9,1e12,1e15,1e18,1e21,1e24};
00041 
00042 static const char InterpKernelDegreeCAscii[3]={-0x50,0x43,0x0};
00043 
00044 static const char InterpKernelDegreeCUnicode[4]={-0x3E,-0x50,0x43,0x0};
00045 
00046 static const char InterpKernelDegreeCUnicodeWin[3]={-0x08,0x43,0x0};
00047 
00048 const char *UnitDataBase::UNITS_RECOGN[NB_OF_UNITS_RECOGN]={"g","m","s","A","K",
00049                                                             "W","J","Hz","V","h","min","t","N","dyn",
00050                                                             "eV","Pa","atm","bar",InterpKernelDegreeCAscii,"C","ohm","F","S",
00051                                                             "T","H","P","St",InterpKernelDegreeCUnicode,InterpKernelDegreeCUnicodeWin};
00052 
00053 const short UnitDataBase::PROJ_IN_BASE[NB_OF_UNITS_RECOGN][SIZE_OF_UNIT_BASE]=
00054   {
00055     {1,0,0,0,0},//g
00056     {0,1,0,0,0},//m
00057     {0,0,1,0,0},//s
00058     {0,0,0,1,0},//A
00059     {0,0,0,0,1},//K
00060     {1,2,-3,0,0},//W
00061     {1,2,-2,0,0},//J
00062     {0,0,-1,0,0},//Hz
00063     {1,2,-3,-1,0},//V
00064     {0,0,1,0,0},//h
00065     {0,0,1,0,0},//min
00066     {1,0,0,0,0},//t
00067     {1,1,-2,0,0},//N
00068     {1,1,-2,0,0},//dyn
00069     {1,2,-2,0,0},//eV
00070     {1,-1,-2,0,0},//Pa
00071     {1,-1,-2,0,0},//atm
00072     {1,-1,-2,0,0},//bar
00073     {0,0,0,0,1},//degree C
00074     {0,0,1,1,0},//C
00075     {1,2,-3,-2,0},//ohm
00076     {-1,-2,4,2,0},//F
00077     {-1,-2,3,2,0},//S
00078     {1,0,-2,-1,0},//T
00079     {1,2,-2,-2,0},//H
00080     {1,-1,-1,0,0},//P
00081     {0,2,-1,0,0},//St
00082     {0,0,0,0,1},//degree C
00083     {0,0,0,0,1}//degree C
00084   };
00085 
00086 const double UnitDataBase::MUL_COEFF[NB_OF_UNITS_RECOGN]=
00087   { 1.,1.,1.,1.,1.,
00088     1000.,1000.,1.,1000.,3600.,3600.,1e6,1000.,1e-2,
00089     1.60217733e-16,1000.,1.01325e8,1e8,1.,1.,1000.,1e-3,
00090     1000.,1000.,100.,1.,1.,1.,1.};
00091 
00092 const double UnitDataBase::ADD_COEFF[NB_OF_UNITS_RECOGN]=
00093   { 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 0., 273.15, 0., 0., 0., 0., 0., 0., 0., 0., 273.15 ,273.15};
00094 
00095 UnitDataBase::UnitDataBase()
00096 {
00097   for(int i=0;i<NB_OF_PREF_POW10;i++)
00098     _prefix_pow_10[PREF_POW10[i]]=POW10[i];
00099   for(int i=0;i<NB_OF_UNITS_RECOGN;i++)
00100     {
00101       _units_semantic[UNITS_RECOGN[i]]=PROJ_IN_BASE[i];
00102       _units_mul[UNITS_RECOGN[i]]=MUL_COEFF[i];
00103       _units_add[UNITS_RECOGN[i]]=ADD_COEFF[i];
00104     }
00105 }
00106 
00107 const short *UnitDataBase::getInfoForUnit(const std::string& unit,
00108                                           double& addFact, double& mFact) const throw(INTERP_KERNEL::Exception)
00109 {
00110   std::size_t lgth=unit.length();
00111   std::string work,work2;
00112   const short *ret=0;
00113   for(std::size_t i=0;i<lgth && !ret;i++)
00114     {
00115       work=unit.substr(i);
00116       std::map<std::string,const short *>::const_iterator iter=_units_semantic.find(work);
00117       if(iter!=_units_semantic.end())
00118         {
00119           ret=(*iter).second;
00120           std::map<std::string,double>::const_iterator iter2=_units_add.find(work);
00121           addFact=(*iter2).second;
00122           std::map<std::string,double>::const_iterator iter3=_units_mul.find(work);
00123           mFact=(*iter3).second;
00124           work2=unit.substr(0,i);
00125         }
00126     }
00127   if(!ret)
00128     {
00129       std::ostringstream os;
00130       os << "Unit : " << unit << " not recognized !";
00131       throw INTERP_KERNEL::Exception(os.str().c_str());
00132     }
00133   if(!work2.empty())
00134     {
00135       std::map<std::string,double>::const_iterator iter4=_prefix_pow_10.find(work2);
00136       if(iter4==_prefix_pow_10.end())
00137         {
00138           std::ostringstream os;
00139           os << "Unit : " << unit << " not fully recognized : \"" << work << "\" detected as core unit and \"";
00140           os << work2 << "\" not recognized prefix !";
00141           throw INTERP_KERNEL::Exception(os.str().c_str());
00142         }
00143       addFact=0.;
00144       mFact*=(*iter4).second;
00145     }
00146   return ret;
00147 }
00148 
00149 DecompositionInUnitBase::DecompositionInUnitBase():_add_to_base(0.),_mult_fact_to_base(1.)
00150 {
00151   _value[0]=0;
00152   _value[1]=0;
00153   _value[2]=0;
00154   _value[3]=0;
00155   _value[4]=0;
00156 }
00157 
00158 void DecompositionInUnitBase::setInfo(const short *vals, double addFact, double mFact)
00159 {
00160   _add_to_base=addFact;
00161   _mult_fact_to_base=mFact;
00162   _value[0]=vals[0];
00163   _value[1]=vals[1];
00164   _value[2]=vals[2];
00165   _value[3]=vals[3];
00166   _value[4]=vals[4];
00167 }
00168 
00169 bool DecompositionInUnitBase::operator==(const DecompositionInUnitBase& other) const
00170 {
00171   return _value[0]==other._value[0] && _value[1]==other._value[1] && _value[2]==other._value[2] && _value[3]==other._value[3] && _value[4]==other._value[4];
00172 }
00173 
00174 void DecompositionInUnitBase::getTranslationParams(const DecompositionInUnitBase& other, double& mul, double& add) const
00175 {
00176   if((*this)==other)
00177     {
00178       mul=_mult_fact_to_base/other._mult_fact_to_base;
00179       add=_add_to_base/other._mult_fact_to_base-other._add_to_base;
00180     }
00181   else
00182     {
00183       mul=std::numeric_limits<double>::max();
00184       add=std::numeric_limits<double>::max();
00185     }
00186 }
00187 
00188 bool DecompositionInUnitBase::isEqual(short mass, short lgth, short time, short intensity, short temp, double add, double mult)
00189 {
00190   bool ret1=mass==_value[0];
00191   bool ret2=lgth==_value[1];
00192   bool ret3=time==_value[2];
00193   bool ret4=intensity==_value[3];
00194   bool ret5=temp==_value[4];
00195   bool ret6=areDoubleEquals(add,_add_to_base);
00196   bool ret7=areDoubleEquals(mult,_mult_fact_to_base);
00197   return ret1 && ret2 && ret3 && ret4 && ret5 && ret6 && ret7;
00198 }
00199 
00200 void DecompositionInUnitBase::negate()
00201 {
00202   _mult_fact_to_base=-_mult_fact_to_base;
00203 }
00204 
00205 bool DecompositionInUnitBase::isAdimensional() const
00206 {
00207   return _value[0]==0 && _value[1]==0 && _value[2]==0 && _value[3]==0 && _value[4]==0;
00208 }
00209 
00210 bool DecompositionInUnitBase::isUnitary() const
00211 {
00212   return areDoubleEquals(_add_to_base,0.) && areDoubleEquals(_mult_fact_to_base,1.);
00213 }
00214 
00215 void DecompositionInUnitBase::tryToConvertInUnit(double val) throw(INTERP_KERNEL::Exception)
00216 {
00217   int valI=(int)val;
00218   if((val-(double)valI)!=0.)
00219     {
00220       std::ostringstream os;
00221       os << "Double value " << val << " can't be considered as integer. Not admitable for units !";
00222       throw INTERP_KERNEL::Exception(os.str().c_str());
00223     }
00224   _value[0]=0;
00225   _value[1]=0;
00226   _value[2]=0;
00227   _value[3]=0;
00228   _value[4]=0;
00229   _add_to_base=0;
00230   _mult_fact_to_base=valI;
00231 }
00232 
00233 DecompositionInUnitBase &DecompositionInUnitBase::operator*(const DecompositionInUnitBase& other)
00234 {
00235   _value[0]+=other._value[0]; _value[1]+=other._value[1]; _value[2]+=other._value[2]; _value[3]+=other._value[3]; _value[4]+=other._value[4];
00236   _mult_fact_to_base*=other._mult_fact_to_base;
00237   _add_to_base=0.;
00238   return *this;
00239 }
00240 
00241 DecompositionInUnitBase &DecompositionInUnitBase::operator/(const DecompositionInUnitBase& other)
00242 {
00243   _value[0]-=other._value[0]; _value[1]-=other._value[1]; _value[2]-=other._value[2]; _value[3]-=other._value[3]; _value[4]-=other._value[4];
00244   _mult_fact_to_base/=other._mult_fact_to_base;
00245  _add_to_base=0.;
00246  return *this;
00247 }
00248 
00249 DecompositionInUnitBase &DecompositionInUnitBase::operator^(const DecompositionInUnitBase& other) throw(INTERP_KERNEL::Exception)
00250 {
00251   if(!other.isAdimensional())
00252     throw INTERP_KERNEL::Exception("Trying to execute operator ^ with a second member not adimensionnal");
00253   int exp=couldItBeConsideredAsInt(other._mult_fact_to_base);
00254   _value[0]*=exp; _value[1]*=exp; _value[2]*=exp; _value[3]*=exp; _value[4]*=exp;
00255   _mult_fact_to_base=powInt(_mult_fact_to_base,exp);
00256   _add_to_base=0.;
00257   return *this;
00258 }
00259 
00260 void DecompositionInUnitBase::dealWithAddFactor(const DecompositionInUnitBase& other)
00261 {
00262   if(!areDoubleEquals(_add_to_base,0.))
00263     if(other.isAdimensional())
00264       if(areDoubleEquals(other._mult_fact_to_base,1.))
00265         return ;
00266   if(!other.areDoubleEquals(_add_to_base,0.))
00267     if(isAdimensional())
00268       if(areDoubleEquals(_mult_fact_to_base,1.))
00269         return ;
00270   _add_to_base=0.;
00271 }
00272 
00273 double DecompositionInUnitBase::powInt(double val, int exp)
00274 {
00275   double work=1.;
00276   if(exp==0)
00277     return 1.;
00278   if(exp>0)
00279     for(int i=0;i<exp;i++)
00280       work*=val;
00281   else
00282     {
00283       int tmp=-exp;
00284       for(int i=0;i<tmp;i++)
00285         work*=1/val;
00286     }
00287   return work;
00288 }
00289 
00290 bool DecompositionInUnitBase::areDoubleEquals(double a, double b)
00291 {
00292   if(a==0. || b==0.)
00293     return a==b;
00294   double ref=std::max(a,b);
00295   return fabs((a-b)/ref)<1e-7;
00296 }
00297 
00298 int DecompositionInUnitBase::couldItBeConsideredAsInt(double val) throw(INTERP_KERNEL::Exception)
00299 {
00300   int ret=(int)val;
00301   double valT=(double) ret;
00302   if(valT==val)
00303     return ret;
00304   else
00305     {
00306       std::ostringstream stream; stream << "Invalid double number " << std::setprecision(16) << val << " can's be considered for ^ operation on unit.";
00307       throw INTERP_KERNEL::Exception(stream.str().c_str());
00308     }
00309 }
00310 
00311 Unit::Unit(const char *reprC, bool tryToInterp):_coarse_repr(reprC),
00312                                                 _is_interpreted(false),
00313                                                 _is_interpretation_ok(false)
00314 {
00315   if(tryToInterp)
00316     tryToInterprate();
00317 }
00318 
00319 Unit::Unit(const char *reprFortran, int sizeOfRepr, bool tryToInterp):_coarse_repr(ExprParser::buildStringFromFortran(reprFortran,sizeOfRepr)),
00320                                                                       _is_interpreted(false),
00321                                                                       _is_interpretation_ok(false)
00322 {
00323 }
00324 
00325 void Unit::tryToInterprate() const
00326 {
00327   if(!_is_interpreted)
00328     {
00329       _is_interpreted=true;
00330       _is_interpretation_ok=false;
00331       try
00332         {
00333           ExprParser expr(_coarse_repr.c_str());
00334           expr.parse();
00335           _decomp_in_base=expr.evaluateUnit();
00336           _is_interpretation_ok=true;
00337         }
00338       catch(INTERP_KERNEL::Exception&) { }
00339     }
00340 }
00341 
00342 bool Unit::isInterpretationOK() const
00343 {
00344   return _is_interpretation_ok;
00345 }
00346 
00347 bool Unit::isCompatibleWith(const Unit& other) const
00348 {
00349   tryToInterprate();
00350   other.tryToInterprate();
00351   if(_is_interpretation_ok && other._is_interpretation_ok)
00352     return _decomp_in_base==other._decomp_in_base;
00353   else
00354     return false;
00355 }
00356 
00357 double Unit::convert(const Unit& target, double sourceVal) const
00358 {
00359   if(isCompatibleWith(target))
00360     {
00361       double mult,add;
00362       _decomp_in_base.getTranslationParams(target._decomp_in_base,mult,add);
00363       return mult*sourceVal+add;
00364     }
00365   else
00366     return std::numeric_limits<double>::max();
00367 }
00368 
00369 std::string Unit::getCoarseRepr() const
00370 {
00371   return _coarse_repr;
00372 }