diff --git a/Makefile b/Makefile index 2aaf0f97..cb10ce79 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,7 @@ Brick.ttl: bricksrc/*.py bricksrc/*.ttl bricksrc/definitions.csv generate_brick. python handle_extensions.py clean: - rm -r Brick.ttl Brick+extensions.ttl imports/ + rm -r Brick.ttl Brick+extensions.ttl imports/ .ontoenv format: black generate_brick.py diff --git a/bricksrc/entity_properties.py b/bricksrc/entity_properties.py index e0378122..65256c78 100644 --- a/bricksrc/entity_properties.py +++ b/bricksrc/entity_properties.py @@ -14,37 +14,37 @@ SKOS.definition: Literal("Marks a concept as deprecated"), "property_of": BRICK.Entity, SH.node: BRICK.DeprecationShape, - RDFS.label: Literal("Deprecation Notice"), + RDFS.label: Literal("Deprecation Notice", lang="en"), }, BRICK.lastKnownValue: { SKOS.definition: Literal("The last known value of the Point entity"), "property_of": BRICK.Point, SH.node: BSH.LastKnownValueShape, - RDFS.label: Literal("Last known value"), + RDFS.label: Literal("Last known value", lang="en"), }, BRICK.area: { SKOS.definition: Literal("Entity has 2-dimensional area"), SH.node: BSH.AreaShape, "property_of": BRICK.Location, - RDFS.label: Literal("Area"), + RDFS.label: Literal("Area", lang="en"), "subproperties": { BRICK.grossArea: { SKOS.definition: Literal("Entity has gross 2-dimensional area"), SH.node: BSH.AreaShape, "property_of": BRICK.Location, - RDFS.label: Literal("Gross area"), + RDFS.label: Literal("Gross area", lang="en"), }, BRICK.netArea: { SKOS.definition: Literal("Entity has net 2-dimensional area"), SH.node: BSH.AreaShape, "property_of": BRICK.Location, - RDFS.label: Literal("Net area"), + RDFS.label: Literal("Net area", lang="en"), }, BRICK.panelArea: { SKOS.definition: Literal("Surface area of a panel, such as a PV panel"), "property_of": BRICK.Equipment, SH.node: BSH.AreaShape, - RDFS.label: Literal("Panel area"), + RDFS.label: Literal("Panel area", lang="en"), }, }, }, @@ -52,14 +52,14 @@ SKOS.definition: Literal("Entity has 3-dimensional volume"), "property_of": [BRICK.Equipment, BRICK.Location], SH.node: BSH.VolumeShape, - RDFS.label: Literal("Volume"), + RDFS.label: Literal("Volume", lang="en"), }, BRICK.azimuth: { SKOS.definition: Literal( "(Horizontal) angle between a projected vector and a reference vector (typically a compass bearing). The projected vector usually indicates the direction of a face or plane." ), SH.node: BSH.AzimuthShape, - RDFS.label: Literal("Azimuth"), + RDFS.label: Literal("Azimuth", lang="en"), "property_of": BRICK.Equipment, }, BRICK.tilt: { @@ -67,20 +67,20 @@ "The direction an entity is facing in degrees above the horizon" ), SH.node: BSH.TiltShape, - RDFS.label: Literal("Tilt"), + RDFS.label: Literal("Tilt", lang="en"), "property_of": BRICK.Equipment, }, BRICK.coordinates: { SKOS.definition: Literal("The location of an entity in latitude/longitude"), SH.node: BSH.CoordinateShape, - RDFS.label: Literal("Coordinates"), + RDFS.label: Literal("Coordinates", lang="en"), "property_of": [BRICK.Equipment, BRICK.Location], }, # electrical properties BRICK.electricalComplexPower: { SKOS.definition: Literal("Associated electrical complexity with the entity"), SH.node: BSH.ElectricalComplexPowerShape, - RDFS.label: Literal("electrical complex power type"), + RDFS.label: Literal("electrical complex power type", lang="en"), "property_of": [BRICK.Equipment, BRICK.Point], }, BRICK.electricalFlow: { @@ -88,59 +88,59 @@ "Entity has this electrical flow relative to the building'" ), SH.node: BSH.ElectricalFlowShape, - RDFS.label: Literal("Electrical flow direction"), + RDFS.label: Literal("Electrical flow direction", lang="en"), "property_of": [BRICK.Equipment, BRICK.Point], }, BRICK.electricalPhases: { SKOS.definition: Literal("Entity has these electrical AC phases"), SH.node: BSH.PhasesShape, - RDFS.label: Literal("Electrical phases"), + RDFS.label: Literal("Electrical phases", lang="en"), "property_of": BRICK.Equipment, }, BRICK.electricalPhaseCount: { SKOS.definition: Literal("Entity has these phases"), SH.node: BSH.PhaseCountShape, - RDFS.label: Literal("Electrical phase count"), + RDFS.label: Literal("Electrical phase count", lang="en"), "property_of": BRICK.Equipment, }, BRICK.currentFlowType: { SKOS.definition: Literal("The current flow type of the entity"), SH.node: BSH.CurrentFlowTypeShape, - RDFS.label: Literal("Current flow type"), + RDFS.label: Literal("Current flow type", lang="en"), "property_of": BRICK.Equipment, }, BRICK.ratedPowerOutput: { SKOS.definition: Literal("The nominal rated power output of the entity"), - RDFS.label: Literal("Rated power output"), + RDFS.label: Literal("Rated power output", lang="en"), SH.node: BSH.PowerQuantityShape, "property_of": BRICK.Equipment, }, BRICK.measuredPowerOutput: { SKOS.definition: Literal("The nominal measured power output of the entity"), - RDFS.label: Literal("Measured power output"), + RDFS.label: Literal("Measured power output", lang="en"), SH.node: BSH.PowerQuantityShape, "property_of": BRICK.Equipment, }, BRICK.ratedPowerInput: { SKOS.definition: Literal("The nominal rated power input of the entity"), - RDFS.label: Literal("Rated power input"), + RDFS.label: Literal("Rated power input", lang="en"), SH.node: BSH.PowerQuantityShape, "property_of": BRICK.Equipment, }, BRICK.measuredPowerInput: { SKOS.definition: Literal("The nominal measured power input of the entity"), - RDFS.label: Literal("Measured power input"), + RDFS.label: Literal("Measured power input", lang="en"), SH.node: BSH.PowerQuantityShape, "property_of": BRICK.Equipment, }, BRICK.ratedVoltageInput: { SKOS.definition: Literal("The nominal rated voltage input of the entity"), SH.node: BSH.VoltageQuantityShape, - RDFS.label: Literal("Measured voltage input"), + RDFS.label: Literal("Measured voltage input", lang="en"), "property_of": BRICK.Equipment, "subproperties": { BRICK.ratedMaximumVoltageInput: { - RDFS.label: Literal("Rated maximum voltage input"), + RDFS.label: Literal("Rated maximum voltage input", lang="en"), SKOS.definition: Literal( "The maximum voltage that can be input to the entity" ), @@ -148,7 +148,7 @@ "property_of": BRICK.Equipment, }, BRICK.ratedMinimumVoltageInput: { - RDFS.label: Literal("Rated minimum voltage input"), + RDFS.label: Literal("Rated minimum voltage input", lang="en"), SKOS.definition: Literal( "The minimum voltage that can be input to the entity" ), @@ -161,10 +161,10 @@ SKOS.definition: Literal("The nominal rated voltage output of the entity"), SH.node: BSH.VoltageQuantityShape, "property_of": BRICK.Equipment, - RDFS.label: Literal("Rated voltage output"), + RDFS.label: Literal("Rated voltage output", lang="en"), "subproperties": { BRICK.ratedMaximumVoltageOutput: { - RDFS.label: Literal("Rated maximum voltage output"), + RDFS.label: Literal("Rated maximum voltage output", lang="en"), SKOS.definition: Literal( "The maximum voltage that can be output by the entity" ), @@ -172,7 +172,7 @@ "property_of": BRICK.Equipment, }, BRICK.ratedMinimumVoltageOutput: { - RDFS.label: Literal("Rated minimum voltage output"), + RDFS.label: Literal("Rated minimum voltage output", lang="en"), SKOS.definition: Literal( "The minimum voltage that can be output by the entity" ), @@ -184,11 +184,11 @@ BRICK.ratedCurrentInput: { SKOS.definition: Literal("The nominal rated current input of the entity"), SH.node: BSH.Electric_CurrentQuantityShape, - RDFS.label: Literal("Rated current input"), + RDFS.label: Literal("Rated current input", lang="en"), "property_of": BRICK.Equipment, "subproperties": { BRICK.ratedMaximumCurrentInput: { - RDFS.label: Literal("Rated maximum current input"), + RDFS.label: Literal("Rated maximum current input", lang="en"), SKOS.definition: Literal( "The maximum current that can be input to the entity" ), @@ -196,7 +196,7 @@ "property_of": BRICK.Equipment, }, BRICK.ratedMinimumCurrentInput: { - RDFS.label: Literal("Rated minimum current input"), + RDFS.label: Literal("Rated minimum current input", lang="en"), SKOS.definition: Literal( "The minimum current that can be input to the entity" ), @@ -208,11 +208,11 @@ BRICK.ratedCurrentOutput: { SKOS.definition: Literal("The nominal rated current output of the entity"), SH.node: BSH.Electric_CurrentQuantityShape, - RDFS.label: Literal("Rated current output"), + RDFS.label: Literal("Rated current output", lang="en"), "property_of": BRICK.Equipment, "subproperties": { BRICK.ratedMaximumCurrentOutput: { - RDFS.label: Literal("Rated maximum current output"), + RDFS.label: Literal("Rated maximum current output", lang="en"), SKOS.definition: Literal( "The maximum current that can be output by the entity" ), @@ -220,7 +220,7 @@ "property_of": BRICK.Equipment, }, BRICK.ratedMinimumCurrentOutput: { - RDFS.label: Literal("Rated minimum current output"), + RDFS.label: Literal("Rated minimum current output", lang="en"), SKOS.definition: Literal( "The minimum current that can be output by the entity" ), @@ -234,7 +234,7 @@ "The % change in power output for every degree celsius that the entity is hotter than 25 degrees celsius" ), SH.node: BSH.TemperatureCoefficientPerDegreeCelsiusShape, - RDFS.label: Literal("Temperature coefficient"), + RDFS.label: Literal("Temperature coefficient", lang="en"), "property_of": BRICK.Equipment, }, BRICK.conversionEfficiency: { @@ -242,7 +242,7 @@ "The percent efficiency of the conversion process (usually to power or energy) carried out by the entity" ), SH.node: BSH.EfficiencyShape, - RDFS.label: Literal("Conversion efficiency"), + RDFS.label: Literal("Conversion efficiency", lang="en"), "property_of": BRICK.Equipment, "subproperties": { BRICK.ratedModuleConversionEfficiency: { @@ -251,7 +251,7 @@ ), "property_of": BRICK.PV_Panel, SH.node: BSH.EfficiencyShape, - RDFS.label: Literal("Rated module conversion efficiency"), + RDFS.label: Literal("Rated module conversion efficiency", lang="en"), }, BRICK.measuredModuleConversionEfficiency: { SKOS.definition: Literal( @@ -259,7 +259,7 @@ ), "property_of": BRICK.PV_Panel, SH.node: BSH.EfficiencyShape, - RDFS.label: Literal("Measured module conversion efficiency"), + RDFS.label: Literal("Measured module conversion efficiency", lang="en"), }, }, }, @@ -267,7 +267,7 @@ BRICK.operationalStage: { SKOS.definition: Literal("The associated operational stage"), SH.node: BSH.StageShape, - RDFS.label: Literal("Operational stage"), + RDFS.label: Literal("Operational stage", lang="en"), "property_of": BRICK.Equipment, }, BRICK.operationalStageCount: { @@ -276,7 +276,7 @@ ), "property_of": BRICK.Equipment, SH.node: BSH.StageShape, - RDFS.label: Literal("Operational stage count"), + RDFS.label: Literal("Operational stage count", lang="en"), }, BRICK.coolingCapacity: { SKOS.definition: Literal( @@ -284,7 +284,7 @@ ), "property_of": BRICK.Chiller, SH.node: BSH.CoolingCapacityShape, - RDFS.label: Literal("Cooling capacity"), + RDFS.label: Literal("Cooling capacity", lang="en"), RDFS.seeAlso: Literal("https://project-haystack.org/tag/coolingCapacity"), }, # building properties @@ -295,7 +295,7 @@ RDFS.seeAlso: Literal("https://project-haystack.org/tag/primaryFunction"), "property_of": BRICK.Building, SH.node: BSH.BuildingPrimaryFunctionShape, - RDFS.label: Literal("Building primary function"), + RDFS.label: Literal("Building primary function", lang="en"), }, BRICK.yearBuilt: { SKOS.definition: Literal( @@ -304,7 +304,7 @@ "property_of": BRICK.Building, SH.node: BSH.YearBuiltShape, RDFS.seeAlso: Literal("https://project-haystack.org/tag/yearBuilt"), - RDFS.label: Literal("Year built"), + RDFS.label: Literal("Year built", lang="en"), }, BRICK.thermalTransmittance: { SKOS.definition: Literal( @@ -312,7 +312,7 @@ ), "property_of": BRICK.Location, SH.node: BSH.ThermalTransmittanceShape, - RDFS.label: Literal("Thermal transmittance"), + RDFS.label: Literal("Thermal transmittance", lang="en"), RDFS.seeAlso: Literal( "https://www.iso.org/obp/ui/#iso:std:iso:13789:ed-3:v1:en" ), @@ -326,7 +326,7 @@ RDFS.seeAlso: Literal( "https://www.iso.org/obp/ui/#iso:std:iso:13789:ed-3:v1:en" ), - RDFS.label: Literal("Building thermal transmittance"), + RDFS.label: Literal("Building thermal transmittance", lang="en"), }, }, }, @@ -337,7 +337,7 @@ ), "property_of": BRICK.Point, SH.node: BSH.AggregationShape, - RDFS.label: Literal("Aggregate"), + RDFS.label: Literal("Aggregate", lang="en"), }, BRICK.isVirtualMeter: { SKOS.definition: Literal( @@ -345,14 +345,14 @@ ), "property_of": BRICK.Meter, SH.node: BSH.VirtualMeterShape, - RDFS.label: Literal("is virtual meter"), + RDFS.label: Literal("is virtual meter", lang="en"), }, BRICK.electricVehicleChargerType: { SKOS.definition: Literal( "Which type of EVSE charger this is, e.g. Level 1 (up to up to 2.5kW of AC power on 1 phase 120V input), Level 2 (direct AC power but can use higher voltage and up to 3 phases), or Level 3 (direct DC power)" ), "property_of": BRICK.Electric_Vehicle_Charging_Station, - RDFS.label: Literal("has electric vehicle charger type"), + RDFS.label: Literal("has electric vehicle charger type", lang="en"), SH.node: BSH.ElectricVehicleChargingTypeShape, }, BRICK.electricVehicleChargerDirectionality: { @@ -363,7 +363,7 @@ BRICK.Electric_Vehicle_Charging_Station, BRICK.Electric_Vehicle_Charging_Port, ], - RDFS.label: Literal("has electric vehicle charger directionality"), + RDFS.label: Literal("has electric vehicle charger directionality", lang="en"), SH.node: BSH.ElectricVehicleChargingDirectionalityShape, }, BRICK.electricVehicleConnectorType: { @@ -371,7 +371,7 @@ "Identifies which kind of connector the port has. This property helps identify the physical connection required between the vehicle and the charging equipment." ), "property_of": BRICK.Electric_Vehicle_Charging_Port, - RDFS.label: Literal("has electric vehicle connector type"), + RDFS.label: Literal("has electric vehicle connector type", lang="en"), SH.node: BSH.ElectricVehicleConnectorTypeShape, }, } diff --git a/bricksrc/env.py b/bricksrc/env.py new file mode 100644 index 00000000..adc146eb --- /dev/null +++ b/bricksrc/env.py @@ -0,0 +1,3 @@ +from ontoenv import OntoEnv, Config +cfg = Config(["support/"], strict=False, offline=True) +env = OntoEnv(cfg) diff --git a/bricksrc/quantities.py b/bricksrc/quantities.py index 6b50c44f..12edb300 100644 --- a/bricksrc/quantities.py +++ b/bricksrc/quantities.py @@ -1,9 +1,9 @@ from brickschema.graph import Graph -from ontoenv import OntoEnv +from ontoenv import OntoEnv, Config from rdflib import Literal, URIRef -from .namespaces import SKOS, RDFS, BRICK, QUDTQK, QUDTDV, QUDT, UNIT +from .namespaces import SKOS, RDFS, BRICK, QUDTQK, QUDTDV, QUDT, UNIT, XSD +from .env import env -env = OntoEnv(initialize=True, search_dirs=["support/"]) g = Graph() g.load_file("support/VOCAB_QUDT-QUANTITY-KINDS-ALL-v2.1.ttl") g.load_file("support/VOCAB_QUDT-UNITS-ALL-v2.1.ttl") @@ -50,7 +50,7 @@ def all_units(): QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], SKOS.definition: Literal("The concentration of Ammonia in a medium"), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("AmmoniaConcentration"), + RDFS.label: Literal("AmmoniaConcentration", lang="en"), SKOS.broader: QUDTQK.DimensionlessRatio, }, "CO_Concentration": { @@ -60,7 +60,7 @@ def all_units(): "The concentration of carbon monoxide in a medium" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("COConcentration"), + RDFS.label: Literal("COConcentration", lang="en"), SKOS.broader: QUDTQK.DimensionlessRatio, SKOS.narrower: { "Differential_CO_Concentration": { @@ -70,7 +70,7 @@ def all_units(): "The difference in carbon monoxide concentration between two areas" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("ΔCOConcentration"), + RDFS.label: Literal("ΔCOConcentration", lang="en"), }, }, }, @@ -81,7 +81,7 @@ def all_units(): "The concentration of carbon dioxide in a medium" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("CO2Concentration"), + RDFS.label: Literal("CO2Concentration", lang="en"), SKOS.broader: QUDTQK.DimensionlessRatio, SKOS.narrower: { "Differential_CO2_Concentration": { @@ -91,7 +91,7 @@ def all_units(): "The difference in carbon dioxide concentration between two areas" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("ΔCO2Concentration"), + RDFS.label: Literal("ΔCO2Concentration", lang="en"), }, }, }, @@ -102,7 +102,7 @@ def all_units(): "The concentration of formaldehyde in a medium" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("FormaldehydeConcentration"), + RDFS.label: Literal("FormaldehydeConcentration", lang="en"), SKOS.broader: QUDTQK.DimensionlessRatio, }, "Ozone_Concentration": { @@ -110,7 +110,7 @@ def all_units(): QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], SKOS.definition: Literal("The concentration of ozone in a medium"), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("OzoneConcentration"), + RDFS.label: Literal("OzoneConcentration", lang="en"), SKOS.broader: QUDTQK.DimensionlessRatio, }, "Methane_Concentration": { @@ -118,7 +118,7 @@ def all_units(): QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], SKOS.definition: Literal("The concentration of methane in a medium"), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("MethaneConcentration"), + RDFS.label: Literal("MethaneConcentration", lang="en"), SKOS.broader: QUDTQK.DimensionlessRatio, }, "NO2_Concentration": { @@ -128,7 +128,7 @@ def all_units(): "The concentration of nitrogen dioxide in a medium" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("PM10Concentration"), + RDFS.label: Literal("PM10Concentration", lang="en"), }, "PM10_Concentration": { QUDT.applicableUnit: [UNIT.PPM, UNIT.PPB, UNIT["MicroGM-PER-M3"]], @@ -136,7 +136,7 @@ def all_units(): "The concentration of particulates with diameter of 10 microns or less in air" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("PM10Concentration"), + RDFS.label: Literal("PM10Concentration", lang="en"), }, "PM2.5_Concentration": { QUDT.applicableUnit: [UNIT.PPM, UNIT.PPB, UNIT["MicroGM-PER-M3"]], @@ -144,7 +144,7 @@ def all_units(): "The concentration of particulates with diameter of 2.5 microns or less in air" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("PM2.5Concentration"), + RDFS.label: Literal("PM2.5Concentration", lang="en"), }, "PM1_Concentration": { QUDT.applicableUnit: [UNIT.PPM, UNIT.PPB, UNIT["MicroGM-PER-M3"]], @@ -152,7 +152,7 @@ def all_units(): "The concentration of particulates with diameter of 1 microns or less in air" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("PM1Concentration"), + RDFS.label: Literal("PM1Concentration", lang="en"), }, "Radioactivity_Concentration": { SKOS.narrower: { @@ -163,7 +163,7 @@ def all_units(): "The concentration of radioactivity due to Radon in a medium" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("RadonConcentration"), + RDFS.label: Literal("RadonConcentration", lang="en"), SKOS.broader: QUDTQK.ActivityConcentration, }, }, @@ -175,7 +175,7 @@ def all_units(): "The concentration of total volatile organic compounds in air" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("TVOCConcentration"), + RDFS.label: Literal("TVOCConcentration", lang="en"), SKOS.broader: QUDTQK.DimensionlessRatio, }, }, @@ -184,7 +184,7 @@ def all_units(): QUDT.applicableUnit: UNIT.GRAIN, QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M1H0T0D0"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("GrainsOfMoisture"), + RDFS.label: Literal("GrainsOfMoisture", lang="en"), SKOS.definition: Literal( "Mass of moisture per pround of air, measured in grains of water" ), @@ -209,7 +209,7 @@ def all_units(): QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], SKOS.definition: Literal("Angle component of a phasor"), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("PhasorAngle"), + RDFS.label: Literal("PhasorAngle", lang="en"), SKOS.broader: QUDTQK.PlaneAngle, }, "Phasor_Magnitude": { @@ -229,7 +229,7 @@ def all_units(): QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], SKOS.definition: Literal("Magnitude component of a phasor"), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("PhasorMagnitude"), + RDFS.label: Literal("PhasorMagnitude", lang="en"), }, }, }, @@ -240,7 +240,7 @@ def all_units(): "The fraction of the sky obscured by clouds when observed from a particular location" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Cloudage"), + RDFS.label: Literal("Cloudage", lang="en"), SKOS.broader: QUDTQK.Dimensionless, }, "Electric_Current": { @@ -266,7 +266,7 @@ def all_units(): QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], SKOS.definition: Literal("Angle of current phasor"), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("CurrentAngle"), + RDFS.label: Literal("CurrentAngle", lang="en"), SKOS.broader: BRICK.Phasor_Angle, }, "Current_Imbalance": { @@ -274,7 +274,7 @@ def all_units(): QUDT.applicableUnit: [UNIT.PERCENT], QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("CurrentImbalance"), + RDFS.label: Literal("CurrentImbalance", lang="en"), SKOS.broader: QUDTQK.Dimensionless, }, "Current_Total_Harmonic_Distortion": { @@ -284,7 +284,7 @@ def all_units(): QUDT.applicableUnit: [UNIT.PERCENT, UNIT.DeciB_M], QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("CurrentTotalHarmonicDistortion"), + RDFS.label: Literal("CurrentTotalHarmonicDistortion", lang="en"), SKOS.broader: QUDTQK.Dimensionless, }, "Alternating_Current_Frequency": { @@ -294,7 +294,7 @@ def all_units(): ), QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T-1D0"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Alternating_Current_Frequency"), + RDFS.label: Literal("Alternating_Current_Frequency", lang="en"), SKOS.broader: QUDTQK.Frequency, }, }, @@ -322,7 +322,7 @@ def all_units(): QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], SKOS.definition: Literal("Angle of voltage phasor"), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("VoltageAngle"), + RDFS.label: Literal("VoltageAngle", lang="en"), SKOS.broader: BRICK.Phasor_Angle, }, "Voltage_Imbalance": { @@ -330,7 +330,7 @@ def all_units(): QUDT.applicableUnit: [UNIT.PERCENT], QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("VoltageImbalance"), + RDFS.label: Literal("VoltageImbalance", lang="en"), SKOS.broader: QUDTQK.Dimensionless, }, }, @@ -354,7 +354,7 @@ def all_units(): QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], SKOS.definition: Literal("Direction of wind relative to North"), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Wind_Direction"), + RDFS.label: Literal("Wind_Direction", lang="en"), } } }, @@ -378,7 +378,7 @@ def all_units(): "A form of energy resulting from the flow of electrical charge" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("ElectricEnergy"), + RDFS.label: Literal("ElectricEnergy", lang="en"), SKOS.broader: QUDTQK["Energy"], SKOS.narrower: { "Active_Energy": { @@ -391,7 +391,7 @@ def all_units(): "The integral of the active power over a time interval" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Active_Energy"), + RDFS.label: Literal("Active_Energy", lang="en"), }, "Reactive_Energy": { QUDT.applicableUnit: [ @@ -403,7 +403,7 @@ def all_units(): "The integral of the reactive power over a time interval" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Reactive_Energy"), + RDFS.label: Literal("Reactive_Energy", lang="en"), }, "Apparent_Energy": { QUDT.applicableUnit: [ @@ -415,7 +415,7 @@ def all_units(): "The integral of the apparent power over a time interval" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Apparent_Energy"), + RDFS.label: Literal("Apparent_Energy", lang="en"), }, }, }, @@ -437,7 +437,7 @@ def all_units(): "The power per unit area of electromagnetic radiation incident on a surface" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Irradiance"), + RDFS.label: Literal("Irradiance", lang="en"), SKOS.broader: QUDTQK.PowerPerArea, SKOS.narrower: { "Solar_Irradiance": { @@ -451,7 +451,7 @@ def all_units(): "The power per unit area of solar electromagnetic radiation incident on a surface" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("SolarIrradiance"), + RDFS.label: Literal("SolarIrradiance", lang="en"), SKOS.broader: BRICK.Irradiance, } }, @@ -470,7 +470,7 @@ def all_units(): ], QUDT.hasDimensionVector: QUDTDV["A0E0L1I0M0H0T0D0"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Level"), + RDFS.label: Literal("Level", lang="en"), SKOS.definition: Literal( "Amount of substance in a container; typically measured in height" ), @@ -493,7 +493,7 @@ def all_units(): ), QUDT.hasDimensionVector: QUDTDV["A0E0L1I0M0H0T0D0"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Precipitation"), + RDFS.label: Literal("Precipitation", lang="en"), SKOS.broader: QUDTQK.Length, }, }, @@ -504,7 +504,7 @@ def all_units(): # QUDT.applicableUnit: [UNIT["People"]], SKOS.definition: Literal("Number of people in an area"), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Occupancy_Count"), + RDFS.label: Literal("Occupancy_Count", lang="en"), SKOS.broader: QUDTQK.Dimensionless, }, "Occupancy_Percentage": { @@ -514,7 +514,7 @@ def all_units(): "Percent of total occupancy of space that is occupied" ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Occupancy_Percentage"), + RDFS.label: Literal("Occupancy_Percentage", lang="en"), SKOS.broader: QUDTQK.Dimensionless, }, } @@ -523,7 +523,7 @@ def all_units(): QUDT.applicableUnit: [UNIT["PERCENT"]], SKOS.definition: Literal("The fraction of the full range of motion"), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Position"), + RDFS.label: Literal("Position", lang="en"), SKOS.broader: QUDTQK.Dimensionless, QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H0T0D1"], }, @@ -557,7 +557,7 @@ def all_units(): ], SKOS.definition: Literal("Pressure relative to atmospheric pressure"), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Gauge_Pressure"), + RDFS.label: Literal("Gauge_Pressure", lang="en"), SKOS.broader: QUDTQK.Pressure, }, "Static_Pressure": { @@ -592,7 +592,7 @@ def all_units(): "The amount of light that passes through or is emitted from the sun and falls within a given solid angle in a specified direction", ), RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Solar_Radiance"), + RDFS.label: Literal("Solar_Radiance", lang="en"), SKOS.broader: QUDTQK.Radiance, } }, @@ -616,7 +616,7 @@ def all_units(): ), QUDT.hasDimensionVector: QUDTDV["A0E0L1I0M0H0T-1D0"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Linear_Speed"), + RDFS.label: Literal("Linear_Speed", lang="en"), SKOS.broader: QUDTQK.Speed, }, "Rotational_Speed": { @@ -633,7 +633,7 @@ def all_units(): ), QUDT.hasDimensionVector: QUDTDV["A0E0L1I0M0H0T-1D0"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Rotational_Speed"), + RDFS.label: Literal("Rotational_Speed", lang="en"), SKOS.broader: [QUDTQK.Speed, QUDTQK.Frequency], }, }, @@ -652,7 +652,7 @@ def all_units(): ), QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H1T0D0"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Operative_Temperature"), + RDFS.label: Literal("Operative_Temperature", lang="en"), SKOS.broader: QUDTQK.Temperature, }, "Radiant_Temperature": { @@ -662,7 +662,7 @@ def all_units(): ), QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H1T0D0"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Radiant_Temperature"), + RDFS.label: Literal("Radiant_Temperature", lang="en"), SKOS.broader: QUDTQK.Temperature, }, "Dry_Bulb_Temperature": { @@ -672,7 +672,7 @@ def all_units(): ), QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H1T0D0"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Dry_Bulb_Temperature"), + RDFS.label: Literal("Dry_Bulb_Temperature", lang="en"), SKOS.broader: QUDTQK.Temperature, SKOS.narrower: { "Differential_Dry_Bulb_Temperature": { @@ -687,7 +687,7 @@ def all_units(): ), QUDT.hasDimensionVector: QUDTDV["A0E0L0I0M0H1T0D0"], RDFS.isDefinedBy: URIRef(str(BRICK).strip("#")), - RDFS.label: Literal("Wet_Bulb_Temperature"), + RDFS.label: Literal("Wet_Bulb_Temperature", lang="en"), SKOS.broader: QUDTQK.Temperature, }, }, @@ -703,7 +703,7 @@ def all_units(): BRICK.hasQUDTReference: QUDTQK["Volume"], QUDT.applicableUnit: [UNIT["M3"], UNIT["FT3"], UNIT["IN3"], UNIT["YD3"]], QUDT.hasDimensionVector: QUDTDV["A0E0L3I0M0H0T0D0"], - RDFS.label: Literal("Volume"), + RDFS.label: Literal("Volume", lang="en"), }, "Weather_Condition": {}, } diff --git a/bricksrc/relationships.py b/bricksrc/relationships.py index 888dfee4..ce39cbac 100644 --- a/bricksrc/relationships.py +++ b/bricksrc/relationships.py @@ -1,5 +1,5 @@ from rdflib import Literal -from .namespaces import A, OWL, RDFS, BRICK, VCARD, UNIT, QUDT, SDO, RDF, BSH, XSD +from .namespaces import A, OWL, RDFS, BRICK, VCARD, QUDT, SDO, RDF, BSH, XSD """ Defining Brick relationships @@ -7,57 +7,57 @@ relationships = { "connectedTo": { A: [OWL.ObjectProperty, OWL.SymmetricProperty, OWL.IrreflexiveProperty], - RDFS.label: Literal("Connected To"), + RDFS.label: Literal("Connected To", lang="en"), }, "isReplacedBy": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], - RDFS.label: Literal("Is replaced by"), + RDFS.label: Literal("Is replaced by", lang="en"), "range": BRICK.Entity, "domain": BRICK.Entity, }, "hasSubstance": { A: [OWL.AsymmetricProperty, OWL.IrreflexiveProperty], - RDFS.label: Literal("Has Substance"), + RDFS.label: Literal("Has Substance", lang="en"), "range": BRICK.Substance, "domain": [BRICK.Point, BRICK.Meter], }, "hasQuantity": { A: [OWL.AsymmetricProperty, OWL.IrreflexiveProperty], - RDFS.label: Literal("Has Quantity"), + RDFS.label: Literal("Has Quantity", lang="en"), RDFS.subPropertyOf: QUDT.hasQuantityKind, "range": [BRICK.Quantity, QUDT.QuantityKind], "domain": BRICK.Point, }, "value": { RDFS.subPropertyOf: QUDT.value, - RDFS.label: Literal("Value"), + RDFS.label: Literal("Value", lang="en"), A: [RDF.Property], "range": RDFS.Resource, "domain": RDFS.Resource, }, "latitude": { RDFS.subPropertyOf: SDO.latitude, - RDFS.label: Literal("Latitude"), + RDFS.label: Literal("Latitude", lang="en"), A: [OWL.ObjectProperty], "domain": BRICK.Entity, "datatype": BSH.NumericValue, }, "longitude": { RDFS.subPropertyOf: SDO.longitude, - RDFS.label: Literal("Longitude"), + RDFS.label: Literal("Longitude", lang="en"), A: [OWL.ObjectProperty], "domain": BRICK.Entity, "datatype": BSH.NumericValue, }, "timestamp": { - RDFS.label: Literal("Timestamp"), + RDFS.label: Literal("Timestamp", lang="en"), A: [RDF.Property], "domain": BRICK.Entity, "datatype": XSD.dateTime, }, "hasQUDTReference": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], - RDFS.label: Literal("Has QUDT reference"), + RDFS.label: Literal("Has QUDT reference", lang="en"), "domain": BRICK.Quantity, "range": QUDT.QuantityKind, }, @@ -66,43 +66,43 @@ OWL.inverseOf: BRICK["hasLocation"], "domain": BRICK.Location, "range": BRICK.Entity, - RDFS.label: Literal("Is location of"), + RDFS.label: Literal("Is location of", lang="en"), }, "hasLocation": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], OWL.inverseOf: BRICK["isLocationOf"], "domain": BRICK.Entity, "range": BRICK.Location, - RDFS.label: Literal("Has location"), + RDFS.label: Literal("Has location", lang="en"), }, "hasInputSubstance": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], "range": BRICK.Substance, "domain": BRICK.Equipment, - RDFS.label: Literal("Has input substance"), + RDFS.label: Literal("Has input substance", lang="en"), }, "hasOutputSubstance": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], "range": BRICK.Substance, "domain": BRICK.Equipment, - RDFS.label: Literal("Has output substance"), + RDFS.label: Literal("Has output substance", lang="en"), }, "feeds": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], OWL.inverseOf: BRICK["isFedBy"], - RDFS.label: Literal("Feeds"), + RDFS.label: Literal("Feeds", lang="en"), }, "isFedBy": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], OWL.inverseOf: BRICK["feeds"], - RDFS.label: Literal("Is fed by"), + RDFS.label: Literal("Is fed by", lang="en"), }, "hasPoint": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], OWL.inverseOf: BRICK["isPointOf"], "range": BRICK.Point, "domain": [BRICK.Equipment, BRICK.Location], - RDFS.label: Literal("Has point"), + RDFS.label: Literal("Has point", lang="en"), }, "isPointOf": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], @@ -112,56 +112,56 @@ BRICK.Equipment, BRICK.Location, ], - RDFS.label: Literal("Is point of"), + RDFS.label: Literal("Is point of", lang="en"), }, "hasPart": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], OWL.inverseOf: BRICK["isPartOf"], - RDFS.label: Literal("Has part"), + RDFS.label: Literal("Has part", lang="en"), }, "isPartOf": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], OWL.inverseOf: BRICK["hasPart"], - RDFS.label: Literal("Is part of"), + RDFS.label: Literal("Is part of", lang="en"), }, "hasTag": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], OWL.inverseOf: BRICK["isTagOf"], "range": BRICK.Tag, "domain": OWL.Class, - RDFS.label: Literal("Has tag"), + RDFS.label: Literal("Has tag", lang="en"), }, "isTagOf": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], "domain": BRICK.Tag, "range": OWL.Class, - RDFS.label: Literal("Is tag of"), + RDFS.label: Literal("Is tag of", lang="en"), }, "hasAssociatedTag": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], OWL.inverseOf: BRICK["isAssociatedWith"], "domain": OWL.Class, "range": BRICK.Tag, - RDFS.label: Literal("Has associated tag"), + RDFS.label: Literal("Has associated tag", lang="en"), }, "isAssociatedWith": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], OWL.inverseOf: BRICK["hasAssociatedTag"], "domain": BRICK.Tag, "range": OWL.Class, - RDFS.label: Literal("Is associated with"), + RDFS.label: Literal("Is associated with", lang="en"), }, "hasAddress": { RDFS.subPropertyOf: VCARD.hasAddress, "domain": BRICK.Building, "range": VCARD.Address, - RDFS.label: Literal("Has address"), + RDFS.label: Literal("Has address", lang="en"), }, "hasUnit": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], "range": QUDT.Unit, "domain": BRICK.Point, - RDFS.label: Literal("Has unit"), + RDFS.label: Literal("Has unit", lang="en"), }, "meters": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], @@ -169,7 +169,7 @@ "domain": BRICK.Meter, # this is a special property that implements the 'range' as a SHACL shape "range": [BRICK.Equipment, BRICK.Location, BRICK.Collection], - RDFS.label: Literal("meters"), + RDFS.label: Literal("meters", lang="en"), }, "isMeteredBy": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], @@ -177,20 +177,20 @@ # this is a special property that implements the 'domain' as a SHACL shape "domain": [BRICK.Equipment, BRICK.Location, BRICK.Collection], "range": BRICK.Meter, - RDFS.label: Literal("is metered by"), + RDFS.label: Literal("is metered by", lang="en"), }, "hasSubMeter": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], OWL.inverseOf: BRICK.isSubMeterOf, "range": BRICK.Meter, "domain": BRICK.Meter, - RDFS.label: Literal("has sub-meter"), + RDFS.label: Literal("has sub-meter", lang="en"), }, "isSubMeterOf": { A: [OWL.ObjectProperty, OWL.AsymmetricProperty, OWL.IrreflexiveProperty], OWL.inverseOf: BRICK.hasSubMeter, "range": BRICK.Meter, "domain": BRICK.Meter, - RDFS.label: Literal("is sub-meter of"), + RDFS.label: Literal("is sub-meter of", lang="en"), }, } diff --git a/bricksrc/root_class_shapes.ttl b/bricksrc/root_class_shapes.ttl index 1f940d5f..82a99cf8 100644 --- a/bricksrc/root_class_shapes.ttl +++ b/bricksrc/root_class_shapes.ttl @@ -32,6 +32,11 @@ brick:Location a sh:NodeShape ; sh:class brick:Equipment; sh:message "Locations can be fed only by other Equipment." ]; + sh:property [ + sh:path brick:hasPoint ; + sh:class brick:Point ; + sh:message "A Location can have Points." + ]; . brick:Equipment a sh:NodeShape ; @@ -45,6 +50,11 @@ brick:Equipment a sh:NodeShape ; sh:class brick:Equipment; sh:message "A piece of Equipment's parts should be always other Equipment." ]; + sh:property [ + sh:path brick:hasPoint ; + sh:class brick:Point ; + sh:message "A piece of Equipment can have Points." + ]; sh:property [ sh:path brick:isPartOf; sh:or ( @@ -82,6 +92,11 @@ brick:Point a sh:NodeShape; sh:maxCount 0 ; sh:message "Points cannot have locations; use 'isPointOf' instead" ; ] ; + sh:property [ + sh:path brick:isPointOf ; + sh:or ( [ sh:class brick:Equipment ] [ sh:class brick:Location ] [ sh:class rec:Space ] ); + sh:message "A Point can be a Point of Equipment, Location or Space." + ] ; . brick:Collection a sh:NodeShape; diff --git a/generate_brick.py b/generate_brick.py index 65810ada..20c19b59 100755 --- a/generate_brick.py +++ b/generate_brick.py @@ -1,4 +1,5 @@ import logging +from itertools import chain import os import brickschema import importlib @@ -18,7 +19,7 @@ define_extension, BRICK_IRI_VERSION, ) - +from bricksrc.env import env from bricksrc.namespaces import ( BRICK, @@ -146,7 +147,7 @@ def add_tags(klass, definition, graph=G): graph.add((klass, BRICK.hasAssociatedTag, tag)) graph.add((tag, A, BRICK.Tag)) # make sure the tag is declared as such graph.add( - (tag, RDFS.label, Literal(tag.split("#")[-1])) + (tag, RDFS.label, Literal(tag.split("#")[-1], lang="en")) ) # make sure the tag is declared as such # add SHACL shape @@ -245,10 +246,6 @@ def define_concept_hierarchy(definitions, typeclasses, broader=None, related=Non if related is not None: G.add((concept, SKOS.related, related)) G.add((related, SKOS.related, concept)) - # add label - label = defn.get(RDFS.label, concept.split("#")[-1].replace("_", " ")) - if not has_label(concept): - G.add((concept, RDFS.label, Literal(label))) # define concept hierarchy # this is a nested dictionary @@ -309,8 +306,6 @@ def define_classes(definitions, parent, pun_classes=False, graph=G): # add label class_label = classname.split("#")[-1].replace("_", " ") - if not has_label(classname, graph=graph): - graph.add((classname, RDFS.label, Literal(class_label))) if pun_classes: graph.add((classname, A, classname)) @@ -347,10 +342,6 @@ def define_classes(definitions, parent, pun_classes=False, graph=G): graph.add((alias, A, SH.NodeShape)) graph.add((alias, OWL.equivalentClass, classname)) graph.add((alias, BRICK.aliasOf, classname)) - if not has_label(alias, graph=graph): - graph.add( - (alias, RDFS.label, Literal(alias.split("#")[-1].replace("_", " "))) - ) # all other key-value pairs in the definition are # property-object pairs @@ -390,13 +381,16 @@ def define_constraints(constraints, classname, graph=G): if isinstance(property_values, URIRef): graph.add((pnode, SH["class"], property_values)) elif isinstance(property_values, list): - graph.add((pnode, SH["or"], onode)) - possible_values = [] - for pv in property_values: - pvnode = BNode() - graph.add((pvnode, SH["class"], pv)) - possible_values.append(pvnode) - Collection(graph, onode, possible_values) + if len(property_values) > 1: + graph.add((pnode, SH["or"], onode)) + possible_values = [] + for pv in property_values: + pvnode = BNode() + graph.add((pvnode, SH["class"], pv)) + possible_values.append(pvnode) + Collection(graph, onode, possible_values) + elif len(property_values) == 1: + graph.add((pnode, SH["class"], property_values[0])) else: raise Exception("Do not know how to handle constraints for %s" % classname) @@ -415,7 +409,6 @@ def define_entity_properties(definitions, superprop=None, graph=G): assert _allowed_annotations.intersection( defn.keys() ), f"{entprop} missing at least one of {_allowed_annotations} so Brick doesn't know what the values of this property can be" - assert RDFS.label in defn, f"{entprop} missing a RDFS.label annotation" graph.add((entprop, A, BRICK.EntityProperty)) if superprop is not None: graph.add((entprop, RDFS.subPropertyOf, superprop)) @@ -432,7 +425,7 @@ def define_entity_properties(definitions, superprop=None, graph=G): if val is not None: val = defn.pop(annotation) graph.add((pshape, annotation, val)) - graph.add((pshape, RDFS.label, Literal(f"has {defn.get(RDFS.label)} property"))) + graph.add((pshape, RDFS.label, Literal(f"has {defn.get(RDFS.label)} property", lang="en"))) # add the entity property as a sh:property on all of the # other Nodeshapes indicated by "property_of" @@ -781,10 +774,6 @@ def handle_deprecations(): G.add((deprecated_term, A, term_type)) G.add((deprecated_term, OWL.deprecated, Literal(True))) - label = deprecated_term.split("#")[-1].replace("_", " ") - G.add( - (deprecated_term, RDFS.label, Literal(label)) - ) # make sure the tag is declared as such # handle subclasses or skos. Only add it as an owl:Class if # the use of rdfs:subClassOf exists, implying this is a Class @@ -821,6 +810,29 @@ def handle_deprecations(): G.add((deprecated_term, BRICK.isReplacedBy, md["replace_with"])) +def handle_concept_labels(): + """ + Adds labels to all concepts in the Brick namespace, unless they already have one. + Brick concepts are all subclasses of Brick.Entity and subproperties of Brick.Relationship. + If there are two or more labels for a concept, choose one and raise a Warning + """ + concepts = chain( + G.subjects(A, BRICK.Entity), + G.subjects(A, OWL.ObjectProperty), + G.subjects(A, OWL.DatatypeProperty), + ) + for s in concepts: + labels = list(G.objects(s, RDFS.label)) + if len(labels) == 0: + G.add((s, RDFS.label, Literal(s.split("#")[-1].replace("_", " "), lang="en"))) + elif len(labels) > 1: + logging.warning(f"Multiple labels for {s}: {labels}") + # choose one and remove the others + for to_remove in labels[1:]: + G.remove((s, RDFS.label, to_remove)) + + + logger.info("Beginning BRICK Ontology compilation") # handle ontology definition define_ontology(G) @@ -846,17 +858,9 @@ def handle_deprecations(): roots = { "Equipment": { "tags": [TAG.Equipment], - "constraints": { - BRICK.hasLocation: [REC.Space], - BRICK.hasPoint: [BRICK.Point], - }, }, "Location": { "tags": [TAG.Location], - "constraints": { - BRICK.hasPoint: [BRICK.Point], - BRICK.hasPart: [BRICK.Location, REC.Space], - } }, "Point": {"tags": [TAG.Point]}, "Measurable": {"tags": [TAG.Measurable]}, @@ -868,7 +872,7 @@ def handle_deprecations(): logger.info("Defining properties") # define BRICK properties G.add((BRICK.Relationship, A, OWL.ObjectProperty)) -G.add((BRICK.Relationship, RDFS.label, Literal("Relationship"))) +G.add((BRICK.Relationship, RDFS.label, Literal("Relationship", lang="en"))) G.add( ( BRICK.Relationship, @@ -921,7 +925,7 @@ def handle_deprecations(): ) # needs the type declaration to satisfy some checkers G.add((BRICK.Quantity, RDFS.subClassOf, BRICK.Measurable)) G.add((BRICK.Quantity, A, OWL.Class)) -G.add((BRICK.Quantity, RDFS.label, Literal("Quantity"))) +G.add((BRICK.Quantity, RDFS.label, Literal("Quantity", lang="en"))) G.add((BRICK.Quantity, RDFS.subClassOf, SKOS.Concept)) # set up Substance definition G.add((BRICK.Substance, RDFS.subClassOf, SOSA.FeatureOfInterest)) @@ -930,7 +934,7 @@ def handle_deprecations(): ) # needs the type declaration to satisfy some checkers G.add((BRICK.Substance, RDFS.subClassOf, BRICK.Measurable)) G.add((BRICK.Substance, A, OWL.Class)) -G.add((BRICK.Substance, RDFS.label, Literal("Substance"))) +G.add((BRICK.Substance, RDFS.label, Literal("Substance", lang="en"))) # We make the punning explicit here. Any subclass of brick:Substance # is itself a substance or quantity. There is one canonical instance of @@ -1087,14 +1091,16 @@ def handle_deprecations(): fp.write("\n") # add rec stuff -env = ontoenv.OntoEnv(initialize=True, search_dirs=["support/"]) -env.import_graph(G, "support/rec.ttl") -env.import_graph(G, "support/brickpatches.ttl") +env.import_graph(G, "https://w3id.org/rec") +env.import_graph(G, "https://w3id.org/rec/brickpatches") # add inferred information to Brick # logger.info("Adding inferred information to Brick") # G.expand('shacl', backend='topquadrant') +# add labels to all concepts +handle_concept_labels() + # serialize Brick to output with open("Brick.ttl", "w", encoding="utf-8") as fp: fp.write(G.serialize(format="turtle").rstrip()) @@ -1108,11 +1114,12 @@ def handle_deprecations(): # create new directory for storing imports os.makedirs("imports", exist_ok=True) for name, uri in ontology_imports.items(): - graph, _ = env.resolve_uri(uri) + graph = env.get_graph(uri) graph.serialize(f"imports/{name}.ttl", format="turtle") - env.import_graph(G, graph) + env.import_graph(G, uri) # add new Brick to ontology environment +env.add("Brick.ttl") env.refresh() # validate Brick diff --git a/requirements.txt b/requirements.txt index 86429079..2a5e27d0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -11,4 +11,4 @@ flake8>=6.0 semver>=2.10.1 pytest-xdist[psutil] html5lib -ontoenv>=0.4.0a12 +pyontoenv>=0.1.8 diff --git a/support/rec.ttl b/support/rec.ttl index 387e2fae..65ad3a5e 100644 --- a/support/rec.ttl +++ b/support/rec.ttl @@ -524,7 +524,6 @@ rec:Asset rec:Atrium rdf:type rdfs:Class ; rdf:type sh:NodeShape ; - rdfs:label "Atrium" ; rdfs:subClassOf rec:Room ; . rec:AudioVisualEquipment diff --git a/tests/__init__.py b/tests/__init__.py index 7587fcbd..e69de29b 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -1,3 +0,0 @@ -import ontoenv - -env = ontoenv.OntoEnv(initialize=True, search_dirs=["support/"]) diff --git a/tests/conftest.py b/tests/conftest.py index 07836d54..2cdd5d70 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -34,7 +34,7 @@ def pytest_configure(config): @pytest.fixture() def brick_with_imports(): - env = ontoenv.OntoEnv(search_dirs=["support/"]) + env = ontoenv.OntoEnv(read_only=True) g = brickschema.Graph() g.load_file("Brick.ttl") g.bind("qudt", QUDT) diff --git a/tests/test_definitions.py b/tests/test_definitions.py index 33e91263..c891fbcd 100644 --- a/tests/test_definitions.py +++ b/tests/test_definitions.py @@ -121,10 +121,10 @@ def test_rdfs_labels(brick_with_imports): assert count == 1, f"Entity {entity} has {count} labels, which is more than 1" res = g.query( - """ SELECT ?class ?label WHERE { + """ SELECT ?class WHERE { ?class rdfs:subClassOf+ brick:Class . - OPTIONAL { ?class rdfs:label ?label } + FILTER NOT EXISTS { ?class rdfs:label ?label } }""" ) for row in res: - assert row[1] is not None, "Class %s has no label" % row[0] + assert "Class %s has no label" % row[0] diff --git a/tests/test_examples.py b/tests/test_examples.py index c06ae0b3..053643aa 100644 --- a/tests/test_examples.py +++ b/tests/test_examples.py @@ -3,7 +3,7 @@ """ import ontoenv -env = ontoenv.OntoEnv() +env = ontoenv.OntoEnv(read_only=True) def test_example_file_with_reasoning(brick_with_imports, filename):