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