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