Salome HOME
Update copyrights
[tools/medcoupling.git] / src / INTERP_KERNEL / ExprEval / InterpKernelUnit.cxx
1 // Copyright (C) 2007-2019  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19 // Author : Anthony Geay (CEA/DEN)
20
21 #include "InterpKernelUnit.hxx"
22 #include "InterpKernelExprParser.hxx"
23
24 #include <algorithm>
25 #include <cmath>
26 #include <sstream>
27 #include <iomanip>
28 #include <limits>
29
30 using namespace INTERP_KERNEL;
31
32 UnitDataBase UnitDataBase::_uniqueMapForExpr;
33
34 static const char InterpKernelMuAscii[2]={-0x4B,0x0};
35
36 static const char InterpKernelMuUnicode[3]={-0x3E,-0x4B,0x0};
37
38 const char *UnitDataBase::PREF_POW10[NB_OF_PREF_POW10]={"y","z","a","f","p","n",InterpKernelMuAscii,InterpKernelMuUnicode,"u","m","c","d",
39                                                         "da","h","k","M","G","T","P","E","Z","Y"};
40
41 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,
42                                                   1e1,1e2,1e3,1e6,1e9,1e12,1e15,1e18,1e21,1e24};
43
44 static const char InterpKernelDegreeCAscii[3]={-0x50,0x43,0x0};
45
46 static const char InterpKernelDegreeCUnicode[4]={-0x3E,-0x50,0x43,0x0};
47
48 static const char InterpKernelDegreeCUnicodeWin[3]={-0x08,0x43,0x0};
49
50 const char *UnitDataBase::UNITS_RECOGN[NB_OF_UNITS_RECOGN]={"g","m","s","A","K",
51                                                             "W","J","Hz","V","h","min","t","N","dyn",
52                                                             "eV","Pa","atm","bar",InterpKernelDegreeCAscii,"C","ohm","F","S",
53                                                             "T","H","P","St",InterpKernelDegreeCUnicode,InterpKernelDegreeCUnicodeWin};
54
55 const short UnitDataBase::PROJ_IN_BASE[NB_OF_UNITS_RECOGN][SIZE_OF_UNIT_BASE]=
56   {
57     {1,0,0,0,0},//g
58     {0,1,0,0,0},//m
59     {0,0,1,0,0},//s
60     {0,0,0,1,0},//A
61     {0,0,0,0,1},//K
62     {1,2,-3,0,0},//W
63     {1,2,-2,0,0},//J
64     {0,0,-1,0,0},//Hz
65     {1,2,-3,-1,0},//V
66     {0,0,1,0,0},//h
67     {0,0,1,0,0},//min
68     {1,0,0,0,0},//t
69     {1,1,-2,0,0},//N
70     {1,1,-2,0,0},//dyn
71     {1,2,-2,0,0},//eV
72     {1,-1,-2,0,0},//Pa
73     {1,-1,-2,0,0},//atm
74     {1,-1,-2,0,0},//bar
75     {0,0,0,0,1},//degree C
76     {0,0,1,1,0},//C
77     {1,2,-3,-2,0},//ohm
78     {-1,-2,4,2,0},//F
79     {-1,-2,3,2,0},//S
80     {1,0,-2,-1,0},//T
81     {1,2,-2,-2,0},//H
82     {1,-1,-1,0,0},//P
83     {0,2,-1,0,0},//St
84     {0,0,0,0,1},//degree C
85     {0,0,0,0,1}//degree C
86   };
87
88 const double UnitDataBase::MUL_COEFF[NB_OF_UNITS_RECOGN]=
89   { 1.,1.,1.,1.,1.,
90     1000.,1000.,1.,1000.,3600.,3600.,1e6,1000.,1e-2,
91     1.60217733e-16,1000.,1.01325e8,1e8,1.,1.,1000.,1e-3,
92     1000.,1000.,100.,1.,1.,1.,1.};
93
94 const double UnitDataBase::ADD_COEFF[NB_OF_UNITS_RECOGN]=
95   { 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};
96
97 UnitDataBase::UnitDataBase()
98 {
99   for(int i=0;i<NB_OF_PREF_POW10;i++)
100     _prefix_pow_10[PREF_POW10[i]]=POW10[i];
101   for(int i=0;i<NB_OF_UNITS_RECOGN;i++)
102     {
103       _units_semantic[UNITS_RECOGN[i]]=PROJ_IN_BASE[i];
104       _units_mul[UNITS_RECOGN[i]]=MUL_COEFF[i];
105       _units_add[UNITS_RECOGN[i]]=ADD_COEFF[i];
106     }
107 }
108
109 const short *UnitDataBase::getInfoForUnit(const std::string& unit, double& addFact, double& mFact) const
110 {
111   std::size_t lgth=unit.length();
112   std::string work,work2;
113   const short *ret=0;
114   for(std::size_t i=0;i<lgth && !ret;i++)
115     {
116       work=unit.substr(i);
117       std::map<std::string,const short *>::const_iterator iter=_units_semantic.find(work);
118       if(iter!=_units_semantic.end())
119         {
120           ret=(*iter).second;
121           std::map<std::string,double>::const_iterator iter2=_units_add.find(work);
122           addFact=(*iter2).second;
123           std::map<std::string,double>::const_iterator iter3=_units_mul.find(work);
124           mFact=(*iter3).second;
125           work2=unit.substr(0,i);
126         }
127     }
128   if(!ret)
129     {
130       std::ostringstream os;
131       os << "Unit : " << unit << " not recognized !";
132       throw INTERP_KERNEL::Exception(os.str().c_str());
133     }
134   if(!work2.empty())
135     {
136       std::map<std::string,double>::const_iterator iter4=_prefix_pow_10.find(work2);
137       if(iter4==_prefix_pow_10.end())
138         {
139           std::ostringstream os;
140           os << "Unit : " << unit << " not fully recognized : \"" << work << "\" detected as core unit and \"";
141           os << work2 << "\" not recognized prefix !";
142           throw INTERP_KERNEL::Exception(os.str().c_str());
143         }
144       addFact=0.;
145       mFact*=(*iter4).second;
146     }
147   return ret;
148 }
149
150 DecompositionInUnitBase::DecompositionInUnitBase():_add_to_base(0.),_mult_fact_to_base(1.)
151 {
152   _value[0]=0;
153   _value[1]=0;
154   _value[2]=0;
155   _value[3]=0;
156   _value[4]=0;
157 }
158
159 void DecompositionInUnitBase::setInfo(const short *vals, double addFact, double mFact)
160 {
161   _add_to_base=addFact;
162   _mult_fact_to_base=mFact;
163   _value[0]=vals[0];
164   _value[1]=vals[1];
165   _value[2]=vals[2];
166   _value[3]=vals[3];
167   _value[4]=vals[4];
168 }
169
170 bool DecompositionInUnitBase::operator==(const DecompositionInUnitBase& other) const
171 {
172   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];
173 }
174
175 void DecompositionInUnitBase::getTranslationParams(const DecompositionInUnitBase& other, double& mul, double& add) const
176 {
177   if((*this)==other)
178     {
179       mul=_mult_fact_to_base/other._mult_fact_to_base;
180       add=_add_to_base/other._mult_fact_to_base-other._add_to_base;
181     }
182   else
183     {
184       mul=std::numeric_limits<double>::max();
185       add=std::numeric_limits<double>::max();
186     }
187 }
188
189 bool DecompositionInUnitBase::isEqual(short mass, short lgth, short time, short intensity, short temp, double add, double mult)
190 {
191   bool ret1=mass==_value[0];
192   bool ret2=lgth==_value[1];
193   bool ret3=time==_value[2];
194   bool ret4=intensity==_value[3];
195   bool ret5=temp==_value[4];
196   bool ret6=areDoubleEquals(add,_add_to_base);
197   bool ret7=areDoubleEquals(mult,_mult_fact_to_base);
198   return ret1 && ret2 && ret3 && ret4 && ret5 && ret6 && ret7;
199 }
200
201 void DecompositionInUnitBase::negate()
202 {
203   _mult_fact_to_base=-_mult_fact_to_base;
204 }
205
206 bool DecompositionInUnitBase::isAdimensional() const
207 {
208   return _value[0]==0 && _value[1]==0 && _value[2]==0 && _value[3]==0 && _value[4]==0;
209 }
210
211 bool DecompositionInUnitBase::isUnitary() const
212 {
213   return areDoubleEquals(_add_to_base,0.) && areDoubleEquals(_mult_fact_to_base,1.);
214 }
215
216 void DecompositionInUnitBase::tryToConvertInUnit(double val)
217 {
218   int valI=(int)val;
219   if((val-(double)valI)!=0.)
220     {
221       std::ostringstream os;
222       os << "Double value " << val << " can't be considered as integer. Not admitable for units !";
223       throw INTERP_KERNEL::Exception(os.str().c_str());
224     }
225   _value[0]=0;
226   _value[1]=0;
227   _value[2]=0;
228   _value[3]=0;
229   _value[4]=0;
230   _add_to_base=0;
231   _mult_fact_to_base=valI;
232 }
233
234 DecompositionInUnitBase &DecompositionInUnitBase::operator*(const DecompositionInUnitBase& other)
235 {
236   _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];
237   _mult_fact_to_base*=other._mult_fact_to_base;
238   _add_to_base=0.;
239   return *this;
240 }
241
242 DecompositionInUnitBase &DecompositionInUnitBase::operator/(const DecompositionInUnitBase& other)
243 {
244   _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];
245   _mult_fact_to_base/=other._mult_fact_to_base;
246  _add_to_base=0.;
247  return *this;
248 }
249
250 DecompositionInUnitBase &DecompositionInUnitBase::operator^(const DecompositionInUnitBase& other)
251 {
252   if(!other.isAdimensional())
253     throw INTERP_KERNEL::Exception("Trying to execute operator ^ with a second member not adimensionnal");
254   int exp=couldItBeConsideredAsInt(other._mult_fact_to_base);
255   _value[0]*=exp; _value[1]*=exp; _value[2]*=exp; _value[3]*=exp; _value[4]*=exp;
256   _mult_fact_to_base=powInt(_mult_fact_to_base,exp);
257   _add_to_base=0.;
258   return *this;
259 }
260
261 void DecompositionInUnitBase::dealWithAddFactor(const DecompositionInUnitBase& other)
262 {
263   if(!areDoubleEquals(_add_to_base,0.))
264     if(other.isAdimensional())
265       if(areDoubleEquals(other._mult_fact_to_base,1.))
266         return ;
267   if(!other.areDoubleEquals(_add_to_base,0.))
268     if(isAdimensional())
269       if(areDoubleEquals(_mult_fact_to_base,1.))
270         return ;
271   _add_to_base=0.;
272 }
273
274 double DecompositionInUnitBase::powInt(double val, int exp)
275 {
276   double work=1.;
277   if(exp==0)
278     return 1.;
279   if(exp>0)
280     for(int i=0;i<exp;i++)
281       work*=val;
282   else
283     {
284       int tmp=-exp;
285       for(int i=0;i<tmp;i++)
286         work*=1/val;
287     }
288   return work;
289 }
290
291 bool DecompositionInUnitBase::areDoubleEquals(double a, double b)
292 {
293   if(a==0. || b==0.)
294     return a==b;
295   double ref=std::max(a,b);
296   return fabs((a-b)/ref)<1e-7;
297 }
298
299 int DecompositionInUnitBase::couldItBeConsideredAsInt(double val)
300 {
301   int ret=(int)val;
302   double valT=(double) ret;
303   if(valT==val)
304     return ret;
305   else
306     {
307       std::ostringstream stream; stream << "Invalid double number " << std::setprecision(16) << val << " can's be considered for ^ operation on unit.";
308       throw INTERP_KERNEL::Exception(stream.str().c_str());
309     }
310 }
311
312 Unit::Unit(const char *reprC, bool tryToInterp):_coarse_repr(reprC),
313                                                 _is_interpreted(false),
314                                                 _is_interpretation_ok(false)
315 {
316   if(tryToInterp)
317     tryToInterprate();
318 }
319
320 Unit::Unit(const char *reprFortran, int sizeOfRepr, bool tryToInterp):_coarse_repr(ExprParser::buildStringFromFortran(reprFortran,sizeOfRepr)),
321                                                                       _is_interpreted(false),
322                                                                       _is_interpretation_ok(false)
323 {
324 }
325
326 void Unit::tryToInterprate() const
327 {
328   if(!_is_interpreted)
329     {
330       _is_interpreted=true;
331       _is_interpretation_ok=false;
332       try
333         {
334           ExprParser expr(_coarse_repr.c_str());
335           expr.parse();
336           _decomp_in_base=expr.evaluateUnit();
337           _is_interpretation_ok=true;
338         }
339       catch(INTERP_KERNEL::Exception&) { }
340     }
341 }
342
343 bool Unit::isInterpretationOK() const
344 {
345   return _is_interpretation_ok;
346 }
347
348 bool Unit::isCompatibleWith(const Unit& other) const
349 {
350   tryToInterprate();
351   other.tryToInterprate();
352   if(_is_interpretation_ok && other._is_interpretation_ok)
353     return _decomp_in_base==other._decomp_in_base;
354   else
355     return false;
356 }
357
358 double Unit::convert(const Unit& target, double sourceVal) const
359 {
360   if(isCompatibleWith(target))
361     {
362       double mult,add;
363       _decomp_in_base.getTranslationParams(target._decomp_in_base,mult,add);
364       return mult*sourceVal+add;
365     }
366   else
367     return std::numeric_limits<double>::max();
368 }
369
370 std::string Unit::getCoarseRepr() const
371 {
372   return _coarse_repr;
373 }