@prefix xml: <http://www.w3.org/XML/1998/namespace> .
@prefix xsd: <http://www.w3.org/2001/XMLSchema#> .
@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .
@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> .
@prefix owl: <http://www.w3.org/2002/07/owl#> .

@prefix sw:     <http://www.w3.org/2003/06/sw-vocab-status/ns#> .
@prefix skos:   <http://www.w3.org/2004/02/skos/core#> .
@prefix vann:   <http://purl.org/vocab/vann/> .
@prefix voaf:   <http://purl.org/vocommons/voaf#> .
@prefix dce:    <http://purl.org/dc/elements/1.1/> .
@prefix dct:    <http://purl.org/dc/terms/> .
@prefix widoco:	<https://w3id.org/widoco/vocab#>.
@prefix vaem:   <http://www.linkedmodel.org/schema/vaem#>.

@base        <https://ontology.flandersmake.be/observable/ontology#> .
@prefix :    <https://ontology.flandersmake.be/observable/ontology#> .
@prefix obs: <https://ontology.flandersmake.be/observable/ontology#> .

#################################################################
#    Observable ontology
#################################################################

<https://ontology.flandersmake.be/observable/ontology> 
    rdf:type owl:Ontology ;
    vann:preferredNamespaceUri    "https://ontology.flandersmake.be/observable/ontology#" ;
    vann:preferredNamespacePrefix "obs" ;
    owl:versionIRI <https://ontology.flandersmake.be/observable/ontology/1.2.0>;
    owl:versionInfo "1.2.0" ;
    rdfs:label "The Observable ontology"@en ;
    rdfs:comment "An ontology of Observations, allowing to associate Properties to Classes";
    dct:created  "2025-01-01"^^xsd:date ;
    dct:modified "2025-11-13"^^xsd:date ;
    dct:issued   "2025-11-13"^^xsd:date ;
    dce:title "The Observable ontology"@en ;

    dce:abstract '''
An observation is a set of data points. Each point is associated to an instance of some Class. 
Each instance is then associated 
to values through a given set of Properties. An Observation is thus specified by a Class 
(the set of instances) and a collection of Properties.
The set of Classes supporting Observations is the Class Observable, a subclass of owl:Class.
The set of Properties that are observed is the Class Dimension, a subclass of rdf:Property.
'''@en;

    widoco:introduction '''
The Observable ontology allows to associate and/or define properties (Dimensions) to classes (Observable).

The ontology was originally created to specify histograms and scattered (correlation) plots. Every plot specification is
an Observation. The application [KGExplore](https://github.com/Flanders-Make-vzw/Ontology-based-KG-Viz2), allows to author Observations, and display
them for some tripe store (form some RDF dataset, for some knowledge graph).

The present ontology is an evolution of the original ontology, implemented in KGExplore version 2.5 onward. Following problems are resolved in this newer version:
- *observable context* becomes first class citizen
- reuse navigation paths over the dimensions
- reuse the dimensions by other dimensions

This ontology allows to describe and reason on mutually (possibly) dependent properties, so on dependencies.
'''@en;

    dce:description '''
The Observable Ontology allows to describe Observations, 
specified by a contextual class (an Observable) 
and a set of observed properties (the Dimensions)

## Concepts Observable and Observation

The following concepts are formalized:
- **Observable**: a Class whose elements are observed
- **Dimension**: an observed property 
- **Observation**: an Observable with some observed Dimensions

```mermaid
classDiagram
  class Class:::owl 
  class Property:::owl 
  class Observable 
  class Observation 
  class Dimension 
  Class <|-- Observable
  Property <|-- Dimension
  Observable <-- Observation : observationObservable
  Dimension <-- Observation : observedDimension
  Class <-- Property : range
  Class <-- Property : domain

  classDef default fill:#f96,color:black
  classDef owl fill:#e9edc9,color:black
```

## Concepts Navigation Path and Element

The following concepts are formalized:
- **NavigationPath**: specifies a path of navigation.
- **NavigationPathElement**: an element of a NavigationPath.
- **NavigationPathElementDirect**: is a NavigationPathElement specifying a property to be navigated in the direct way.
- **NavigationPathElementReverse**: is a NavigationPathElement specifying a property to be navigated in the reverse way.
- **NavigationPathElementDowncast**: is a NavigationPathElement specifying a type to downcast to.
- **NavigationPathElementCondition**: is a Navigation specifying a condition to be satisfied by the navigated instance

```mermaid
classDiagram
  direction BT
  class Class:::owl
  class Property:::owl
  Class <-- Property : range
  Class <-- Property : domain
  class ObjectProperty:::owl
  ObjectProperty --|> Property 
  
  class NavigationPath

  class NavigationPathElement {}
  NavigationPathElement <--o NavigationPath : elements

  NavigationPathElementDowncast --|> NavigationPathElement 
  NavigationPathElementDowncast -->  Class : downcastTo

  NavigationPathElementCondition --|> NavigationPathElement
  NavigationPathElementCondition --> Property: conditionProperty
  class NavigationPathElementCondition {
    value
  }

  NavigationPathElementProperty --|> NavigationPathElement 
  class NavigationPathElementProperty{
    direct: boolean
  }
  NavigationPathElementProperty --> ObjectProperty: navigatedProperty

  NavigationPathElementDirect --|> NavigationPathElementProperty
  class NavigationPathElementDirect{
    direct: true
  }
  NavigationPathElementReverse --|> NavigationPathElementProperty
  class NavigationPathElementReverse{
    direct: false
  }
  

  classDef default fill:#f96,color:black
  classDef owl fill:#e9edc9,color:black
```

## Concepts ObservableContext and DimensionContext

The following concepts are formalized:
- **ObservableContextNavigationPath**: is an ObservableContext defined by a NavigationPath
- **DimensionContext**: is an Dimension defined by an ObjectProperty and a DatatypeProperty

```mermaid
classDiagram
  direction BT
  class Property:::owl
  class ObjectProperty:::owl
  ObjectProperty --|> Property 
  class DatatypeProperty:::owl
  DatatypeProperty --|> Property 
  
  ObservableContext --|> ObjectProperty 
  
  ObservableContextNavigationPath --|> ObservableContext 
  ObservableContextNavigationPath  o--> NavigationPath : navigationPath

  Dimension --|> DatatypeProperty
  
  DimensionContext --|> Dimension 
  Class DimensionContext
  DimensionContext --> ObjectProperty : context
  DimensionContext --> DatatypeProperty: property

  classDef default fill:#f96,color:black
  classDef owl fill:#e9edc9,color:black
```
'''@en.  
    
#################################################################
#    Observable
#################################################################

obs:Observable
    rdf:type rdfs:Class ;
    rdfs:subClassOf owl:Class ;
    rdfs:comment "Observable is the set of owl:Class's supporting Observations, that is, providing Dimensions"@en;
    rdfs:isDefinedBy <https://www.fm.codesigns.org/observable/ontology> .

#################################################################
#    ObservableContext
#################################################################

obs:ObservableContext 
    rdfs:subClassOf owl:ObjectProperty; # its elements are properties, associating the contextual class with its observable contexts
    rdfs:comment "An ObservableContext provides a context to be observed from a contextual class".

obs:ObservableContextNavigationPath
    rdfs:subClassOf obs:ObservableContext;
    rdfs:comment "An ObservableContextNavigationPath provides the observed context via a navigation path"@en.

obs:observableContextNavigationPath
    rdf:type rdf:Property;
    rdfs:domain obs:ObservableContextNavigationPath;
    rdfs:range obs:NavigationPath .

obs:NavigationPath
    rdfs:subClassOf rdf:List;
    rdfs:label "Path"@en;
    rdfs:comment "An navigation path"@en .

obs:NavigationPathElement 
    rdf:type rdfs:Class;
    rdfs:label "Element"@en;
    rdfs:comment "A navigation element of a navigation path"@en .

obs:navigationPathFirst 
    rdfs:subPropertyOf rdf:first;
    rdfs:domain obs:NavigationPath ;
    rdfs:range obs:NavigationPathElement .

# the 3 following statements derive obs:navigationPathFirst/rest
#   the make the corresponding rules not necessary
#   ms20251219: must still be validated
obs:NavigationPath 
    rdfs:subClassOf [
        rdf:type owl:Restriction;
        owl:onProperty obs:selfNavigationPath;
        owl:hasSelf "true"^^xsd:boolean
    ].
obs:navigationPathFirst
    owl:propertyChainAxiom (obs:selfNavigationPath rdf:first).     
obs:navigationPathRest
    owl:propertyChainAxiom (obs:selfNavigationPath rdf:rest).     

obs:navigationPathRest
    rdfs:subPropertyOf rdf:rest;
    rdfs:domain obs:NavigationPath ;
    rdfs:range obs:NavigationPath .

# path element property
obs:NavigationPathElementProperty 
    rdfs:subClassOf obs:NavigationPathElement;
    rdfs:label "Property"@en;
    rdfs:comment "A navigation element using 1 property for navigation"@en .

obs:navigationPathElementDirect 
    rdf:type    rdf:Property ;
    rdfs:domain obs:NavigationPathElementProperty ;
    rdfs:range  xsd:boolean;
    rdfs:label "direct"@en;
    rdfs:comment "Indicate if the property is navigated in the direct or the reverse way"@en.

obs:navigationPathElementProperty
    rdf:type    rdf:Property;
    rdfs:domain obs:NavigationPathElementProperty ;
    rdfs:range  owl:ObjectProperty;
    rdfs:label "property"@en;
    rdfs:comment "The navigated property of a property navigation element"@en.

obs:NavigationPathElementPropertyDirect
    rdfs:subClassOf obs:NavigationPathElementProperty;
    rdfs:label "Direct property"@en;
    rdfs:comment "A property navigation element navigated in the direct way"@en.

obs:NavigationPathElementPropertyDirect
    rdfs:subClassOf [
        rdf:type owl:Restriction ;
        owl:onProperty obs:navigationPathElementDirect ;
        owl:hasValue true
    ].

obs:navigationPathElementPropertyDirect
    rdf:type    rdf:Property;
    rdfs:domain obs:NavigationPathElementPropertyDirect ;
    rdfs:subPropertyOf obs:navigationPathElementProperty.

obs:NavigationPathElementPropertyReverse
    rdfs:subClassOf obs:NavigationPathElementProperty;
    rdfs:label "Reverse property"@en;
    rdfs:comment "A property navigation element navigated in the reverse way"@en .

obs:NavigationPathElementPropertyReverse
    rdfs:subClassOf [
        rdf:type owl:Restriction ;
        owl:onProperty obs:navigationPathElementDirect ;
        owl:hasValue false
    ].

obs:navigationPathElementPropertyReverse
    rdf:type    rdf:Property;
    rdfs:domain obs:NavigationPathElementPropertyReverse ;
    rdfs:subPropertyOf obs:navigationPathElementProperty.

# path element downcast
obs:NavigationPathElementDowncast
    rdfs:subClassOf obs:NavigationPathElement;
    rdfs:label "Downcast"@en;
    rdfs:comment "A navigation path element allowing elements belonging to a given class"@en .

obs:navigationPathElementDowncast
    rdf:type    rdf:Property ;
    rdfs:domain obs:NavigationPathElementDowncast ;
    rdfs:range  owl:Class .

# path element condition
obs:NavigationPathElementCondition
    rdfs:subClassOf obs:NavigationPathElement;
    rdfs:label "Condition"@en;
    rdfs:comment "A navigation path element setting a necessary conditon on the navigated instance"@en .

obs:navigationPathElementConditionProperty
    rdf:type    rdf:Property ;
    rdfs:domain obs:NavigationPathElementCondition;
    rdfs:range  rdf:Property;
    rdfs:label "Condition property"@en.

obs:navigationPathElementConditionValue
    rdf:type    rdf:Property ;
    rdfs:domain obs:NavigationPathElementCondition;
    rdfs:label "Condition value"@en.

#################################################################
#    Dimension (singular)
#################################################################

obs:Dimension 
    rdfs:subClassOf rdf:Property;
    rdfs:subClassOf obs:DimensionOrNull;
    rdfs:comment "A Dimension is just an rdf:Property, associating contextual class instances with its observable values"@en.

obs:null 
    rdf:type obs:DimensionOrNull.    

obs:DimensionContext 
    rdfs:subClassOf obs:Dimension;
    rdfs:comment "A DimensionContext associates a value to an Observable via an ObservableContext and a property"@en . 

obs:dimensionContext  
    rdf:type rdf:Property;
    rdfs:domain obs:DimensionContext ;
    rdfs:range obs:ObservableContext .

obs:dimensionProperty 
    rdf:type    rdf:Property ;
    rdfs:domain obs:DimensionContext ;
    rdfs:range  rdf:Property .

#################################################################
#   Dimension (specific kinds)
#################################################################

# this is called 'SynthesisProperty' in Ansymo DependencyModel (DM)
# michel question: should we not make the rule for inheriting ExogenousDimension for the subproperties?
obs:ExogenousDimension 
    rdfs:subClassOf obs:Dimension .

obs:BooleanDimension 
    rdfs:subClassOf owl:DatatypeProperty;
    rdfs:subClassOf obs:Dimension;
    rdfs:subClassOf [
        rdf:type owl:Restriction;
        owl:onProperty rdfs:range;
        owl:hasValue xsd:Boolean].

obs:NumericalDimension 
    rdfs:subClassOf owl:DatatypeProperty;
    rdfs:subClassOf obs:Dimension;
    rdfs:subClassOf [
        rdf:type owl:Restriction;
        owl:onProperty rdfs:range;
        owl:hasValue xsd:decimal].

obs:EnumerationDimension 
    rdfs:subClassOf obs:Dimension.

obs:ObjectEnumerationDimension 
    rdfs:subClassOf owl:ObjectProperty;
    rdfs:subClassOf obs:EnumerationDimension.

# specify the possible values for the Enumeration
#    a possible enumerated value (object or datatype) is associated with a numerical value: the rank
#    so the possible values is specified by a list of pairs (value rank)
obs:EnumerationValues 
    rdfs:subClassOf rdf:List.

obs:enumerationValues
    rdf:type owl:ObjectProperty;
    rdfs:domain obs:EnumerationDimension;
    rdfs:range obs:EnumerationValues.

obs:EnumerationValue 
    rdf:type owl:Class.

obs:enumerationValue
    rdf:type owl:ObjectProperty;
    rdfs:domain obs:EnumerationValue.
    
obs:enumerationRank
    rdf:type owl:ObjectProperty;
    rdfs:domain obs:EnumerationValue;
    rdfs:range xsd:decimal.


#################################################################
#    Dimensions (plural)
#################################################################

obs:Dimensions
    rdfs:subClassOf rdf:List.

obs:firstDimension
    rdf:type rdf:Property;
    rdfs:subPropertyOf rdf:first;
    rdfs:domain obs:Dimensions;
    rdfs:range obs:Dimension.

obs:restDimensions
    rdf:type rdf:Property;
    rdfs:subPropertyOf rdf:rest;
    rdfs:domain obs:Dimensions;
    rdfs:range obs:Dimensions.

#################################################################
#    Observation
#################################################################

obs:Observation 
    rdf:type rdfs:Class;
    rdfs:label "Observation"@en ;
    rdfs:comment "An Observation is a set of observed properties (Dimensions) in some observed context (Observable)" ;
    vann:example "The breakstress related to the curing temperature of my sample."@en ;
    vaem:rationale "This is a solution for associating properties (Dimensions) to a class (Observable) with some purpose (correlation, to be plotted, dependency, ...)."@en ;
    sw:status "stable";
    rdfs:isDefinedBy <https://ontology.flandersmake.be/observable/ontology> ;
    skos:editorialNote '''
Related mechanism are rdfs:domain/range, schema:domain/rangeIncludes, mm:ownedProperty.
An Observation is broader, as it allows to associate several dimenstions to one class;
furthermore, it allows to make different Observations for the same Class and the same Properties
but with different purpose or meaning.
''';
    skos:scopeNote "This concept is meant to be used at the upper level" .


obs:observationObservable 
    rdf:type    rdf:Property ;
    rdfs:domain obs:Observation ;
    rdfs:range  obs:Observable;
    rdfs:comment "The observation context, or Observable"@en .

obs:observableObservation
    owl:inverseOf obs:observationObservable;
    rdfs:comment "The Observations associated to this Observable".

# number of non-grouped dimensions
# or may we should distinguish between observedDimensions and groupingDimensions ?
obs:observationArity 
    rdf:type rdf:Property ;
    rdfs:domain obs:Observation ;
    rdfs:range xsd:integer .

obs:observedDimension
    rdf:type    rdf:Property ;
    rdfs:domain obs:Observation ;
    rdfs:range  obs:Dimension .

obs:observationInstanceProperty
    rdf:type rdf:Property;
    rdfs:domain rdf:Class; # the set of all concrete Observation specializations
    rdf:range rdf:Property;
    rdfs:comment "Associate a Observation with a property, to use between the observation instance and the observed instance"@en.

obs:obs:observationDimensionProperty 
    rdf:type rdf:Property;
    rdfs:domain rdf:Property; # the set of all concrete observedDimension specialization
    rdf:range rdf:Property;
    rdfs:comment "Associate a observedDimension with a property, to use between the observation instance and the observed value"@en.

    
# question: should the groupingObservations be observedDimensions?
#           or should we make the distinction between grouping and observed
obs:observationGroupingDimensions 
    rdf:type    rdf:Property ;
    rdfs:subPropertyOf obs:observedDimension;
    rdfs:domain obs:Observation ;
    rdfs:range  obs:Dimension .

# unary observation
obs:UnaryObservation 
    rdfs:subClassOf obs:Observation;
    rdfs:comment "An Observation with one single observed dimension"@en .

obs:unaryObservationDimension 
    rdf:type    rdf:Property ;
    rdfs:subPropertyOf obs:observedDimension;
    rdfs:domain obs:UnaryObservation ;
    rdfs:range  obs:Dimension .

# binary observation
obs:BinaryObservation 
    rdfs:subClassOf obs:Observation;
    rdfs:comment "An Observation with two observed dimensions"@en;
    obs:observationInstanceProperty obs:binaryObservationInstance.

obs:binaryObservationDimension1 
    rdf:type    rdf:Property ;
    rdfs:subPropertyOf obs:observedDimension;
    rdfs:domain obs:BinaryObservation ;
    rdfs:range  obs:Dimension; 
    obs:observationDimensionProperty obs:binaryObservationDimension1Value.

obs:binaryObservationDimension2 
    rdf:type    rdf:Property ;
    rdfs:subPropertyOf obs:observedDimension;
    rdfs:domain obs:BinaryObservation ;
    rdfs:range  obs:Dimension; 
    obs:observationDimensionProperty obs:binaryObservationDimension2Value.


#################################################################
#    Property (draft)
# 
# A Property is some physical extent that can be repressented by 
# a or several properties (i.e. a obs:Dimension), as it can be expressed 
# in different reference frames and can can measured in several 
# ways.
# Note that temporality is not yet approached.
#################################################################

#obs:Property rdf:type owl:Class .
#
#obs:propertyContext  
#    rdf:type rdf:Property;
#    rdfs:domain obs:Property ;
#    rdfs:range obs:ObservableContext .
#
#obs:propertyRepresentedByDimensions
#    rdf:type owl:ObjectProperty ;
#    rdfs:subPropertyOf owl:topObjectProperty ;
#    rdfs:domain obs:Property ;
#    rdfs:range owl:DatatypeProperty .

#################################################################
#    Influence (draft)
#
# An Influence is some physical law relating obs:Property's
# An Influence could be represented by an obs:Dependency
# An Influence could be observed by an obs:Observation
# Both associations are modeled by obs:observedInfluence
#################################################################

#obs:Influence rdf:type  owl:Class .
#
#obs:influenceObservable 
#    rdf:type    rdf:Property ;
#    rdfs:domain obs:Influence ;
#    rdfs:range  obs:Observable .
#
#obs:influenceProperties
#    rdf:type  owl:ObjectProperty ;
#    rdfs:domain obs:Influence ;
#    rdfs:range obs:Property .
#
#obs:observedInfluence
#    rdf:type owl:ObjectProperty ;
#    rdfs:domain obs:Observation ;
#    rdfs:range obs:Influence .    
# Serialization annotations added by generate_docs.py
<https://ontology.flandersmake.be/observable/ontology>
    <https://w3id.org/widoco/vocab#turtleSerialization> "observable.ttl" ;
    <https://w3id.org/widoco/vocab#rdfxmlSerialization> "observable.rdf" ;
    <https://w3id.org/widoco/vocab#ntSerialization> "observable.nt" ;
    <https://w3id.org/widoco/vocab#jsonldSerialization> "observable.jsonld" .
