convert_units.h
Go to the documentation of this file.
1 /*
2  -------------------------------------------------------------------
3 
4  Copyright (C) 2008-2018, Andrew W. Steiner
5 
6  This file is part of O2scl.
7 
8  O2scl is free software; you can redistribute it and/or modify
9  it under the terms of the GNU General Public License as published by
10  the Free Software Foundation; either version 3 of the License, or
11  (at your option) any later version.
12 
13  O2scl is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  GNU General Public License for more details.
17 
18  You should have received a copy of the GNU General Public License
19  along with O2scl. If not, see <http://www.gnu.org/licenses/>.
20 
21  -------------------------------------------------------------------
22 */
23 #ifndef O2SCL_CONVERT_UNITS_H
24 #define O2SCL_CONVERT_UNITS_H
25 
26 /** \file convert_units.h
27  \brief File defining \ref o2scl::convert_units
28 */
29 
30 #include <cstdio>
31 #include <cstdlib>
32 #include <iostream>
33 #include <map>
34 
35 #include <o2scl/misc.h>
36 #include <o2scl/constants.h>
37 #include <o2scl/string_conv.h>
38 
39 #ifndef DOXYGEN_NO_O2NS
40 namespace o2scl {
41 #endif
42 
43  /** \brief Convert units
44 
45  Allow the user to convert between two different units after
46  specifying a conversion factor. This class will also
47  automatically combine two conversion factors to create a new
48  unit conversion (but it cannot combine more than two).
49 
50  Conversions are performed by the \ref convert() function. The
51  run-time unit cache is initially filled with hard-coded
52  conversions, and \ref convert() searches this cache is searched
53  for the requested conversion first. If the conversion is not
54  found and if \ref use_gnu_units is true, then \ref convert()
55  tries to open a pipe to open a shell to get the conversion
56  factor from <tt>'units'</tt>. If this is successful, then the
57  conversion factor is returned and the conversion is added to the
58  cache.
59 
60  If the GNU units command is not in the local path, the user may
61  modify \ref units_cmd_string to specify the full pathname. One
62  can also modify \ref units_cmd_string to specify a different
63  <tt>units.dat</tt> file.
64 
65  Example:
66  \code
67  convert_units cu;
68  cout << "A solar mass is " << cu.convert("Msun","g",1.0)
69  << " g. " << endl;
70  \endcode
71 
72  An object of this type is created by \ref o2scl_settings
73  (of type \ref lib_settings_class) for several unit
74  conversions used internally in \o2 .
75 
76  \note Combining two conversions allows for some surprising
77  apparent contradictions from numerical precision errors. If
78  there are two matching unit conversion pairs which give the same
79  requested conversion factor, then one can arrange a situation
80  where the same conversion factor is reported with slightly
81  different values after adding a related conversion to the table.
82  One way to fix this is to force the class not to combine two
83  conversions by setting \ref combine_two_conv to false.
84  Alternatively, one can ensure that no combination is necessary
85  by manually adding the desired combination conversion to the
86  cache after it is first computed.
87 
88  \note \o2 uses some unit aliases which are not used the the GNU
89  or OSX units commands, like "Msun" for the solar mass and adds
90  some units not present like "Rschwarz" for the Schwarzchild
91  radius of a 1 solar mass black hole.
92 
93  \note Only the const versions, \ref convert_const and
94  \ref convert_ret_const are guaranteed to be thread-safe,
95  since they are not allowed to update the unit cache.
96 
97  \future Add G=1.
98 
99  \future An in_cache() function to test
100  to see if a conversion is currently in the cache.
101 
102  \future Ideally, a real C++ API for the GNU units command
103  would be better.
104  */
106 
107 #ifndef DOXYGEN_INTERNAL
108 
109  protected:
110 
111  /// The type for caching unit conversions
112  typedef struct {
113  /// The input unit
114  std::string f;
115  /// The output unit
116  std::string t;
117  /// The conversion factor
118  double c;
119  } unit_t;
120 
121  /// The cache where unit conversions are stored
122  std::map<std::string,unit_t,std::greater<std::string> > mcache;
123 
124  /// The iterator type
125  typedef std::map<std::string,unit_t,
126  std::greater<std::string> >::iterator miter;
127 
128  /// The const iterator type
129  typedef std::map<std::string,unit_t,
130  std::greater<std::string> >::const_iterator mciter;
131 
132  /** \brief The internal conversion function which tries the
133  cache first and, if that failed, tries GNU units.
134 
135  This function returns 0 if the conversion was successful. If
136  the conversion fails and \ref err_on_fail is \c true, then the
137  error handler is called. If the conversion fails and \ref
138  err_on_fail is \c false, then the value \ref
139  o2scl::exc_enotfound is returned.
140 
141  The public conversion functions in this class are
142  basically just wrappers around this internal function.
143  */
144  int convert_internal(std::string from, std::string to,
145  double val, double &converted,
146  double &factor, bool &new_conv) const;
147 
148  /** \brief Attempt to use GNU units to perform a conversion
149 
150  This function attempts to open a pipe to GNU units independent
151  of the value of \ref use_gnu_units. However, it will always
152  return a non-zero valeu if \c HAVE_POPEN is not defined
153  signaling that the <tt>popen()</tt> function is not available
154  (but does not call the error handler in this case). The
155  function returns 0 if the conversion was successful. If
156  HAVE_POPEN is defined but the call to GNU units fails
157  for some reason, then the error handler is called if
158  \ref err_on_fail is true.
159  */
160  int convert_gnu_units(std::string from, std::string to,
161  double val, double &converted,
162  double &factor, bool &new_conv) const;
163 
164  /** \brief Attempt to construct a conversion from the internal
165  unit cache
166 
167  This function returns 0 if the conversion was successful and
168  \ref o2scl::exc_efailed otherwise. This function
169  does not call the error handler.
170  */
171  int convert_cache(std::string from, std::string to,
172  double val, double &converted,
173  double &factor) const;
174 
175 #endif
176 
177  public:
178 
179  /// Create a unit-conversion object
180  convert_units();
181 
182  virtual ~convert_units() {}
183 
184  /// \name Basic usage
185  //@{
186  /** \brief Return the value \c val after converting using units \c
187  from and \c to
188  */
189  virtual double convert(std::string from, std::string to, double val);
190 
191  /** \brief Return the value \c val after converting using units \c
192  from and \c to (const version)
193  */
194  virtual double convert_const(std::string from, std::string to,
195  double val) const;
196  //@}
197 
198  /// \name User settings
199  //@{
200  /// Verbosity (default 0)
201  int verbose;
202 
203  /** \brief If true, use a system call to units to derive new
204  conversions (default true)
205 
206  This also requires <tt>popen()</tt>.
207  */
209 
210  /// If true, throw an exception when a conversion fails (default true)
212 
213  /// If true, allow combinations of two conversions (default true)
215 
216  /// Command string to call units (default "units")
217  std::string units_cmd_string;
218  //@}
219 
220  /// \name Conversions which don't throw exceptions
221  //@{
222  /** \brief Return the value \c val after converting using units \c
223  from and \c to, returning a non-zero value on failure
224  */
225  virtual int convert_ret(std::string from, std::string to, double val,
226  double &converted);
227 
228  /** \brief Return the value \c val after converting using units \c
229  from and \c to, returning a non-zero value on failure
230  (const version)
231  */
232  virtual int convert_ret_const(std::string from, std::string to,
233  double val, double &converted) const;
234  //@}
235 
236  /// \name Manipulate cache and create units.dat files
237  //@{
238  /// Manually insert a unit conversion into the cache
239  void insert_cache(std::string from, std::string to, double conv);
240 
241  /// Manually remove a unit conversion into the cache
242  void remove_cache(std::string from, std::string to);
243 
244  /// Print the present unit cache to std::cout
245  void print_cache() const;
246 
247  /** \brief Make a GNU \c units.dat file from the GSL constants
248 
249  If \c c_1 is true, then the second is defined in terms of
250  meters so that the speed of light is unitless. If \c hbar_1 is
251  true, then the kilogram is defined in terms of <tt>s/m^2</tt>
252  so that \f$ \hbar \f$ is unitless.
253 
254  \note While convert() generally works with the OSX version
255  of 'units', the OSX version can't read units.dat files
256  created by this function.
257 
258  \note Not all of the GSL constants or the canonical GNU units
259  conversions are given here.
260  */
261  void make_units_dat(std::string fname, bool c_1=false,
262  bool hbar_1=false, bool K_1=false) const;
263 
264  /** \brief Exhaustive test the cache against GNU units
265  */
266  int test_cache();
267  //@}
268 
269  };
270 
271 #ifndef DOXYGEN_NO_O2NS
272 }
273 #endif
274 
275 #endif
std::string t
The output unit.
bool use_gnu_units
If true, use a system call to units to derive new conversions (default true)
The main O<span style=&#39;position: relative; top: 0.3em; font-size: 0.8em&#39;>2</span>scl O$_2$scl names...
Definition: anneal.h:42
virtual double convert(std::string from, std::string to, double val)
Return the value val after converting using units from and to.
Convert units.
virtual double convert_const(std::string from, std::string to, double val) const
Return the value val after converting using units from and to (const version)
bool err_on_fail
If true, throw an exception when a conversion fails (default true)
int convert_gnu_units(std::string from, std::string to, double val, double &converted, double &factor, bool &new_conv) const
Attempt to use GNU units to perform a conversion.
std::string units_cmd_string
Command string to call units (default "units")
int test_cache()
Exhaustive test the cache against GNU units.
std::map< std::string, unit_t, std::greater< std::string > > mcache
The cache where unit conversions are stored.
int verbose
Verbosity (default 0)
convert_units()
Create a unit-conversion object.
void print_cache() const
Print the present unit cache to std::cout.
bool combine_two_conv
If true, allow combinations of two conversions (default true)
virtual int convert_ret(std::string from, std::string to, double val, double &converted)
Return the value val after converting using units from and to, returning a non-zero value on failure...
virtual int convert_ret_const(std::string from, std::string to, double val, double &converted) const
Return the value val after converting using units from and to, returning a non-zero value on failure ...
void insert_cache(std::string from, std::string to, double conv)
Manually insert a unit conversion into the cache.
int convert_internal(std::string from, std::string to, double val, double &converted, double &factor, bool &new_conv) const
The internal conversion function which tries the cache first and, if that failed, tries GNU units...
std::map< std::string, unit_t, std::greater< std::string > >::iterator miter
The iterator type.
void make_units_dat(std::string fname, bool c_1=false, bool hbar_1=false, bool K_1=false) const
Make a GNU units.dat file from the GSL constants.
std::string f
The input unit.
The type for caching unit conversions.
void remove_cache(std::string from, std::string to)
Manually remove a unit conversion into the cache.
int convert_cache(std::string from, std::string to, double val, double &converted, double &factor) const
Attempt to construct a conversion from the internal unit cache.
std::map< std::string, unit_t, std::greater< std::string > >::const_iterator mciter
The const iterator type.
double c
The conversion factor.

Documentation generated with Doxygen. Provided under the GNU Free Documentation License (see License Information).