/** * \file Unit.h \brief Classes to help with converting between units. * * Copyright 2007-2013 IMP Inventors. All rights reserved. * */ #ifndef IMPKERNEL_UNIT_H #define IMPKERNEL_UNIT_H #include "ExponentialNumber.h" #include "../utility.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // what is wrong with argment-dependent lookup? #ifdef _MSC_VER #pragma warning (disable : 4675) #endif IMPKERNEL_BEGIN_NAMESPACE namespace internal { namespace unit { namespace internal { template inline std::string get_unit_name(int) { return ""; } // for stupid line length limits using boost::mpl::transform; using boost::mpl::minus; using boost::mpl::plus; using boost::mpl::divides; using boost::mpl::multiplies; using boost::mpl::int_; using boost::mpl::vector_c; using boost::mpl::at; namespace pl= boost::mpl::placeholders; /* These classes allow the Units part of a unit to be manipulated */ template struct Divide { typedef typename transform >::type type; }; template struct Inverse { typedef typename transform, pl::_1> >::type type; }; template struct Multiply { typedef typename transform >::type type; }; template struct Sqrt { typedef typename transform > >::type type; }; template struct Exponentiate { typedef typename transform >::type type; }; template struct DoNormalize { typedef int type; }; /* The boost MPI multiply sorts of routines return a slightly different type that we want so we have to change it into the exact type to get certain things to work right. */ template struct DoNormalize { typedef vector_c type; }; template struct DoNormalize { typedef vector_c >::type::value> type; }; template struct DoNormalize { typedef vector_c >::type::value, at >::type::value> type; }; template struct DoNormalize { typedef vector_c >::type::value, at >::type::value, at >::type::value> type; }; template struct DoNormalize { typedef vector_c >::type::value, at >::type::value, at >::type::value, at >::type::value> type; }; template struct DoNormalize { typedef vector_c >::type::value, at >::type::value, at >::type::value, at >::type::value, at >::type::value> type; }; template struct Normalize { typedef typename DoNormalize::type::value > ::type type; }; // Recursive type to print out the unit names and powers template struct PrintUnits { PrintUnits p_; void operator()(std::ostream &out) const { std::string str= get_unit_name(O); int e= boost::mpl::at >::type::value; if (e != 0) { out << " " << str; if (e != 1) { out << "^" << e; } } p_(out); } }; //! \internal Terminate the recursion template struct PrintUnits { void operator()(std::ostream &) const{}; }; //! \internal Specializaton for singleton units template struct PrintUnits > { void operator()(std::ostream &out) const { std::string str= get_unit_name(O); out << " " << str; } }; // recursive type to check if all the unit powers are zero template struct IsNoUnits { typedef IsNoUnits Next; static const bool value= Next::value && !(boost::mpl::at >::type::value); }; template struct IsNoUnits { static const bool value =true; }; } // namespace unit::internal //! \internal A base class for units template class Unit { template friend class Unit; typedef Unit This; typedef ExponentialNumber V; V v_; bool is_default() const { return v_== V(); } public: typedef TagT Tag; typedef UnitsT Units; static const int EXP= EXPT; explicit Unit(V v): v_(v){} explicit Unit(double v): v_(v){} //Unit(int v): v_(v){} Unit(){} template Unit(Unit o): v_(o.v_) { BOOST_STATIC_ASSERT(( boost::mpl::equal::type::value )); } template Unit(Unit o): v_(o.v_) {} operator double() const { BOOST_STATIC_ASSERT((internal::IsNoUnits<0, boost::mpl::size::type::value, Units>::value)); return v_.get_normalized_value(); } IMP_COMPARISONS_1(Unit, v_); #ifndef IMP_DOXYGEN //! Get the current value /** \note The value returned is the value before it is multiplied by the appropriate power of 10. That means, 1 Angstrom returns 1, as does 1 Meter. */ double get_value() const { return v_.get_value(); } V get_exponential_value() const { return v_; } #endif This operator+(This o) const { return This(v_+o.v_); } This operator-(This o) const { return This(v_-o.v_); } This operator-() const { return This(-v_); } void show(std::ostream &out) const { out << v_; internal::PrintUnits::type::value, Units> p; p(out); } }; template inline std::ostream &operator<<(std::ostream &out, Unit o) { o.show(out); return out; } // Multiply and divide Unit instantiations template struct Divide { BOOST_STATIC_ASSERT((boost::mpl::equal::type::value)); typedef typename internal::Divide::type raw_units; typedef typename internal::Normalize::type units; typedef Unit type; }; template struct Multiply { BOOST_STATIC_ASSERT((boost::mpl::equal::type::value)); typedef typename internal::Multiply::type raw_units; typedef typename internal::Normalize::type units; typedef Unit type; }; template struct Inverse { typedef typename internal::Inverse::type raw_units; typedef typename internal::Normalize::type units; typedef Unit type; }; template struct Shift { typedef Unit type; }; template struct Exchange { BOOST_STATIC_ASSERT((boost::mpl::equal::type::value)); BOOST_STATIC_ASSERT((boost::mpl::equal::type::value)); typedef typename internal::Divide::type Div; typedef typename internal::Multiply::type Mul; typedef typename internal::Normalize::type units; typedef Unit type; }; typedef boost::mpl::vector_c SingletonUnit; /** \internal need to be careful of integer division */ template inline Unit::type > sqrt(Unit o) { return Unit::type > (ExponentialNumber(std::sqrt(o.get_value()))); } /** \internal */ template inline typename Multiply , Unit >::type square(Unit o) { return typename Multiply , Unit >::type (::IMP::algebra::get_squared(o.get_value())); } template inline Unit operator*(Unit o, double d) { return Unit(d*o.get_value()); } template inline Unit operator*(double d, Unit o) { return Unit(d*o.get_value()); } template inline Unit operator*(int d, Unit o) { return Unit(d*o.get_value()); } template inline typename Multiply, Unit >::type operator*(Unit a, Unit b) { return typename Multiply, Unit >::type(a.get_value()*b.get_value()); } template inline typename Divide, Unit >::type operator/(Unit a, Unit b) { return typename Divide, Unit >::type(a.get_value()/b.get_value()); } template inline Unit operator/(Unit o, double d) { return Unit(o.get_value()/d); } template inline typename Inverse >::type operator/(double d, Unit o) { return typename Inverse >::type(d/o.get_value()); } template inline Unit operator/(Unit u, ExponentialNumber o) { return Unit(u.get_exponential_value()/o); } template inline Unit::type>::type> operator/(ExponentialNumber o, Unit u) { return Unit::type>:: type> (o/u.get_exponential_value()); } } // namespace unit } // namespace internal IMPKERNEL_END_NAMESPACE #endif /* IMPKERNEL_UNIT_H */