|
Boost Users : |
Subject: [Boost-users] [Units] Molecular units base_units trouble: please help
From: Christopher Bruns (cmbruns_at_[hidden])
Date: 2009-01-03 20:39:34
I am using the Boost Units library to support molecule scale
dynamic simulations, but I am pretty sure I am using Boost
Units wrong. I am looking for some guidance and
explanations for some confusing compile errors I get (see below).
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]
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).
Listing 1 shows a stripped down example using three base_units: mass,
length, and time. This program compiles and runs, but notice the
conversion factors of 1.0 in the BOOST_UNITS_DEFINE_CONVERSION_FACTOR
macros toward the end.
Listing 1: Compiles and runs, but I had to explicitly create every base_unit.
THIS PROGRAM WORKS -- LOOK FARTHER DOWN FOR THE ONE THAT FAILS
*** BEGIN LISTING 1 ***
#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
struct meter_base_unit :
boost::units::base_unit<meter_base_unit, length_dimension, 1>
{
static std::string name() { return "meter"; }
static std::string symbol() { return "m"; }
};
typedef scaled_base_unit<
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
struct second_base_unit :
boost::units::base_unit<second_base_unit, time_dimension, 3>
{
static std::string name() { return "second"; }
static std::string symbol() { return "s"; }
};
typedef scaled_base_unit<
second_base_unit,
scale<10, static_rational<-12> >
> picosecond_base_unit;
// create the units system
typedef boost::units::make_system<
nanometer_base_unit,
dalton_base_unit,
picosecond_base_unit
>::type md_units_system;
// define quantity types
typedef unit<length_dimension, md_units_system> nanometer_unit;
BOOST_UNITS_STATIC_CONSTANT(nanometer, nanometer_unit);
BOOST_UNITS_STATIC_CONSTANT(nanometers, nanometer_unit);
typedef quantity<nanometer_unit> length_t;
typedef unit<mass_dimension, md_units_system> 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 unit<time_dimension, md_units_system> picosecond_unit;
BOOST_UNITS_STATIC_CONSTANT(picosecond, picosecond_unit);
BOOST_UNITS_STATIC_CONSTANT(picoseconds, picosecond_unit);
typedef quantity<picosecond_unit> time_t;
} // namespace md
// length conversions
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(
md::meter_base_unit,
si::meter_base_unit,
double, 1.0);
// mass conversions
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(
md::dalton_base_unit,
si::kilogram_base_unit,
double, 1.6605388628e-27);
// time conversions
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(
md::second_base_unit,
si::second_base_unit,
double, 1.0);
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;
}
*** END LISTING 1 ***
Actually, I can directly base the LENGTH dimension on the SI units by
changing line 27 of Listing 1 from
26: typedef scaled_base_unit<
27: meter_base_unit,
28: scale<10, static_rational<-9> >
29: > nanometer_base_unit;
to
26: typedef scaled_base_unit<
27: si::meter_base_unit, // <== note si prefix
28: scale<10, static_rational<-9> >
29: > nanometer_base_unit;
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.
Listing 2: Fails to compile; lots of indecipherable template errors.
Time dimension is based on si::second_base_unit.
THIS PROGRAM FAILS TO COMPILE
*** BEGIN LISTING 2 ***
#include <boost/units/conversion.hpp>
#include <boost/units/systems/si.hpp>
#include <iostream>
namespace si = boost::units::si;
namespace md
{
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;
// mass
struct dalton_base_unit :
boost::units::base_unit<dalton_base_unit, mass_dimension, 1>
{
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;
// create the units system
typedef boost::units::make_system<
dalton_base_unit,
picosecond_base_unit
>::type md_units_system;
// define quantity types
typedef unit<mass_dimension, md_units_system> 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 unit<time_dimension, md_units_system> 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;
// nonsense, but exercises composite dimensions
cout << "composite value = " << timeStep * carbonMass << endl;
return 0;
}
*** END LISTING 2 ***
One way to get listing 2 to compile and run is to change line 20 from
19: struct dalton_base_unit :
20: boost::units::base_unit<dalton_base_unit, mass_dimension, 1>
to
19: struct dalton_base_unit :
20: boost::units::base_unit<dalton_base_unit, mass_dimension, -1000> // <==
The program compiles when I use a large negative value for the
base_unit id. But the documentation states that negative values are reserved.
I am a bad boy for even trying. In any case, that "-1000" trick only
works when
the TIME dimension is the only dimension that is directly based on SI units.
ERROR MESSAGES FROM LISTING 2:
**** small sample of the top of the compile errors I get with
unmodified Listing 2: ****
1>C:\cygwin\home\Christopher\svn\dnamodel\include\boost/units/detail/linear_algebra.hpp(207)
: error C2976: 'boost::units::detail::determine_extra_equations_skip_zeros_impl<true,true>::apply'
: too few template arguments
1> C:\cygwin\home\Christopher\svn\dnamodel\include\boost/units/detail/linear_algebra.hpp(217)
: see declaration of
'boost::units::detail::determine_extra_equations_skip_zeros_impl<true,true>::apply'
1> C:\cygwin\home\Christopher\svn\dnamodel\include\boost/units/detail/linear_algebra.hpp(259)
: see reference to class template instantiation
'boost::units::detail::determine_extra_equations_skip_zeros_impl<true,false>::apply<RowsBegin,RemainingRows,CurrentColumn,TotalColumns,Result>'
being compiled
1> with
1> [
1> RowsBegin=boost::units::list<boost::units::list<boost::units::detail::calculate_base_dimension_coefficients_func<false>::apply<boost::units::list<boost::units::dim<boost::units::time_base_dimension,boost::units::static_rational<1>>,boost::units::dimensionless_type>>::type,boost::units::list<boost::units::static_rational<1>,boost::units::detail::expand_dimensions<0>::apply<boost::units::dimensionless_type,boost::units::dimensionless_type>::type>>,boost::units::list<boost::units::list<boost::units::static_rational<1>,boost::units::list<boost::units::detail::calculate_base_dimension_coefficients_func<false>::apply<boost::units::dimensionless_type>::type,boost::units::detail::expand_dimensions<0>::apply<boost::units::dimensionless_type,boost::units::dimensionless_type>::type>>,boost::units::dimensionless_type>>,
1> RemainingRows=2,
1> CurrentColumn=0,
1> TotalColumns=2,
1> Result=boost::units::list<boost::units::list<boost::units::detail::calculate_base_dimension_coefficients_func<false>::apply<boost::units::list<boost::units::dim<boost::units::time_base_dimension,boost::units::static_rational<1>>,boost::units::dimensionless_type>>::type,boost::units::list<boost::units::static_rational<1>,boost::units::detail::expand_dimensions<0>::apply<boost::units::dimensionless_type,boost::units::dimensionless_type>::type>>,boost::units::list<boost::units::list<boost::units::static_rational<1>,boost::units::list<boost::units::detail::calculate_base_dimension_coefficients_func<false>::apply<boost::units::dimensionless_type>::type,boost::units::detail::expand_dimensions<0>::apply<boost::units::dimensionless_type,boost::units::dimensionless_type>::type>>,boost::units::dimensionless_type>>
1> ]
1> C:\cygwin\home\Christopher\svn\dnamodel\include\boost/units/detail/linear_algebra.hpp(538)
: see reference to class template instantiation
'boost::units::detail::determine_extra_equations<RemainingColumns,is_done>::apply<RowsBegin,TotalColumns,Result>'
being compiled
1> with
1> [
1> RemainingColumns=2,
1> is_done=false,
1> RowsBegin=boost::units::list<boost::units::list<boost::units::detail::calculate_base_dimension_coefficients_func<false>::apply<boost::units::list<boost::units::dim<boost::units::time_base_dimension,boost::units::static_rational<1>>,boost::units::dimensionless_type>>::type,boost::units::list<boost::units::static_rational<1>,boost::units::detail::expand_dimensions<0>::apply<boost::units::dimensionless_type,boost::units::dimensionless_type>::type>>,boost::units::list<boost::units::list<boost::units::static_rational<1>,boost::units::list<boost::units::detail::calculate_base_dimension_coefficients_func<false>::apply<boost::units::dimensionless_type>::type,boost::units::detail::expand_dimensions<0>::apply<boost::units::dimensionless_type,boost::units::dimensionless_type>::type>>,boost::units::dimensionless_type>>,
1> TotalColumns=2,
1> Result=boost::units::list<boost::units::list<boost::units::detail::calculate_base_dimension_coefficients_func<false>::apply<boost::units::list<boost::units::dim<boost::units::time_base_dimension,boost::units::static_rational<1>>,boost::units::dimensionless_type>>::type,boost::units::list<boost::units::static_rational<1>,boost::units::detail::expand_dimensions<0>::apply<boost::units::dimensionless_type,boost::units::dimensionless_type>::type>>,boost::units::list<boost::units::list<boost::units::static_rational<1>,boost::units::list<boost::units::detail::calculate_base_dimension_coefficients_func<false>::apply<boost::units::dimensionless_type>::type,boost::units::detail::expand_dimensions<0>::apply<boost::units::dimensionless_type,boost::units::dimensionless_type>::type>>,boost::units::dimensionless_type>>
1> ]
1> C:\cygwin\home\Christopher\svn\dnamodel\include\boost/units/detail/linear_algebra.hpp(828)
: see reference to class template instantiation
'boost::units::detail::make_square_and_invert<Matrix>' being compiled
1> with
1> [
1> Matrix=boost::units::list<boost::units::list<boost::units::detail::calculate_base_dimension_coefficients_func<false>::apply<boost::units::list<boost::units::dim<boost::units::time_base_dimension,boost::units::static_rational<1>>,boost::units::dimensionless_type>>::type,boost::units::list<boost::units::static_rational<1>,boost::units::detail::expand_dimensions<0>::apply<boost::units::dimensionless_type,boost::units::dimensionless_type>::type>>,boost::units::list<boost::units::list<boost::units::static_rational<1>,boost::units::list<boost::units::detail::calculate_base_dimension_coefficients_func<false>::apply<boost::units::dimensionless_type>::type,boost::units::detail::expand_dimensions<0>::apply<boost::units::dimensionless_type,boost::units::dimensionless_type>::type>>,boost::units::dimensionless_type>>
1> ]
1> C:\cygwin\home\Christopher\svn\dnamodel\include\boost/units/detail/linear_algebra.hpp(1032)
: see reference to class template instantiation
'boost::units::detail::normalize_units<T>' being compiled
1> with
1> [
1> T=boost::units::list<boost::units::scaled_base_unit<boost::units::si::second_base_unit,boost::units::scale<10,boost::units::static_rational<-12>>>,boost::units::list<md::dalton_base_unit,boost::units::dimensionless_type>>
1> ]
[snip]
****** END snippet of compile errors *********
Environment details:
I am developing in Visual Studio Express 9.0 on Windows XP at the moment. The
version of boost::units I am using is from subversion on January 3, 2009.
I would feel better if I could reuse several of the base_units from
SI. Just reusing length and not the others seems painfully sloppy.
I welcome any comments that might nudge me in the right direction.
Thanks in advance for any help.
--Chris Bruns
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