Flow123d  master-49d9643
unit_converter.cc
Go to the documentation of this file.
1 /*!
2  *
3  * Copyright (C) 2015 Technical University of Liberec. All rights reserved.
4  *
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License version 3 as published by the
7  * Free Software Foundation. (http://www.gnu.org/licenses/gpl-3.0.en.html)
8  *
9  * This program is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11  * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
12  *
13  *
14  * @file unit_converter.cc
15  * @brief
16  */
17 
18 
20 #include "input/type_record.hh"
21 
22 
23 /*******************************************************************
24  * implementation of BasicFactors
25  */
26 
28  UnitsMap base_units_map = {
29  { "*m", { 1, UnitSI().m() } },
30  { "*g", { 0.001, UnitSI().kg() } },
31  { "*s", { 1, UnitSI().s() } },
32  { "*A", { 1, UnitSI().A() } },
33  { "*K", { 1, UnitSI().K() } },
34  { "*cd", { 1, UnitSI().cd() } },
35  { "*mol",{ 1, UnitSI().mol() } },
36  { "md", { 1, UnitSI().md() } }, // m^{-d} where d is the element dimension
37 
38  { "*N", { 1, UnitSI().m().kg().s(-2) } },
39  { "*J", { 1, UnitSI().m(2).kg().s(-2) } },
40  { "*W", { 1, UnitSI().m(2).kg().s(-3) } },
41  { "*Pa", { 1, UnitSI().m(-1).kg().s(-2) } },
42  { "*C", { 1, UnitSI().A(1).s(1) } },
43  { "*D", { 9.869233E-13, UnitSI().m(2) } }, // Darcy
44  { "*l", { 1e-3, UnitSI().m(3) } }, // litr
45 
46  //{ "cm", { 0.01, UnitSI().m() } },
47  //{ "dm", { 0.1, UnitSI().m() } },
48  { "t", { 1000, UnitSI().kg() } },
49  { "min", { 60, UnitSI().s() } },
50  { "h", { 3600, UnitSI().s() } },
51  { "d", { 24*3600, UnitSI().s() } },
52  { "y", { 365.2425*24*3600, UnitSI().s() } },
53  //{ "hPa", { 100, UnitSI().m(-1).kg().s(-2) } },
54 
55  { "rad", { 1, UnitSI().m(0) } }
56  };
57 
58  // map of prefixes and multiplicative constants
59  std::map<std::string, double> prefix_map = {
60  { "a", 1e-18 },
61  { "f", 1e-15 },
62  { "p", 1e-12 },
63  { "n", 1e-9 },
64  { "u", 1e-6 },
65  { "m", 1e-3 },
66  { "c", 1e-2 },
67  { "d", 1e-1 },
68  { "", 1 },
69  { "h", 1e+2 }, // deka is missing as it is a two letter prefix
70  { "k", 1e+3 },
71  { "M", 1e+6 },
72  { "G", 1e+9 },
73  { "T", 1e+12 },
74  { "P", 1e+15 },
75  { "E", 1e+18 }
76 
77  };
78 
79  // add derived units
81  for (it=base_units_map.begin(); it!=base_units_map.end(); ++it) {
82  if (it->first.at(0)=='*') {
83  std::string shortcut = it->first.substr(1);
84  double coef = it->second.coef_;
85 
86  for (std::map<std::string, double>::iterator prefix_it=prefix_map.begin(); prefix_it!=prefix_map.end(); ++prefix_it) {
87  std::string key = prefix_it->first + shortcut;
88  units_map_.insert(std::pair<std::string, DerivedUnit>( key, { coef*prefix_it->second, it->second.unit_ } ));
89  }
90  } else {
91  units_map_.insert( std::pair<std::string, DerivedUnit>( it->first, it->second ) );
92  }
93  }
94 }
95 
96 
97 /*******************************************************************
98  * implementation of UnitConverter
99  */
100 
102  return Input::Type::Record("Unit",
103  "Specify the unit of an input value. "
104  "Evaluation of the unit formula results into a coeficient and a "
105  "unit in terms of powers of base SI units. The unit must match the"
106  "expected SI unit of the value, while the value provided on the input "
107  "is multiplied by the coefficient before further processing. "
108  "The unit formula have a form:\n"
109  "```\n"
110  "<UnitExpr>;<Variable>=<Number>*<UnitExpr>;...,\n"
111  "```\n"
112  "where ```<Variable>``` is a variable name and ```<UnitExpr>``` is a units expression "
113  "which consists of products and divisions of terms.\n\n"
114  "A term has a form: "
115  "```<Base>^<N>```, where ```<N>``` is an integer exponent and ```<Base>``` "
116  "is either a base SI unit, a derived unit, or a variable defined in the same unit formula. "
117  "Example, unit for the pressure head:\n\n"
118  "```MPa/rho/g_; rho = 990*kg*m^-3; g_ = 9.8*m*s^-2```"
119  )
120  .allow_auto_conversion("unit_formula")
122  "Definition of unit." )
123  .close();
124 }
125 
126 
128 : coef_(1.0) {}
129 
130 
132 
133 
135 {
136  typedef spirit_namespace::position_iterator< std::string::iterator > PosnIterT;
137 
138  std::string::iterator begin = s.begin();
139  std::string::iterator end = s.end();
140 
141  const PosnIterT posn_begin( begin, end );
142  const PosnIterT posn_end( end, end );
143 
145 
146  try {
147  spirit_namespace::parse( begin, end,
149  spirit_namespace::space_p );
150  semantic_actions.check_unit_data();
151  } catch (ExcInvalidUnit &e) {
152  e << EI_UnitDefinition(s);
153  throw;
154  }
155 
156  return semantic_actions.unit_data();
157 }
158 
159 
160 double UnitConverter::convert(std::string actual_unit) {
161  unit_si_.reset();
162  coef_ = 1.0;
163  UnitData unit_data = read_unit(actual_unit);
164 
165  Formula &formula = unit_data.find("")->second;
166  for( std::vector<struct Factor>::iterator it = formula.factors_.begin(); it !=formula.factors_.end(); ++it ) {
167  add_converted_unit(*it, unit_data, unit_si_, coef_);
168  }
169 
170  return coef_;
171 }
172 
173 
174 void UnitConverter::add_converted_unit(Factor factor, UnitData &unit_data, UnitSI &unit_si, double &coef) {
175  if (factor.basic_) {
177  ASSERT(it != UnitConverter::basic_factors.units_map_.end())(factor.factor_).error("Undefined unit.");
178  coef *= pow(it->second.coef_, factor.exponent_);
179  unit_si.multiply(it->second.unit_, factor.exponent_);
180  } else {
182  ASSERT(it != unit_data.end())(factor.factor_).error("Undefined unit.");
183  coef *= pow(it->second.coef_, factor.exponent_);
184  for( std::vector<struct Factor>::iterator in_it = it->second.factors_.begin(); in_it !=it->second.factors_.end(); ++in_it ) {
185  Factor new_factor = Factor(in_it->factor_, in_it->exponent_*factor.exponent_, in_it->basic_ );
186  add_converted_unit(new_factor, unit_data, unit_si, coef);
187  }
188  }
189 }
190 
#define ASSERT(expr)
Definition: asserts.hh:351
Helper class. Defines basic factors of SI, non-SI and derived units.
UnitsMap units_map_
Define all base and derived units given by their symbol.
BasicFactors()
Constructor.
static Default obligatory()
The factory function to make an empty default value which is obligatory.
Definition: type_record.hh:110
Record type proxy class.
Definition: type_record.hh:182
virtual Record & allow_auto_conversion(const string &from_key)
Allows shorter input of the Record providing only value of the from_key given as the parameter.
Definition: type_record.cc:133
Record & close() const
Close the Record for further declarations of keys.
Definition: type_record.cc:304
Record & declare_key(const string &key, std::shared_ptr< TypeBase > type, const Default &default_value, const string &description, TypeBase::attribute_map key_attributes=TypeBase::attribute_map())
Declares a new key of the Record.
Definition: type_record.cc:503
Class for declaration of the input data that are in string format.
Definition: type_base.hh:582
void add_converted_unit(Factor factor, UnitData &unit_data, UnitSI &unit_si, double &coef)
Calculates UnitSi and coeficient of Factor, recursively calls this method for user defined formula.
static const Input::Type::Record & get_input_type()
static const BasicFactors basic_factors
Define all base and derived units given by their symbol.
UnitConverter()
Constructor.
UnitSI unit_si() const
Return unit_si_.
double convert(std::string actual_unit)
UnitData read_unit(std::string s)
Parse and check unit defined in string format.
Class for representation SI units of Fields.
Definition: unit_si.hh:40
UnitSI & kg(int exp=1)
Definition: unit_si.cc:70
UnitSI & mol(int exp=1)
Definition: unit_si.cc:94
UnitSI & A(int exp=1)
Definition: unit_si.cc:82
UnitSI & s(int exp=1)
Definition: unit_si.cc:76
UnitSI & m(int exp=1)
Methods set values of exponents for SI units with similar name.
Definition: unit_si.cc:64
void reset()
Reset UnitSI object (set vector of exponents to zeros and set undef flag)
Definition: unit_si.cc:212
UnitSI & K(int exp=1)
Definition: unit_si.cc:88
UnitSI & md(int exp=-1)
The dimension dependent meter: md^y = m^(yd), where 'd' is dimension.
Definition: unit_si.cc:106
void multiply(const UnitSI &other, int exp=1)
Multiply with power of given unit.
Definition: unit_si.cc:205
UnitSI & cd(int exp=1)
Definition: unit_si.cc:100
Class manages parsing of user defined field unit.
void check_unit_data()
Check unit_data_ object.
Store structure given by parser.
int exponent_
exponent
std::string factor_
string represantation of unit or user defined constant
bool basic_
unit is basic (strict defined in application) / derived (defined by user as formula)
std::vector< struct Factor > factors_
factors of formula