1 // Written in the D programming language 2 /++ 3 This module defines the SI units and prefixes. 4 5 All the quantities and units defined in this module store a value 6 of type double intenally. So the predefined parsers can only parse 7 double values. 8 9 Copyright: Copyright 2013-2014, Nicolas Sicard 10 Authors: Nicolas Sicard 11 License: $(LINK www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 12 Standards: $(LINK http://www.bipm.org/en/si/si_brochure/) 13 Source: $(LINK https://github.com/biozic/quantities) 14 +/ 15 module quantities.si; 16 17 import quantities.base; 18 import quantities.math; 19 import quantities.parsing; 20 import std.conv; 21 import std.math : PI; 22 import std.typetuple; 23 import core.time : Duration, dur; 24 25 version (unittest) import std.math : approxEqual; 26 27 /++ 28 Predefined SI units. 29 +/ 30 enum meter = unit!(double, "L"); 31 alias metre = meter; /// ditto 32 enum kilogram = unit!(double, "M"); /// ditto 33 enum second = unit!(double, "T"); /// ditto 34 enum ampere = unit!(double, "I"); /// ditto 35 enum kelvin = unit!(double, "Θ"); /// ditto 36 enum mole = unit!(double, "N"); /// ditto 37 enum candela = unit!(double, "J"); /// ditto 38 39 enum radian = meter / meter; // ditto 40 enum steradian = square(meter) / square(meter); /// ditto 41 enum hertz = 1 / second; /// ditto 42 enum newton = kilogram * meter / square(second); /// ditto 43 enum pascal = newton / square(meter); /// ditto 44 enum joule = newton * meter; /// ditto 45 enum watt = joule / second; /// ditto 46 enum coulomb = second * ampere; /// ditto 47 enum volt = watt / ampere; /// ditto 48 enum farad = coulomb / volt; /// ditto 49 enum ohm = volt / ampere; /// ditto 50 enum siemens = ampere / volt; /// ditto 51 enum weber = volt * second; /// ditto 52 enum tesla = weber / square(meter); /// ditto 53 enum henry = weber / ampere; /// ditto 54 enum celsius = kelvin; /// ditto 55 enum lumen = candela / steradian; /// ditto 56 enum lux = lumen / square(meter); /// ditto 57 enum becquerel = 1 / second; /// ditto 58 enum gray = joule / kilogram; /// ditto 59 enum sievert = joule / kilogram; /// ditto 60 enum katal = mole / second; /// ditto 61 62 enum gram = 1e-3 * kilogram; /// ditto 63 enum minute = 60 * second; /// ditto 64 enum hour = 60 * minute; /// ditto 65 enum day = 24 * hour; /// ditto 66 enum degreeOfAngle = PI / 180 * radian; /// ditto 67 enum minuteOfAngle = degreeOfAngle / 60; /// ditto 68 enum secondOfAngle = minuteOfAngle / 60; /// ditto 69 enum hectare = 1e4 * square(meter); /// ditto 70 enum liter = 1e-3 * cubic(meter); /// ditto 71 alias litre = liter; /// ditto 72 enum ton = 1e3 * kilogram; /// ditto 73 enum electronVolt = 1.60217653e-19 * joule; /// ditto 74 enum dalton = 1.66053886e-27 * kilogram; /// ditto 75 76 enum one = Quantity!double(1); /// The dimensionless unit 'one' 77 78 alias Length = typeof(meter); /// Predefined quantity type templates for SI quantities 79 alias Mass = typeof(kilogram); /// ditto 80 alias Time = typeof(second); /// ditto 81 alias ElectricCurrent = typeof(ampere); /// ditto 82 alias Temperature = typeof(kelvin); /// ditto 83 alias AmountOfSubstance = typeof(mole); /// ditto 84 alias LuminousIntensity = typeof(candela); /// ditto 85 86 alias Area = typeof(square(meter)); /// ditto 87 alias Surface = Area; 88 alias Volume = typeof(cubic(meter)); /// ditto 89 alias Speed = typeof(meter/second); /// ditto 90 alias Acceleration = typeof(meter/square(second)); /// ditto 91 alias MassDensity = typeof(kilogram/cubic(meter)); /// ditto 92 alias CurrentDensity = typeof(ampere/square(meter)); /// ditto 93 alias MagneticFieldStrength = typeof(ampere/meter); /// ditto 94 alias Concentration = typeof(mole/cubic(meter)); /// ditto 95 alias MolarConcentration = Concentration; /// ditto 96 alias MassicConcentration = typeof(kilogram/cubic(meter)); /// ditto 97 alias Luminance = typeof(candela/square(meter)); /// ditto 98 alias RefractiveIndex = typeof(kilogram); /// ditto 99 100 alias Angle = typeof(radian); /// ditto 101 alias SolidAngle = typeof(steradian); /// ditto 102 alias Frequency = typeof(hertz); /// ditto 103 alias Force = typeof(newton); /// ditto 104 alias Pressure = typeof(pascal); /// ditto 105 alias Energy = typeof(joule); /// ditto 106 alias Work = Energy; /// ditto 107 alias Heat = Energy; /// ditto 108 alias Power = typeof(watt); /// ditto 109 alias ElectricCharge = typeof(coulomb); /// ditto 110 alias ElectricPotential = typeof(volt); /// ditto 111 alias Capacitance = typeof(farad); /// ditto 112 alias ElectricResistance = typeof(ohm); /// ditto 113 alias ElectricConductance = typeof(siemens); /// ditto 114 alias MagneticFlux = typeof(weber); /// ditto 115 alias MagneticFluxDensity = typeof(tesla); /// ditto 116 alias Inductance = typeof(henry); /// ditto 117 alias LuminousFlux = typeof(lumen); /// ditto 118 alias Illuminance = typeof(lux); /// ditto 119 alias CelsiusTemperature = typeof(celsius); /// ditto 120 alias Radioactivity = typeof(becquerel); /// ditto 121 alias AbsorbedDose = typeof(gray); /// ditto 122 alias DoseEquivalent = typeof(sievert); /// ditto 123 alias CatalyticActivity = typeof(katal); /// ditto 124 125 alias Dimensionless = typeof(meter/meter); /// The type of dimensionless quantities 126 127 /// SI prefixes. 128 alias yotta = prefix!1e24; 129 alias zetta = prefix!1e21; /// ditto 130 alias exa = prefix!1e18; /// ditto 131 alias peta = prefix!1e15; /// ditto 132 alias tera = prefix!1e12; /// ditto 133 alias giga = prefix!1e9; /// ditto 134 alias mega = prefix!1e6; /// ditto 135 alias kilo = prefix!1e3; /// ditto 136 alias hecto = prefix!1e2; /// ditto 137 alias deca = prefix!1e1; /// ditto 138 alias deci = prefix!1e-1; /// ditto 139 alias centi = prefix!1e-2; /// ditto 140 alias milli = prefix!1e-3; /// ditto 141 alias micro = prefix!1e-6; /// ditto 142 alias nano = prefix!1e-9; /// ditto 143 alias pico = prefix!1e-12; /// ditto 144 alias femto = prefix!1e-15; /// ditto 145 alias atto = prefix!1e-18; /// ditto 146 alias zepto = prefix!1e-21; /// ditto 147 alias yocto = prefix!1e-24; /// ditto 148 149 private alias siSymbolTuple = TypeTuple!( 150 withUnit("m", meter), 151 withUnit("kg", kilogram), 152 withUnit("s", second), 153 withUnit("A", ampere), 154 withUnit("K", kelvin), 155 withUnit("mol", mole), 156 withUnit("cd", candela), 157 withUnit("rad", radian), 158 withUnit("sr", steradian), 159 withUnit("Hz", hertz), 160 withUnit("N", newton), 161 withUnit("Pa", pascal), 162 withUnit("J", joule), 163 withUnit("W", watt), 164 withUnit("C", coulomb), 165 withUnit("V", volt), 166 withUnit("F", farad), 167 withUnit("Ω", ohm), 168 withUnit("S", siemens), 169 withUnit("Wb", weber), 170 withUnit("T", tesla), 171 withUnit("H", henry), 172 withUnit("lm", lumen), 173 withUnit("lx", lux), 174 withUnit("Bq", becquerel), 175 withUnit("Gy", gray), 176 withUnit("Sv", sievert), 177 withUnit("kat", katal), 178 withUnit("g", gram), 179 withUnit("min", minute), 180 withUnit("h", hour), 181 withUnit("d", day), 182 withUnit("l", liter), 183 withUnit("L", liter), 184 withUnit("t", ton), 185 withUnit("eV", electronVolt), 186 withUnit("Da", dalton), 187 withPrefix("Y", 1e24), 188 withPrefix("Z", 1e21), 189 withPrefix("E", 1e18), 190 withPrefix("P", 1e15), 191 withPrefix("T", 1e12), 192 withPrefix("G", 1e9), 193 withPrefix("M", 1e6), 194 withPrefix("k", 1e3), 195 withPrefix("h", 1e2), 196 withPrefix("da", 1e1), 197 withPrefix("d", 1e-1), 198 withPrefix("c", 1e-2), 199 withPrefix("m", 1e-3), 200 withPrefix("µ", 1e-6), 201 withPrefix("n", 1e-9), 202 withPrefix("p", 1e-12), 203 withPrefix("f", 1e-15), 204 withPrefix("a", 1e-18), 205 withPrefix("z", 1e-21), 206 withPrefix("y", 1e-24), 207 withPrefix("Yi", 1024.0^^8), 208 withPrefix("Zi", 1024.0^^7), 209 withPrefix("Ei", 1024.0^^6), 210 withPrefix("Pi", 1024.0^^5), 211 withPrefix("Ti", 1024.0^^4), 212 withPrefix("Gi", 1024.0^^3), 213 withPrefix("Mi", 1024.0^^2), 214 withPrefix("Ki", 1024.0) 215 ); 216 217 enum _siSymbolList = makeSymbolList!double(siSymbolTuple); 218 static __gshared SymbolList!double siSymbolList; 219 shared static this() 220 { 221 siSymbolList = _siSymbolList; 222 } 223 224 /// Creates a function that parses a string for a SI unit or quantity at runtime. 225 alias parseSI = rtQuantityParser!(double, siSymbolList); 226 /// 227 unittest 228 { 229 auto t = parseSI!Time("90 min"); 230 assert(t == 90 * minute); 231 t = parseSI!Time("h"); 232 assert(t == 1 * hour); 233 } 234 235 unittest 236 { 237 auto v = parseSI!Dimensionless("2"); 238 assert(v == (2 * meter) / meter); 239 } 240 241 /// Creates a function that parses a string for a SI unit or quantity at compile-time. 242 alias si = ctQuantityParser!(double, _siSymbolList, std.conv.parse!(double, string)); 243 /// 244 unittest 245 { 246 enum min = si!"min"; 247 enum inch = si!"2.54 cm"; 248 249 auto conc = si!"1 µmol/L"; 250 auto speed = si!"m s^-1"; 251 auto value = si!"0.5"; 252 253 static assert(is(typeof(conc) == Concentration)); 254 static assert(is(typeof(speed) == Speed)); 255 static assert(is(typeof(value) == Dimensionless)); 256 } 257 258 /++ 259 Helper template that can be used to add all SI units and prefixes when 260 building a symbol list with makeSymbolList. 261 +/ 262 alias withAllSI = siSymbolTuple; 263 264 /// Converts a quantity of time to or from a core.time.Duration 265 Time fromDuration(Duration d) 266 { 267 return d.total!"hnsecs" * hecto(nano(second)); 268 } 269 270 /// ditto 271 Duration toDuration(Q)(Q quantity) 272 if (isQuantity!Q) 273 { 274 import std.conv; 275 auto hns = quantity.value(hecto(nano(second))); 276 return dur!"hnsecs"(roundTo!long(hns)); 277 } 278 279 static if (__VERSION__ <= 2065) // Deprecation of Duration.get 280 { 281 unittest // Durations 282 { 283 auto d = 4.dur!"msecs"; 284 auto t = fromDuration(d); 285 assert(t.value(milli(second)).approxEqual(4)); 286 287 auto t2 = 3.5 * minute; 288 auto d2 = t2.toDuration; 289 assert(d2.get!"minutes" == 3); 290 assert(d2.get!"seconds" == 30); 291 } 292 } 293 else 294 { 295 unittest // Durations 296 { 297 auto d = 4.dur!"msecs"; 298 auto t = fromDuration(d); 299 assert(t.value(milli(second)).approxEqual(4)); 300 301 auto t2 = 3.5 * minute; 302 auto d2 = t2.toDuration; 303 auto s = d2.split!("minutes", "seconds")(); 304 assert(s.minutes == 3 && s.seconds == 30); 305 } 306 }