-
-
Notifications
You must be signed in to change notification settings - Fork 88
User Guide for QUDT
This guide attempts to explain how the QUDT model should be used.
3. Introducing Dimension Vectors (for SI units)
4. Conversion Multipliers in QUDT
6. Using Quantity Kinds with Dimensionless Quantities
7. Special case of Quantity Kind with no Dimension Vector
8. A Quantity with multiple units
Please refer to the following architecture diagram for the key QUDT classes (the QUDT architecture overview can be read here.
Let's suppose you have a smart thermostat and it generates a digital signal for the temperature setting in degrees Fahrenheit. You could name the QUDT Quantity something like wiki-examples:MyThermostatSetting. The Quantity instance is yours - you can name it whatever you want, but in a professional/interoperability scenario the name might include other information, such as the location of the thermostat. One way or another, the name establishes the context of the value you are storing. For the simple case, the Quantity instance has a property qudt:value, which you could assign the value 72.0. The Quantity instance also points to an instance of qudt:Unit called unit:DEG_F.
Here's the Turtle source code for this:
wiki-examples:MyThermostatSetting
rdf:type qudt:Quantity ;
qudt:hasUnit unit:DEG_F ;
qudt:value "72.0"^^xsd:float ;
.
Here's how it fits into the QUDT model. (Orange is your new instance, blue is defined by QUDT).
The next important concept to understand is the QuantityKind. Simply stated, a QuantityKind is just that: a kind, and answers the question "What is this measurement and unit a measure of?". Answers might be things like "Thermodynamic Temperature" (i.e. quantitykind:ThermodynamicTemperature). So the QuantityKind vocabulary is a set of all the kinds of things we might measure... length, area, electrical capacitance, torque, and really obscure ones like power per area quartic temperature. This last one is measured in units of Watts Per Square Meter Per Quartic Kelvin by the way.
Every Unit is associated with at least one QuantityKind - sometimes more than one if there are different ways people refer to a QuantityKind, but usually just one. You don't need to populate that link, it is already populated. For example, the following SPARQL query produces 2 quantity kinds associated with the unit unit:A-PER-MilliM:
SELECT ?un ?qk
WHERE {
BIND (unit:A-PER-MilliM AS ?un) .
?un qudt:hasQuantityKind ?qk
}
which produces the following:
un qk
unit:A-PER-MilliM quantitykind:LinearElectricCurrent
unit:A-PER-MilliM quantitykind:MagneticFieldStrength
Of course, each QuantityKind could be measured in any of several units, such as different units for temperature, or different units for length. For example, the following SPARQL query shows the different units associated with the quantity kind quantitykind:Force:
SELECT DISTINCT ?qk ?qku (COALESCE(?labelEn, ?qkl) AS ?label)
WHERE {
BIND (quantitykind:Force AS ?arg1) .
?qk rdf:type qudt:QuantityKind .
FILTER (?qk = ?arg1) .
?qku qudt:hasQuantityKind ?qk .
?qku a qudt:Unit .
?qku rdfs:label ?qkl .
OPTIONAL {
?qku rdfs:label ?labelEn .
FILTER (lang(?labelEn) = "en")
}
} ORDER BY ?qku
which results in 23 values for ?qku:
qk qku label
qudtqk:Force unit:CentiN CentiNewton
qudtqk:Force unit:DYN Dyne
qudtqk:Force unit:DeciN DeciNewton
qudtqk:Force unit:GM_F Gram Force
qudtqk:Force unit:GigaN GigaN
qudtqk:Force unit:KIP_F Kip
qudtqk:Force unit:KiloGM-M-PER-SEC2 kilogram metre per second squared
qudtqk:Force unit:KiloGM_F Kilogram Force
qudtqk:Force unit:KiloLB_F KiloPound Force
qudtqk:Force unit:KiloN Kilonewton
qudtqk:Force unit:KiloPOND Kilopond
qudtqk:Force unit:LB_F Pound Force
qudtqk:Force unit:MegaLB_F Mega Pound Force
qudtqk:Force unit:MegaN Meganewton
qudtqk:Force unit:MicroN Micronewton
qudtqk:Force unit:MilliN Millinewton
qudtqk:Force unit:N newton
qudtqk:Force unit:NanoN NanoN
qudtqk:Force unit:OZ_F Imperial Ounce Force
qudtqk:Force unit:PDL Poundal
qudtqk:Force unit:POND pond
qudtqk:Force unit:PlanckForce Planck Force
qudtqk:Force unit:TON_F_US Ton Force (US Short)
Here is where the power of the QUDT ontology starts to reveal itself. In the SI system of units, all physical measurements can be described in terms of 7 basic dimensions, and the associated base units:
- Amount of substance - mole (mole)
- Electric current - ampere (A)
- Length - meter (m)
- Luminous intensity - candela (cd)
- Mass - kilogram (kg)
- Temperature - kelvin (K)
- Time - second (s)
(Note that the choice of what the basic dimensions are could have been different. The SI community could have chosen Electric charge instead of Electric current, for example, in which case the Coulomb would have been the base unit for SI. This is important, because there are other systems of units, such as the CGS-EMU system, and the CGS-ESU system, that made different choices for the base dimensions.)
In QUDT every dimension vector is comprised of each of the above base dimensions and an associated exponent in the following way:
(Dimension1 * dimensional_exponent1) * (Dimension2 * dimensional_exponent2) * ...
This is repeated for all 7 dimensions and the dimensionless indicator in the following order:
Amount of substance, Electric current, Length, Luminous intensity, Mass, Temperature, Time, Dimensionless
The dimensions and the dimensionless value are indicated with single letter codes which, for the above dimensions and dimensionless are, in order, as above:
A E L I M H T D
An example for the QuantityKindDimensionVector associated with Force is:
qkdv:A0E0L1I0M1H0T-2D0
where the only non-zero exponents are for L (length), M (mass), and T (time), i.e., M1L1T-2. (Please note that in QUDT we add a coefficient for dimensionless quantity kinds. This is the last item, D, in the example above. When a quantity kind is dimensionless all the base units will have zero exponents except D. An example of a dimensionless quantity kind is TemperatureRatio:
qkdv:A0E0L0I0M0H0T0D1
Using the base dimensions is how you can determine whether one unit can be converted into another. They must be commensurate, which means they must be associated with the same "dimension vector". The dimension vector (known in QUDT as the QuantityKindDimensionVector_SI for the SI dimension vector) is simply a description of a given unit in terms of the appropriate powers of the underlying base dimensions. For example, speed is (Length / Time); acceleration is (Length / Time**2).
The QUDT vocabulary contains over two thousand units compliant with ISO 80000 and several other standards including IEC 61360. For example, we could execute the following SPARQL query to produce all of the units in the vocabulary associated with the base units of M * L / T^2. We get to this through the DimensionVector:
SELECT DISTINCT ?un (COALESCE(?labelEn, ?unl) AS ?label)
WHERE {
BIND ("A0E0L1I0M1H0T-2D0" AS ?arg1) .
?dv rdf:type qudt:QuantityKindDimensionVector_SI .
BIND(REPLACE(STR(?dv), ".*[#/]", "") AS ?dvn) .
FILTER CONTAINS(UCASE(STR(?dvn)), UCASE(STR(?arg1)))
?qk qudt:hasDimensionVector ?dv .
?un qudt:hasQuantityKind ?qk .
?un a qudt:Unit .
?un rdfs:label ?unl .
OPTIONAL {
?un rdfs:label ?labelEn .
FILTER (lang(?labelEn) = "en")
}
}
ORDER BY ?un
which produces the following:
un label
unit:CentiN CentiNewton
unit:DYN Dyne
unit:DeciN DeciNewton
unit:ERG-PER-CentiM Erg per Centimetre
unit:EV-PER-ANGSTROM Electronvolt per Angstrom
unit:EV-PER-M Electronvolt per Metre
unit:GM_F Gram Force
unit:GigaN GigaN
unit:J-PER-M Joule per Metre
unit:KIP_F Kip
unit:KiloEV-PER-MicroM Kilo Electron Volt per Micrometre
unit:KiloGM-M-PER-SEC2 kilogram metre per second squared
unit:KiloGM_F Kilogram Force
unit:KiloLB_F KiloPound Force
unit:KiloN Kilonewton
unit:KiloN-M-PER-DEG-M kilonewton metre per degree metre
unit:KiloN-M-PER-M Kilonewton Metre per metre
unit:KiloPOND Kilopond
unit:LB_F Pound Force
unit:LB_F-FT-PER-IN pound-force foot per inch
unit:LB_F-IN-PER-IN pound-force inch per inch
unit:MegaEV-PER-CentiM Mega Electron Volt per Centimetre
unit:MegaLB_F Mega Pound Force
unit:MegaN Meganewton
unit:MicroN Micronewton
unit:MilliN Millinewton
unit:N newton
unit:N-M-PER-DEG-M Newton metre per degree metre
unit:N-M-PER-M Newton metre per metre
unit:N-M-PER-M-RAD Newton Metre per Metre Radian
unit:N-PER-RAD Newton per radian
unit:NanoN NanoN
unit:OZ_F Imperial Ounce Force
unit:PDL Poundal
unit:POND pond
unit:PlanckForce Planck Force
unit:TON_F_US Ton Force (US Short)
Every unit has an associated quantity kind and dimension vector. You cannot add a speed to a temperature because Length / Time is different from Temperature. You can add a furlong to a kilometer, because they both have a dimension vector of Length. Of course, you need to convert one unit into the other before adding the numbers, which leads us to...
Each instance of Unit has a property called qudt:conversionMultiplier. The value of the multiplier tells you what number to multiply to convert a given unit into the SI version of that unit. So, for example the conversionMultiplier for an inch (unit:IN) is 0.0245. That is, 1 Inch equals 0.0245 Meters.
Measurements that have the same QuantityKind can often be combined mathematically. You can add two lengths, once you accommodate their conversion multipliers, but it doesn't make sense to add a length and a temperature - they are of different quantity kinds. As an example of how to use conversion multipliers in QUDT, consider the following relationship to calculate the circumference of a rectangle:
rectangleCircumference = 2 x length + 2 * width
Lets say that, for the purposes of discussion, the length is measured in inches (IN) and the width is measured in centimeters (CentiM). Then if the length is 19 and the width is 12 we could use the following to calculate the circumference in the base unit of Meters. The essence of the query, after doing some bindings for the values and the unit types, comes down to getting the conversion multipliers for the units and performing the calculation:
SELECT ?rectCircum
WHERE {
BIND (19 AS ?length) .
BIND (12 AS ?width) .
BIND (unit:IN AS ?arg1) .
BIND (unit:CentiM AS ?arg2) .
?arg1 qudt:conversionMultiplier ?cm1 .
?arg2 qudt:conversionMultiplier ?cm2 .
BIND (((2 * ?length * ?cm1) + (2 * ?width * ?cm2)) AS ?rectCircum) .
}
The query above produces the value of 1.2052, which is now in SI units of meter (M). Of course, we could add another last line (e.g., BIND ((?rectCircum / ?cm1) AS ?rectCircumIN) .
, which produces 47.44881 in
, or BIND ((?rectCircum / ?cm2) AS ?rectCircumCentiM) .
, which produces 120.52 cm
) to the query to return the circumference in either inches or centimeters, respectively. Alternatively, we could have just converted one of the two (length or width) to the other before calculating the circumference.
Building on the above discussion of dimension vectors and conversion multipliers leads us to an elegant way to do unit conversions. (Important caveat: The following example works to convert incremental values of units where the only important factor is the relative size of the unit. This example does not handle absolute values for units with offsets (think Celsius and Fahrenheit degrees). QUDT supports that too - the QUDT treatment of absolute and incremental values is discussed here.
The approach we will use is shown in the following pseudocode:
1. start with a given instance of a Unit
1.1 find out what QuantityKind it has
1.1.1 determine its QuantityKindDimensionVector
1.2 find out all the QuantityKinds that have that same QuantityKindDimensionVector
1.3 find all the Units with those QuantityKinds
2. multiply your starting unit by its conversionMultiplier
2.1 divide the result by the target unit conversionMultiplier
That is the logic behind the following SPARQL query:
SELECT DISTINCT ?toConvert ?label ?into (COALESCE(?labelEn, ?otherUnitLabel) AS ?otherlabel) ?multiplyBy ?multiplier
WHERE {
BIND ("To convert" AS ?toConvert) .
BIND ("into" AS ?into) .
BIND ("multiply by" AS ?multiplyBy) .
BIND (unit:MilliGRAY as ?unit) .
?unit rdfs:label ?label .
?unit qudt:conversionMultiplier ?cm1 .
?unit qudt:hasQuantityKind/qudt:hasDimensionVector ?qkdv .
?otherUnit qudt:hasQuantityKind/qudt:hasDimensionVector ?qkdv .
?otherUnit a qudt:Unit .
FILTER (?otherUnit != ?unit) .
?otherUnit qudt:conversionMultiplier ?cm2 .
?otherUnit rdfs:label ?otherUnitLabel .
OPTIONAL {
?otherUnit rdfs:label ?labelEn .
FILTER (lang(?labelEn) = "en") .
}
BIND ((?cm1/?cm2) AS ?multiplier) .
}
ORDER BY ?otherlabel
Executing this query produces output that looks like this:
To convert Milligray into BTU-IT-PER-lb multiply by 0.000000429922613929492691
To convert Milligray into British Thermal Unit (TH) per Pound multiply by 0.000000430210433032265002
To convert Milligray into Calorie (international Table) per Gram multiply by 0.000000238845896627495939
To convert Milligray into Calorie (thermochemical) per Gram multiply by 0.000000239005736137667304
To convert Milligray into Erg per Gram multiply by 10.0
To convert Milligray into Gigapascal Cubed Centimetre per Gram multiply by 0.000000001
To convert Milligray into Joule per Gram multiply by 0.000001
To convert Milligray into Joule per Kilogram multiply by 0.001
To convert Milligray into Kilocalorie per Gram multiply by 0.000000000239005736137667
To convert Milligray into Kilojoule per Kilogram multiply by 0.000001
To convert Milligray into Megajoule per Kilogram multiply by 0.000000001
To convert Milligray into MicroGray multiply by 1000.0
To convert Milligray into MicroSievert multiply by 1000.0
To convert Milligray into MilliRad multiply by 100.0
To convert Milligray into Millijoule per Gram multiply by 0.001
To convert Milligray into Milliroentgen Equivalent Man multiply by 100.0
To convert Milligray into Millisievert multiply by 1.0
To convert Milligray into NanoGRAY multiply by 1000000.0
To convert Milligray into NanoSV multiply by 1000000.0
To convert Milligray into Newton Metre per Kilogram multiply by 0.001
To convert Milligray into Pound Force Foot per Pound multiply by 0.000000334552554358935413
To convert Milligray into Rad multiply by 0.1
To convert Milligray into Rem multiply by 0.1
To convert Milligray into Square kilometres per square second multiply by 0.000000001
To convert Milligray into Square metres per square second multiply by 0.001
To convert Milligray into centigray multiply by 0.1
To convert Milligray into gray multiply by 0.001
To convert Milligray into kilogray multiply by 0.000001
To convert Milligray into megagray multiply by 0.000000001
To convert Milligray into roentgen equivalent man multiply by 0.1
To convert Milligray into sievert multiply by 0.001
To convert Milligray into watt hour per kilogram multiply by 0.000000277777777777777777
None of these pairwise relationships had to be stored. The query simply returns all the other units that have the same associated dimension vector. You can try queries for both incremental and absolute unit conversion, as well as any of the above examples, using our SPARQL endpoint. Just copy the query, and stick the following prefix definitions at the top of the query window:
PREFIX qudt: <http://qudt.org/schema/qudt/>
PREFIX rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#>
PREFIX unit: <http://qudt.org/vocab/unit/>
PREFIX dcat: <http://www.w3.org/ns/dcat#>
PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
PREFIX quantitykind: <http://qudt.org/vocab/quantitykind/>
A whole category of units are actually dimensionless, and QUDT has a specific modeling pattern to handle these. Think about the unit "relative humidity" which is generally expressed as a percentage. In QUDT, the instance is unit:PERCENT_RH. While the unit is a dimensionless number, it is actually the ratio of two partial pressures, and the dimensions cancel out because of the ratio. It is important to capture this, because it would be nonsensical to compare a relative humidity percentage with a savings account yield percentage, even though they are both just nondimensional percentages.
To capture the full semantics, unit:PERCENT_RH points to quantitykind:PressureRatio using the qudt:hasQuantityKind relation. The quantitykind:PressureRatio has a dimensionality that is the result of a combination of other quantity kinds. In this specific case, it is the ratio of two pressures. quantitykind:PressureRatio points to the dimension vector of qkdv:A0E0L0I0M0H0T0D1 (the dimensionless dimension vector), but it also has two other properties, qudt:qkdvDenominator and qudt:qkdvNumerator. In this example, they are both populated with qkdv:A0E0L-1I0M1H0T-2D0, the dimension vector for a pressure. Using this pattern, the model captures the fact that unit:PERCENT_RH is dimensionless, but also that it derives from the ratio of two pressures.
Finally, quantitykind:PressureRatio also uses the skos:broader relation to position it in a hierarchy that, in this case, broadens to quantitykind:DimensionlessRatio, and then to quantitykind:Dimensionless.
Here's a diagram that shows the final result:
Most of the dimensionless quantity kind instances are simple ratios of a single kind of quantitykind, but this may not always be the case. Sometimes the final dimensionality hides the fact that some of the dimensions in the definition formula "cancel out", and this can be made explicit using the numerator and denominator properties.
On rare occasions, one encounters a quantity kind that has no dimension vector. (Normally, all quantity kinds are required to have an associated dimension vector). It is important to recognize this as distinct from quantity kinds that have a dimensionless dimension vector (i.e. A0E0L0I0M0H0T0D1). These quantity kinds might be useful to refer to in some specialized domain, but they are ambiguous. For example, quantitykind:VisionThresholds refers to the sensitivity of the eye to light. It might be reported as the number of photons incident on a prescribed part of the retina, or it might be in terms of luminance, or even illuminance. It is arguable that such concepts don't really even belong in QUDT as defined Quantity Kinds and are best treated as contextual Quantity instances instead. As of the writing of this wiki, QUDT only has 7 such quantity kinds.
Let's say your smart thermostat is even smarter than the one in the first example, and communicates in both Fahrenheit and Kelvin (the SI unit for temperature). Here's how we could store all that information. Keep in mind that the "concept" of the temperature setting is still a single concept, even when its value is represented in multiple units. So in this case, instead of using the built-in data property qudt:hasUnit inside the qudt:Quantity class, we use the object property qudt:quantityValue that points to the class qudt:QuantityValue in the first diagram on this page. There will be two instances of qudt:QuantityValue, one that points to the unit:DEG_F unit instance, and one that points to the unit:K unit instance. Here's the code:
wiki-examples:MySmarterThermostatSetting
a qudt:Quantity ;
qudt:quantityValue wiki-examples:FahrenheitSetting ;
qudt:quantityValue wiki-examples:KelvinSetting ;
.
wiki-examples:FahrenheitSetting
rdf:type qudt:QuantityValue ;
qudt:hasUnit unit:DEG_F ;
qudt:value "72.0"^^xsd:float ;
.
wiki-examples:KelvinSetting
rdf:type qudt:QuantityValue ;
qudt:hasUnit unit:K ;
qudt:value "295.37"^^xsd:float ;
.