00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #ifndef UNITS_H
00026 #define UNITS_H
00027
00028 #include "config.h"
00029 #include "isinfnan.h"
00030 #include "measurement.h"
00031
00032 #include <iostream>
00033 #include <sstream>
00034 #include <cmath>
00035 #include <stdexcept>
00036
00037 #define UNITS_ALLOW_CAST_TO_DOUBLE
00038
00039 #define UNITS_ALLOW_GET_RAW_VALUE
00040
00041 #define CHECK_UNITS
00042
00043
00044
00045
00046
00048
00076 template< int M ,int L=0 ,int T=0 ,int K=0 ,int I=0 >
00077 class Units {
00078
00079 public:
00080
00081 Units():d_val(1.0){}
00082 Units( const Units& u ):d_val( u.d_val ){}
00083
00084 Units(const Measurement &m);
00085 operator Measurement() const;
00086
00087 const Units& operator=( const Units& u ){ d_val=u.d_val; return *this; }
00088
00089
00090 Units operator*( const double d ) const { Units u; u.d_val=d_val*d; return u; }
00091 Units operator/( const double d ) const { Units u; u.d_val=d_val/d; return u; }
00092
00093
00094
00095
00096
00097 const Units& operator*=( const double d ) { d_val*=d; return *this; }
00098 const Units& operator/=( const double d ) { d_val/=d; return *this; }
00099
00100
00101 Units operator+( const Units& u ) const { Units v; v.d_val=d_val+u.d_val; return v; }
00102 Units operator-( const Units& u ) const { Units v; v.d_val=d_val-u.d_val; return v; }
00103 Units& operator+=( const Units& u ) { d_val+=u.d_val; return *this; }
00104 Units& operator-=( const Units& u ) { d_val-=u.d_val; return *this; }
00105 Units operator-() const { Units u; u.d_val=-d_val; return u; }
00106
00107
00108 bool operator==( const Units& u ) const { return d_val==u.d_val; }
00109 bool operator!=( const Units& u ) const { return d_val!=u.d_val; }
00110 bool operator< ( const Units& u ) const { return d_val< u.d_val; }
00111 bool operator<=( const Units& u ) const { return d_val<=u.d_val; }
00112 bool operator> ( const Units& u ) const { return d_val> u.d_val; }
00113 bool operator>=( const Units& u ) const { return d_val>=u.d_val; }
00114
00115
00116 #ifndef UNITS_CAST_THROW
00117 # ifdef UNITS_ALLOW_CAST_TO_DOUBLE
00118 inline operator double() const;
00119 # endif
00120 #else
00121
00125 inline operator double() const {
00126 throw new std::runtime_error("Invalid cast to double!");
00127 }
00128 #endif
00129
00130 #ifdef UNITS_ALLOW_GET_RAW_VALUE
00131 inline double getRawValue() const{
00132 return d_val;
00133 }
00134 #endif
00135
00137
00140 template< int m, int l, int t, int k, int i >
00141 Units<M-m,L-l,T-t,K-k,I-i>
00142 operator/( const Units<m,l,t,k,i>& u2 ) const {
00143
00144 Units<(M-m),(L-l),(T-t),(K-k),(I-i)> r;
00145 *reinterpret_cast<double*>(&r) = d_val/ *reinterpret_cast<const double*>(&u2);
00146 return r;
00147 }
00148
00150
00157 template<int n>
00158 Units<M*n,L*n,T*n,K*n,I*n>
00159 ipow() const{
00160 Units<M*n,L*n,T*n,K*n,I*n> r;
00161 *reinterpret_cast<double*>(&r) = pow(double(d_val),n);
00162 return r;
00163 }
00164
00166
00173 static inline Units
00174 sqrt(const Units <2*M,2*L,2*T,2*K,2*I> u) {
00175 Units r;
00176 double n = (*reinterpret_cast<const double*>(&u));
00177 *reinterpret_cast<double*>(&r) = std::sqrt(n);
00178 return r;
00179 }
00180
00181 private:
00182
00183
00184 double d_val;
00185
00186
00187
00188
00189 };
00190
00191
00193
00196 #ifdef UNITS_ALLOW_CAST_TO_DOUBLE
00197 template<>
00198 inline Units<0,0,0,0,0>::operator double() const {
00199 return d_val;
00200 }
00201 #endif
00202
00203
00204
00205
00206
00207
00208
00209
00210
00211
00212
00214 template< int m, int l, int t, int k, int i >
00215 inline
00216 Units<m,l,t,k,i>
00217 operator*( const double d, const Units<m,l,t,k,i> &u) {
00218 return u*d;
00219 }
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00232 template< int m, int l, int t, int k,int i >
00233 inline
00234 Units<-m,-l,-t,-k,-i>
00235 operator/( const double d, const Units<m,l,t,k,i>& u) {
00236
00237 Units< -m, -l, -t, -k, -i > r;
00238 *reinterpret_cast<double*>(&r) = d / *reinterpret_cast<const double*>(&u);
00239 return r;
00240 }
00241
00243 template<int M, int L, int T, int K, int I, int m, int l, int t, int k, int i >
00244 Units<M+m,L+l,T+t,K+k,I+i >
00245 operator*(const Units<M,L,T,K,I>& u1, const Units<m,l,t,k,i>& u2 ){
00246 Units<M+m,L+l,T+t,K+k,I+i> r;
00247 *reinterpret_cast<double*>(&r) = *reinterpret_cast<const double*>(&u1) * *reinterpret_cast<const double*>(&u2);
00248 return r;
00249 }
00250
00251
00253
00254
00255
00256
00257
00258
00259
00260
00261
00262
00264 template < int M, int L, int T, int K, int I >
00265 inline
00266 bool
00267 eq(const Units<M,L,T,K,I> &u, const Units<M,L,T,K,I> &v, const Units<M,L,T,K,I> &tol) {
00268 if(fabs(u-v) < tol){
00269 return true;
00270 }
00271 return false;
00272 }
00273
00274
00275 template < int M, int L, int T, int K, int I >
00276 inline
00277 Units<M,L,T,K,I>
00278 fabs(const Units<M,L,T,K,I> u) {
00279 if (*reinterpret_cast<const double*>(&u) < 0) {
00280 Units < M, L, T, K, I > r;
00281 *reinterpret_cast<double*>(&r) = - *reinterpret_cast<const double*>(&u);
00282 return r;
00283 } else {
00284 return u;
00285 }
00286 }
00287
00289 template < int M, int L, int T, int K, int I >
00290 inline Units<2*M, 2*L, 2*T, 2*K, 2*I>
00291 sq(const Units < M, L, T, K, I > u) {
00292 return u*u;
00293 }
00294
00296 template < int M, int L, int T, int K, int I >
00297 inline Units<3*M, 3*L, 3*T, 3*K, 3*I>
00298 cube(const Units < M, L, T, K, I > u) {
00299 return u * u * u;
00300 }
00301
00302
00303
00304 template < int M, int L, int T, int K, int I >
00305 inline bool isnan(const Units<M,L,T,K,I>& u){
00306 return isnan(*reinterpret_cast<const double*>(&u));
00307 }
00308
00309
00310
00311 template < int M, int L, int T, int K, int I >
00312 inline bool isinf(const Units<M,L,T,K,I>& u){
00313 return isinf(*reinterpret_cast<const double*>(&u));
00314 }
00315
00316
00317
00318
00319 #if defined(__GNUC__) && !defined(__STRICT_ANSI__)
00320 # define MAX(X,Y) \
00321 ( { __typeof__ (X) x_ = (X); \
00322 __typeof__ (Y) y_ = (Y); \
00323 (x_ > y_) ? x_ : y_; \
00324 } )
00325 # define MIN(X,Y) \
00326 ( { __typeof__ (X) x_ = (X); \
00327 __typeof__ (Y) y_ = (Y); \
00328 (x_ < y_) ? x_ : y_; \
00329 } )
00330 # define ABS(X) \
00331 ( { __typeof__ (X) x_ = (X); \
00332 (x_ > 0) ? x_ : -x_; \
00333 } )
00334 #else
00335 # define MAX(a,b) ( (a) < (b) ? (b) : (a) )
00336 # define MIN(a,b) ( (a) < (b) ? (a) : (b) )
00337 # define ABS(x) ( ((x) > 0) ? (x) : -(x) )
00338 #endif
00339
00340
00341
00342
00343 template < int m, int l, int t, int k, int i >
00344 inline
00345 std::ostream & operator <<(std::ostream & os, const Units < m,
00346 l, t, k, i > &u) {
00347 double d = *reinterpret_cast<const double*>(&u);
00348 os << d;
00349 os.flags() & std::ios_base::showbase && os << " (dim)";
00350 return os;
00351 }
00352
00353 inline
00354 std::ostream & operator <<(std::ostream & os, const Units < 0,
00355 0, 0, 0, 0 > &u) {
00356 double d = *reinterpret_cast<const double*>(&u);
00357 os << d;
00358 return os;
00359 }
00360
00361 #define DEFINE_OUTPUT_METHOD(MM,LL,TT,KK,II,UNITS) \
00362 inline \
00363 std::ostream& operator <<(std::ostream &os,const Units<MM,LL,TT,KK,II> &u){ \
00364 double d = *reinterpret_cast<const double*>(&u); \
00365 os << d; \
00366 os.flags() & std::ios_base::showbase && os << " " << UNITS; \
00367 return os; \
00368 }
00369
00370 DEFINE_OUTPUT_METHOD( 1, 0, 0, 0, 0, "kg");
00371 DEFINE_OUTPUT_METHOD( 0, 1, 0, 0, 0, "m");
00372 DEFINE_OUTPUT_METHOD( 0, 2, 0, 0, 0, "m²");
00373 DEFINE_OUTPUT_METHOD( 0, 3, 0, 0, 0, "m³");
00374 DEFINE_OUTPUT_METHOD( 1, -1, 0, 0, 0, "kg/m");
00375 DEFINE_OUTPUT_METHOD( 1, -2, 0, 0, 0, "kg/m²");
00376 DEFINE_OUTPUT_METHOD( 1, -3, 0, 0, 0, "kg/m³");
00377 DEFINE_OUTPUT_METHOD(-1, 3, 0, 0, 0, "m³/kg");
00378 DEFINE_OUTPUT_METHOD( 0, 0, 1, 0, 0, "s");
00379 DEFINE_OUTPUT_METHOD( 0, 0, -1, 0, 0, "Hz");
00380 DEFINE_OUTPUT_METHOD( 1, 0, -1, 0, 0, "kg/s");
00381 DEFINE_OUTPUT_METHOD( 1, 0, -3, 0, 0, "W/m²");
00382 DEFINE_OUTPUT_METHOD( 0, 1, -1, 0, 0, "m/s");
00383 DEFINE_OUTPUT_METHOD( 0, 2, -2, 0, 0, "J/kg");
00384 DEFINE_OUTPUT_METHOD( 1, -1, -2, 0, 0, "Pa");
00385 DEFINE_OUTPUT_METHOD( 1, -1, -1, 0, 0, "Pa·s");
00386 DEFINE_OUTPUT_METHOD( 1, 1, -3, 0, 0, "W/m");
00387 DEFINE_OUTPUT_METHOD( 1, 2, -3, 0, 0, "W");
00388 DEFINE_OUTPUT_METHOD( 1, -2, -1, 0, 0, "kg/s/m²");
00389 DEFINE_OUTPUT_METHOD( 0, 0, 0, 1, 0, "K");
00390 DEFINE_OUTPUT_METHOD( 0, 2, -2, -1, 0, "J/kgK");
00391 DEFINE_OUTPUT_METHOD( 1, 1, -3, -1, 0, "W/m/K");
00392
00393
00394
00395
00396 typedef Units < 1 > Mass;
00397 typedef Units < 0, 1 > Length;
00398 typedef Units < 0, 0, 1 > Time;
00399 typedef Units < 0, 0, 0, 1 > Temperature;
00400 typedef Units < 0, 0, 0, 0, 1 > Current;
00401
00402
00403
00404
00405 typedef Units < 0, 2 > Area;
00406 typedef Units < 0, 3 > Volume;
00407
00408 typedef Units < 1, -3 > Density;
00409 typedef Units <-1, 3 > SpecificVolume;
00410
00411 typedef Units < 1, -3, -1> DensityPerTime;
00412
00413 typedef Units < 0, 0, -1> Frequency;
00414
00415 typedef Units < 1, 1, -2 > Force;
00416 typedef Units < 1, -1, -2 > Pressure;
00417 typedef Units < 0, 1, -1 > Velocity;
00418 typedef Units < 0, 1, -2 > Acceleration;
00419 typedef Units < 1, 2, -2 > Torque;
00420 typedef Units < 1, 2, -2 > Energy;
00421 typedef Units < 1, 2, -3 > Power;
00422 typedef Units < 0, 2, -2 > SpecificEnergy;
00423
00424 typedef Units < 1, -1, -1 > DynamicViscosity;
00425 typedef Units < 0, 2, -1 > KinematicViscosity;
00426 typedef Units < 1, 1, -3 > PowerPerLength;
00427 typedef Units < 1, -2, -2 > PressurePerLength;
00428 typedef Units < 1, 0, -2 > ForcePerLength;
00429 typedef Units < 0, 2, -3 > PowerPerMass;
00430
00431 typedef Units < 1, -1, -3 > DensitySpecificEnergyPerTime;
00432
00433 typedef Units < 0, 3, -1 > VolFlowRate;
00434 typedef Units < 1, 0, -1 > MassFlowRate;
00435 typedef Units < 1, -1, -1 > MassFlowRatePerLength;
00436 typedef Units < 1, 0, -2 > MassFlowRatePerTime;
00437
00438 typedef Units < 1, 0, -3 > HeatFlux;
00439 typedef Units < 1, -2, -1 > MassFlux;
00440
00441
00442
00443 typedef Units < 1, 2, -2, -1 > Entropy;
00444 typedef Units < 0, 2, -2, -1 > SpecificEntropy;
00445 typedef Units < 1, 1, -3, -1 > ThermalConductivity;
00446 typedef Units < 1, 0, -3, -1 > HeatTransferCoefficient;
00447 typedef Units <-1, 0, 3, 1 > ThermalResistance;
00448
00449 typedef Units < 1, 1, -2, -1 > HeatCapacityPerLength;
00450 typedef Units < 1, 2, -3, -1 > PowerPerTemperature;
00451
00452 typedef Units < 0, 0, 0, -1 > ThermalExpansionCoefficient;
00453
00454
00455
00456 typedef Units < 0, 0, 1, 0, 1 > Charge;
00457 typedef Units < 1, 2, -3, 0, -1 > ElecPotential;
00458 typedef Units < 1, 2, -4, 0, -2 > Capacitance;
00459 typedef Units < 1, 2, -3, 0, -2 > Resistance;
00460 typedef Units <-1, -2, 3, 0, 2 > Conductance;
00461
00462
00463
00464
00465 const Mass kilogram;
00466 const Length metre;
00467 const Time second;
00468 const Temperature Kelvin;
00469 const Current ampere;
00470
00471
00472
00473
00474 typedef Velocity Speed;
00475 typedef Length Distance;
00476 typedef Energy Heat;
00477 typedef Heat Work;
00478
00479 typedef Power HeatRate;
00480 typedef PowerPerLength HeatRatePerLength;
00481 typedef PowerPerTemperature HeatRatePerTemperature;
00482
00483 typedef Pressure Stress;
00484 typedef HeatTransferCoefficient HTCoeff;
00485 typedef SpecificEntropy SpecificHeatCapacity;
00486 typedef SpecificHeatCapacity SpecHeatCap;
00487 typedef SpecificHeatCapacity SpecificGasConstant;
00488 typedef SpecificGasConstant SpecGasConst;
00489
00490 typedef ForcePerLength SurfaceTension;
00491
00492
00493
00494
00495 const double Tera = 1e12;
00496 const double Giga = 1e9;
00497 const double Mega = 1e6;
00498 const double kilo = 1e3;
00499 const double hecta = 1e2;
00500 const double Deca = 10;
00501 const double deci = 0.1;
00502 const double centi = 1e-2;
00503 const double milli = 1e-3;
00504 const double micro = 1e-6;
00505
00506
00507
00508
00509 const Mass gram = milli * kilogram;
00510 const Mass kg = kilogram;
00511
00512 const Length centimetre = metre / 100.0;
00513 const Length kilometre = 1000.0 * metre;
00514
00515 const Area metre2 = metre * metre;
00516 const Area hectare = (100.0 * metre) * (100.0 * metre);
00517
00518 const Volume metre3 = metre2 * metre;
00519 const Volume litre = milli * metre3;
00520 const Volume centimetre3 =
00521 (centi * metre) * (centi * metre) * (centi * metre);
00522
00523 const Time minute = 60.0 * second;
00524 const Time hour = 60.0 * minute;
00525 const Time day = 24.0 * hour;
00526
00527 const Frequency Hertz = 1.0 / second;
00528
00529 const Force Newton = kilogram * metre / (second * second);
00530
00531 const Pressure Pascal = Newton / (metre * metre);
00532 const Pressure bar = 100.0 * kilo * Pascal;
00533 const Pressure MPa = Mega * Pascal;
00534 const Pressure kPa = kilo * Pascal;
00535 const Energy Joule = Newton * metre;
00536 const Energy kJ = kilo * Joule;
00537 const Energy Btu = 1055.05585262 * Joule;
00538
00539 const Power Watt = Joule / second;
00540
00541 const HeatFlux W_m2 = Watt / metre2;
00542
00543 const double Percent = 1.0 / 100;
00544
00545
00546
00547
00548 const SpecificEnergy kJ_kg = kilo * Joule / kilogram;
00549 const SpecificEnergy J_kg = Joule / kilogram;
00550
00551 const SpecificEntropy kJ_kgK = kilo * Joule / kilogram / Kelvin;
00552 const SpecificEntropy J_kgK = Joule / kilogram / Kelvin;
00553
00554 const HeatTransferCoefficient W_m2K = Watt / metre2 / Kelvin;
00555 const ThermalConductivity W_mK = Watt / metre / Kelvin;
00556 const ThermalConductivity mW_mK = milli * W_mK;
00557 const Density kg_m3 = kilogram / metre3;
00558 const SpecificVolume m3_kg = metre3 / kilogram;
00559
00560 const MassFlowRate kg_s = kilogram / second;
00561 const VolFlowRate m3_s = metre3 / second;
00562
00563 const HeatCapacityPerLength J_mK = Joule / metre / Kelvin;
00564
00565
00566
00567
00568 const ElecPotential volt = Watt / ampere;
00569 const Charge Coulomb = ampere * second;
00570 const Capacitance Farad = volt / Coulomb;
00571 const Resistance Ohm = volt / ampere;
00572
00573
00574
00575
00576 const Temperature Rankin = 0.556 * Kelvin;
00577 const Frequency RPM = 1. / minute;
00578
00579 const Length yard = 0.9144 * metre;
00580 const Length foot = yard / 3.;
00581 const Length inch = foot / 12.;
00582 const Length mile = 1760. * yard;
00583
00584 const Mass lbm = 0.45359237 * kilogram;
00585 const Acceleration grav_accel = 9.80665 * metre / second / second;
00586 const Force lbf = grav_accel * lbm;
00587 const Pressure lbf_in2 = lbf / inch / inch;
00588
00589
00590
00591
00592 const Temperature ZeroCelsius = 273.15 * Kelvin;
00593 const Temperature ZeroFahrenheit = ZeroCelsius - 32.0 * Rankin;
00594
00599 inline double
00600 tocelsius(const Temperature& T){
00601 double d = *reinterpret_cast<const double*>(&T);
00602 return d - 273.15;
00603 }
00604
00610 inline Temperature
00611 fromcelsius(const double &T_C){
00612 return (T_C * Kelvin) + ZeroCelsius;
00613 }
00614
00618 inline double
00619 tofahrenheit(const Temperature &T){
00620 return (T - ZeroFahrenheit) / Rankin;
00621 }
00622
00624
00627 inline Temperature
00628 fromfahrenheit(const double &T_F){
00629 return (T_F * Rankin) + ZeroFahrenheit;
00630 }
00631
00632
00633
00635 const Units<1,0,-3,-4> SIGMA_C = (5.670e-8) * W_m2 /sq(sq(Kelvin));
00636
00637
00638
00639
00640 #define UNITS_CAST_ERROR(M,L,T,K,I,dim) \
00641 "Invalid cast from Measurement <" << dim.m << "," << dim.l << "," << dim.t << "," \
00642 << dim.k << "," << dim.i << "> to Units <" << M << "," << L << "," << T << "," \
00643 << K << "," << I << ">"
00644
00645 template< int M ,int L,int T ,int K,int I >
00646 Units<M,L,T,K,I>::Units(const Measurement &m){
00647 char prob='\0';
00648 if(m.dim.i!=I)prob='I';
00649 if(m.dim.k!=K)prob='K';
00650 if(m.dim.t!=T)prob='T';
00651 if(m.dim.l!=L)prob='L';
00652 if(m.dim.m!=M)prob='M';
00653 if(prob!='\0'){
00654 std::stringstream ss;
00655 ss << UNITS_CAST_ERROR(M,L,T,K,I,m.dim) << ", mismatched " << prob << ".";
00656 throw std::runtime_error(ss.str());
00657 }
00658 d_val = m.value;
00659 }
00660
00664 template<int M,int L,int T,int K,int I>
00665 Units<M,L,T,K,I>::operator Measurement() const{
00666 Measurement m;
00667 m.dim.m=M;
00668 m.dim.l=L;
00669 m.dim.t=T;
00670 m.dim.k=K;
00671 m.dim.i=I;
00672 m.value = d_val;
00673 return m;
00674 }
00675
00676 #endif // UNITS_H
00677