Skip to content

Commit

Permalink
Refactoring of Unit.factorUnits and Unit.conversionMultiplier (#63)
Browse files Browse the repository at this point in the history
* REFAC: change Unit.factorUnits from List<FactorUnit> to FactorUnits in order to allow extracing the scale factor from the model and integrate it there

* FIX: Handle missing conversion multipliers as missing

* FIX: Handle missing/wrong dimension vector explicitly

* FEAT: Add implicit factors

* FIX: Add contributed triples
  • Loading branch information
fkleedorfer authored Dec 15, 2023
1 parent b4082a1 commit 95e4eeb
Show file tree
Hide file tree
Showing 28 changed files with 1,319 additions and 247 deletions.
86 changes: 86 additions & 0 deletions qudtlib-data-gen/src/main/resources/triples-to-add-to-units.ttl
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,29 @@ unit:LB_F
qudt:unit unit:SEC ;
qudt:exponent -2
].

unit:LA
qudt:factorUnitScalar 0.31830988618 ;
qudt:factorUnit [
qudt:unit unit:CD ;
qudt:exponent 1
];
qudt:factorUnit [
qudt:unit unit:M ;
qudt:exponent -2
].

unit:LA_FT
qudt:factorUnitScalar 0.31830988618 ;
qudt:factorUnit [
qudt:unit unit:CD ;
qudt:exponent 1
];
qudt:factorUnit [
qudt:unit unit:FT ;
qudt:exponent -2
].

# Triples to until this is merged and released: https://github.com/qudt/qudt-public-repo/pull/837

# Triples added until https://github.com/qudt/qudt-public-repo/pull/830 is merged
Expand Down Expand Up @@ -342,3 +365,66 @@ unit:M2-PER-M a qudt:Unit;
"metrekare per metre"@tr;
qudt:plainTextDescription "square metre divided by metre: plain text description in English" .





unit:BTU_IT-PER-MOL_LB
a qudt:DerivedUnit ;
a qudt:Unit ;
dcterms:description "\\({\\bf BTU \\, per \\, Pound \\,Mole}\\) is an Imperial unit for 'Energy And Work Per Mass Amount Of Substance' expressed as \\(Btu/(lb-mol)\\)."^^qudt:LatexString ;
qudt:applicableSystem sou:IMPERIAL ;
qudt:applicableSystem sou:USCS ;
qudt:expression "\\(Btu/(lb-mol)\\)"^^qudt:LatexString ;
qudt:hasDimensionVector qkdv:A-1E0L2I0M1H0T-2D0 ;
qudt:hasQuantityKind qk:EnergyPerMassAmountOfSubstance ;
qudt:symbol "Btu{IT}/(mol-lb)" ;
qudt:ucumCode "[Btu_IT].[mol_lb]-1"^^qudt:UCUMcs ;
qudt:ucumCode "[Btu_IT]/[mol_lb]"^^qudt:UCUMcs ;
rdfs:isDefinedBy <http://qudt.org/2.1/vocab/unit> ;
rdfs:label "BTU per Pound Mole"@en ;
.

unit:BTU_IT-PER-MOL_LB-DEG_F
a qudt:DerivedUnit ;
a qudt:Unit ;
dcterms:description "\\({\\bf BTU \\, per \\, Pound \\, Mole \\, Degree \\, Fahrenheit}\\) is an Imperial unit for 'Molar Heat Capacity' expressed as \\(Btu/(lb-mol-degF)\\)."^^qudt:LatexString ;
qudt:applicableSystem sou:IMPERIAL ;
qudt:applicableSystem sou:USCS ;
qudt:definedUnitOfSystem sou:IMPERIAL ;
qudt:expression "\\(Btu/(lb-mol-degF)\\)"^^qudt:LatexString ;
qudt:hasDimensionVector qkdv:A-1E0L2I0M1H-1T-2D0 ;
qudt:hasQuantityKind qk:MolarHeatCapacity ;
qudt:symbol "Btu{IT}/(lb-mol⋅°F)" ;
qudt:ucumCode "[Btu_IT].[mol_lb]-1.[degF]-1"^^qudt:UCUMcs ;
qudt:ucumCode "[Btu_IT]/([mol_lb].[degF])"^^qudt:UCUMcs ;
rdfs:isDefinedBy <http://qudt.org/2.1/vocab/unit> ;
rdfs:label "BTU per Pound Mole Degree Fahrenheit"@en ;
.

unit:MOL_LB
a qudt:DerivedUnit ;
a qudt:Unit ;
dcterms:description "<p><strong>Pound Mole</strong> is a unit for \\textit{'Mass Amount Of Substance'} expressed as \\(lb-mol\\).</p>."^^qudt:LatexString ;
qudt:conversionMultiplier 0.45359237 ;
qudt:expression "\\(lb-mol\\)"^^qudt:LatexString ;
qudt:hasDimensionVector qkdv:A1E0L0I0M0H0T0D0 ;
qudt:hasQuantityKind qk:MassAmountOfSubstance ;
qudt:symbol "lb-mol" ;
qudt:ucumCode "[mol_lb]"^^qudt:UCUMcs ;
rdfs:isDefinedBy <http://qudt.org/2.1/vocab/unit> ;
rdfs:label "Pound Mole"@en ;
.

unit:MOL_LB-DEG_F
a qudt:DerivedUnit ;
a qudt:Unit ;
dcterms:description "\\(\\textbf{Pound Mole Degree Fahrenheit} is a unit for 'Mass Amount Of Substance Temperature' expressed as \\(lb-mol-degF\\)."^^qudt:LatexString ;
qudt:expression "\\(lb-mol-degF\\)"^^qudt:LatexString ;
qudt:hasDimensionVector qkdv:A1E0L0I0M0H1T0D0 ;
qudt:hasQuantityKind qk:MassAmountOfSubstanceTemperature ;
qudt:symbol "lb-mol⋅°F" ;
qudt:ucumCode "[mol_lb].[degF]"^^qudt:UCUMcs ;
rdfs:isDefinedBy <http://qudt.org/2.1/vocab/unit> ;
rdfs:label "Pound Mole Degree Fahrenheit"@en ;
.
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ public static void main(String[] args) {
System.out.println("unit : " + unit);
}
System.out.println("---");
List<FactorUnit> myFactorUnits = Qudt.Units.N.getFactorUnits();
List<FactorUnit> myFactorUnits = Qudt.Units.N.getFactorUnits().getFactorUnits();
System.out.println("finding factors of unit " + Qudt.Units.N);
for (FactorUnit factorUnit : myFactorUnits) {
System.out.println("factor unit:" + factorUnit);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -179,17 +179,20 @@ public class InitializerImpl implements Initializer {
<#if unit.hasFactorUnits()>
private static void setFactorUnits${iri?counter?c}(Definitions definitions){
String iri = "${iri}";
var builder = FactorUnits.builder();
builder.scaleFactor(${bigDec(unit.factorUnits.scaleFactor)});
<#list unit.factorUnits.factorUnits as factorUnit>
builder.factor(
FactorUnit
.builder()
.unit(definitions.expectUnitDefinition("${factorUnit.unit.iri}"))
.exponent(${factorUnit.exponent}));
</#list>
Unit.Definition def =
definitions.getUnitDefinition(iri).orElseThrow(exceptionSupplier(iri))
<#list unit.factorUnits as factorUnit>
.addFactorUnit(
FactorUnit
.builder()
.unit(definitions.expectUnitDefinition("${factorUnit.unit.iri}"))
.exponent(${factorUnit.exponent})
)
</#list>
;
definitions
.getUnitDefinition(iri)
.orElseThrow(exceptionSupplier(iri))
.setFactorUnits(builder);
}
</#if>
</#list>
Expand Down
2 changes: 1 addition & 1 deletion qudtlib-js
2 changes: 1 addition & 1 deletion qudtlib-js-gen/src/main/resources/template/units.ts.ftl
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ for (const unit of config.units.values()){
<#list units as iri, unit>
<#if unit.hasFactorUnits()>
unit = getUnit("${iri}");
<#list unit.factorUnits as factorUnit>
<#list unit.factorUnits.factorUnits as factorUnit>
unit.addFactorUnit(new FactorUnit(getUnit("${factorUnit.unit.iri}"), ${factorUnit.exponent}));
</#list>
</#if>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
package io.github.qudtlib.model;

import java.util.Arrays;
import java.util.Objects;
import java.util.Optional;

/**
* Represents the QUDT dimension vector and allows for converting between a dimension vector IRI and
* the numeric values, as well as for some manipulations.
Expand All @@ -9,17 +13,36 @@
* never changes by multiplication, and its value is only 1 iff all other dimensions are 0.
*/
public class DimensionVector {
private String dimensionVectorIri;

private static final char[] dimensions = new char[] {'A', 'E', 'L', 'I', 'M', 'H', 'T', 'D'};

public static DimensionVector DIMENSIONLESS =
new DimensionVector(new int[] {0, 0, 0, 0, 0, 0, 0, 1});

private String dimensionVectorIri;

private final int[] values;

public static DimensionVector of(String dimensionVectorIri) {
public static Optional<DimensionVector> of(String dimensionVectorIri) {
try {
return Optional.of(new DimensionVector(dimensionVectorIri));
} catch (Exception e) {
return Optional.empty();
}
}

public static DimensionVector ofRequired(String dimensionVectorIri) {
return new DimensionVector(dimensionVectorIri);
}

public static DimensionVector of(int[] dimensionValues) {
public static Optional<DimensionVector> of(int[] dimensionValues) {
try {
return Optional.of(new DimensionVector(dimensionValues));
} catch (Exception e) {
return Optional.empty();
}
}

public static DimensionVector ofRequired(int[] dimensionValues) {
return new DimensionVector(dimensionValues);
}

Expand Down Expand Up @@ -67,6 +90,10 @@ public DimensionVector() {
this(new int[8]);
}

public boolean isDimensionless() {
return this.equals(DIMENSIONLESS);
}

public String getDimensionVectorIri() {
return dimensionVectorIri;
}
Expand Down Expand Up @@ -104,4 +131,20 @@ public DimensionVector combine(DimensionVector other) {
setRatio(combined, isRatio);
return new DimensionVector(combined);
}

@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof DimensionVector)) return false;
DimensionVector that = (DimensionVector) o;
return Objects.equals(getDimensionVectorIri(), that.getDimensionVectorIri())
&& Arrays.equals(getValues(), that.getValues());
}

@Override
public int hashCode() {
int result = Objects.hash(getDimensionVectorIri());
result = 31 * result + Arrays.hashCode(getValues());
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ public FactorUnits(List<FactorUnit> factorUnits) {
this(factorUnits, new BigDecimal("1"));
}

public FactorUnits(FactorUnits other) {
this(other.factorUnits, other.scaleFactor);
}

public static FactorUnits ofUnit(Unit unit) {
return new FactorUnits(
List.of(FactorUnit.builder().unit(Unit.definition(unit)).exponent(1).build()));
Expand All @@ -32,6 +36,13 @@ public static Builder builder() {
return new Builder();
}

public static Builder builderOf(FactorUnits factorUnits) {
Builder builder = builder();
builder.scaleFactor(factorUnits.getScaleFactor());
factorUnits.factorUnits.forEach(fu -> builder.factor(fu));
return builder;
}

public static boolean hasFactorUnits(List<FactorUnit> factorUnits) {
if (factorUnits == null) {
return false;
Expand All @@ -46,7 +57,7 @@ public static boolean hasFactorUnits(List<FactorUnit> factorUnits) {
}

public static class Builder {
private List<FactorUnit> factorUnits = new ArrayList<>();
private List<FactorUnit.Builder> factorUnitBuilders = new ArrayList<>();
private BigDecimal scale = BigDecimal.ONE;

private Builder() {}
Expand All @@ -58,7 +69,12 @@ public Builder factor(Unit unit, int exponent) {
}

public Builder factor(FactorUnit factorUnit) {
this.factorUnits.add(factorUnit);
this.factor(FactorUnit.builder(factorUnit));
return this;
}

public Builder factor(FactorUnit.Builder factorUnitBuilder) {
this.factorUnitBuilders.add(factorUnitBuilder);
return this;
}

Expand All @@ -75,7 +91,9 @@ public Builder scaleFactor(BigDecimal scaleFactor) {
}

public FactorUnits build() {
return new FactorUnits(this.factorUnits, this.scale);
return new FactorUnits(
factorUnitBuilders.stream().map(FactorUnit.Builder::build).collect(toList()),
this.scale);
}
}

Expand Down Expand Up @@ -209,9 +227,9 @@ public String getDimensionVectorIri() {
+ this.toString());
}
if (dv == null) {
dv = DimensionVector.of(fudvOpt.get());
dv = DimensionVector.ofRequired(fudvOpt.get());
} else {
dv = dv.combine(DimensionVector.of(fudvOpt.get()));
dv = dv.combine(DimensionVector.ofRequired(fudvOpt.get()));
}
}
return dv.getDimensionVectorIri();
Expand Down Expand Up @@ -275,16 +293,54 @@ public BigDecimal conversionFactor(Unit other) {
break;
}
}
if (processed != null) {
if (processed == null) {
// no match for myFactor in OtherFactorUnitList. If myFactor is D1, multiply it in
// anyway so we get its conversionMultiplier.
if (myFactor.getDimensionVectorIri()
.map(dv -> DimensionVector.ofRequired(dv).isDimensionless())
.orElse(false)) {
factor =
factor.multiply(
myFactor.getUnit()
.getConversionMultiplier()
.orElse(BigDecimal.ONE));
} else {
throw new RuntimeException(
String.format(
"Cannot calculate conversion factor beween factor units %s and %s: factor(s) %s of %s is unmatched",
myFactors, otherFactors, myFactor, myFactorUnitList));
}
} else {
otherFactorUnitList.remove(processed);
processed = null;
}
}
if (!otherFactorUnitList.isEmpty()) {
throw new RuntimeException(
String.format(
"Cannot calculate conversion factor beween factor units %s and %s: %s is unmatched on the right-hand side",
myFactors, otherFactors, otherFactorUnitList));
List<FactorUnit> unmatchedFactors = new ArrayList<>();
for (FactorUnit otherFactor : otherFactorUnitList) {
// no match for myFactor in OtherFactorUnitList. If myFactor is D1, multiply it in
// anyway so we get its conversionMultiplier.
if (otherFactor
.getDimensionVectorIri()
.map(dv -> DimensionVector.ofRequired(dv).isDimensionless())
.orElse(false)) {
factor =
factor.divide(
otherFactor
.getUnit()
.getConversionMultiplier()
.orElse(BigDecimal.ONE),
MathContext.DECIMAL128);
} else {
unmatchedFactors.add(otherFactor);
}
}
if (!unmatchedFactors.isEmpty()) {
throw new RuntimeException(
String.format(
"Cannot calculate conversion factor beween factor units %s and %s: factor(s) %s of %s is unmatched ",
myFactors, otherFactors, unmatchedFactors, otherFactors));
}
}
return factor;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ public boolean allowsUnit(Unit toCheck) {
return allowsUnit(base);
}
if (toCheck.hasFactorUnits()) {
return toCheck.getFactorUnits().stream().allMatch(fu -> this.allowsUnit(fu.unit));
return toCheck.getFactorUnits().getFactorUnits().stream()
.allMatch(fu -> this.allowsUnit(fu.unit));
}
return false;
}
Expand Down
Loading

0 comments on commit 95e4eeb

Please sign in to comment.