ReFRACtor
unit.cc
Go to the documentation of this file.
1 #include "unit.h"
2 #include "fp_exception.h"
3 #include <cmath>
4 using namespace FullPhysics;
5 
6 #include <boost/spirit/include/qi.hpp>
7 #include <boost/spirit/include/phoenix_operator.hpp>
8 // Don't think this is needed, but leave this commented out for a
9 // short bit in case we find things breaking and need to come back to
10 // this. We might need to have a boost version conditional here if
11 // older versions of boost break. Believe this is the same as
12 // phoenix_bind.hpp in older versions of boost.
13 // #include <boost/spirit/home/phoenix/bind/bind_function.hpp>
14 #include <boost/spirit/include/phoenix_bind.hpp>
15 
16 //-----------------------------------------------------------------------
20 //-----------------------------------------------------------------------
21 
22 Unit::Unit(const std::string& Name, double Conversion_to_si,
23  const boost::rational<int>& Length_power,
24  const boost::rational<int>& Mass_power,
25  const boost::rational<int>& Time_power,
26  const boost::rational<int>& Current_power,
27  const boost::rational<int>& Temperature_power,
28  const boost::rational<int>& Amount_power,
29  const boost::rational<int>& Luminous_intensity_power,
30  const boost::rational<int>& Solid_angle_power,
31  const boost::rational<int>& Angle_power,
32  const boost::rational<int>& Photon_count_power,
33  const boost::rational<int>& Sample_index)
34 : conversion_to_si_(Conversion_to_si),
35  name_(Name)
36 {
37  base_unit_powers_[0] = Length_power;
38  base_unit_powers_[1] = Mass_power;
39  base_unit_powers_[2] = Time_power;
40  base_unit_powers_[3] = Current_power;
41  base_unit_powers_[4] = Temperature_power;
42  base_unit_powers_[5] = Amount_power;
43  base_unit_powers_[6] = Luminous_intensity_power;
44  base_unit_powers_[7] = Solid_angle_power;
45  base_unit_powers_[8] = Angle_power;
46  base_unit_powers_[9] = Photon_count_power;
47  base_unit_powers_[10] = Sample_index;
48 }
49 
50 //-----------------------------------------------------------------------
54 //-----------------------------------------------------------------------
55 
56 Unit::Unit(const std::string& Name, const Unit& Dunit)
57 : base_unit_powers_(Dunit.base_unit_powers()),
58  conversion_to_si_(Dunit.conversion_to_si()),
59  name_(Name)
60 {
61 }
62 
63 //-----------------------------------------------------------------------
65 //-----------------------------------------------------------------------
67  :conversion_to_si_(1.0)
68 {
69  for(int i = 0; i < number_base_unit; ++i)
70  base_unit_powers_[i] = 0;
71 }
72 
73 //-----------------------------------------------------------------------
76 //-----------------------------------------------------------------------
77 
78 Unit::Unit(const std::string& Name_to_parse)
79 {
80  *this = parse(Name_to_parse);
81 }
82 
83 //-----------------------------------------------------------------------
85 //-----------------------------------------------------------------------
86 
87 Unit& Unit::operator*=(const Unit& Dunit)
88 {
89  name_ += " " + Dunit.name();
90  conversion_to_si_ *= Dunit.conversion_to_si();
91  for(int i = 0; i < number_base_unit; ++i)
92  base_unit_powers_[i] += Dunit.base_unit_powers()[i];
93  return *this;
94 }
95 
96 //-----------------------------------------------------------------------
98 //-----------------------------------------------------------------------
99 Unit& Unit::operator*=(double Scale_factor)
100 {
101  name_ = "";
102  conversion_to_si_ *= Scale_factor;
103  return *this;
104 }
105 
106 Unit& Unit::operator/=(double Scale_factor)
107 {
108  name_ = "";
109  conversion_to_si_ /= Scale_factor;
110  return *this;
111 }
112 
113 //-----------------------------------------------------------------------
115 //-----------------------------------------------------------------------
116 
117 Unit& Unit::operator/=(const Unit& Dunit)
118 {
119  name_ += " / (" + Dunit.name() + ")";
120  conversion_to_si_ /= Dunit.conversion_to_si();
121  for(int i = 0; i < number_base_unit; ++i)
122  base_unit_powers_[i] -= Dunit.base_unit_powers()[i];
123  return *this;
124 }
125 
126 //-----------------------------------------------------------------------
131 //-----------------------------------------------------------------------
132 
133 bool Unit::operator==(const Unit& U) const
134 {
135  return (is_commensurate(U) &&
136  fabs(conversion_to_si() / U.conversion_to_si() - 1.0) < 1e-8);
137 }
138 
139 //-----------------------------------------------------------------------
141 //-----------------------------------------------------------------------
142 
143 void Unit::print(std::ostream& Os) const
144 {
145  Os << "Unit:\n"
146  << " Name: " << name_ << "\n"
147  << " Conversion to SI: " << conversion_to_si_ << "\n"
148  << " Unit powers: (";
149  for(int i = 0; i < number_base_unit - 1; ++i)
150  Os << base_unit_powers_[i] << ", ";
151  Os << base_unit_powers_[number_base_unit - 1] << ")\n";
152 }
153 
154 //-----------------------------------------------------------------------
155 // Take a dynamic unit
156 //-----------------------------------------------------------------------
157 
158 Unit FullPhysics::pow(const Unit& Dunit, const boost::rational<int>& Exponent)
159 {
160  return Unit("",
161  ::pow(Dunit.conversion_to_si(), boost::rational_cast<double>(Exponent)),
162  Dunit.base_unit_powers()[0] * Exponent,
163  Dunit.base_unit_powers()[1] * Exponent,
164  Dunit.base_unit_powers()[2] * Exponent,
165  Dunit.base_unit_powers()[3] * Exponent,
166  Dunit.base_unit_powers()[4] * Exponent,
167  Dunit.base_unit_powers()[5] * Exponent,
168  Dunit.base_unit_powers()[6] * Exponent,
169  Dunit.base_unit_powers()[7] * Exponent,
170  Dunit.base_unit_powers()[8] * Exponent,
171  Dunit.base_unit_powers()[9] * Exponent,
172  Dunit.base_unit_powers()[10] * Exponent);
173 }
174 
175 //-----------------------------------------------------------------------
178 //-----------------------------------------------------------------------
179 
180 double FullPhysics::conversion(const Unit& Dunit_from, const Unit& Dunit_to)
181 {
182  if(Dunit_from.base_unit_powers() != Dunit_to.base_unit_powers()) {
183  Exception e;
184  e << "Attempt to convert between Units that are not commensurate.\n"
185  << "From unit:\n" << Dunit_from << "To unit:\n" << Dunit_to << "\n";
186  throw e;
187  }
188  return Dunit_from.conversion_to_si() / Dunit_to.conversion_to_si();
189 }
190 
191 namespace qi = boost::spirit::qi;
192 namespace ascii = boost::spirit::ascii;
193 
194 /****************************************************************/
198 struct base_unit_ : qi::symbols<char, Unit>
199 {
201  {
202  using namespace units;
203  add
204  ("m", m)
205  ("meter", m)
206  ("Meters", m)
207  ("micron", micron)
208  ("Microns", micron)
209  ("um", micron)
210  ("g", g)
211  ("gram", g)
212  ("s", s)
213  ("second", s)
214  ("Second", s)
215  ("sec", s)
216  ("day", day)
217  ("year", year)
218  ("K", K)
219  ("A", A)
220  ("mol", mol)
221  ("mole", mol)
222  ("cd", cd)
223  ("sr", sr)
224  ("rad", rad)
225  ("deg", deg)
226  ("Degrees", deg)
227  ("ph", ph)
228  ("Ph", ph)
229  ("sample_index", sample_index)
230  ("dimensionless", dimensionless)
231  ("N", N)
232  ("Pa", Pa)
233  ("J", J)
234  ("W", W)
235  ("Wavenumbers", inv_cm)
236  ("Meters per second", m / s)
237  ;
238  }
239 } base_unit;
240 
241 /****************************************************************/
245 struct prefix_ : qi::symbols<char, double>
246 {
248  {
249  using namespace units;
250  add
251  ("Y", 1e24)
252  ("yotta", 1e24)
253  ("Z", 1e21)
254  ("zetta", 1e21)
255  ("E", 1e18)
256  ("exa", 1e18)
257  ("P", 1e15)
258  ("peta", 1e15)
259  ("T", 1e12)
260  ("tera", 1e12)
261  ("G", 1e9)
262  ("giga", 1e9)
263  ("M", 1e6)
264  ("mega", 1e6)
265  ("k", 1000)
266  ("kilo", 1000)
267  ("h", 100)
268  ("hecto", 100)
269  ("da", 10)
270  ("deca", 10)
271  ("d", 1e-1)
272  ("deci", 1e-1)
273  ("c", 1e-2)
274  ("centi", 1e-2)
275  ("m", 1e-3)
276  ("milli", 1e-3)
277  ("micro", 1e-6)
278  ("n", 1e-9)
279  ("nano", 1e-9)
280  ("p", 1e-12)
281  ("pico", 1e-12)
282  ("f", 1e-15)
283  ("femto", 1e-15)
284  ("a", 1e-18)
285  ("atto", 1e-18)
286  ("z", 1e-21)
287  ("zepto", 1e-21)
288  ("y", 1e-24)
289  ("yocto", 1e-24)
290  ;
291  }
292 } prefix;
293 
294 /****************************************************************/
297 typedef std::string::const_iterator iterator_type;
298 struct unit_parser : qi::grammar<iterator_type, Unit()>
299 {
300  unit_parser() : unit_parser::base_type(exp)
301  {
302  using namespace qi;
303  using namespace boost::phoenix;
304  typedef Unit (*pow_f)(const Unit&,
305  const boost::rational<int>&);
306  // Eat white space
307  ws = *lit(' ');
308  // This rule gets a base type, with a prefix.
309  prefixunit =
310  lexeme[prefix [_val *= _1] >>
311  base_unit [_val *= _1]
312  ];
313  // This gets either a unit, or a unit with a prefix
314  unit = prefixunit [_val *= _1] || base_unit [_val *= _1];
315 
316  // A term is either a single unit, or a expresion between
317  // "(" and ")". Possibly raised to a power
318  term = (unit [_val *= _1] || ('(' >> ws >> exp [_val *= _1] >> ws >> ')'))
319  // This complicated expression just matches things like
320  // "^5" or "^{-1}".
321  >> -((ws >> lit('^') >> ws >> int_ [_val = bind((pow_f) &pow,_val, _1)])
322  ||
323  (ws >> lit('^') >> ws >> lit('{') >> ws
324  >> int_ [_val = bind((pow_f) &pow,_val, _1)]
325  >> ws >> lit('}'))
326  );
327 
328  // A subexpression is either a term, or a term divided by another term
329 
330  subexp = term [_val *= _1] >> *(ws >> lit('/') >> ws >> term [_val /= _1]);
331 
332  // A expression is any product of subexpressions, possibly with '*'
333 
334  exp = ws >> subexp [_val *= _1] % (( ws >> lit('*') >> ws) || +lit(' '))
335  >> ws;
336  }
337  qi::rule<iterator_type, Unit()> prefixunit;
338  qi::rule<iterator_type, Unit()> unit;
339  qi::rule<iterator_type, Unit()> term;
340  qi::rule<iterator_type, Unit()> subexp;
341  qi::rule<iterator_type, Unit()> exp;
342  qi::rule<iterator_type> ws;
343 };
344 
345 //-----------------------------------------------------------------------
348 //-----------------------------------------------------------------------
349 
350 Unit Unit::parse(const std::string& S)
351 {
352  unit_parser unitp;
353  Unit result = units::dimensionless;
354  std::string::const_iterator iter = S.begin();
355  bool r = qi::parse(iter, S.end(), unitp, result);
356  if(r && iter == S.end()) {
357  result.name(S);
358  return result;
359  }
360  Exception e;
361  e << "Parsing of unit string '" << S << "' failed.\n"
362  << "Parsing stopped at: '" << std::string(iter, S.end()) << "'\n";
363  throw e;
364 }
365 
const boost::array< boost::rational< int >, number_base_unit > & base_unit_powers() const
Array of the powers of the base units (so m^2 would return (1,0,0,0,0,0,0,0))
Definition: unit.h:53
qi::rule< iterator_type, Unit()> subexp
Definition: unit.cc:340
Unit & operator/=(double Scale_factor)
Definition: unit.cc:106
const Unit s("s", 1.0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0)
prefix_()
Definition: unit.cc:247
base_unit_ base_unit
static Unit parse(const std::string &S)
Parse a string, and return a Unit that matches the given units.
Definition: unit.cc:350
bool operator==(const Unit &U) const
Test for equality.
Definition: unit.cc:133
const Unit dimensionless("dimensionless", 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
Unit()
Default constructor. This creates a dimensionless unit.
Definition: unit.cc:66
const Unit Pa("Pa", N/(m *m))
This is the base of the exception hierarchy for Full Physics code.
Definition: fp_exception.h:16
double conversion(const Unit &Dunit_from, const Unit &Dunit_to)
Return conversion factor to go from one unit to another.
Definition: unit.cc:180
const Unit sr("sr", 1.0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0)
const Unit J("J", N *m)
const Unit micron("micron", 1e-6 *m)
Symbol table to parse a prefix.
Definition: unit.cc:245
const Unit sample_index("sample_index", 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1)
const Unit A("A", 1.0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0)
void print(std::ostream &Os) const
Print to a stream.
Definition: unit.cc:143
qi::rule< iterator_type, Unit()> exp
Definition: unit.cc:341
const Unit inv_cm("cm^-1", pow(cm, -1))
const Unit K("K", 1.0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0)
qi::rule< iterator_type > ws
Definition: unit.cc:342
qi::rule< iterator_type, Unit()> term
Definition: unit.cc:339
const Unit m("m", 1.0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
Unit pow(const Unit &Dunit, const boost::rational< int > &Exponent)
Definition: unit.cc:158
double conversion_to_si() const
Conversion factor to go to SI units.
Definition: unit.h:60
const Unit day("day", 24 *60 *60 *s)
const Unit year("year", 365.25 *24 *60 *60 *s)
prefix_ prefix
const Unit cd("cd", 1.0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0)
const Unit g("g", 1e-3 *kg)
Libraries such as boost::units allow unit handling where we know the units at compile time...
Definition: unit.h:25
bool is_commensurate(const Unit &Units) const
Test if this set of units is commensurate with another set.
Definition: unit.h:68
Symbol table to parse a base unit.
Definition: unit.cc:198
const Unit N("N", kg *m/(s *s))
Contains classes to abstract away details in various Spurr Radiative Transfer software.
Definition: doxygen_python.h:1
qi::rule< iterator_type, Unit()> unit
Definition: unit.cc:338
base_unit_()
Definition: unit.cc:200
const Unit mol("mol", 1.0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0)
unit_parser()
Definition: unit.cc:300
const Unit ph("ph", 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0)
const std::string & name() const
Name of unit. May be an empty string if a name wasn&#39;t assigned.
Definition: unit.h:77
Unit & operator*=(const Unit &Dunit)
Basic math operators for units.
Definition: unit.cc:87
const Unit rad("rad", 1.0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0)
std::string::const_iterator iterator_type
The grammer for parsing units.
Definition: unit.cc:297
qi::rule< iterator_type, Unit()> prefixunit
Definition: unit.cc:337
const Unit deg("deg", pi/180.0 *rad)
const Unit W("W", J/s)

Copyright © 2017, California Institute of Technology.
ALL RIGHTS RESERVED.
U.S. Government Sponsorship acknowledged.
Generated Fri Aug 24 2018 15:44:11