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