From 1a1bc108d62e65965c708dc1c7432b47951f1a0e Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez-Beltran Date: Thu, 9 Oct 2025 21:04:35 +0100 Subject: [PATCH 1/7] Refactored CI workflow, added terms to the ontology --- .github/workflows/ci-common.yaml | 115 +----------- .github/workflows/ci-dev.yaml | 48 +---- .github/workflows/ci-release.yaml | 22 ++- .gitignore | 20 ++ README.md | 8 +- src/fuel.ttl | 297 +++++++++++++++++++++--------- src/scripts/onto_syntax_doc.py | 122 ++++++++++++ 7 files changed, 385 insertions(+), 247 deletions(-) create mode 100644 .gitignore create mode 100644 src/scripts/onto_syntax_doc.py diff --git a/.github/workflows/ci-common.yaml b/.github/workflows/ci-common.yaml index e687c31..a3626ce 100644 --- a/.github/workflows/ci-common.yaml +++ b/.github/workflows/ci-common.yaml @@ -9,6 +9,10 @@ on: DEV_DIR: required: false type: string + RELEASES_DIR: + required: false + type: string + default: ./public/releases env: ONTO_DIR: src @@ -47,7 +51,7 @@ jobs: - name: Validate ontology profile run: | - ./robot validate-profile --input "${ONTO_DIR}/${ONTO_FILE}" --profile DL || \ + ./robot validate-profile --input "${ONTO_DIR}/${ONTO_FILE}" --profile DL -vvv || \ (echo "Profile check failed." && exit 1) - name: Reasoning and consistency check @@ -58,114 +62,9 @@ jobs: echo "REASON_RESULT=inconsistent" >> $GITHUB_ENV fi - - name: Generate ontology syntaxes and documentation + - name: Generate ontology syntaxes and documentation run: | - python3 - << 'PY' - import os - from rdflib import Graph - from shutil import rmtree, copytree - import subprocess - - ONTO_DIR = os.environ['ONTO_DIR'] - ONTO_FILE = os.environ['ONTO_FILE'] - ONTO_ABBREV = os.environ['ONTO_ABBREV'] - DOCS_DIR = os.environ['DOCS_DIR'] - RELEASES_DIR = os.environ['RELEASES_DIR'] - - RELEASE_VERSION = os.environ.get('RELEASE_VERSION') - DEV_DIR = os.environ.get('DEV_DIR') - - g = Graph() - g.parse(os.path.join(ONTO_DIR, ONTO_FILE)) - target_fmts = [("ttl","turtle"),("jsonld","json-ld"),("nt","nt"),("owl","xml")] - - if RELEASE_VERSION: - # --- release build --- - release_dir = os.path.join(RELEASES_DIR, RELEASE_VERSION) - os.makedirs(release_dir, exist_ok=True) - - # Generate syntaxes - for fmt in target_fmts: - g.serialize(destination=os.path.join(release_dir, f"{ONTO_ABBREV}.{fmt[0]}"), format=fmt[1], encoding="utf-8") - - # Versioned docs - release_docs_dir = os.path.join(release_dir, "docs") - os.makedirs(release_docs_dir, exist_ok=True) - - # Pylode docs - pylode_outdir = os.path.join(release_docs_dir, "pylode") - os.makedirs(pylode_outdir, exist_ok=True) - subprocess.run([ - "pylode", - "-o", os.path.join(pylode_outdir, "index"), - os.path.join(ONTO_DIR, ONTO_FILE) - ], check=True) - - # Widoco docs - widoco_dir = os.path.join(release_docs_dir, "widoco") - os.makedirs(widoco_dir, exist_ok=True) - subprocess.run([ - "wget", "-O", os.path.join(widoco_dir,"widoco.jar"), - "https://github.com/dgarijo/Widoco/releases/download/v1.4.25/widoco-1.4.25-jar-with-dependencies_JDK-17.jar" - ], check=True) - subprocess.run([ - "java","-jar", os.path.join(widoco_dir,"widoco.jar"), - "-ontFile", os.path.join(ONTO_DIR, ONTO_FILE), - "-oops","-webVowl","-includeAnnotationProperties", - "-outFolder", widoco_dir, - "-rewriteAll","-includeImportedOntologies","-uniteSections","-excludeIntroduction" - ], check=True) - - # Update latest - latest_dir = os.path.join(RELEASES_DIR, "latest") - if os.path.exists(latest_dir): - rmtree(latest_dir) - copytree(release_dir, latest_dir) - - # Generate releases index.html - releases_index = os.path.join(RELEASES_DIR, 'index.html') - release_folders = sorted([d for d in os.listdir(RELEASES_DIR) if os.path.isdir(os.path.join(RELEASES_DIR,d))]) - with open(releases_index, 'w') as f: - f.write("FUEL Releases\n") - f.write("

FUEL Ontology Releases

\n\n\n") - - elif DEV_DIR: - # --- development build --- - os.makedirs(DEV_DIR, exist_ok=True) - - # Generate syntaxes - for fmt in target_fmts: - g.serialize(destination=os.path.join(DEV_DIR, f"{ONTO_ABBREV}.{fmt[0]}"), format=fmt[1], encoding="utf-8") - - # Development docs - dev_docs_dir = os.path.join(DEV_DIR, "docs") - os.makedirs(dev_docs_dir, exist_ok=True) - - pylode_outdir = os.path.join(dev_docs_dir, "pylode") - os.makedirs(pylode_outdir, exist_ok=True) - subprocess.run([ - "pylode", - "-o", os.path.join(pylode_outdir, "index"), - os.path.join(ONTO_DIR, ONTO_FILE) - ], check=True) - - widoco_dir = os.path.join(dev_docs_dir,"widoco") - os.makedirs(widoco_dir, exist_ok=True) - subprocess.run([ - "wget", "-O", os.path.join(widoco_dir,"widoco.jar"), - "https://github.com/dgarijo/Widoco/releases/download/v1.4.25/widoco-1.4.25-jar-with-dependencies_JDK-17.jar" - ], check=True) - subprocess.run([ - "java","-jar", os.path.join(widoco_dir,"widoco.jar"), - "-ontFile", os.path.join(ONTO_DIR, ONTO_FILE), - "-oops","-webVowl","-includeAnnotationProperties", - "-outFolder", widoco_dir, - "-rewriteAll","-includeImportedOntologies","-uniteSections","-excludeIntroduction" - ], check=True) - PY + python3 src/scripts/onto_syntax_doc.py - name: Upload dev artifact if: ${{ inputs.DEV_DIR != '' && inputs.DEV_DIR != null }} diff --git a/.github/workflows/ci-dev.yaml b/.github/workflows/ci-dev.yaml index 9bfd906..a18a54c 100644 --- a/.github/workflows/ci-dev.yaml +++ b/.github/workflows/ci-dev.yaml @@ -9,9 +9,9 @@ jobs: dev: uses: ./.github/workflows/ci-common.yaml with: - DEV_DIR: dev # build ontologies into "dev" folder + DEV_DIR: ./public/dev # build ontologies into "dev" folder - dev_index_and_deploy: + deploy: needs: dev runs-on: ubuntu-latest permissions: @@ -28,47 +28,7 @@ jobs: uses: actions/download-artifact@v4 with: name: dev - path: dev - - - name: Generate dev index.html - run: | - DEV_DIR=dev - DEV_SITE=dev_site - mkdir -p $DEV_SITE/dev - - # Copy all ontology outputs into /dev - cp -r $DEV_DIR/* $DEV_SITE/dev/ || echo "No files to copy yet" - - #### Root index.html (at /dev/index.html) - ROOT_INDEX=$DEV_SITE/dev/index.html - echo "FUEL Dev Build" > $ROOT_INDEX - echo "

Development Build

" >> $ROOT_INDEX - - # List ontology files (inside /dev) - for f in $DEV_SITE/dev/*; do - fname=$(basename $f) - if [ "$fname" != "index.html" ] && [ "$fname" != "docs" ]; then - echo "$fname
" >> $ROOT_INDEX - fi - done - - # Add link to docs folder - if [ -d "$DEV_SITE/dev/docs" ]; then - echo "
Documentation
" >> $ROOT_INDEX - fi - echo "" >> $ROOT_INDEX - - #### Docs index.html (at /dev/docs/index.html) - if [ -d "$DEV_SITE/dev/docs" ]; then - DOCS_INDEX=$DEV_SITE/dev/docs/index.html - echo "FUEL Dev Docs" > $DOCS_INDEX - echo "

Ontology Documentation

" >> $DOCS_INDEX - for d in $DEV_SITE/dev/docs/*/; do - dname=$(basename $d) - echo "$dname
" >> $DOCS_INDEX - done - echo "" >> $DOCS_INDEX - fi + path: ./public/dev - name: Configure GitHub Pages uses: actions/configure-pages@v5 @@ -76,7 +36,7 @@ jobs: - name: Upload dev site artifact uses: actions/upload-pages-artifact@v4 with: - path: dev_site + path: ./public - name: Deploy dev site id: deployment diff --git a/.github/workflows/ci-release.yaml b/.github/workflows/ci-release.yaml index 71d8bbc..1f52223 100644 --- a/.github/workflows/ci-release.yaml +++ b/.github/workflows/ci-release.yaml @@ -16,6 +16,7 @@ jobs: uses: ./.github/workflows/ci-common.yaml with: RELEASE_VERSION: ${{ github.event.inputs.release_version }} + RELEASES_DIR: ./public/releases deploy: needs: release @@ -27,6 +28,23 @@ jobs: pages: write id-token: write steps: - - name: Deploy to GitHub Pages + - name: Checkout + uses: actions/checkout@v4 + + - name: Download release artifact + uses: actions/download-artifact@v4 + with: + name: release + path: ./public/releases # download into ./public/releases + + - name: Configure GitHub Pages + uses: actions/configure-pages@v5 + + - name: Upload site artifact + uses: actions/upload-pages-artifact@v4 + with: + path: ./public # publish the full public/ tree + + - name: Deploy site id: deployment - uses: actions/deploy-pages@v4.0.5 \ No newline at end of file + uses: actions/deploy-pages@v4 \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d98f6a4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,20 @@ +# VSCode settings +.vscode/ + +# VSCode extensions +*.code-workspace + +# VSCode logs +*.log + +# VSCode backup files +*.tmp + +# VSCode history +.history/ + +# VSCode crash reports +crash-reports/ + +# Mac system files +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md index 0e6847d..1a62461 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,10 @@ # FUsion Energy Lexicon (FUEL) FUsion Energy Lexicon (FUEL) is an ontology for fusion energy data and processes. -FUEL is currently under development and will be available in this repository in the near future. + +FUEL is currently under development. + +### Development version + +To check the development version, visit [FUEL Dev](https://ukaea.github.io/fuel/dev/) + diff --git a/src/fuel.ttl b/src/fuel.ttl index 3af8e13..26cb1f8 100644 --- a/src/fuel.ttl +++ b/src/fuel.ttl @@ -1,106 +1,219 @@ -@prefix fuel: . +@prefix : . +@prefix mod: . +@prefix omv: . @prefix owl: . @prefix rdf: . -@prefix rdfs: . +@prefix sdo: . @prefix xml: . @prefix xsd: . -@prefix dcterms: . -@prefix foaf: . @prefix dcat: . +@prefix foaf: . +@prefix fuel: . +@prefix rdfs: . @prefix vann: . -@prefix mod: . -@prefix omv: . -@prefix sdo: . -@base . - -### AnnotationProperties declarations -dcterms:title a owl:AnnotationProperty . -dcterms:abstract a owl:AnnotationProperty . -dcterms:created a owl:AnnotationProperty . -dcterms:creator a owl:AnnotationProperty . -dcterms:description a owl:AnnotationProperty . -dcterms:issued a owl:AnnotationProperty . -dcterms:license a owl:AnnotationProperty . -dcterms:modified a owl:AnnotationProperty . - -vann:preferredNamespacePrefix a owl:AnnotationProperty . -vann:preferredNamespaceUri a owl:AnnotationProperty . - -dcat:version a owl:AnnotationProperty . - -mod:definitionProperty a owl:AnnotationProperty . -mod:hasRepresentationLanguage a owl:AnnotationProperty . -mod:hasSyntax a owl:AnnotationProperty . -mod:prefLabelProperty a owl:AnnotationProperty . -mod:status a owl:AnnotationProperty . - -foaf:name a owl:AnnotationProperty . -foaf:homepage a owl:AnnotationProperty . - -sdo:name a owl:AnnotationProperty . -sdo:identifier a owl:AnnotationProperty . -sdo:affiliation a owl:AnnotationProperty . - -### Class declarations -foaf:Person a owl:Class . - -sdo:Person a owl:Class . - - - - a owl:Ontology ; - - dcterms:title "FUsion Energy Lexicon"@en ; - rdfs:label "FUsion Energy Lexicon"@en , - "Léxico de energía de fusión"@es ; - - dcterms:abstract "FUEL is a vocabulary designed to facilitate the interoperability of fusion energy data."@en; - rdfs:comment "FUEL is a vocabulary designed to facilitate the interoperability of fusion energy data."@en ; - dcterms:description "FUEL is a vocabulary designed to facilitate the interoperability of fusion energy data."@en ; - - dcterms:license ; - dcterms:creator [ - a foaf:Person ; - a sdo:Person ; - foaf:homepage ; - foaf:name "Alejandra Gonzalez Beltran" ; - sdo:name "Alejandra Gonzalez Beltran" ; - rdfs:seeAlso ; - sdo:identifier ; - sdo:affiliation [ - sdo:identifier - ] - ]; - - dcat:version "0.1" ; - dcterms:created "2024-11-06"^^xsd:date ; - dcterms:issued "2024-11-06"^^xsd:date ; - dcterms:modified "2025-09-08"^^xsd:dateTime ; - vann:preferredNamespacePrefix "fuel" ; - vann:preferredNamespaceUri "https://w3id.org/fuel#" ; - - mod:definitionProperty rdfs:comment ; - mod:hasRepresentationLanguage omv:OWL ; - mod:hasSyntax ; - mod:prefLabelProperty rdfs:label ; - mod:status "active" ; - - dcterms:license ; - - ## owl:backwardCompatibleWith fuel:0.0.1 ; - ## owl:priorVersion fuel:0.0.1 ; - owl:versionIRI fuel:0.0.1 ; - owl:versionInfo "0.0.1"^^xsd:string - . +@prefix dcterms: . +@prefix skos: . +@base . + + rdf:type owl:Ontology ; + owl:versionIRI ; + dcterms:abstract "FUEL is a vocabulary designed to facilitate the interoperability of fusion energy data."@en ; + dcterms:created "2024-11-06"^^xsd:date ; + dcterms:creator [ rdf:type foaf:Person , + sdo:Person ; + rdfs:seeAlso ; + foaf:homepage ; + foaf:name "Alejandra Gonzalez Beltran" ; + sdo:affiliation [ sdo:identifier + ] ; + sdo:identifier ; + sdo:name "Alejandra Gonzalez Beltran" + ] ; + dcterms:description "FUEL is a vocabulary designed to facilitate the interoperability of fusion energy data."@en ; + dcterms:issued "2024-11-06"^^xsd:date ; + dcterms:license ; + dcterms:modified "2025-09-08"^^xsd:date ; + dcterms:title "FUsion Energy Lexicon"@en ; + vann:preferredNamespacePrefix "fuel" ; + vann:preferredNamespaceUri "https://w3id.org/fuel#" ; + rdfs:comment "FUEL is a vocabulary designed to facilitate the interoperability of fusion energy data."@en ; + rdfs:label "FUsion Energy Lexicon"@en , + "Léxico de energía de fusión"@es ; + owl:versionInfo "0.0.1" ; + dcat:version "0.1" ; + mod:definitionProperty rdfs:comment ; + mod:hasRepresentationLanguage omv:OWL ; + mod:hasSyntax ; + mod:prefLabelProperty rdfs:label ; + mod:status "active" . + +################################################################# +# Annotation properties +################################################################# + +### http://purl.org/dc/terms/abstract +dcterms:abstract rdf:type owl:AnnotationProperty . + + +### http://purl.org/dc/terms/created +dcterms:created rdf:type owl:AnnotationProperty . + + +### http://purl.org/dc/terms/creator +dcterms:creator rdf:type owl:AnnotationProperty . + + +### http://purl.org/dc/terms/description +dcterms:description rdf:type owl:AnnotationProperty . + + +### http://purl.org/dc/terms/issued +dcterms:issued rdf:type owl:AnnotationProperty . + + +### http://purl.org/dc/terms/license +dcterms:license rdf:type owl:AnnotationProperty . + + +### http://purl.org/dc/terms/modified +dcterms:modified rdf:type owl:AnnotationProperty . + + +### http://purl.org/dc/terms/source +dcterms:source rdf:type owl:AnnotationProperty . + + +### http://purl.org/dc/terms/title +dcterms:title rdf:type owl:AnnotationProperty . + + +### http://purl.org/vocab/vann/preferredNamespacePrefix +vann:preferredNamespacePrefix rdf:type owl:AnnotationProperty . + + +### http://purl.org/vocab/vann/preferredNamespaceUri +vann:preferredNamespaceUri rdf:type owl:AnnotationProperty . + + +### http://www.w3.org/2004/02/skos/core#altLabel + rdf:type owl:AnnotationProperty . + + +### http://www.w3.org/ns/dcat#version +dcat:version rdf:type owl:AnnotationProperty . + + +### http://xmlns.com/foaf/0.1/homepage +foaf:homepage rdf:type owl:AnnotationProperty . + + +### http://xmlns.com/foaf/0.1/name +foaf:name rdf:type owl:AnnotationProperty . + + +### https://schema.org/affiliation +sdo:affiliation rdf:type owl:AnnotationProperty . + + +### https://schema.org/identifier +sdo:identifier rdf:type owl:AnnotationProperty . + + +### https://schema.org/name +sdo:name rdf:type owl:AnnotationProperty . + + +### https://w3id.org/mod#definitionProperty +mod:definitionProperty rdf:type owl:AnnotationProperty . + + +### https://w3id.org/mod#hasRepresentationLanguage +mod:hasRepresentationLanguage rdf:type owl:AnnotationProperty . + + +### https://w3id.org/mod#hasSyntax +mod:hasSyntax rdf:type owl:AnnotationProperty . + + +### https://w3id.org/mod#prefLabelProperty +mod:prefLabelProperty rdf:type owl:AnnotationProperty . + + +### https://w3id.org/mod#status +mod:status rdf:type owl:AnnotationProperty . + + +################################################################# +# Datatypes +################################################################# + +### http://www.w3.org/2001/XMLSchema#date +xsd:date rdf:type rdfs:Datatype . + ################################################################# # Classes ################################################################# +### http://xmlns.com/foaf/0.1/Person +foaf:Person rdf:type owl:Class . + + +### https://schema.org/Person +sdo:Person rdf:type owl:Class . + + ### http://w3id.org/fuel#campaign -fuel:campaign - a owl:Class ; - rdfs:comment "A set of connected experiments that are run across a time period."@en . +fuel:campaign rdf:type owl:Class ; + rdfs:comment "A set of connected experiments that are run across a time period."@en , + "Un conjunto de experimentos conectados que se ejecutan durante un período específico de tiempo"@es ; + rdfs:label "campaign"@en , + "campaña"@en ; + "experimental campaign"@en . + + +### http://w3id.org/fuel#fusion_reactor +fuel:fusion_reactor rdf:type owl:Class ; + rdfs:subClassOf fuel:nuclear_reactor ; + dcterms:source ; + rdfs:comment "A device in which controlled thermonuclear fusion takes place, either for scientific purposes or for the production of energy. Since there are different ways to achieve fusion conditions, a fusion reactor can be a tokamak, a stellarator, a fusor or any other device in which the conditions for fusion can be achieved and maintained."@en , + "Dispositivo en el que se produce la fusión termonuclear controlada, ya sea con fines científicos o para la producción de energía. Dado que existen diferentes maneras de lograr las condiciones de fusión, un reactor de fusión puede ser un tokamak, un stellarator, un fusor o cualquier otro dispositivo que permita alcanzar y mantener las condiciones para la fusión."@es ; + rdfs:label "fusion reactor"@en , + "reactor de fusión"@es ; + skos:altLabel "dispositivo de fusión"@es , + "fusion device"@en , + "nuclear fusion reactor"@en , + "reactor de fusión nuclear"@es . + + +### http://w3id.org/fuel#nuclear_reactor +fuel:nuclear_reactor rdf:type owl:Class ; + dcterms:source ; + rdfs:comment "A device inside which a controlled chain fission reaction takes place. The reactor usually has the form of a metal pressure vessel, in the middle of which the nuclear fuel is arranged in a so-called core. A coolant, whether gas or liquid, circulates through the core to dissipate the heat generated by the fission reaction. The power of the reactor is controlled by control rods that are inserted or withdrawn from the core as necessary. If the reactor uses thermal neutrons for fission, it also includes a moderator, either in the form of a liquid or a solid, which slows down the neutrons. Heat, generated by a reactor, is most commonly used. Either directly for technological purposes (e.g., hydrogen production by steam reforming) or for electricity generation by a steam turbine. The reactor can also be used to produce nuclear fuel (breeder reactor), or the strong neutron fluxes produced by the reaction can be used for research purposes or for the production of radiopharmaceuticals. There are a number of types of nuclear reactors, with the most common types used for electricity generation being water-cooled PWRs and BWRs. In 2023, there were 436 nuclear reactors in operation in the world."@en , + "Dispositivo en el que ocurre una reacción nuclear en cadena controlada y autosostenida. Los reactores nucleares se utilizan en las centrales nucleares para la generación de electricidad y en la propulsión de barcos. El calor de la fis nuclear se transfiere a un fluido de trabajo (agua o gas), que pasa por turbinas."@es ; + rdfs:label "nuclear reactor"@en , + "reactor nuclear"@es ; + skos:altLabel "nuclear fission reactor"@en , + "reactor de fisión nuclear"@es . + + + +### http://w3id.org/fuel#shot +fuel:shot rdf:type owl:Class ; + dcterms:source ; + rdfs:comment "A “shot” is any kind of experiment conducted on a test machine following defined parameters. It could be many actual firings of the machine following a variation in the parameters. So one or more “shots” make up an experiment." ; + rdfs:label "shot"@en . + + +### http://w3id.org/fuel#stellarator +fuel:stellarator rdf:type owl:Class ; + rdfs:subClassOf fuel:fusion_reactor . + + +### http://w3id.org/fuel#tokamak +fuel:tokamak rdf:type owl:Class ; + rdfs:subClassOf fuel:fusion_reactor . + -### Generated by the OWL API (version 4.5.26.2023-07-17T20:34:13Z) https://github.com/owlcs/owlapi +### Generated by the OWL API (version 4.5.29.2024-05-13T12:11:03Z) https://github.com/owlcs/owlapi diff --git a/src/scripts/onto_syntax_doc.py b/src/scripts/onto_syntax_doc.py new file mode 100644 index 0000000..322bf0a --- /dev/null +++ b/src/scripts/onto_syntax_doc.py @@ -0,0 +1,122 @@ +import os +from rdflib import Graph +import urllib.request +from shutil import rmtree, copytree, copy +import shutil +import subprocess + +ONTO_DIR = os.environ['ONTO_DIR'] +ONTO_FILE = os.environ['ONTO_FILE'] +ONTO_ABBREV = os.environ['ONTO_ABBREV'] +DOCS_DIR = os.environ['DOCS_DIR'] +RELEASES_DIR = os.environ['RELEASES_DIR'] + +RELEASE_VERSION = os.environ.get('RELEASE_VERSION') +DEV_DIR = os.environ.get('DEV_DIR') + +g = Graph() +g.parse(os.path.join(ONTO_DIR, ONTO_FILE)) +target_fmts = [("ttl","turtle"),("jsonld","json-ld"),("nt","nt"),("owl","xml")] + +# function to generate the ontology syntaxes +def generate_syntaxes(outdir): + os.makedirs(outdir, exist_ok=True) + for ext, fmt in target_fmts: + g.serialize( + destination=os.path.join(outdir, f"{ONTO_ABBREV}.{ext}"), + format=fmt, + encoding="utf-8" + ) + +# function to create the documentation with pylode +def generate_pylode_docs(outdir): + pylode_outdir = os.path.join(outdir, "pylode") + os.makedirs(pylode_outdir, exist_ok=True) + subprocess.run([ + "pylode", + "-o", os.path.join(pylode_outdir, "index"), + os.path.join(ONTO_DIR, ONTO_FILE) + ], check=True) + +# function to create the documentation with widoco +def generate_widoco_docs(outdir, onto_dir, onto_file, version="1.4.25"): + widoco_dir = os.path.join(outdir, "widoco") + os.makedirs(widoco_dir, exist_ok=True) + widoco_jar = os.path.join(widoco_dir, "widoco.jar") + + # Download Widoco if not already present + if not os.path.exists(widoco_jar): + url = f"https://github.com/dgarijo/Widoco/releases/download/v{version}/widoco-{version}-jar-with-dependencies_JDK-17.jar" + print(f"Downloading Widoco {version}...") + urllib.request.urlretrieve(url, widoco_jar) + + # Run Widoco + cmd = [ + "java", "-jar", widoco_jar, + "-ontFile", os.path.join(onto_dir, onto_file), + "-oops", "-webVowl", "-includeAnnotationProperties", + "-outFolder", widoco_dir, + "-rewriteAll", "-includeImportedOntologies", "-uniteSections", "-excludeIntroduction", + "-lang", "en-es" + ] + + try: + subprocess.run(cmd, check=True) + print(f"Widoco documentation generated at {widoco_dir}") + + # Copy index-en.html to index.html if it exists + index_en = os.path.join(widoco_dir, "index-en.html") + index_default = os.path.join(widoco_dir, "index.html") + if os.path.exists(index_en): + shutil.copy(index_en, index_default) + print("Copied index-en.html → index.html") + else: + print("index-en.html not found, skipping copy.") + + except subprocess.CalledProcessError as e: + print("Widoco execution failed:") + print(e) + +if RELEASE_VERSION: +# --- release build --- + release_dir = os.path.join(RELEASES_DIR, RELEASE_VERSION) + generate_syntaxes(release_dir) + + release_docs_dir = os.path.join(release_dir, "docs") + generate_pylode_docs(release_docs_dir) + generate_widoco_docs(release_docs_dir) + + # Update latest + latest_dir = os.path.join(RELEASES_DIR, "latest") + if os.path.exists(latest_dir): + rmtree(latest_dir) + copytree(release_dir, latest_dir) + + # Generate releases index.html + releases_index = os.path.join(RELEASES_DIR, 'index.html') + release_folders = sorted([d for d in os.listdir(RELEASES_DIR) if os.path.isdir(os.path.join(RELEASES_DIR,d))]) + with open(releases_index, 'w') as f: + f.write("FUEL Releases\n") + f.write("

FUEL Ontology Releases

\n
    \n") + for r in release_folders: + f.write(f'
  • {r}
  • \n') + f.write("
\n\n") + +elif DEV_DIR: + # --- development build --- + generate_syntaxes(DEV_DIR) + + dev_docs_dir = os.path.join(DEV_DIR, "docs") + generate_pylode_docs(dev_docs_dir) + generate_widoco_docs(dev_docs_dir, ONTO_DIR, ONTO_FILE) + + # Generate dev index.html + dev_index = os.path.join(DEV_DIR, 'index.html') + with open(dev_index, 'w') as f: + f.write("FUEL Development Build\n") + f.write("

FUEL Ontology (Development)

\n\n\n") \ No newline at end of file From 0e1c37515656645519304dcf16cb351c58848542 Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez-Beltran Date: Fri, 10 Oct 2025 18:17:27 +0100 Subject: [PATCH 2/7] Update to ontology and wikidata utils --- .gitignore | 5 +- src/fuel.ttl | 30 ++++++-- src/scripts/wikidata.py | 135 ++++++++++++++++++++++++++++++++++ src/scripts/wikidata_match.py | 76 +++++++++++++++++++ 4 files changed, 238 insertions(+), 8 deletions(-) create mode 100644 src/scripts/wikidata.py create mode 100644 src/scripts/wikidata_match.py diff --git a/.gitignore b/.gitignore index d98f6a4..f6a860b 100644 --- a/.gitignore +++ b/.gitignore @@ -17,4 +17,7 @@ crash-reports/ # Mac system files -.DS_Store \ No newline at end of file +.DS_Store + +# Python cache files +__pycache__/ \ No newline at end of file diff --git a/src/fuel.ttl b/src/fuel.ttl index 26cb1f8..0ca7892 100644 --- a/src/fuel.ttl +++ b/src/fuel.ttl @@ -168,7 +168,7 @@ fuel:campaign rdf:type owl:Class ; rdfs:comment "A set of connected experiments that are run across a time period."@en , "Un conjunto de experimentos conectados que se ejecutan durante un período específico de tiempo"@es ; rdfs:label "campaign"@en , - "campaña"@en ; + "campaña"@es ; "experimental campaign"@en . @@ -205,14 +205,30 @@ fuel:shot rdf:type owl:Class ; rdfs:label "shot"@en . -### http://w3id.org/fuel#stellarator -fuel:stellarator rdf:type owl:Class ; - rdfs:subClassOf fuel:fusion_reactor . - - ### http://w3id.org/fuel#tokamak fuel:tokamak rdf:type owl:Class ; - rdfs:subClassOf fuel:fusion_reactor . + rdfs:subClassOf fuel:fusion_reactor ; + rdfs:label "tokamak"@en ; + skos:altLabel "toroidal chamber with magnetic coils"@en , + "cámara toroidal con bobinas magnéticas"@es ; + rdfs:comment "A device for magnetic confinement of plasma by a combination of a toroidal magnetic field and a current flowing through the plasma in which conditions for thermonuclear fusion ignition can be achieved. The word “tokamak” is of Russian origin and is an acronym for “TOroidalnaya KAmera i MAgnitnye Katushki” — toroidal chamber and magnetic coils. The magnetic field necessary to keep the hot plasma inside the toroidal chamber is generated as a combination of the field of the toroidal coils and the magnetic field generated by the current flowing through the plasma. Since the current in the plasma is induced on the transformer principle, the tokamak is a pulse device."@en ; + dcterms:source . + +### http://w3id.org/fuel#spherical_tokamak +fuel:spherical_tokamak rdf:type owl:Class ; + rdfs:subClassOf fuel:tokamak ; + rdfs:label "spherical tokamak"@en , + "tokamak esférico"@es ; + dcterms:source ; + rdfs:comment "Tokamak with a low aspect ratio and a round plasma in a shape resembling a cored apple. While a conventional tokamak has a more donut-like shape with a central hole, a spherical tokamak minimizes this hole to achieve a higher compactness. A single common conductor runs through the centre of the tokamak, to which toroidal magnets in the shape of semicircles are connected. Due to its more compact shape, the spherical tokamak achieves the same plasma parameters as a conventional tokamak with a lower magnetic field. This allows it to be smaller and cheaper. Typical spherical tokamaks are the Small Tight Aspect Ratio Tokamak (START) or the Mega Ampere Spherical Tokamak (MAST)."@en . + + +### http://w3id.org/fuel#stellarator +fuel:stellarator rdf:type owl:Class ; + rdfs:subClassOf fuel:fusion_reactor ; + rdfs:label "stellarator"@en ; + rdfs:comment "A device for thermonuclear fusion research that uses a combination of differently shaped coils which together create a desired helical magnetic field to confine the hot plasma. To hold the particles in the donut-shaped magnetic container, they must circulate in spirals, once on the inside and once on the outside of the torus. The stellarator creates a suitable magnetic field by combining helical, toroidal and poloidal coils. There are many variations that use different combinations and shapes of coils (classical, heliac, heliotron, torsatron, and helias). In the most modern modular stellarators, an assembly of specially twisted coils creates the magnetic field."@en ; + dcterms:source . diff --git a/src/scripts/wikidata.py b/src/scripts/wikidata.py new file mode 100644 index 0000000..0592a58 --- /dev/null +++ b/src/scripts/wikidata.py @@ -0,0 +1,135 @@ +import re +import json +import requests +from typing import Any, Dict, List +import re +import json +import requests +from typing import Any, Dict, List, Union + +WIKIDATA_API_URL = "https://www.wikidata.org/w/api.php" +USER_AGENT = "WikidataClient/1.0 (https://github.com/ukaea/fuel)" + + +def wikidata_fetch(params: Dict[str, str]) -> Union[Dict[str, Any], str]: + """Fetch data from the Wikidata API with error handling.""" + try: + resp: requests.Response = requests.get(WIKIDATA_API_URL, params=params, headers={"User-Agent":USER_AGENT}, timeout=10) + + if resp.status_code == requests.codes.ok: + return resp.json() + else: + return f"HTTP {resp.status_code}: {resp.content}" + except requests.RequestException as e: + return f"Request error: {e}" + except Exception as e: + return f"Unexpected error: {e}" + + +def wikidata_search(query: str) -> List[Dict[str, Any]]: + """Search Wikidata for a query string and return entities with their types.""" + if not query: + return [] + + + # Build set of search terms: original + split tokens + query_strings = {query, *re.split(r"[ _\-\+\*\(\)\[\]]", query)} - {''} + + # Collect raw search results + search_results: set[str] = set() + for qs in query_strings: + params = { + 'action': 'wbsearchentities', + 'format': 'json', + 'search': qs, + 'language': 'en' + } + res = wikidata_fetch(params) + + if isinstance(res, dict) and res.get('success'): + for r in res.get('search', []): + entry = { + 'id': r['id'], + 'url': r['url'], + 'label': r.get('label', ''), + 'aliases': r.get('aliases', []), + 'description': r.get('description', ''), + 'type': '' # Will be filled later + } + search_results.add(json.dumps(entry)) # deduplicate + + if not search_results: + return [] + + # Deduplicate and map by ID + results_list = [json.loads(r) for r in search_results] + for r in results_list: + r.setdefault("type", "") + + search_results_map = {r['id']: r for r in results_list} + + # Fetch entity details in one batch + ids = '|'.join(search_results_map.keys()) + params = { + 'action': 'wbgetentities', + 'ids': ids, + 'format': 'json', + 'languages': 'en' + } + entities = wikidata_fetch(params) + + if isinstance(entities, dict) and 'entities' in entities: + #if isinstance(entities, dict) and entities.get('success') and 'entities' in entities: + type_ids: set[str] = set() + ent_map = entities['entities'] + + # Extract type IDs (P31) for each entity + for eid, ent in ent_map.items(): + etype_id = ( + ent.get('claims', {}) + .get('P31', [{}])[0] + .get('mainsnak', {}) + .get('datavalue', {}) + .get('value', {}) + .get('id', '') + ) + if etype_id: + type_ids.add(etype_id) + search_results_map[eid]['_type_id'] = etype_id # temp + + # Batch fetch type labels + if type_ids: + type_params = { + 'action': 'wbgetentities', + 'ids': '|'.join(type_ids), + 'format': 'json', + 'languages': 'en' + } + type_entities = wikidata_fetch(type_params) + if isinstance(type_entities, dict) and 'entities' in type_entities: + for tid, tdata in type_entities['entities'].items(): + etype_label = tdata.get('labels', {}).get('en', {}).get('value', '') + # Assign labels back to results + for ent in search_results_map.values(): + if ent.get('_type_id') == tid: + ent['type'] = etype_label + del ent['_type_id'] + + return list(search_results_map.values()) + + +# ----------------- +# Test harness +# ----------------- +if __name__ == "__main__": + test_queries = ["tokamak", "stellarator", "nuclear reactor"] + + for q in test_queries: + print(f"\n=== Results for: {q} ===") + results = wikidata_search(q) + for r in results[:5]: # show first 5 results for brevity + print(f"- {r['label']} ({r['id']})") + print(f" Type: {r['type']}") + print(f" Desc: {r['description']}") + print(f" URL : {r['url']}\n") + diff --git a/src/scripts/wikidata_match.py b/src/scripts/wikidata_match.py new file mode 100644 index 0000000..17084c8 --- /dev/null +++ b/src/scripts/wikidata_match.py @@ -0,0 +1,76 @@ +import numpy as np +from typing import List, Dict, Any, Optional, Tuple +from sklearn.metrics.pairwise import cosine_similarity +from sentence_transformers import SentenceTransformer +from pydantic import BaseModel, Field +from wikidata import wikidata_search + +class Property(BaseModel): + key: str + value: str + +class Node(BaseModel): + id: str = Field(..., description="The identifying property of the node in Title Case") + type: str = Field(..., description="The entity type / label of the node in PascalCase.") + properties: Optional[List[Property]] = Field(default=[], description="Detailed properties of the node") + aliases: List[str] = Field(default=[], description="Alternative names or identifiers for the entity in Title Case") + definition: Optional[str] = Field(None, description="A concise definition or description of the entity") + +# Correct model name +model = SentenceTransformer('all-MiniLM-L6-v2', tokenizer_kwargs={"clean_up_tokenization_spaces": False}) + +def convert_case(text: str) -> str: + return text.title().replace(" ", "") + +def calculate_cosine_similarity(sentences: List[str]) -> np.ndarray: + sentence_embeddings = model.encode(sentences) + return cosine_similarity([sentence_embeddings[0]], sentence_embeddings[1:]).flatten() + +def link_nodes(entities: List[Node], sim_thresh: float = 0.5) -> Tuple[List[Dict[str, Any]], List[Node]]: + matched_nodes, unmatched_nodes = [], [] + + for entity in entities: + res = wikidata_search(entity.id) + if not res: + unmatched_nodes.append(entity) + continue + + if ' ' not in entity.id: + tcase_id = convert_case(entity.id) + eid = f"{entity.id}/{tcase_id}" if tcase_id != entity.id else entity.id + else: + eid = f"{entity.id.replace(' ', '')}/{entity.id}" + + sentences = [f"{eid}, {', '.join(entity.aliases)}, {convert_case(entity.type)}, {entity.definition}"] + sentences.extend([f"{r['label']}, {', '.join(r['aliases'])}, {r['type']}, {r['description']}".lower() for r in res]) + + scores = calculate_cosine_similarity(sentences) + best_match_index = np.argmax(scores) + + if scores[best_match_index] < sim_thresh: + unmatched_nodes.append(entity) + else: + best_match = res[best_match_index] + matched_nodes.append({ + "id": best_match["id"], + "definition": entity.definition, + "desc": best_match["description"], + "type": entity.type, + "wiki_type": best_match["type"], + "alias": entity.id, + "url": best_match["url"].strip('/'), + "labels": entity.aliases + best_match['aliases'] + [best_match['label']], + "properties": {p.key: p.value for p in entity.properties} + }) + + return matched_nodes, unmatched_nodes + +# Example usage +if __name__ == "__main__": + nodes = [ + Node(id="tokamak", type="Concept", aliases=["tokamak"], definition="A device for magnetic confinement of plasma by a combination of a toroidal magnetic field and a current flowing through the plasma in which conditions for thermonuclear fusion ignition can be achieved. The word “tokamak” is of Russian origin and is an acronym for “TOroidalnaya KAmera i MAgnitnye Katushki” — toroidal chamber and magnetic coils. The magnetic field necessary to keep the hot plasma inside the toroidal chamber is generated as a combination of the field of the toroidal coils and the magnetic field generated by the current flowing through the plasma. Since the current in the plasma is induced on the transformer principle, the tokamak is a pulse device.") + ] + matched, unmatched = link_nodes(nodes) + print("Matched Nodes:", matched) + print("Unmatched Nodes:", unmatched) + From db627dddbbb34ab747db04955ac453168dea1331 Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez-Beltran Date: Fri, 17 Oct 2025 09:47:45 +0100 Subject: [PATCH 3/7] Updates to ontology, adding badges --- .github/workflows/ci-common.yaml | 34 +++++++++++++++--- README.md | 11 ++++++ src/fuel.ttl | 62 ++++++++++++++++++++++++++------ 3 files changed, 93 insertions(+), 14 deletions(-) diff --git a/.github/workflows/ci-common.yaml b/.github/workflows/ci-common.yaml index a3626ce..8254c92 100644 --- a/.github/workflows/ci-common.yaml +++ b/.github/workflows/ci-common.yaml @@ -25,8 +25,9 @@ jobs: build: runs-on: ubuntu-latest env: - DEV_DIR: ${{ inputs.DEV_DIR }} - RELEASE_VERSION: ${{ inputs.RELEASE_VERSION }} + DEV_DIR: ${{ inputs.DEV_DIR || 'dev' }} + RELEASE_VERSION: ${{ inputs.RELEASE_VERSION || '' }} + GIST_ID: ${{ secrets.GIST_ID || '' }} steps: - name: Checkout @@ -50,17 +51,42 @@ jobs: pip install rdflib dotenv pylode - name: Validate ontology profile + id: profile run: | ./robot validate-profile --input "${ONTO_DIR}/${ONTO_FILE}" --profile DL -vvv || \ (echo "Profile check failed." && exit 1) + - name: Badge — Syntax + if: always() + uses: schneegans/dynamic-badges-action@v1.7.0 + with: + auth: ${{ secrets.GIST_TOKEN }} + gistID: ${{ env.GIST_ID }} + filename: fuel-ci-profile-${{ github.ref_name }}.json + label: OWL DL Profile (${{ github.ref_name }}) + message: ${{ steps.profile.outcome }} + color: ${{ steps.profile.outcome == 'success' && 'brightgreen' || steps.profile.outcome == 'cancelled' && 'yellow' || 'red' }} + - name: Reasoning and consistency check + id: reasoning run: | if ./robot reason --reasoner HermiT --input "${ONTO_DIR}/${ONTO_FILE}" --output reasoned.owl; then - echo "REASON_RESULT=consistent" >> $GITHUB_ENV + echo "result=consistent" >> $GITHUB_OUTPUT else - echo "REASON_RESULT=inconsistent" >> $GITHUB_ENV + echo "result=inconsistent" >> $GITHUB_OUTPUT + exit 1 fi + + - name: Badge — Reasoning + if: always() + uses: schneegans/dynamic-badges-action@v1.7.0 + with: + auth: ${{ secrets.GIST_TOKEN }} + gistID: ${{ env.GIST_ID }} + filename: ontology-ci-reasoning-${{ github.ref_name }}.json + label: Reasoning (${{ github.ref_name }}) + message: ${{ steps.reasoning.outputs.result }} + color: ${{ steps.reasoning.outputs.result == 'consistent' && 'brightgreen' || 'red' }} - name: Generate ontology syntaxes and documentation run: | diff --git a/README.md b/README.md index 1a62461..979d7e6 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,14 @@ +### CI Status + +**Dev:** +![OWL DL Profile (dev)](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/agbeltran/21194e497875f56c63a36e638e5e7f6b/raw/fuel-ci-profile-dev.json) +![Reasoning (dev)](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com//21194e497875f56c63a36e638e5e7f6b/raw/fuel-ci-reasoning-dev.json) + +**Main:** +![OWL DL Profile (main)](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/agbeltran/21194e497875f56c63a36e638e5e7f6b/raw/fuel-ci-profile-main.json) +![Reasoning (main)](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/agbeltran/21194e497875f56c63a36e638e5e7f6b/raw/fuel-ci-reasoning-main.json) + + # FUsion Energy Lexicon (FUEL) FUsion Energy Lexicon (FUEL) is an ontology for fusion energy data and processes. diff --git a/src/fuel.ttl b/src/fuel.ttl index 0ca7892..10136f8 100644 --- a/src/fuel.ttl +++ b/src/fuel.ttl @@ -13,6 +13,9 @@ @prefix vann: . @prefix dcterms: . @prefix skos: . +@prefix ssn: . +@prefix sosa: . +@prefix wd: . @base . rdf:type owl:Ontology ; @@ -40,7 +43,7 @@ rdfs:label "FUsion Energy Lexicon"@en , "Léxico de energía de fusión"@es ; owl:versionInfo "0.0.1" ; - dcat:version "0.1" ; + dcat:version "0.0.1" ; mod:definitionProperty rdfs:comment ; mod:hasRepresentationLanguage omv:OWL ; mod:hasSyntax ; @@ -96,7 +99,7 @@ vann:preferredNamespaceUri rdf:type owl:AnnotationProperty . ### http://www.w3.org/2004/02/skos/core#altLabel - rdf:type owl:AnnotationProperty . +skos:altLabel rdf:type owl:AnnotationProperty . ### http://www.w3.org/ns/dcat#version @@ -158,10 +161,32 @@ xsd:date rdf:type rdfs:Datatype . ### http://xmlns.com/foaf/0.1/Person foaf:Person rdf:type owl:Class . - ### https://schema.org/Person sdo:Person rdf:type owl:Class . +### https://w3c.org/ns/sosa/Sensor +sosa:Sensor rdf:type owl:Class . + +### Wikidata classes +### fusion reactor Q11536219 +wd:Q11536219 rdf:type owl:Class . + +### nuclear reactor Q80877 +wd:Q80877 rdf:type owl:Class . + +### spherical tokamak Q7576717 +wd:Q7576717 rdf:type owl:Class . + +### stellarator Q1360597 +wd:Q1360597 rdf:type owl:Class . + +### tokamak Q188589 +wd:Q188589 rdf:type owl:Class . + +### thermocouple Q190241 +wd:Q190241 rdf:type owl:Class . + + ### http://w3id.org/fuel#campaign fuel:campaign rdf:type owl:Class ; @@ -169,7 +194,7 @@ fuel:campaign rdf:type owl:Class ; "Un conjunto de experimentos conectados que se ejecutan durante un período específico de tiempo"@es ; rdfs:label "campaign"@en , "campaña"@es ; - "experimental campaign"@en . + skos:altLabel "experimental campaign"@en . ### http://w3id.org/fuel#fusion_reactor @@ -183,7 +208,8 @@ fuel:fusion_reactor rdf:type owl:Class ; skos:altLabel "dispositivo de fusión"@es , "fusion device"@en , "nuclear fusion reactor"@en , - "reactor de fusión nuclear"@es . + "reactor de fusión nuclear"@es ; + owl:equivalentClass wd:Q11536219 . ### http://w3id.org/fuel#nuclear_reactor @@ -194,7 +220,8 @@ fuel:nuclear_reactor rdf:type owl:Class ; rdfs:label "nuclear reactor"@en , "reactor nuclear"@es ; skos:altLabel "nuclear fission reactor"@en , - "reactor de fisión nuclear"@es . + "reactor de fisión nuclear"@es ; + owl:equivalentClass wd:Q80877 . @@ -212,7 +239,8 @@ fuel:tokamak rdf:type owl:Class ; skos:altLabel "toroidal chamber with magnetic coils"@en , "cámara toroidal con bobinas magnéticas"@es ; rdfs:comment "A device for magnetic confinement of plasma by a combination of a toroidal magnetic field and a current flowing through the plasma in which conditions for thermonuclear fusion ignition can be achieved. The word “tokamak” is of Russian origin and is an acronym for “TOroidalnaya KAmera i MAgnitnye Katushki” — toroidal chamber and magnetic coils. The magnetic field necessary to keep the hot plasma inside the toroidal chamber is generated as a combination of the field of the toroidal coils and the magnetic field generated by the current flowing through the plasma. Since the current in the plasma is induced on the transformer principle, the tokamak is a pulse device."@en ; - dcterms:source . + dcterms:source ; + owl:equivalentClass wd:Q188589 . ### http://w3id.org/fuel#spherical_tokamak fuel:spherical_tokamak rdf:type owl:Class ; @@ -220,7 +248,8 @@ fuel:spherical_tokamak rdf:type owl:Class ; rdfs:label "spherical tokamak"@en , "tokamak esférico"@es ; dcterms:source ; - rdfs:comment "Tokamak with a low aspect ratio and a round plasma in a shape resembling a cored apple. While a conventional tokamak has a more donut-like shape with a central hole, a spherical tokamak minimizes this hole to achieve a higher compactness. A single common conductor runs through the centre of the tokamak, to which toroidal magnets in the shape of semicircles are connected. Due to its more compact shape, the spherical tokamak achieves the same plasma parameters as a conventional tokamak with a lower magnetic field. This allows it to be smaller and cheaper. Typical spherical tokamaks are the Small Tight Aspect Ratio Tokamak (START) or the Mega Ampere Spherical Tokamak (MAST)."@en . + rdfs:comment "Tokamak with a low aspect ratio and a round plasma in a shape resembling a cored apple. While a conventional tokamak has a more donut-like shape with a central hole, a spherical tokamak minimizes this hole to achieve a higher compactness. A single common conductor runs through the centre of the tokamak, to which toroidal magnets in the shape of semicircles are connected. Due to its more compact shape, the spherical tokamak achieves the same plasma parameters as a conventional tokamak with a lower magnetic field. This allows it to be smaller and cheaper. Typical spherical tokamaks are the Small Tight Aspect Ratio Tokamak (START) or the Mega Ampere Spherical Tokamak (MAST)."@en ; + owl:equivalentClass wd:Q7576717 . ### http://w3id.org/fuel#stellarator @@ -228,8 +257,21 @@ fuel:stellarator rdf:type owl:Class ; rdfs:subClassOf fuel:fusion_reactor ; rdfs:label "stellarator"@en ; rdfs:comment "A device for thermonuclear fusion research that uses a combination of differently shaped coils which together create a desired helical magnetic field to confine the hot plasma. To hold the particles in the donut-shaped magnetic container, they must circulate in spirals, once on the inside and once on the outside of the torus. The stellarator creates a suitable magnetic field by combining helical, toroidal and poloidal coils. There are many variations that use different combinations and shapes of coils (classical, heliac, heliotron, torsatron, and helias). In the most modern modular stellarators, an assembly of specially twisted coils creates the magnetic field."@en ; - dcterms:source . - + dcterms:source ; + owl:equivalentClass wd:Q1360597 . + +### http://w3id.org/fuel#thermocouple +fuel:thermocouple rdf:type owl:Class ; + rdfs:subClassOf sosa:Sensor ; + rdfs:label "thermocouple"@en , + "termopar"@es ; + rdfs:comment "A thermocouple is a temperature-measuring device consisting of two wires of different metals joined at each end. One junction is placed where the temperature is to be measured, and the other is kept at a constant lower temperature. A measuring instrument is connected in the circuit. The temperature difference causes the development of an electromotive force (known as the Seebeck effect) that is approximately proportional to the difference between the temperatures of the two junctions. Temperature can be read from standard tables, or the measuring instrument can be calibrated to read temperature directly."@en , + "Un termopar es un dispositivo de medición de temperatura que consta de dos cables de diferentes metales unidos por cada extremo. Una unión se coloca donde se va a medir la temperatura y la otra se mantiene a una temperatura inferior constante. Se conecta un instrumento de medición al circuito. La diferencia de temperatura genera una fuerza electromotriz (conocida como efecto Seebeck) aproximadamente proporcional a la diferencia de temperatura entre las dos uniones. La temperatura puede leerse en tablas estándar o el instrumento de medición puede calibrarse para leerla directamente."@es ; + dcterms:source ; + skos:altLabel "thermo couple"@en , + "thermoelectrical thermometer"@en , + "termocupla"@es ; + owl:equivalentClass wd:Q190241. ### Generated by the OWL API (version 4.5.29.2024-05-13T12:11:03Z) https://github.com/owlcs/owlapi From 370d80aa0b0d7efb1b0264cc8eaf2c6314e56269 Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez-Beltran Date: Mon, 15 Dec 2025 17:30:44 +0000 Subject: [PATCH 4/7] Fixes to ci and badges --- .github/workflows/ci-common.yaml | 6 +++--- README.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci-common.yaml b/.github/workflows/ci-common.yaml index 8254c92..700e09d 100644 --- a/.github/workflows/ci-common.yaml +++ b/.github/workflows/ci-common.yaml @@ -64,7 +64,7 @@ jobs: gistID: ${{ env.GIST_ID }} filename: fuel-ci-profile-${{ github.ref_name }}.json label: OWL DL Profile (${{ github.ref_name }}) - message: ${{ steps.profile.outcome }} + message: ${{ steps.profile.outcome || 'failed' }} color: ${{ steps.profile.outcome == 'success' && 'brightgreen' || steps.profile.outcome == 'cancelled' && 'yellow' || 'red' }} - name: Reasoning and consistency check @@ -83,9 +83,9 @@ jobs: with: auth: ${{ secrets.GIST_TOKEN }} gistID: ${{ env.GIST_ID }} - filename: ontology-ci-reasoning-${{ github.ref_name }}.json + filename: fuel-ci-reasoning-${{ github.ref_name }}.json label: Reasoning (${{ github.ref_name }}) - message: ${{ steps.reasoning.outputs.result }} + message: ${{ steps.reasoning.outputs.result || 'failed'}} color: ${{ steps.reasoning.outputs.result == 'consistent' && 'brightgreen' || 'red' }} - name: Generate ontology syntaxes and documentation diff --git a/README.md b/README.md index 979d7e6..3c5b57e 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ **Dev:** ![OWL DL Profile (dev)](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/agbeltran/21194e497875f56c63a36e638e5e7f6b/raw/fuel-ci-profile-dev.json) -![Reasoning (dev)](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com//21194e497875f56c63a36e638e5e7f6b/raw/fuel-ci-reasoning-dev.json) +![Reasoning (dev)](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/agbeltran/21194e497875f56c63a36e638e5e7f6b/raw/fuel-ci-reasoning-dev.json) **Main:** ![OWL DL Profile (main)](https://img.shields.io/endpoint?url=https://gist.githubusercontent.com/agbeltran/21194e497875f56c63a36e638e5e7f6b/raw/fuel-ci-profile-main.json) From 6bd625d4691e9b8c1668edba430d1e672de36a88 Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez-Beltran Date: Mon, 15 Dec 2025 17:42:51 +0000 Subject: [PATCH 5/7] After setting GIST_ID --- .github/workflows/ci-common.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci-common.yaml b/.github/workflows/ci-common.yaml index 700e09d..1ce6c99 100644 --- a/.github/workflows/ci-common.yaml +++ b/.github/workflows/ci-common.yaml @@ -61,7 +61,7 @@ jobs: uses: schneegans/dynamic-badges-action@v1.7.0 with: auth: ${{ secrets.GIST_TOKEN }} - gistID: ${{ env.GIST_ID }} + gistID: ${{ secrets.GIST_ID }} filename: fuel-ci-profile-${{ github.ref_name }}.json label: OWL DL Profile (${{ github.ref_name }}) message: ${{ steps.profile.outcome || 'failed' }} @@ -82,7 +82,7 @@ jobs: uses: schneegans/dynamic-badges-action@v1.7.0 with: auth: ${{ secrets.GIST_TOKEN }} - gistID: ${{ env.GIST_ID }} + gistID: ${{ secrets.GIST_ID }} filename: fuel-ci-reasoning-${{ github.ref_name }}.json label: Reasoning (${{ github.ref_name }}) message: ${{ steps.reasoning.outputs.result || 'failed'}} From b1c42c7843754746b9f5cfd24f398455f70416b0 Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez-Beltran Date: Tue, 16 Dec 2025 08:22:13 +0000 Subject: [PATCH 6/7] Fixing gist access for badges --- .github/workflows/ci-common.yaml | 12 ++++++++++++ .github/workflows/ci-dev.yaml | 1 + .github/workflows/ci-release.yaml | 1 + 3 files changed, 14 insertions(+) diff --git a/.github/workflows/ci-common.yaml b/.github/workflows/ci-common.yaml index 1ce6c99..02818c8 100644 --- a/.github/workflows/ci-common.yaml +++ b/.github/workflows/ci-common.yaml @@ -2,6 +2,11 @@ name: FUEL_CI_Common on: workflow_call: + secrets: + GIST_ID: + required: true + GIST_TOKEN: + required: true inputs: RELEASE_VERSION: required: false @@ -55,6 +60,13 @@ jobs: run: | ./robot validate-profile --input "${ONTO_DIR}/${ONTO_FILE}" --profile DL -vvv || \ (echo "Profile check failed." && exit 1) + + - name: Check badge secrets + if: always() + run: | + test -n "${{ secrets.GIST_ID }}" || (echo "Missing GIST_ID secret" && exit 1) + test -n "${{ secrets.GIST_TOKEN }}" || (echo "Missing GIST_TOKEN secret" && exit 1) + - name: Badge — Syntax if: always() diff --git a/.github/workflows/ci-dev.yaml b/.github/workflows/ci-dev.yaml index a18a54c..189ff5f 100644 --- a/.github/workflows/ci-dev.yaml +++ b/.github/workflows/ci-dev.yaml @@ -8,6 +8,7 @@ on: jobs: dev: uses: ./.github/workflows/ci-common.yaml + secrets: inherit with: DEV_DIR: ./public/dev # build ontologies into "dev" folder diff --git a/.github/workflows/ci-release.yaml b/.github/workflows/ci-release.yaml index 1f52223..5d31890 100644 --- a/.github/workflows/ci-release.yaml +++ b/.github/workflows/ci-release.yaml @@ -14,6 +14,7 @@ on: jobs: release: uses: ./.github/workflows/ci-common.yaml + secrets: inherit with: RELEASE_VERSION: ${{ github.event.inputs.release_version }} RELEASES_DIR: ./public/releases From 46d889a0964c26edd8d7a20cce511cfc14df60d7 Mon Sep 17 00:00:00 2001 From: Alejandra Gonzalez-Beltran Date: Tue, 16 Dec 2025 08:31:54 +0000 Subject: [PATCH 7/7] Avoiding race condition when updating gist --- .github/workflows/ci-common.yaml | 2 ++ .github/workflows/ci-dev.yaml | 4 ++++ .github/workflows/ci-release.yaml | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/.github/workflows/ci-common.yaml b/.github/workflows/ci-common.yaml index 02818c8..d2de783 100644 --- a/.github/workflows/ci-common.yaml +++ b/.github/workflows/ci-common.yaml @@ -72,6 +72,7 @@ jobs: if: always() uses: schneegans/dynamic-badges-action@v1.7.0 with: + forceUpdate: true auth: ${{ secrets.GIST_TOKEN }} gistID: ${{ secrets.GIST_ID }} filename: fuel-ci-profile-${{ github.ref_name }}.json @@ -93,6 +94,7 @@ jobs: if: always() uses: schneegans/dynamic-badges-action@v1.7.0 with: + forceUpdate: true auth: ${{ secrets.GIST_TOKEN }} gistID: ${{ secrets.GIST_ID }} filename: fuel-ci-reasoning-${{ github.ref_name }}.json diff --git a/.github/workflows/ci-dev.yaml b/.github/workflows/ci-dev.yaml index 189ff5f..cb96780 100644 --- a/.github/workflows/ci-dev.yaml +++ b/.github/workflows/ci-dev.yaml @@ -1,5 +1,9 @@ name: FUEL_CI_Dev +concurrency: + group: fuel-gist-badges + cancel-in-progress: true + on: push: branches: diff --git a/.github/workflows/ci-release.yaml b/.github/workflows/ci-release.yaml index 5d31890..bf5f274 100644 --- a/.github/workflows/ci-release.yaml +++ b/.github/workflows/ci-release.yaml @@ -1,5 +1,9 @@ name: FUEL_CI_Release +concurrency: + group: fuel-gist-badges + cancel-in-progress: true + on: workflow_dispatch: inputs: