@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 dcterms: <http://purl.org/dc/terms/> .
@prefix xsd:     <http://www.w3.org/2001/XMLSchema#> .
@prefix mastr:   <mastr#> .
@prefix :        <vocab#> .

# ---- Ontology declaration -----------------------------------------------

<vocab>
    a               owl:Ontology ;
    rdfs:label      "Linked MaStR vocabulary"@en , "Linked-MaStR-Vokabular"@de ;
    dcterms:title   "Linked MaStR vocabulary"@en , "Linked-MaStR-Vokabular"@de ;
    dcterms:description
        "The DOMAIN vocabulary the linked-mastr wrapper maps the Marktstammdatenregister INTO: source-agnostic concepts (generation units, market actors, locations, installations) plus a few cross-record bridge properties. It is NOT the upstream field names — those are mirrored verbatim in the sibling namespace mastr: (<mastr#…>) under their original German PascalCase identifiers; do not expect catalogue-coded or literal-valued upstream fields here. Stable English local-names are the identifiers; rdfs:label carries display names in en + de."@en ;
    rdfs:comment
        "Layering: mastr: is the SOURCE layer (every Gesamtdatenexport field mirrored 1:1, German names); this vocab: is the DOMAIN layer (the cleaned, typed model records are mapped into). The genuinely source-agnostic terms here — :GenerationUnit, :Operator, :GridOperator, :Location, :StorageUnit and the like — are candidates for a SHARED energy-domain vocabulary that the sibling Ontologycentral wrappers (linked-netztransparenz, …) could reuse rather than re-mint per source. The MaStR-structural terms (:KwkAnlage, :StorageAnlage, the Anlage-vs-Einheit split, :MarketRole) are register-shaped and would stay wrapper-local. If/when the shared vocabulary is split out, the domain terms move to it under stable IRIs and this document imports them."@en ;
    dcterms:license <https://www.govdata.de/dl-de/by-2-0> ;
    dcterms:source  <https://www.marktstammdatenregister.de/MaStR/Datendownload> ;
    rdfs:seeAlso    <mastr> .

# ---- Generation-unit classes (dispatched from Einheitentyp) -------------

:GenerationUnit
    a               rdfs:Class ;
    rdfs:label      "Generation unit"@en , "Stromerzeugungseinheit"@de ;
    rdfs:comment    "A registered electricity generation unit (Stromerzeugungseinheit). MaStR-Nr prefix SEE." .

:SolarUnit       a rdfs:Class ; rdfs:subClassOf :GenerationUnit ;
    rdfs:label "Solar unit"@en , "Solareinheit"@de .
:WindUnit        a rdfs:Class ; rdfs:subClassOf :GenerationUnit ;
    rdfs:label "Wind unit"@en , "Windeinheit"@de .
:HydroUnit       a rdfs:Class ; rdfs:subClassOf :GenerationUnit ;
    rdfs:label "Hydro unit"@en , "Wassereinheit"@de .
:BiomassUnit     a rdfs:Class ; rdfs:subClassOf :GenerationUnit ;
    rdfs:label "Biomass unit"@en , "Biomasseeinheit"@de .
:GeothermalUnit  a rdfs:Class ; rdfs:subClassOf :GenerationUnit ;
    rdfs:label "Geothermal unit"@en , "Geothermieeinheit"@de .
:StorageUnit     a rdfs:Class ; rdfs:subClassOf :GenerationUnit ;
    rdfs:label "Storage unit"@en , "Stromspeichereinheit"@de .
:OtherUnit       a rdfs:Class ; rdfs:subClassOf :GenerationUnit ;
    rdfs:label "Other / unmapped technology unit"@en , "Sonstige / nicht zugeordnete Einheit"@de .

# ---- Marktakteur classes (dispatched from MaStR-Nr prefix) --------------

:MarketActor
    a               rdfs:Class ;
    rdfs:label      "Market actor"@en , "Marktakteur"@de ;
    rdfs:comment    "Any market actor in the Marktstammdatenregister, regardless of role. Every Marktakteur record (any MaStR-Nr prefix from {ABR,SNB,GNB,SUP,SOM,SEM,GEM,ADM}) is at least a :MarketActor; role-specific subclasses below carry the precise role information that the 3-letter MaStR-Nr prefix encodes. NOTE — a :MarketActor resource fuses ORGANISATION IDENTITY AND ROLE: it is one *registration* (a legal entity acting in one role), not a stable organisation node. The same legal company registered in several roles gets several MaStR-Nrs and therefore several distinct, unconnected IRIs (e.g. an ABR :Operator and an SNB :GridOperator of one firm); no owl:sameAs links them and foaf:name (Firmenname) is duplicated per registration. So every actor-scoped link — :hasSite, :operatesUnit, and a unit's mastr:AnlagenbetreiberMastrNummer — means 'of this registration', not 'of the company'. Unifying registrations into one company node (owl:sameAs / Firmenname+address reconciliation) is out of scope for this vocabulary." .

:Operator
    a               rdfs:Class ;
    rdfs:subClassOf :MarketActor ;
    rdfs:label      "Plant operator"@en , "Anlagenbetreiber"@de ;
    rdfs:comment    "Legal entity or natural person that operates one or more generation/storage units. MaStR-Nr prefix ABR." .

:GridOperator
    a               rdfs:Class ;
    rdfs:subClassOf :MarketActor ;
    rdfs:label      "Grid operator"@en , "Netzbetreiber"@de ;
    rdfs:comment    "Network operator. MaStR-Nr prefix SNB for electricity grids, GNB for gas grids." .

:Supplier
    a               rdfs:Class ;
    rdfs:subClassOf :MarketActor ;
    rdfs:label      "Supplier"@en , "Lieferant"@de ;
    rdfs:comment    "Energy supplier. MaStR-Nr prefix SUP." .

:Administrator
    a               rdfs:Class ;
    rdfs:subClassOf :MarketActor ;
    rdfs:label      "Administrator / authority"@en , "Behörde"@de ;
    rdfs:comment    "Regulator or other administrative actor. MaStR-Nr prefix ADM (the Bundesnetzagentur is itself one of these)." .

# ---- Other record-type classes -----------------------------------------

:Location
    a               rdfs:Class ;
    rdfs:label      "Generation site"@en , "Stromerzeugungslokation"@de ;
    rdfs:comment    "Site that groups one or more generation units sharing a single grid-connection setup. MaStR-Nr prefix SEL." .

:Permit
    a               rdfs:Class ;
    rdfs:label      "Permit"@en , "Genehmigung"@de ;
    rdfs:comment    "Authority-issued permit covering one or more units. MaStR-Nr prefix SGE." .

:EegAnlage
    a               rdfs:Class ;
    rdfs:label      "EEG installation"@en , "EEG-Anlage"@de ;
    rdfs:comment    "Subsidy registration under the Erneuerbare-Energien-Gesetz. MaStR-Nr prefix EEG." .

:KwkAnlage
    a               rdfs:Class ;
    rdfs:label      "Cogeneration installation"@en , "KWK-Anlage"@de ;
    rdfs:comment    "Combined heat & power registration. MaStR-Nr prefix KWK." .

:StorageAnlage
    a               rdfs:Class ;
    rdfs:label      "Storage installation"@en , "Stromspeicheranlage"@de ;
    rdfs:comment    "Parent installation of a storage unit. MaStR-Nr prefix SSE (storage UNITS themselves use prefix SEE like every other generation unit)." .

:GridConnectionPoint
    a               rdfs:Class ;
    rdfs:label      "Grid connection point"@en , "Netzanschlusspunkt"@de ;
    rdfs:comment    "Grid connection point. Carries voltage level and the link to the grid operator. MaStR-Nr prefix SAN." .

:Network
    a               rdfs:Class ;
    rdfs:label      "Network / grid"@en , "Netz"@de ;
    rdfs:comment    "Grid / network entity. MaStR-Nr prefix SNE." .

# ---- Sub-resource classes (materialised by the wrapper) ----------------

:MarketRole
    a               rdfs:Class ;
    rdfs:label      "Market role"@en , "Marktrolle"@de ;
    rdfs:comment    "Role-specific binding of a Marktakteur to one upstream Marktrolle, carrying role-specific contact / register details. Materialised as a hash-IRI sub-resource on the actor (e.g. <abr/X#role-UN>); originates from a row in MarktakteureUndRollen.xml. A single actor can have multiple roles." .

:Refurbishment
    a               rdfs:Class ;
    rdfs:label      "Refurbishment"@en , "Ertüchtigung"@de ;
    rdfs:comment    "One capacity-increase event in the lifetime of an EEG-Anlage. Materialised as a hash-IRI sub-resource on the Anlage (e.g. <eeg/X#refurb-42>); originates from a row in Ertuechtigungen.xml. A single EEG-Anlage can have many refurbishments over time." .

# ---- Bridge / dispatch properties (the only literal-named vocab terms) -

:hasRole
    a               rdf:Property ;
    rdfs:label      "has role"@en , "hat Rolle"@de ;
    rdfs:domain     :MarketActor ;
    rdfs:range      :MarketRole ;
    rdfs:comment    "Links a Marktakteur to one of its MarketRole hash-IRI sub-resources." .

:hasRefurbishment
    a               rdf:Property ;
    rdfs:label      "has refurbishment"@en , "hat Ertüchtigung"@de ;
    rdfs:domain     :EegAnlage ;
    rdfs:range      :Refurbishment ;
    rdfs:comment    "Links an EEG-Anlage to one of its Refurbishment hash-IRI sub-resources." .

:hasSite
    a               rdf:Property ;
    rdfs:label      "has site"@en , "hat Lokation"@de ;
    rdfs:domain     :MarketActor ;
    rdfs:range      :Location ;
    rdfs:comment    "Links a Marktakteur (operator) to a Lokation (SEL) one of its units sits at. The materialised inverse of a unit's mastr:LokationMaStRNummer (reached via its mastr:AnlagenbetreiberMastrNummer): the upstream records the link only from the unit, so without this the operator document is a leaf and cannot be navigated to its sites." .

:operatesUnit
    a               rdf:Property ;
    rdfs:label      "operates unit"@en , "betreibt Einheit"@de ;
    rdfs:domain     :MarketActor ;
    rdfs:range      :GenerationUnit ;
    rdfs:comment    "Links a Marktakteur (operator) to a generation/storage unit (SEE) it operates. The materialised inverse of a unit's mastr:AnlagenbetreiberMastrNummer, so the operator document can be navigated to its units." .

:hasUnit
    a               rdf:Property ;
    rdfs:label      "has unit"@en , "hat Einheit"@de ;
    rdfs:domain     :Location ;
    rdfs:range      :GenerationUnit ;
    rdfs:comment    "Links a Lokation (SEL) to a generation/storage unit (SEE) sited there. The materialised, navigable form of the unit's mastr:LokationMaStRNummer (and of the Lokation's own opaque mastr:VerknuepfteEinheitenMaStRNummern literal), so the Lokation document can be navigated to its units." .

:hasOperator
    a               rdf:Property ;
    rdfs:label      "has operator"@en , "hat Betreiber"@de ;
    rdfs:domain     :Location ;
    rdfs:range      :MarketActor ;
    rdfs:comment    "Links a Lokation (SEL) to a Marktakteur (operator) of a unit sited there. Materialised from the units at the site (the upstream records no Lokation→operator link), so the Lokation document can be navigated to its operators. The inverse of :hasSite." .

:domain
    a               rdf:Property ;
    rdfs:label      "domain (Strom / Gas)"@en , "Sparte (Strom / Gas)"@de ;
    rdfs:comment    "Sparte; pre-resolved to a skos:Concept in the cl/2 codelist. Stamped on every generation unit (cl/2#20 = Strom; gas-side prefixes are filtered at load time). For Netz records, look up upstream mastr:Sparte instead — it carries the same value via the YAML-driven generic path." .

# ---- Linked Data Service (LIDS) terms -----------------------------------
# The /within and /filter endpoints are modelled as Linked Data Services
# (Speiser & Harth, "Integrating Linked Data and Services with Linked Data
# Services", ESWC 2011): the service call is reified as a named input entity
# under a #id fragment (a mastr:BoundingBox for /within, a mastr:Query for /filter),
# minted from the query parameters and related to each result hit.
# Resolving the call URI returns the input and its result links. In Turtle the
# call entity is relativized against the query-less route base, so it serializes
# host-free as <?…#id>. These terms sit in the mastr: namespace (matching the
# per-hit mastr:Energietraeger the same documents already carry).

mastr:BoundingBox
    a               rdfs:Class ;
    rdfs:label      "Bounding-box query"@en , "Begrenzungsrechteck-Anfrage"@de ;
    rdfs:comment    "The input entity of a /within service call: a WGS84 lon/lat extent, related via mastr:contains to each record whose coordinate falls within it."@en .

mastr:Query
    a               rdfs:Class ;
    rdfs:label      "Register query"@en , "Registerabfrage"@de ;
    rdfs:comment    "The input entity of a /filter service call: the active facets (mastr:ags, mastr:carrier), related via mastr:result to each matching record."@en .

mastr:contains
    a               rdf:Property ;
    rdfs:label      "contains record"@en , "enthält Datensatz"@de ;
    rdfs:domain     mastr:BoundingBox ;
    rdfs:comment    "Links a /within bounding-box query to a record it contains — i.e. whose coordinate falls within the box (a centroid/point test, not full-geometry topology, hence a wrapper term rather than geosparql:sfContains)."@en .

mastr:result
    a               rdf:Property ;
    rdfs:label      "query result"@en , "Abfrageergebnis"@de ;
    rdfs:domain     mastr:Query ;
    rdfs:comment    "Links a /filter query to one of its matching records."@en .

mastr:minLon
    a               rdf:Property ;
    rdfs:label      "minimum longitude"@en , "minimaler Längengrad"@de ;
    rdfs:domain     mastr:BoundingBox ; rdfs:range xsd:decimal ;
    rdfs:comment    "Western bound (WGS84 longitude) of the queried bounding box."@en .

mastr:minLat
    a               rdf:Property ;
    rdfs:label      "minimum latitude"@en , "minimaler Breitengrad"@de ;
    rdfs:domain     mastr:BoundingBox ; rdfs:range xsd:decimal ;
    rdfs:comment    "Southern bound (WGS84 latitude) of the queried bounding box."@en .

mastr:maxLon
    a               rdf:Property ;
    rdfs:label      "maximum longitude"@en , "maximaler Längengrad"@de ;
    rdfs:domain     mastr:BoundingBox ; rdfs:range xsd:decimal ;
    rdfs:comment    "Eastern bound (WGS84 longitude) of the queried bounding box."@en .

mastr:maxLat
    a               rdf:Property ;
    rdfs:label      "maximum latitude"@en , "maximaler Breitengrad"@de ;
    rdfs:domain     mastr:BoundingBox ; rdfs:range xsd:decimal ;
    rdfs:comment    "Northern bound (WGS84 latitude) of the queried bounding box."@en .

mastr:ags
    a               rdf:Property ;
    rdfs:label      "AGS prefix filter"@en , "AGS-Präfix-Filter"@de ;
    rdfs:domain     mastr:Query ; rdfs:range xsd:string ;
    rdfs:comment    "The Amtlicher Gemeindeschlüssel prefix (Land/Kreis/Gemeinde grain) a /filter query selects on."@en .

mastr:carrier
    a               rdf:Property ;
    rdfs:label      "energy-carrier filter"@en , "Energieträger-Filter"@de ;
    rdfs:domain     mastr:Query ; rdfs:range xsd:string ;
    rdfs:comment    "A MaStR Energietraeger code a /filter query selects on; repeated once per requested carrier."@en .
