RDFLib / pySHACL

A Python validator for SHACL
Apache License 2.0
241 stars 63 forks source link

Unable to see the validation result in pyshacl #209

Closed AJAY31797 closed 9 months ago

AJAY31797 commented 9 months ago

Hi,

I am trying to develop a shape for validating the distance constraint between two walls. The data graph is coming from a converted ifc file and the shape I have developed by myself, taking help from (https://github.com/RDFLib/pySHACL/blob/master/examples/advanced.py). Here is my data graph (in a simplified form, I have removed irrelevant data for clarity):

Datagraph = '''
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix bot: <https://w3id.org/bot#> .
@prefix ifc: <https://standards.buildingsmart.org/IFC/DEV/IFC2x3/TC1/OWL#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix lbd: <https://linkebuildingdata.org/LBD#> .
@prefix props: <http://lbd.arch.rwth-aachen.de/props#> .
@prefix geo: <http://www.opengis.net/ont/geosparql#> .
@prefix unit: <http://qudt.org/vocab/unit/> .
@prefix IFC4-PSD: <https://www.linkedbuildingdata.net/IFC4-PSD#> .
@prefix smls: <https://w3id.org/def/smls-owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix inst: <https://www.ugent.be/myAwesomeFirstBIMProject#> .
@prefix fog: <https://w3id.org/fog#> .

inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c353
        props:objectTypeIfcObject  inst:objectTypeIfcObject_1eec9390-5f68-4a64-aaa9-34a883f3c353 ;
        props:reference            inst:reference_1eec9390-5f68-4a64-aaa9-34a883f3c353 ;
        props:extendToStructure    inst:extendToStructure_1eec9390-5f68-4a64-aaa9-34a883f3c353 ;
        props:loadBearing          inst:loadBearing_1eec9390-5f68-4a64-aaa9-34a883f3c353 ;
        props:isExternal           inst:isExternal_1eec9390-5f68-4a64-aaa9-34a883f3c353 ;
        props:category             inst:category_1eec9390-5f68-4a64-aaa9-34a883f3c353 ;
        rdf:type                   bot:Element ;
        props:globalIdIfcRoot      inst:globalIdIfcRoot_1eec9390-5f68-4a64-aaa9-34a883f3c353 ;
        props:nameIfcRoot          inst:nameIfcRoot_1eec9390-5f68-4a64-aaa9-34a883f3c353 ;
        props:batid                inst:batid_1eec9390-5f68-4a64-aaa9-34a883f3c353 ;
        geo:hasGeometry            inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c353_geometry .

inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c353_geometry
        fog:asObj_v3.0-obj  "diAzODcyLjM3ODM0NTUyNjY4OSAtNDY2LjM1NTc3MjU3ODAzNjA3IDAuMAp2IDM4NzIuMzc4MzQ1NTI2Njg5IC00NjYuMzU1NzcyNTc4MDM2MDcgNzk5OS45OTkAxMjEgMTI0CmYgMTI3IDEyOCAxMjUKZiAxMjggMTI2IDEyNQpmIDEyOSAxMzAgMTMxCmYgMTMyIDEyOSAxMzEK"^^<https://www.w3.org/TR/xmlschema-2/#base64Binary> ;
        lbd:hasBoundingBox  inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c353_geometry_bb .

inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c353_geometry_bb
        lbd:z-max  "7999.999999999999"^^xsd:double ;
        lbd:z-min  "0.0"^^xsd:double ;
        lbd:y-max  "-466.35577257803607"^^xsd:double ;
        lbd:y-min  "-4066.3557725780365"^^xsd:double ;
        lbd:x-max  "4162.378345526689"^^xsd:double ;
        lbd:x-min  "3872.378345526689"^^xsd:double .

inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c0dd
        props:nameIfcRoot          inst:nameIfcRoot_1eec9390-5f68-4a64-aaa9-34a883f3c0dd ;
        props:reference            inst:reference_1eec9390-5f68-4a64-aaa9-34a883f3c0dd ;
        props:loadBearing          inst:loadBearing_1eec9390-5f68-4a64-aaa9-34a883f3c0dd ;
        props:objectTypeIfcObject  inst:objectTypeIfcObject_1eec9390-5f68-4a64-aaa9-34a883f3c0dd ;
        props:globalIdIfcRoot      inst:globalIdIfcRoot_1eec9390-5f68-4a64-aaa9-34a883f3c0dd ;
        props:category             inst:category_1eec9390-5f68-4a64-aaa9-34a883f3c0dd ;
        props:isExternal           inst:isExternal_1eec9390-5f68-4a64-aaa9-34a883f3c0dd ;
        geo:hasGeometry            inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c0dd_geometry ;
        lbd:containsInBoundingBox  inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c31b ;
        props:batid                inst:batid_1eec9390-5f68-4a64-aaa9-34a883f3c0dd ;
        props:extendToStructure    inst:extendToStructure_1eec9390-5f68-4a64-aaa9-34a883f3c0dd ;
        rdf:type                   bot:Element .

inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c0dd_geometry
        fog:asObj_v3.0-obj  "diAtODYzNy42MjE2NTQ0NzMyOTIgLTQzNTYuMzU1NzcyNTc3OTk2IDAuMAp2IC04NjM3LjYyMTY1NDQ3MzI5MiAtNDM1Ni4zNTU3NzI1Nzc5OTYgNzk5OS45O=="^^<https://www.w3.org/TR/xmlschema-2/#base64Binary> ;
        lbd:hasBoundingBox  inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c0dd_geometry_bb .

inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c0dd_geometry_bb
        lbd:z-max  "7999.999999999999"^^xsd:double ;
        lbd:z-min  "0.0"^^xsd:double ;
        lbd:y-max  "8243.64422742201"^^xsd:double ;
        lbd:y-min  "-4356.355772577996"^^xsd:double ;
        lbd:x-max  "-8637.621654473292"^^xsd:double ;
        lbd:x-min  "-8927.621654473292"^^xsd:double .
'''

The shape I have written is as follows:

Shapegraph = ''' 
@prefix owl: <http://www.w3.org/2002/07/owl#> .
@prefix bot: <https://w3id.org/bot#> .
@prefix ifc: <https://standards.buildingsmart.org/IFC/DEV/IFC2x3/TC1/OWL#> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix lbd: <https://linkebuildingdata.org/LBD#> .
@prefix props: <http://lbd.arch.rwth-aachen.de/props#> .
@prefix geo: <http://www.opengis.net/ont/geosparql#> .
@prefix unit: <http://qudt.org/vocab/unit/> .
@prefix IFC4-PSD: <https://www.linkedbuildingdata.net/IFC4-PSD#> .
@prefix smls: <https://w3id.org/def/smls-owl#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix inst: <https://www.ugent.be/myAwesomeFirstBIMProject#> .
@prefix fog: <https://w3id.org/fog#> .
@prefix sh: <http://www.w3.org/ns/shacl#> .

ifc:computedistance a sh:SPARQLFunction;
    rdfs:comment "Finds the distance between the two elements";
    sh:parameter[
        sh:path ifc:op1 ;
        sh:datatype xsd:double;
        sh:description "The inner x coordinate of the wall on the right side";
        ];

    sh:parameter[
        sh:path ifc:op2 ;
        sh:datatype xsd:double;
        sh:description "The outer x coordinate of the wall on the left side";
        ];

    sh:returnType xsd:double;
    sh:select"""
    SELECT ?result
    WHERE {
        BIND ((($op1 - $op2)/1000) AS ?result).
        }
    """.

ifc:lessThan a sh:SPARQLFunction;
    rdfs:comment "Returns if op1<op2.";
    sh:parameter[
        sh:path ifc:op1;
        sh:datatype xsd:double;
        sh:description "The difference between the two coordinates";
        ] ;

    sh:parameter[
        sh:path ifc:op2;
        sh:datatype xsd:double;
        sh:description "The constraint value to be checked against";
        ] ;

    sh:returnType xsd:boolean ;
    sh:select """
        SELECT ?result
        WHERE {
            BIND (IF(?op1<?op2, true, false) AS ?result).
            }
        """.

ifc:geometricconstraintshape a sh:NodeShape ;
        sh:targetClass bot:Element;
        sh:expression[
            sh:message "The geometric constraint is violated" ;
            ifc:lessThan(
                [
                    ifc:computedistance(
                        [sh:path (inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c353_geometry_bb lbd:x-min)]
                        [sh:path (inst:wall_1eec9390-5f68-4a64-aaa9-34a883f3c0dd_geometry_bb lbd:x-max)]
                        )
                    ]
                15000.0
                );
            ].   
'''

I am using the following code for performing validation:

from pyshacl import validate
r = validate(data_graph = Datagraph, shacl_graph = Shapegraph, data_graph_format="turtle", shacl_graph_format="turtle", inference = "rdfs", debug = True, abort_on_error = False, meta_shacl = False, serialize_report_graph = "ttl")
conforms, results_graph, results_text = r

However, the validation result does not show me whether the constraints are satisfied or not. Here is the validation result which I am getting:

Usage of abort_on_error is deprecated. Use abort_on_first instead.
Cloning DataGraph to temporary memory graph before pre-inferencing.
Running pre-inferencing with option='rdfs'.
Found 1 SHACL Shapes defined with type sh:NodeShape.
Found 0 SHACL Shapes defined with type sh:PropertyShape.
Found 0 property paths to follow.
Found 1 implied SHACL Shapes based on their properties.
Found 0 implied SHACL Shapes used as values in shape-expecting constraints.
Cached 1 unique NodeShapes and 0 unique PropertyShapes.
Will run validation on 1 named graph/s.
Validating DataGraph named Ne8ebf9cc09f14e2d9f9b0b851a4f51db
Checking if Shape <NodeShape https://standards.buildingsmart.org/IFC/DEV/IFC2x3/TC1/OWL#geometricconstraintshape> defines its own targets.
Identifying targets to find focus nodes.
Milliseconds to find focus nodes: 0.037ms
Found 2 Focus Nodes to evaluate.
Running evaluation of Shape <NodeShape https://standards.buildingsmart.org/IFC/DEV/IFC2x3/TC1/OWL#geometricconstraintshape>
Current shape evaluation path: <NodeShape https://standards.buildingsmart.org/IFC/DEV/IFC2x3/TC1/OWL#geometricconstraintshape>
Milliseconds to evaluate shape <NodeShape https://standards.buildingsmart.org/IFC/DEV/IFC2x3/TC1/OWL#geometricconstraintshape>: 0.385ms

As seen above, the result does not mention anything about whether the constraints are satisfied or not. Is it something related to some error in the shape? I checked it based on the example, and it looks correct to me. Or is it because of some other issue in compiling the code? Thanks in advance for any help.

Best Regards, Ajay

ashleysommer commented 9 months ago

Hi @AJAY31797 It seems like you are looking for the validation results amongst the Debug log messages. You will not find the conformance reports and validation result in those debug logs. The conformance result (boolean True/False) is in the variable conforms and the result text is in the variable results_text.

Try this:

from pyshacl import validate
r = validate(data_graph = Datagraph, shacl_graph = Shapegraph, data_graph_format="turtle", shacl_graph_format="turtle", inference = "rdfs", debug = True, abort_on_error = False, meta_shacl = False, serialize_report_graph = "ttl")
conforms, results_graph, results_text = r
print("Conforms: ", str(conforms))
print("Results:\n", results_text)

Note, these basic usage instructions are in the README file, and this kind of question should be asked on the Discord SHACL Discussion forum, not on the issue tracker.

AJAY31797 commented 9 months ago

Thanks @ashleysommer. I am still not able to see the correct results. Basically, for every constraint, my query results in Conforms:True. Seems like some mistake with my query. Anyways, thanks for your support and suggestion of the Discord SHACL discussion forum.