Boost logo

Boost Users :

Subject: Re: [Boost-users] [Units] Molecular units base_units trouble: please help
From: Matthias Schabel (boost_at_[hidden])
Date: 2009-01-05 12:04:16


> I am creating a units system using a mixture of custom base_units
> (mass, amount, charge), scaled base units based on si::base_units
> (time, length), and unmodified si::base_units (plane_angle,
> solid_angle, temperature).
>
> The full set of base units I intend to use are as follows:
> * time in picoseconds
> * mass in daltons
> * length in nanometers
> * amount in molecules
> * angle in radians
> * solid angle in steradians
> * charge in elementary charges
> * temperature in kelvin
> * [I'm ignoring luminous intensity for now]

You should be able to reuse radians, steradians, and kelvin directly
and use scaled units for picoseconds and nanometers. You will need to
create your own base units for daltons and amount in molecules.

>
> Perhaps I am being too picky, because I can build up a molecular
> dynamics
> scale units system if I explicitly create every base_unit myself.
> But I
> would like to take maximum advantage of the SI units infrastructure
> that
> is already available. I suspect that directly using some of the SI
> base_units would be more efficient than the method I am currently
> using,
> which establishes conversion factors to the SI units. Some of these
> conversion
> factors are 1.0 (unity).
>
> Actually, I can directly base the LENGTH dimension on the SI units by
> changing line 27 of Listing 1 from

snip

> So shouldn't I be able to do the same thing for all of the other SI
> units?
> I would have thought so. But doing the same thing for the the TIME
> dimension
> always results in trouble, in my experience. Witness listing 2,
> below.

I would do it this way:

#include <boost/units/conversion.hpp>
#include <boost/units/systems/si.hpp>
#include <iostream>

namespace si = boost::units::si;

namespace md
{
   using boost::units::length_dimension;
   using boost::units::mass_dimension;
   using boost::units::time_dimension;

   using boost::units::quantity;
   using boost::units::unit;
   using boost::units::scaled_base_unit;
   using boost::units::scale;
   using boost::units::static_rational;

   // length
   typedef scaled_base_unit<
           si::meter_base_unit,
           scale<10, static_rational<-9> > > nanometer_base_unit;

   // mass
   struct dalton_base_unit :
      boost::units::base_unit<dalton_base_unit, mass_dimension, 2>
   {
      static std::string name() { return "Dalton"; }
      static std::string symbol() { return "Da"; }
   };

   // time
   typedef scaled_base_unit<
           si::second_base_unit,
           scale<10, static_rational<-12> > > picosecond_base_unit;

   // define quantity types

   typedef nanometer_base_unit::unit_type nanometer_unit;
   BOOST_UNITS_STATIC_CONSTANT(nanometer, nanometer_unit);
   BOOST_UNITS_STATIC_CONSTANT(nanometers, nanometer_unit);
   typedef quantity<nanometer_unit> length_t;

   typedef dalton_base_unit::unit_type dalton_unit;
   BOOST_UNITS_STATIC_CONSTANT(dalton, dalton_unit);
   BOOST_UNITS_STATIC_CONSTANT(daltons, dalton_unit);
   BOOST_UNITS_STATIC_CONSTANT(atomic_mass_unit, dalton_unit);
   BOOST_UNITS_STATIC_CONSTANT(atomic_mass_units, dalton_unit);
   typedef quantity<dalton_unit> mass_t;

   typedef picosecond_base_unit::unit_type picosecond_unit;
   BOOST_UNITS_STATIC_CONSTANT(picosecond, picosecond_unit);
   BOOST_UNITS_STATIC_CONSTANT(picoseconds, picosecond_unit);
   typedef quantity<picosecond_unit> time_t;

} // namespace md

// mass conversions
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(
       md::dalton_base_unit,
       si::kilogram_base_unit,
       double, 1.6605388628e-27);

using namespace md;
using namespace std;

int main ()
{
   md::time_t timeStep = 0.002 * picoseconds;
   cout << "time step = " << timeStep << endl;

   mass_t carbonMass = 12.0 * daltons;
   cout << "carbon mass = " << carbonMass << endl;

   length_t bondLength = 0.15 * nanometers;
   cout << "bond length = " << bondLength << endl;

   // nonsense, but exercises composite dimensions
   cout << "composite value = " << timeStep * bondLength << endl;

   return 0;
}

This code compiles and runs correctly, giving:

time step = 0.002 ps
carbon mass = 12 Da
bond length = 0.15 nm
composite value = 0.0003 nm ps

In general, it's easiest to avoid explicitly creating unit systems by
using the ::unit_type approach. For most cases, the unit system ought
to be considered an implementation detail since the library supports
heterogeneous units transparently. That is, for any given unit, the
appropriate system is just the set of units needed to fully describe
the unit itself...

Matthias



Boost-users list run by williamkempf at hotmail.com, kalb at libertysoft.com, bjorn.karlsson at readsoft.com, gregod at cs.rpi.edu, wekempf at cox.net