Search code examples
owlontologyreasoning

OWL reasoning based on subset of relationships


I have the following example instance of the Brick.ttl buildings ontology

@prefix : <https://example.org/ontologies/test#> .
@prefix brick: <https://brickschema.org/schema/1.1/Brick#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .

:CH1_Active_Power_Sensor a owl:NamedIndividual,
    brick:Active_Power_Sensor ;
    brick:isPointOf :CH1 .

:CH1_Chilled_Water_Entering_Temperature_Sensor a owl:NamedIndividual,
    brick:Chilled_Water_Entering_Temperature_Sensor ;
    brick:isPointOf :CH1 .

:CH1_Chilled_Water_Leaving_Temperature_Sensor a owl:NamedIndividual,
    brick:Chilled_Water_Leaving_Temperature_Sensor ;
    brick:isPointOf :CH1 .

:CH2_Active_Power_Sensor a owl:NamedIndividual,
    brick:Active_Power_Sensor ;
    brick:isPointOf :CH2 .

:CH2_Chilled_Water_Leaving_Temperature_Sensor a owl:NamedIndividual,
    brick:Chilled_Water_Leaving_Temperature_Sensor ;
    brick:isPointOf :CH2 .

:CH3_Chilled_Water_Entering_Temperature_Sensor a owl:NamedIndividual,
    brick:Chilled_Water_Entering_Temperature_Sensor ;
    brick:isPointOf :CH3 .

:CH3_Chilled_Water_Leaving_Temperature_Sensor a owl:NamedIndividual,
    brick:Chilled_Water_Leaving_Temperature_Sensor ;
    brick:isPointOf :CH3 .


:CH1 a owl:NamedIndividual, brick:Chiller ;
    brick:hasPoint :CH1_Active_Power_Sensor ;
    brick:hasPoint :CH1_Chilled_Water_Entering_Temperature_Sensor ;
    brick:hasPoint :CH1_Chilled_Water_Leaving_Temperature_Sensor .

:CH2 a owl:NamedIndividual, brick:Chiller ;
    brick:hasPoint :CH2_Active_Power_Sensor ;
    brick:hasPoint :CH2_Chilled_Water_Leaving_Temperature_Sensor .

:CH3 a owl:NamedIndividual, brick:Chiller ;
    brick:hasPoint :CH3_Chilled_Water_Entering_Temperature_Sensor ;
    brick:hasPoint :CH3_Chilled_Water_Leaving_Temperature_Sensor .

I need to identify instances which have a set of points, i.e. all brick:Chiller which has all members from {brick:Chilled_Water_Entering_Temperature_Sensor, brick:Chilled_Water_Leaving_Temperature_Sensor} (and any others).

It's easy using SPARQL, i.e.

SELECT ?subject WHERE {
    ?subject brick:hasPoint ?p1 .
    ?p1 rdf:type/rdfs:subClassOf* brick:Chilled_Water_Entering_Temperature_Sensor .
    ?subject brick:hasPoint ?p2 .
    ?p2 rdf:type/rdfs:subClassOf* brick:Chilled_Water_Leaving_Temperature_Sensor .
    }

But I have a lot of these combinations and I was hoping I could define them in such a way that it's possible to reason that :CH1 and :CH3 are a specific subtype so I can directly query for it. My attempt so far is:

:CHWETLT a owl:Class ;
    owl:equivalentClass [ 
        a owl:Restriction ;
        owl:onProperty :hasPoint ;
        owl:allValuesFrom [
            a owl:Class ;
            owl:intersectionOf (
                brick:Chilled_Water_Entering_Temperature_Sensor
                brick:Chilled_Water_Leaving_Temperature_Sensor
            )
        ]
    ] .

I'm hoping that inference would identify that :CH1 and :CH3 belong to :CHWETLT so I can query for that directly. This doesn't seem to work though - I'm not sure where to go from now. Is this possible? If so can someone point me in the correct direction?

I'm using the brickschema python package which is (afaik) built on rdflib and uses reasonable as the reasoner.


Solution

  • In Manchester syntax, instead of

    hasPoint only ( Chilled_Water_Entering_Temperature_Sensor and
                    Chilled_Water_Leaving_Temperature_Sensor )
    

    you need rather

    ( hasPoint some Chilled_Water_Entering_Temperature_Sensor ) and
    ( hasPoint some Chilled_Water_Leaving_Temperature_Sensor  )
    

    Back to Turtle syntax:

    :CHWETLT a owl:Class ;
        owl:equivalentClass [
            a owl:Class ;
            owl:intersectionOf (
                [ a owl:Restriction ;
                  owl:onProperty brick:hasPoint ;
                  owl:someValuesFrom brick:Chilled_Water_Entering_Temperature_Sensor
                ]
                [ a owl:Restriction ;
                  owl:onProperty brick:hasPoint ;
                  owl:someValuesFrom brick:Chilled_Water_Leaving_Temperature_Sensor
                ]
            ) 
        ] .
    

    Strictly speaking, this axiom is outside OWL 2 RL. However, all you need for your inference is the left-to-right subsumption. Why OWL 2 RL? The owlrl Python reasoner mentioned in the documentation supports only this OWL profile, I suppose.