root/trunk/units/si2.d

Revision 689, 17.1 kB (checked in by BCS, 7 months ago)

implemented switching to full 7 SI units
added version statement to demonstrate bug in DMD 2.039

Line 
1 /************************
2 Author: Benjamin Shropshire
3
4 This is a unit bearing type that handles unit conversion and uses compile time
5 checks to protect against errors like adding distance and time value.
6 ************************/
7
8
9
10 import std.stdio;
11 import std.math;
12 import std.traits;
13
14 import rational;
15
16 version(FullSI)
17 {
18     template SI(int LengthN, int MassN, int TimeN, int TempN, int CurrentN, int MoleN, int LumiN, T = real)
19     {
20         alias SIB!(LengthN, 1, MassN, 1, TimeN, 1, TempN, 1, CurrentN, 1, MoleN, 1, LumiN, 1, T) SI;
21     }
22     template SI(
23                 int LengthN,  int LengthD,
24                 int MassN,    int MassD,
25                 int TimeN,    int TimeD,
26                 int TempN,    int TempD,
27                 int CurrentN, int CurrentD,
28                 int MoleN,    int MoleD,
29                 int LuminN,   int LuminD,
30                 T = real
31                 )
32     {
33         alias SIB!( LengthN, LengthD, MassN, MassD, TimeN, TimeD, TempN, TempD, CurrentN, CurrentD, MoleN, MoleD, LuminN, LuminD, T ) SI;
34     }
35 }
36 else
37 {
38     template Batch(
39                 int LengthN,  int LengthD,
40                 int MassN,    int MassD,
41                 int TimeN,    int TimeD,
42                 int TempN,    int TempD,
43                 int CurrentN, int CurrentD
44                 )
45     {
46         // sanity check
47         static assert (Reduce!(LengthN,  LengthD).Reduced, "Length must be in reduced form");
48         static assert (Reduce!(MassN,    MassD).Reduced,   "Mass must be in reduced form");
49         static assert (Reduce!(TimeN,    TimeD).Reduced,   "Time must be in reduced form");
50         static assert (Reduce!(TempN,    TempD).Reduced,   "Temp must be in reduced form");
51         static assert (Reduce!(CurrentN, CurrentD).Reduced,"Current must be in reduced form");
52
53         /// visable units
54         enum LenN = LengthN,  LenD = LengthD;
55         enum MasN = MassN,    MasD = MassD;     ///
56         enum TimN = TimeN,    TimD = TimeD;     ///
57         enum TmpN = TempN,    TmpD = TempD;     ///
58         enum CurN = CurrentN, CurD = CurrentD;  ///
59     }
60
61     template SI(int LengthN, int MassN, int TimeN, int TempN, int CurrentN, T = real)
62     {
63         alias SIB!(Batch!(
64                 /// visable units
65                 LengthN,  1,
66                 MassN,    1,
67                 TimeN,    1,
68                 TempN,    1,
69                 CurrentN, 1
70                 ), T ) SI;
71     }
72     template SI(
73                 int LengthN,  int LengthD,
74                 int MassN,    int MassD,
75                 int TimeN,    int TimeD,
76                 int TempN,    int TempD,
77                 int CurrentN, int CurrentD,
78                 T = real
79                 )
80     {
81
82         alias SIB!(Batch!(
83                 /// visable units
84                 LengthN,  LengthD,
85                 MassN,    MassD,
86                 TimeN,    TimeD,
87                 TempN,    TempD,
88                 CurrentN, CurrentD
89                 ), T ) SI;
90     }
91 }
92 struct SIB(alias Exp_, U)
93 {
94
95     alias Exp_ Exp;
96
97
98     // generate a usable name string
99     static if(Exp.LenD == 1) private enum sLen = Exp.LenN.stringof; else private enum sLen = Exp.LenN.stringof~"/"~Exp.LenD.stringof;
100     static if(Exp.MasD == 1) private enum sMas = Exp.MasN.stringof; else private enum sMas = Exp.MasN.stringof~"/"~Exp.MasD.stringof;
101     static if(Exp.TimD == 1) private enum sTim = Exp.TimN.stringof; else private enum sTim = Exp.TimN.stringof~"/"~Exp.TimD.stringof;
102     static if(Exp.TmpD == 1) private enum sTmp = Exp.TmpN.stringof; else private enum sTmp = Exp.TmpN.stringof~"/"~Exp.TmpD.stringof;
103     static if(Exp.CurD == 1) private enum sCur = Exp.CurN.stringof; else private enum sCur = Exp.CurN.stringof~"/"~Exp.CurD.stringof;
104     /// The type name
105     public enum Stringof = "SI!("~sLen~","~sMas~","~sTim~","~sTmp~","~sCur~","~U.stringof~")";
106
107     /// the value
108     private U value;
109
110     /// a more meaningful name
111     private alias SIB This;
112
113     // check to make shure it's right!
114     static assert(is(SIB!(Exp,U) == This));
115
116     template Using(V)
117     {
118         alias SIB!(Exp,V) Using;
119     }
120
121     template Alike(V)
122     {
123         version(BUG)
124         {
125         enum bool Alike =
126             LenN == V.LenN && LenD == V.LenD &&
127             MasN == V.MasN && MasD == V.MasD &&
128             TimN == V.TimN && TimD == V.TimD &&
129             TmpN == V.TmpN && TmpD == V.TmpD &&
130             CurN == V.CurN && CurD == V.CurD;
131         }
132         else
133         {
134         enum bool Alike =
135             Exp.LenN == V.Exp.LenN && Exp.LenD == V.Exp.LenD &&
136             Exp.MasN == V.Exp.MasN && Exp.MasD == V.Exp.MasD &&
137             Exp.TimN == V.Exp.TimN && Exp.TimD == V.Exp.TimD &&
138             Exp.TmpN == V.Exp.TmpN && Exp.TmpD == V.Exp.TmpD &&
139             Exp.CurN == V.Exp.CurN && Exp.CurD == V.Exp.CurD;
140         }
141     }
142
143
144     /// find the type of "This * T"
145     private template Mul(T)
146     {
147         static if(is(T : U))
148             alias This Mul;
149         else
150             alias SIB!(Batch!(
151                         Reduce!(Exp.LenN*T.Exp.LenD + Exp.LenD*T.Exp.LenN, Exp.LenD*T.Exp.LenD).V,
152                         Reduce!(Exp.MasN*T.Exp.MasD + Exp.MasD*T.Exp.MasN, Exp.MasD*T.Exp.MasD).V,
153                         Reduce!(Exp.TimN*T.Exp.TimD + Exp.TimD*T.Exp.TimN, Exp.TimD*T.Exp.TimD).V,
154                         Reduce!(Exp.TmpN*T.Exp.TmpD + Exp.TmpD*T.Exp.TmpN, Exp.TmpD*T.Exp.TmpD).V,
155                         Reduce!(Exp.CurN*T.Exp.CurD + Exp.CurD*T.Exp.CurN, Exp.CurD*T.Exp.CurD).V),
156                         U
157                     ) Mul;
158     }
159
160     /// find the type of "This / T"
161     public template Div(T)
162     {
163         static if(is(T : U))
164             alias This Div;
165         else
166             alias SIB!(Batch!(
167                         Reduce!(Exp.LenN*T.Exp.LenD - Exp.LenD*T.Exp.LenN, Exp.LenD*T.Exp.LenD).V,
168                         Reduce!(Exp.MasN*T.Exp.MasD - Exp.MasD*T.Exp.MasN, Exp.MasD*T.Exp.MasD).V,
169                         Reduce!(Exp.TimN*T.Exp.TimD - Exp.TimD*T.Exp.TimN, Exp.TimD*T.Exp.TimD).V,
170                         Reduce!(Exp.TmpN*T.Exp.TmpD - Exp.TmpD*T.Exp.TmpN, Exp.TmpD*T.Exp.TmpD).V,
171                         Reduce!(Exp.CurN*T.Exp.CurD - Exp.CurD*T.Exp.CurN, Exp.CurD*T.Exp.CurD).V),
172                         U
173                     ) Div;
174     }
175
176     /// find the type of "This ^ 1/i"
177     static public template RootT(int i)
178     {
179         alias SIB!(Batch!(
180             Reduce!(Exp.LenN, Exp.LenD*i).V,
181             Reduce!(Exp.MasN, Exp.MasD*i).V,
182             Reduce!(Exp.TimN, Exp.TimD*i).V,
183             Reduce!(Exp.TmpN, Exp.TmpD*i).V,
184             Reduce!(Exp.CurN, Exp.CurD*i).V
185             ),
186             U) RootT;
187     }
188
189     /// find the type of "This ^ i"
190     public template Power(int i)
191     {
192         alias SIB!(Batch!(
193             Reduce!(Exp.LenN*i, Exp.LenD).V,
194             Reduce!(Exp.MasN*i, Exp.MasD).V,
195             Reduce!(Exp.TimN*i, Exp.TimD).V,
196             Reduce!(Exp.TmpN*i, Exp.TmpD).V,
197             Reduce!(Exp.CurN*i, Exp.CurD).V
198             ),
199             U) Power;
200     }
201
202     // I don;t think I need this anymore
203     //This opCall(This ret) { return ret; }
204
205
206     private this(U u) { value = u; }
207
208     int opCmp(This that)
209     {
210         if(this.value < that.value) return -1;
211         if(this.value > that.value) return +1;
212         return 0;
213     }
214
215     int opCmp(U that)
216     {
217         if(this.value < that) return -1;
218         if(this.value > that) return +1;
219         return 0;
220     }
221
222     /// Homomorphic math operators
223     This opNeg() { return This(- this.value);}
224     This opPos() { return this; }   ///
225
226     This opAdd(This that) { return This(this.value + that.value);}  ///
227     This opSub(This that) { return This(this.value - that.value);}  ///
228     This opAddAssign(This that) { this.value += that.value; return this; }  ///
229     This opSubAssign(This that) { this.value -= that.value; return this; }  ///
230
231     This opMulAssign(U r) { this.value *= r; return this; }
232     This opDivAssign(U r) { this.value /= r; return this; } ///
233    
234     This opMul_r(U that) { return This(this.value * that); }    ///
235
236         /// non-Homomorphic math operators
237     auto opDiv_r(U that) { return Power!(-1)(that / this.value); }  ///
238
239     static if(Exp.LenN == 0 && Exp.MasN == 0 && Exp.TimN == 0 && Exp.TmpN == 0 && Exp.CurN == 0)
240         alias value this;
241     else
242     {
243         // these conflict if the "alias value this" is in effect
244
245         /// non-Homomorphic math operators
246         auto opMul(T)(T that)
247         {
248             static if(is(T : U)) return Mul!(T)(this.value * that);
249             else return Mul!(T)(this.value * that.value);
250         }
251         auto opDiv(T)(T that)   ///
252         {
253             static if(is(T : U)) return Div!(T)(this.value / that);
254             else return Div!(T)(this.value / that.value);
255         }
256     }
257
258     /// test if these are close enough
259     bool Near(This that, int count = 5)
260     {
261         static if(isFloatingPoint!(U))
262             return std.math.feqrel!(U)(this.value,that.value) + count >= U.mant_dig;
263         else
264             return this.value == that.value;
265     }
266
267     /// common math functions
268     auto Root(int i)(){return RootT!(i)(std.math.sqrt(this.value));}
269     auto Pow(int i)(){return Power!(i)(std.math.pow(this.value,i));}    ///
270     This Abs() { return This(std.math.abs(this.value)); }   ///
271
272
273     /// convert to real from type "s"
274     U opDispatch(string s)()
275     {
276         static if(!is(Unit!(s).type)) static assert(false, "SI has no member named "~s~" nor is it a known type");
277         else
278         {
279             static assert(This.Alike!(Unit!(s).type), "Can't convert type "~This.Stringof~" to \""~s~"\" of type "~Unit!(s).type.Stringof);
280             return value / Unit!(s).mul;
281         }
282     }
283
284 }
285
286 /// convert from real to type "s"
287 struct OfType
288 {
289     static auto opDispatch(string s, U)(U v) ///
290     {
291         static if(!is(Unit!(s).type)) static assert(false, "OfType."~s~" is not a known type");
292         else return Unit!(s).type.Using!(U)(cast(U)(v * Unit!(s).mul));
293     }
294 }
295
296
297 /// Basic types
298 public struct Types
299 {
300     alias SI!( 0, 0, 0, 0, 0) Value;        ///
301     alias SI!( 1, 0, 0, 0, 0) Distance;     ///
302     alias SI!( 0, 1, 0, 0, 0) Mass;         ///
303     alias SI!( 0, 0, 1, 0, 0) Time;         ///
304     alias SI!( 0, 0, 0, 1, 0) Temp;         ///
305     alias SI!( 0, 0, 0, 0, 1) Current;      ///
306
307     alias SI!(-3, 1, 0, 0, 0) MassDensity;  ///
308
309     alias SI!(-2,-1, 3, 0, 2) Resistance;   ///
310     alias SI!(-2,-1, 4, 0, 2) Capacitance;  ///
311
312     alias SI!(-1, 1,-2, 0, 0) Pressure;     ///
313     alias SI!(-1, 1,-1, 0, 0) Viscosity;    ///
314
315     alias SI!( 0, 0,-1, 0, 0) Frequency;    ///
316     alias SI!( 0, 0, 1, 0, 1) Charge;       ///
317     alias SI!( 0, 1,-1, 0, 0) MassFlow;     ///
318     alias SI!( 0, 1,-2, 0,-1) MagneticFluxD;///
319
320     alias SI!( 1, 1,-2, 0, 0) Force;        ///
321     alias SI!( 1, 0,-2, 0, 0) Acceleration; ///
322     alias SI!( 1, 0,-1, 0, 0) Speed;        ///
323
324
325     alias SI!( 2, 1,-3, 0,-1) Voltage;      ///
326     alias SI!( 2, 1,-3, 0, 0) Power;        ///
327     alias SI!( 2, 1,-2, 0,-2) Inductance;   ///
328     alias SI!( 2, 1,-2, 0, 0) Energy;       ///
329     alias SI!( 2, 0, 0, 0, 0) Area;         ///
330     alias SI!( 2, 0,-1, 0, 0) KViscosity;   ///
331
332     alias SI!( 3, 0,-1, 0, 0) VolumeFlow;   ///
333     alias SI!( 3, 0, 0, 0, 0) Volume;       ///
334 }
335
336 /// Some less common types
337 public struct Engr
338 {
339     ///
340     public struct Thermal
341     {
342         alias SI!( 2, 0,-2,-1, 0) ThermalCap;       ///
343         alias SI!( 1, 1,-3,-1, 0) ThermalCond;      ///
344         alias SI!( 0, 1,-3,-1, 0) ConvectionCoeff;  ///
345     }
346     ///
347     public struct FracturMechanics
348     {
349         alias SI!(-1,2, 1,1,-2,1, 0,1, 0,1) StressIntensity;///
350     }
351 }
352
353 /// Base SI units
354 template Unit(string name : "value")    { enum mul = 1.0;               alias Value          type; }
355 template Unit(string name : "meter")    { enum mul = 1.0;               alias Types.Distance type; }    ///
356 template Unit(string name : "kilogram") { enum mul = 1.0;               alias Types.Mass     type; }    ///
357 template Unit(string name : "second")   { enum mul = 1.0;               alias Types.Time     type; }    ///
358 template Unit(string name : "kelvin")   { enum mul = 1.0;               alias Types.Temp     type; }    ///
359 template Unit(string name : "ampere")   { enum mul = 1.0;               alias Types.Current  type; }    ///
360
361 /// Distance Unit Types
362 template Unit(string name : "Angstrom") { enum mul = 1e-10;             alias Types.Distance type; }
363 template Unit(string name : "Micron")   { enum mul = 1e-6;              alias Types.Distance type; }    ///
364 template Unit(string name : "mm")       { enum mul = 1e-3;              alias Types.Distance type; }    ///
365 template Unit(string name : "cm")       { enum mul = 1e-2;              alias Types.Distance type; }    ///
366 template Unit(string name : "km")       { enum mul = 1e3;               alias Types.Distance type; }    ///
367 template Unit(string name : "inch")     { enum mul = 2.54e-2;           alias Types.Distance type; }    ///
368 template Unit(string name : "foot")     { enum mul = 3.04799835e-1;     alias Types.Distance type; }    ///
369 template Unit(string name : "yard")     { enum mul = 9.14399506e-1;     alias Types.Distance type; }    ///
370 template Unit(string name : "mile")     { enum mul = 1.609343130e3;     alias Types.Distance type; }    ///
371 template Unit(string name : "parsec")   { enum mul = 3.085677473598e13; alias Types.Distance type; }    ///
372
373 /// Mass Unit Types
374 template Unit(string name : "gram")     { enum mul = 1e-3;              alias Types.Mass type; }
375 template Unit(string name : "lb")       { enum mul = 4.5359237e-1;      alias Types.Mass type; }    ///
376 template Unit(string name : "Ounce")    { enum mul = 2.834952e-2;       alias Types.Mass type; }    ///
377
378 /// Time Unit Types
379 template Unit(string name : "minute")   { enum mul = 60.0;              alias Types.Time type; }
380 template Unit(string name : "hour")     { enum mul = 3600.0;            alias Types.Time type; }    ///
381 template Unit(string name : "day")      { enum mul = 86400.0;           alias Types.Time type; }    ///
382
383 /// Temperature Unit Types
384 template Unit(string name : "R")        { enum mul = 0.5555555555;      alias Types.Temp type; }
385
386 /// Force  Unit Types
387 template Unit(string name : "newton")   { enum mul = 1.0;               alias Types.Force type; }
388 template Unit(string name : "dyne")     { enum mul = 1e-5;              alias Types.Force type; }   ///
389 template Unit(string name : "lbf")      { enum mul = 4.44822246806;     alias Types.Force type; }   ///
390
391 /// Charge Unit Types
392 template Unit(string name : "coulomb")  { enum mul = 1.0;               alias Types.Charge type; }
393
394 /// Magnetic flux density
395 template Unit(string name : "tesla")        { enum mul = 1.0;               alias Types.MagneticFluxD type; }
396
397 /// magnetic flux
398 template Unit(string name : "weber")        { enum mul = 1.0;               alias SI!(2,1,-2,0,1) type; }
399
400 /// inductance
401 template Unit(string name : "henry")        { enum mul = 1.0;               alias Types.Inductance type; }
402
403 /// Energy Unit Types
404 template Unit(string name : "joule")    { enum mul = 1.0;               alias Types.Energy type; }
405 template Unit(string name : "Erg")      { enum mul = 1e-7L;             alias Types.Energy type; }  ///
406 template Unit(string name : "cal")      { enum mul = 4.1868L;           alias Types.Energy type; }  ///
407 template Unit(string name : "eV")       { enum mul = 1.602176462e-19L;  alias Types.Energy type; }  ///
408 template Unit(string name : "BTU")      { enum mul = 1.0550558526e3L;   alias Types.Energy type; }  ///
409
410 /// Voltage Unit Types
411 template Unit(string name : "volt")     { enum mul = 1.0;               alias Types.Voltage type; }
412
413 /// Frequency Unit Types
414 template Unit(string name : "hertz")        { enum mul = 1.0;               alias Types.Frequency type; }
415
416 /// Resistance Unit Types
417 template Unit(string name : "ohm")      { enum mul = 1.0;               alias Types.Resistance type; }
418
419 /// Pressure Unit Types
420 template Unit(string name : "pascal")       { enum mul = 1.0;               alias Types.Pressure type; }
421 template Unit(string name : "Bar")      { enum mul = 1e5L;              alias Types.Pressure type; }    ///
422 template Unit(string name : "Atm")      { enum mul = 1.01325e5L;        alias Types.Pressure type; }    ///
423 template Unit(string name : "psi")      { enum mul = 6.89475729e3;      alias Types.Pressure type; }    ///
424
425 /// Viscosity
426 //
427 template Unit(string name : "poise")    { enum mul = 0.1;               alias Types.Viscosity type; }
428 //
429 template Unit(string name : "stokes")   { enum mul = 0.0001;            alias Types.KViscosity type; }
430
431 /// Power Unit Types
432 template Unit(string name : "watt")     { enum mul = 1.0;               alias Types.Power type; }
433 template Unit(string name : "kWatt")    { enum mul = 1000;              alias Types.Power type; }   ///
434 template Unit(string name : "Hp")       { enum mul = 745.69987158L;     alias Types.Power type; }   ///
435
436 /// Volume Unit Types
437 template Unit(string name : "steres")   { enum mul = 1.0;               alias Types.Volume type; }
438 template Unit(string name : "litre")    { enum mul = 0.001L;            alias Types.Volume type; }  ///
439 template Unit(string name : "Gal")      { enum mul = 0.0037854120L;     alias Types.Volume type; }  ///
440 template Unit(string name : "Cup")      { enum mul = 0.0002365883L;     alias Types.Volume type; }  ///
441
442 /// volume rate
443 template Unit(string name : "gpm")      { enum mul = 6.30901995e-5L;    alias Types.VolumeFlow type; }
444 template Unit(string name : "cfm")      { enum mul = 4.71947443e-4L;    alias Types.VolumeFlow type; }  ///
445
446 /// Speed Unit Types
447 template Unit(string name : "mps")      { enum mul = 1L;                alias Types.Speed type; }
448 template Unit(string name : "Knots")    { enum mul = 1.51444L;          alias Types.Speed type; }   ///
449 template Unit(string name : "mph")      { enum mul = 0.44704L;          alias Types.Speed type; }   ///
450 template Unit(string name : "kph")      { enum mul = 0.27778L;          alias Types.Speed type; }   ///
451 template Unit(string name : "fps")      { enum mul = 0.3048L;           alias Types.Speed type; }   ///
452
453 /// Capacitance Unit Types
454 template Unit(string name : "farad")    { enum mul = 1.0;               alias Types.Capacitance type; }
455
456 /// Area Unit Types
457 template Unit(string name : "Acre")     { enum mul = 4046.856421L;      alias Types.Area type; }
458
459 /// Acceleration Unit Types
460 template Unit(string name : "G")        { enum mul = 9.80665L;          alias Types.Acceleration type; }
461
462 /// alterant names
463 private:
464
465 template Alt(string name : "C")  { enum Alt = "coulomb"; }
466 template Alt(string name : "N")  { enum Alt = "newton"; }
467 template Alt(string name : "J")  { enum Alt = "joule"; }
468 template Alt(string name : "V")  { enum Alt = "volt"; }
469 template Alt(string name : "Hz") { enum Alt = "hertz"; }
470 template Alt(string name : "Pa") { enum Alt = "pascal"; }
471 template Alt(string name : "P")  { enum Alt =" poise"; }
472 template Alt(string name : "W")  { enum Alt = "watt"; }
473 template Alt(string name : "L")  { enum Alt = "litre"; }
474 template Alt(string name : "liter") { enum Alt = "litre"; }
475 template Alt(string name : "F")  { enum Alt = "farad"; }
476 template Alt(string name : "H")  { enum Alt = "henry"; }
477 template Alt(string name : "Wb") { enum Alt = "weber"; }
478 template Alt(string name : "T")  { enum Alt = "tesla"; }
479
480 public:
481
482 template Unit(string name) { alias Unit!(Alt!(name)) Unit; }
483
484
485 unittest
486 {
487     writef("%s\n", OfType.foot(3.0).meter);
488
489     SI!(1,1, 0,1, 0,1, 0,1, 0,1) v;  //pragma(msg,"v:\t"~typeof(v).stringof);
490
491     auto v2 = v * v;  //pragma(msg,"v2:\t"~typeof(v2).stringof);
492     auto v3 = v2 / v; //pragma(msg,"v3:\t"~typeof(v3).stringof);
493     auto v4 = v / v;  //pragma(msg,"v4:\t"~typeof(v4).stringof);
494     real r = v4;
495     auto v5 = v4 / v; //pragma(msg,"v5:\t"~typeof(v5).stringof);
496     //auto v6a = v2 + v;
497     auto v6b = v3 + v;
498     auto v7 = v.Root!(2)(); //pragma(msg,"v7:\t"~typeof(v7).stringof);
499     auto v8 = v7.Pow!(4)(); //pragma(msg,"v8:\t"~typeof(v8).stringof);
500
501     Engr.FracturMechanics.StressIntensity k;
502     auto k2 = k*k;
503     auto p = OfType.psi(0.0L);
504     k2 = p*p*OfType.foot(3.0L);
505
506     auto newton = OfType.N(5);
507 }
Note: See TracBrowser for help on using the browser.