3using System.Reflection;
17 private readonly
Prefix prefix;
18 private readonly ICollection<UnitFactor> factors;
19 private bool hasBaseUnits =
false;
20 private bool hasReferenceUnits =
false;
49 : this(
Prefix.None, AtomicUnits)
59 : this(
Prefix, Prepare(AtomicUnits))
65 int i, c = AtomicUnits.Length;
68 for (i = 0; i < c; i++)
78 public Unit(params
string[] AtomicUnits)
79 : this(
Prefix.None, AtomicUnits)
92 int i, c = AtomicUnits.Length;
95 for (i = 0; i < c; i++)
111 throw new Exceptions.ScriptException(
"Unable to parse unit: " + UnitString);
123 int Len = UnitString?.Length ?? 0;
125 if (!
TryParse(UnitString, ref Pos, Len,
true, out
Unit))
134 private static bool TryParse(
string UnitString, ref
int Pos,
int Len,
bool PermitPrefix, out
Unit Unit)
142 KeyValuePair<Prefix, UnitFactor[]> CompoundFactors;
143 bool HasCompoundFactors;
144 string Name, Name2, s;
148 char ch = UnitString[Pos++];
149 bool LastDivision =
false;
153 if (ch ==
'd' && Pos < Len && UnitString[Pos] ==
'a')
158 else if (!Prefixes.TryParsePrefix(ch, out
Prefix))
162 ch = Pos < Len ? UnitString[Pos++] : (char)0;
174 ch = Pos < Len ? UnitString[Pos++] : (char)0;
179 ch = Pos < Len ? UnitString[Pos++] : (char)0;
180 while (ch > 0 && (ch <=
' ' || ch == 160))
181 ch = Pos < Len ? UnitString[Pos++] : (
char)0;
184 while (
char.IsLetter(ch) || ch ==
'(' || ch ==
'°' || ch ==
'%' || ch ==
'‰' || ch ==
'‱' || ch ==
'1')
188 if (!
TryParse(UnitString, ref Pos, Len,
false, out Unit Unit2))
191 ch = Pos < Len ? UnitString[Pos++] : (char)0;
192 while (ch > 0 && (ch <=
' ' || ch == 160))
193 ch = Pos < Len ? UnitString[Pos++] : (
char)0;
198 ch = Pos < Len ? UnitString[Pos++] : (char)0;
199 while (ch > 0 && (ch <=
' ' || ch == 160))
200 ch = Pos < Len ? UnitString[Pos++] : (
char)0;
204 ch = Pos < Len ? UnitString[Pos++] : (char)0;
205 while (ch > 0 && (ch <=
' ' || ch == 160))
206 ch = Pos < Len ? UnitString[Pos++] : (
char)0;
208 if (ch ==
'-' ||
char.IsDigit(ch))
213 ch = Pos < Len ? UnitString[Pos++] : (char)0;
215 while (
char.IsDigit(ch))
216 ch = Pos < Len ? UnitString[Pos++] : (
char)0;
219 s = UnitString.Substring(i, Pos - i);
221 s = UnitString.Substring(i, Pos - i - 1);
232 ch = Pos < Len ? UnitString[Pos++] : (char)0;
237 ch = Pos < Len ? UnitString[Pos++] : (char)0;
244 foreach (UnitFactor Factor
in Unit2.Factors)
245 Factors.Add(
new UnitFactor(Factor.Unit, -Factor.Exponent * Exponent));
249 foreach (UnitFactor Factor
in Unit2.Factors)
250 Factors.Add(
new UnitFactor(Factor.Unit, Factor.Exponent * Exponent));
255 if (
char.IsLetter(ch))
259 ch = Pos < Len ? UnitString[Pos++] : (char)0;
261 while (
char.IsLetter(ch));
265 ch = Pos < Len ? UnitString[Pos++] : (char)0;
267 while (
char.IsLetter(ch))
268 ch = Pos < Len ? UnitString[Pos++] : (
char)0;
272 ch = Pos < Len ? UnitString[Pos++] : (char)0;
276 ch = Pos < Len ? UnitString[Pos++] : (char)0;
279 ch = Pos < Len ? UnitString[Pos++] : (char)0;
282 else if (ch ==
'‰' || ch ==
'‱')
283 ch = Pos < Len ? UnitString[Pos++] : (char)0;
286 ch = Pos < Len ? UnitString[Pos++] : (char)0;
287 if (
char.IsDigit(ch))
297 Name = UnitString.Substring(i, Pos - i);
299 Name = UnitString.Substring(i, Pos - i - 1);
303 if (
Expression.keywords.ContainsKey(Name2 = UnitString.Substring(Start, i - Start) + Name))
305 else if (HasCompoundFactors = TryGetCompoundUnit(Name2, out CompoundFactors))
307 Prefix = CompoundFactors.Key;
310 else if (ContainsDerivedOrBaseUnit(Name2))
316 HasCompoundFactors = TryGetCompoundUnit(Name, out CompoundFactors);
319 HasCompoundFactors = TryGetCompoundUnit(Name, out CompoundFactors);
321 while (ch > 0 && (ch <=
' ' || ch == 160))
322 ch = Pos < Len ? UnitString[Pos++] : (char)0;
326 ch = Pos < Len ? UnitString[Pos++] : (char)0;
327 while (ch > 0 && (ch <=
' ' || ch == 160))
328 ch = Pos < Len ? UnitString[Pos++] : (
char)0;
330 if (ch ==
'-' ||
char.IsDigit(ch))
335 ch = Pos < Len ? UnitString[Pos++] : (char)0;
337 while (
char.IsDigit(ch))
338 ch = Pos < Len ? UnitString[Pos++] : (
char)0;
341 s = UnitString.Substring(i, Pos - i);
343 s = UnitString.Substring(i, Pos - i - 1);
354 ch = Pos < Len ? UnitString[Pos++] : (char)0;
359 ch = Pos < Len ? UnitString[Pos++] : (char)0;
364 if (HasCompoundFactors)
368 foreach (UnitFactor Segment
in CompoundFactors.Value)
369 Factors.Add(
new UnitFactor(Segment.Unit, -Segment.Exponent * Exponent));
373 foreach (UnitFactor Segment
in CompoundFactors.Value)
374 Factors.Add(
new UnitFactor(Segment.Unit, Segment.Exponent * Exponent));
380 Factors.Add(
new UnitFactor(Name, -Exponent));
382 Factors.Add(
new UnitFactor(Name, Exponent));
386 while (ch > 0 && (ch <=
' ' || ch == 160))
387 ch = Pos < Len ? UnitString[Pos++] : (
char)0;
389 if (ch ==
'*' || ch ==
'⋅')
390 LastDivision =
false;
403 ch = Pos < Len ? UnitString[Pos++] : (char)0;
404 while (ch > 0 && (ch <=
' ' || ch == 160))
405 ch = Pos < Len ? UnitString[Pos++] : (
char)0;
408 PermitPrefix =
false;
427 public ICollection<UnitFactor>
Factors => this.factors;
436 return this.prefix == Prefix.None && this.factors.Count == 0;
447 return this.factors.Count > 0;
476 if (!(obj is
Unit U))
479 return this.
Equals(U,
true);
490 if (CheckPrefix && this.prefix != Unit2.prefix)
493 if (this.factors.Count != Unit2.factors.Count)
526 int i = (int)this.prefix;
546 StringBuilder Numerator =
null;
547 StringBuilder Denominator =
null;
548 int NrDenominators = 0;
554 if (Numerator is
null)
559 Numerator =
new StringBuilder();
562 Numerator.Append(
'⋅');
569 Numerator.Append(
'²');
571 Numerator.Append(
'³');
574 Numerator.Append(
'^');
575 Numerator.Append(Factor.
Exponent.ToString());
581 if (Denominator is
null)
582 Denominator =
new StringBuilder();
584 Denominator.Append(
'⋅');
587 Denominator.Append(Factor.
Unit.
Name);
592 Denominator.Append(
'²');
594 Denominator.Append(
'³');
597 Denominator.Append(
'^');
598 Denominator.Append((-Factor.
Exponent).ToString());
604 if (Numerator is
null)
609 Numerator =
new StringBuilder();
612 if (!(Denominator is
null))
614 Numerator.Append(
'/');
616 if (NrDenominators > 1)
617 Numerator.Append(
'(');
619 Numerator.Append(Denominator.ToString());
621 if (NrDenominators > 1)
622 Numerator.Append(
')');
625 return Numerator.ToString();
640 int ResultExponent = LeftExponent + RightExponent;
650 if (!Result.Update((ref
UnitFactor f, out
bool Keep) =>
652 if (f.Unit.Name == Name)
654 f = new UnitFactor(f.Unit, f.Exponent + Factor.Exponent);
655 Keep = f.Exponent != 0;
671 return new Unit(ResultPrefix, Result);
686 int ResultExponent = LeftExponent - RightExponent;
696 if (!Result.Update((ref
UnitFactor f, out
bool Keep) =>
698 if (f.Unit.Name == Name)
700 f = new UnitFactor(f.Unit, f.Exponent - Factor.Exponent);
701 Keep = f.Exponent != 0;
717 return new Unit(ResultPrefix, Result);
727 if (this.hasBaseUnits)
732 if (baseUnits is
null)
735 bool HasNonBase =
false;
739 if (!baseUnits.ContainsKey(Factor.
Unit.
Name))
757 if (baseUnits.ContainsKey(Name = Factor.
Unit.
Name))
761 Magnitude *= Math.Pow(Quantity.Magnitude, FactorExponent);
765 this.Add(BaseFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
767 else if (compoundUnits.TryGetValue(Name, out KeyValuePair<
Prefix,
UnitFactor[]> Units))
772 this.Add(BaseFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
779 if (FactorExponent != 0)
780 Magnitude *= Math.Pow(10, FactorExponent);
782 Result.hasBaseUnits =
true;
788 this.hasBaseUnits =
true;
800 if (f.Unit.Name == Name)
802 f = new UnitFactor(f.Unit, f.Exponent + Exponent);
803 Keep = f.Exponent != 0;
813 Factors.
Add(
new UnitFactor(AtomicUnit, Exponent));
825 return this.ToReferenceUnits(ref Magnitude, ref x);
836 if (this.hasReferenceUnits)
841 if (baseUnits is
null)
844 bool HasNonReference =
false;
848 if (!referenceUnits.ContainsKey(Factor.
Unit.
Name))
850 HasNonReference =
true;
866 if (referenceUnits.ContainsKey(Name = Factor.
Unit.
Name))
867 this.Add(ReferenceFactors, Factor.
Unit, Factor.
Exponent);
868 else if (baseUnits.TryGetValue(Name, out
IBaseQuantity BaseQuantity))
870 if (BaseQuantity.ToReferenceUnit(ref Magnitude, ref NrDecimals, Name, FactorExponent))
871 this.Add(ReferenceFactors, BaseQuantity.ReferenceUnit, FactorExponent);
873 this.Add(ReferenceFactors, Factor.
Unit, Factor.
Exponent);
877 if (FactorExponent != 0)
879 double k = Math.Pow(Quantity.Magnitude, FactorExponent);
881 NrDecimals -= Math.Log10(k);
887 if (referenceUnits.ContainsKey(Name = Segment.
Unit.
Name))
888 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
889 else if (baseUnits.TryGetValue(Name, out BaseQuantity))
891 if (BaseQuantity.ToReferenceUnit(ref Magnitude, ref NrDecimals, Name, Segment.
Exponent * FactorExponent))
892 this.Add(ReferenceFactors, BaseQuantity.ReferenceUnit, Segment.
Exponent * FactorExponent);
894 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
897 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
900 else if (compoundUnits.TryGetValue(Name, out KeyValuePair<
Prefix,
UnitFactor[]> Units))
906 if (referenceUnits.ContainsKey(Name = Segment.
Unit.
Name))
907 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
908 else if (baseUnits.TryGetValue(Name, out BaseQuantity))
910 if (BaseQuantity.ToReferenceUnit(ref Magnitude, ref NrDecimals, Name, Segment.
Exponent * FactorExponent))
911 this.Add(ReferenceFactors, BaseQuantity.ReferenceUnit, Segment.
Exponent * FactorExponent);
913 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
916 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
920 this.Add(ReferenceFactors, Factor.
Unit, Factor.
Exponent);
924 if (FactorExponent != 0)
926 Magnitude *= Math.Pow(10, FactorExponent);
927 NrDecimals -= FactorExponent;
930 Result.hasBaseUnits =
true;
931 Result.hasReferenceUnits =
true;
937 this.hasBaseUnits =
true;
938 this.hasReferenceUnits =
true;
952 return this.FromReferenceUnits(ref Magnitude, ref x);
963 if (this.hasReferenceUnits)
968 if (baseUnits is
null)
971 bool HasNonReference =
false;
975 if (!referenceUnits.ContainsKey(Factor.
Unit.
Name))
977 HasNonReference =
true;
993 if (referenceUnits.ContainsKey(Name = Factor.
Unit.
Name))
994 this.Add(ReferenceFactors, Factor.
Unit, Factor.
Exponent);
995 else if (baseUnits.TryGetValue(Name, out
IBaseQuantity BaseQuantity))
997 if (BaseQuantity.FromReferenceUnit(ref Magnitude, ref NrDecimals, Name, FactorExponent))
998 this.Add(ReferenceFactors, BaseQuantity.ReferenceUnit, FactorExponent);
1000 this.Add(ReferenceFactors, Factor.
Unit, Factor.
Exponent);
1004 if (FactorExponent != 0)
1006 double k = Math.Pow(Quantity.Magnitude, FactorExponent);
1008 NrDecimals += Math.Log10(k);
1014 if (referenceUnits.ContainsKey(Name = Segment.
Unit.
Name))
1015 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
1016 else if (baseUnits.TryGetValue(Name, out BaseQuantity))
1018 if (BaseQuantity.FromReferenceUnit(ref Magnitude, ref NrDecimals, Name, Segment.
Exponent * FactorExponent))
1019 this.Add(ReferenceFactors, BaseQuantity.ReferenceUnit, Segment.
Exponent * FactorExponent);
1021 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
1024 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
1027 else if (compoundUnits.TryGetValue(Name, out KeyValuePair<
Prefix,
UnitFactor[]> Units))
1033 if (referenceUnits.ContainsKey(Name = Segment.
Unit.
Name))
1034 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
1035 else if (baseUnits.TryGetValue(Name, out BaseQuantity))
1037 if (BaseQuantity.FromReferenceUnit(ref Magnitude, ref NrDecimals, Name, Segment.
Exponent * FactorExponent))
1038 this.Add(ReferenceFactors, BaseQuantity.ReferenceUnit, Segment.
Exponent * FactorExponent);
1040 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
1043 this.Add(ReferenceFactors, Segment.
Unit, Segment.
Exponent * FactorExponent);
1047 this.Add(ReferenceFactors, Factor.
Unit, Factor.
Exponent);
1051 if (FactorExponent != 0)
1053 Magnitude *= Math.Pow(10, FactorExponent);
1054 NrDecimals -= FactorExponent;
1057 Result.hasBaseUnits =
true;
1058 Result.hasReferenceUnits =
true;
1064 this.hasBaseUnits =
true;
1065 this.hasReferenceUnits =
true;
1071 private static void Search()
1073 Dictionary<string, IBaseQuantity> BaseUnits =
new Dictionary<string, IBaseQuantity>();
1074 Dictionary<string, IBaseQuantity> ReferenceUnits =
new Dictionary<string, IBaseQuantity>();
1075 Dictionary<string, KeyValuePair<Prefix, UnitFactor[]>> CompoundUnits =
new Dictionary<string, KeyValuePair<Prefix, UnitFactor[]>>();
1076 Dictionary<string, PhysicalQuantity> DerivedUnits =
new Dictionary<string, PhysicalQuantity>();
1091 catch (Exception ex)
1099 foreach (
string Unit
in BaseQuantity.
BaseUnits)
1100 BaseUnits[Unit] = BaseQuantity;
1113 catch (Exception ex)
1119 foreach (Tuple<
string, Prefix, UnitFactor[]> CompoundUnit
in CompoundQuantity.
CompoundQuantities)
1120 CompoundUnits[CompoundUnit.Item1] =
new KeyValuePair<Prefix, UnitFactor[]>(CompoundUnit.Item2, CompoundUnit.Item3);
1133 catch (Exception ex)
1139 foreach (KeyValuePair<string, PhysicalQuantity> Derived
in DerivedQuantity.
DerivedUnits)
1140 DerivedUnits[Derived.Key] = Derived.Value;
1143 baseUnits = BaseUnits;
1144 referenceUnits = ReferenceUnits;
1145 compoundUnits = CompoundUnits;
1146 derivedUnits = DerivedUnits;
1149 private readonly
static Dictionary<string, IUnitCategory> categoryPerUnit =
new Dictionary<string, IUnitCategory>();
1150 private static Dictionary<string, IBaseQuantity> baseUnits =
null;
1151 private static Dictionary<string, IBaseQuantity> referenceUnits =
null;
1152 private static Dictionary<string, KeyValuePair<Prefix, UnitFactor[]>> compoundUnits =
null;
1153 private static Dictionary<string, PhysicalQuantity> derivedUnits =
null;
1154 private static IUnitCategory[] unitCategories =
null;
1155 private static readonly
object synchObject =
new object();
1159 Types.OnInvalidated += Types_OnInvalidated;
1162 private static void Types_OnInvalidated(
object Sender, EventArgs e)
1167 referenceUnits =
null;
1168 compoundUnits =
null;
1169 derivedUnits =
null;
1170 unitCategories =
null;
1171 categoryPerUnit.Clear();
1181 internal static bool TryGetCompoundUnit(
string Name, out KeyValuePair<Prefix, UnitFactor[]> Factors)
1185 if (compoundUnits is
null)
1188 return compoundUnits.TryGetValue(Name, out Factors);
1197 internal static bool ContainsDerivedOrBaseUnit(
string Name)
1201 if (baseUnits is
null)
1204 return baseUnits.ContainsKey(Name) || derivedUnits.ContainsKey(Name);
1218 return TryConvert(From, FromUnit, 0, ToUnit, out To, out
_);
1231 public static bool TryConvert(
double From,
Unit FromUnit,
byte FromNrDec,
Unit ToUnit, out
double To, out
byte ToNrDec)
1235 if (FromUnit.
Equals(ToUnit,
false))
1238 ToNrDec = FromNrDec;
1240 if (FromUnit.prefix != ToUnit.prefix)
1245 if (ExponentDiff != 0)
1247 To *= Math.Pow(10, ExponentDiff);
1248 ToNrDec2 = ToNrDec - ExponentDiff;
1251 else if (ToNrDec2 > 255)
1254 ToNrDec = (byte)ToNrDec2;
1261 double NrDec = FromNrDec;
1266 ToNrDec2 = (int)Math.Round(NrDec);
1268 Unit Div = Divide(FromUnit, ToUnit, out
int Exponent);
1272 To *= Math.Pow(10, Exponent);
1273 ToNrDec2 -= Exponent;
1278 else if (ToNrDec2 > 255)
1281 ToNrDec = (byte)ToNrDec2;
1298 if (categoryPerUnit.TryGetValue(s, out Category))
1299 return !(Category is
null);
1301 if (unitCategories is
null)
1315 catch (Exception ex)
1321 Categories.Add(Category);
1324 unitCategories = Categories.ToArray();
1334 Category = Category2;
1341 categoryPerUnit[s] = Category;
1344 return !(Category is
null);
Static class managing the application event log. Applications and services log events on this static ...
static void Exception(Exception Exception, string Object, string Actor, string EventId, EventLevel Level, string Facility, string Module, params KeyValuePair< string, object >[] Tags)
Logs an exception. Event type will be determined by the severity of the exception.
A chunked list is a linked list of chunks of objects of type T .
void AddRange(IEnumerable< T > Collection)
Adds a range of elements (last) to the list.
bool Update(UpdateCallback< T > Callback)
Iterates through all elements in the collection, and calls the callback method in Callback for each ...
void Add(T Item)
Adds an item to the collection.
Static class that dynamically manages types and interfaces available in the runtime environment.
static object[] NoParameters
Contains an empty array of parameter values.
static Type[] GetTypesImplementingInterface(string InterfaceFullName)
Gets all types implementing a given interface.
static ConstructorInfo GetDefaultConstructor(Type Type)
Gets the default constructor of a type, if one exists.
Class managing a script expression.
Represents an atomic unit.
override int GetHashCode()
Static class managing units.
static Prefix ExponentToPrefix(int Exponent, out int ResidueExponent)
Converts an exponent to a prefix.
static int PrefixToExponent(Prefix Prefix)
Conerts a prefix to an exponent.
static string ToString(Prefix Prefix)
Converts a prefix to its string representation.
A unit factor, used to form compound units.
int Exponent
Exponent of the unit factor.
AtomicUnit Unit
Unit factor, without its exponent.
static bool TryConvert(double From, Unit FromUnit, byte FromNrDec, Unit ToUnit, out double To, out byte ToNrDec)
Tries to convert a magnitude in one unit to a magnitude in another.
Unit(Prefix Prefix, params AtomicUnit[] AtomicUnits)
Represents a unit.
ICollection< UnitFactor > Factors
Sequence of atomic unit factors, and their corresponding exponents.
static bool TryConvert(double From, Unit FromUnit, Unit ToUnit, out double To)
Tries to convert a magnitude in one unit to a magnitude in another.
Unit FromReferenceUnits(ref double Magnitude, ref double NrDecimals)
Converts the unit to a series of reference unit factors. (Unrecognized units will be assumed to be re...
static Unit Divide(Unit Left, Unit Right, out int ResidueExponent)
Divides the right unit from the left unit: Left /Right .
Unit ToReferenceUnits(ref double Magnitude, ref double NrDecimals)
Converts the unit to a series of reference unit factors. (Unrecognized units will be assumed to be re...
override string ToString()
static Unit Parse(string UnitString)
Parses a unit string.
Unit(params string[] AtomicUnits)
Represents a unit.
bool IsEmpty
If the unit is empty. (A unit of only a prefix, but no factors, is not empty.)
Unit Invert(out int ResidueExponent)
Inverts the unit.
Unit(Prefix Prefix, params string[] AtomicUnits)
Represents a unit.
override bool Equals(object obj)
bool HasFactors
If the unit has any factors.
Unit(Prefix Prefix, params UnitFactor[] Factors)
Represents a unit.
Unit(Prefix Prefix, ICollection< UnitFactor > Factors)
Represents a unit.
bool Equals(Unit Unit2, bool CheckPrefix)
Checks if the unit is equal to another
static readonly Unit Empty
Empty unit.
Unit FromReferenceUnits(ref double Magnitude)
Converts the unit to a series of reference unit factors. (Unrecognized units will be assumed to be re...
string ToString(bool IncludePrefix)
Converts the unit to a string.
static Unit Multiply(Unit Left, Unit Right, out int ResidueExponent)
Multiplies two units with each other.
override int GetHashCode()
Unit ToReferenceUnits(ref double Magnitude)
Converts the unit to a series of reference unit factors. (Unrecognized units will be assumed to be re...
static bool TryParse(string UnitString, out Unit Unit)
Tries to parse a string into a unit.
static bool TryGetCategory(Unit Unit, out IUnitCategory Category)
Tries to get the unit category of a unit.
Unit(params AtomicUnit[] AtomicUnits)
Represents a unit.
Unit ToBaseUnits(ref double Magnitude)
Converts the unit to a series of base unit factors. (Unrecognized units will be assumed to be base un...
Prefix Prefix
Associated prefix.
Interface for physical base quantities
string[] BaseUnits
Base Units supported.
AtomicUnit ReferenceUnit
Reference unit of category.
Interface for physical compound quantities
Tuple< string, Prefix, UnitFactor[]>[] CompoundQuantities
Compound quantities. Must only use base quantity units.
Interface for derived quantities
KeyValuePair< string, PhysicalQuantity >[] DerivedUnits
Derived Units supported.
Interface for a category of units.
Unit Reference
Reference unit for category.
Prefix
SI prefixes. http://physics.nist.gov/cuu/Units/prefixes.html