> **PROTOTYPE:** a suggestion, not an official CIAAW or IUPAC page. Official values are at [ciaaw.org](https://ciaaw.org).

# Data Model

The model is written once, as a [DCTAP](https://www.dublincore.org/specifications/dctap/) table. The SHACL shapes and all diagrams below are generated from it, so they cannot drift apart. The same approach is used for the [PubChemRDF schema](https://pubchem.ncbi.nlm.nih.gov/docs/rdf-schema), and other formats such as ShEx or LinkML can be derived from the same table.

| File | Purpose |
| --- | --- |
| [model_dctap.csv](model/model_dctap.csv) | The DCTAP profile, the source of the model |
| [dctap.yaml](model/dctap.yaml) | Prefixes, extra columns and aspects |
| [rules.ttl](model/rules.ttl) | Rules that compare several nodes, which a DCTAP row cannot express |
| [model_shacl.ttl](model/model_shacl.ttl) | The generated SHACL shapes, including those rules |
| [ciaaw.owl](model/ciaaw.owl) | OWL ontology generated via SPARQL CONSTRUCT |

## Validation

Checked against the shapes when this site was built:

- `ciaaw.ttl`: conforms
- `example-output-next.ttl`: conforms

## Overview

The main classes and how they connect. Attributes, back-references and history links are in the diagrams for each aspect.

```mermaid
classDiagram
    direction TB
    class Element["chemrof:ChemicalElement"]
    class Isotope["chemrof:Isotope"]
    class StandardAtomicWeightDeclaration["ciaaw:StandardAtomicWeightDeclaration"]
    class ConventionalAtomicWeightDeclaration["ciaaw:ConventionalAtomicWeightDeclaration"]
    class IsotopicAbundanceDeclaration["ciaaw:IsotopicAbundanceDeclaration"]
    class AtomicMassDeclaration["ciaaw:AtomicMassDeclaration"]
    class Declaration["Declaration"] {
        <<abstract>>
    }
    class Footnote["ciaaw:Footnote"]
    class IntervalValue["Interval"]
    class ValueWithUncertainty["Value with uncertainty"]
    class SingleValue["Single value"]
    class MassValue["Mass with uncertainty"]
    Declaration <|-- StandardAtomicWeightDeclaration
    Declaration <|-- ConventionalAtomicWeightDeclaration
    Declaration <|-- IsotopicAbundanceDeclaration
    Declaration <|-- AtomicMassDeclaration
    Element --> "0..*" Isotope : ciaaw#58;hasIsotope
    Element --> "0..1" StandardAtomicWeightDeclaration : ciaaw#58;currentStandardAtomicWeight
    Element --> "0..1" ConventionalAtomicWeightDeclaration : ciaaw#58;currentConventionalAtomicWeight
    Isotope --> "1" IsotopicAbundanceDeclaration : ciaaw#58;currentAbundance
    Isotope --> "0..1" AtomicMassDeclaration : ciaaw#58;currentAtomicMass
    Declaration --> "0..*" Footnote : ciaaw#58;footnote
    StandardAtomicWeightDeclaration --> "1" IntervalValue : ciaaw#58;value (one of)
    StandardAtomicWeightDeclaration --> "1" ValueWithUncertainty : ciaaw#58;value (one of)
    StandardAtomicWeightDeclaration --> "1" SingleValue : ciaaw#58;value (one of)
    ConventionalAtomicWeightDeclaration --> "1" SingleValue : ciaaw#58;value
    IsotopicAbundanceDeclaration --> "1" IntervalValue : ciaaw#58;value (one of)
    IsotopicAbundanceDeclaration --> "1" ValueWithUncertainty : ciaaw#58;value (one of)
    IsotopicAbundanceDeclaration --> "1" SingleValue : ciaaw#58;value (one of)
    AtomicMassDeclaration --> "1" MassValue : ciaaw#58;value
```

## Elements and isotopes

Elements and isotopes keep a stable IRI. They hold identifying facts and pointers, while every published value lives in a separate declaration.

```mermaid
classDiagram
    direction LR
    class Element["chemrof:ChemicalElement"] {
        rdfs:label : langString [1..*]
        chemrof:symbol : string [1]
        chemrof:atomic_number : integer [1]
        skos:closeMatch : IRI [0..*]
        ciaaw:longestLivedMassNumber : integer [0..1]
    }
    class Isotope["chemrof:Isotope"] {
        ciaaw:massNumber : integer [1]
        skos:closeMatch : IRI [0..*]
    }
    Element --> "0..*" Isotope : ciaaw#58;hasIsotope
```

| Shape | Property | Count | Value | Note |
| --- | --- | --- | --- | --- |
| Chemical element | `rdfs:label` | 1..* | `rdf:langString` | Lower case as printed in the CIAAW tables. Further languages may be added. |
| Chemical element | `chemrof:symbol` | 1 | `xsd:string` |  |
| Chemical element | `chemrof:atomic_number` | 1 | `xsd:integer` |  |
| Chemical element | `skos:closeMatch` | 0..* | `IRI` | Taken from the supplement. Never guessed. |
| Chemical element | `ciaaw:hasIsotope` | 0..* | `shape:Isotope` |  |
| Chemical element | `ciaaw:longestLivedMassNumber` | 0..1 | `xsd:integer` | Elements without stable isotopes: the mass number bracketed in the table. |
| Isotope | `ciaaw:massNumber` | 1 | `xsd:integer` |  |
| Isotope | `skos:closeMatch` | 0..* | `IRI` | Taken from the supplement. Never guessed. |

## Atomic weight declarations

A standard atomic weight is either an interval or a value with an uncertainty. The element points to the one current declaration and repeats its numbers as derived shortcuts.

```mermaid
classDiagram
    direction TB
    class Element["chemrof:ChemicalElement"] {
        ciaaw:standardAtomicWeightLower : decimal [0..1]
        ciaaw:standardAtomicWeightUpper : decimal [0..1]
        ciaaw:standardAtomicWeightValue : decimal [0..1]
        ciaaw:standardAtomicWeightUncertainty : decimal [0..1]
    }
    class StandardAtomicWeightDeclaration["ciaaw:StandardAtomicWeightDeclaration"]
    class ConventionalAtomicWeightDeclaration["ciaaw:ConventionalAtomicWeightDeclaration"]
    class IntervalValue["Interval"]
    class ValueWithUncertainty["Value with uncertainty"]
    class SingleValue["Single value"]
    Element --> "0..1" StandardAtomicWeightDeclaration : ciaaw#58;currentStandardAtomicWeight
    Element --> "0..1" ConventionalAtomicWeightDeclaration : ciaaw#58;currentConventionalAtomicWeight
    Element --> "0..*" StandardAtomicWeightDeclaration : ciaaw#58;hasDeclaration (one of)
    Element --> "0..*" ConventionalAtomicWeightDeclaration : ciaaw#58;hasDeclaration (one of)
    StandardAtomicWeightDeclaration --> "1" Element : ciaaw#58;ofElement
    StandardAtomicWeightDeclaration --> "1" IntervalValue : ciaaw#58;value (one of)
    StandardAtomicWeightDeclaration --> "1" ValueWithUncertainty : ciaaw#58;value (one of)
    StandardAtomicWeightDeclaration --> "1" SingleValue : ciaaw#58;value (one of)
    ConventionalAtomicWeightDeclaration --> "1" Element : ciaaw#58;ofElement
    ConventionalAtomicWeightDeclaration --> "1" SingleValue : ciaaw#58;value
```

| Shape | Property | Count | Value | Note |
| --- | --- | --- | --- | --- |
| Chemical element | `ciaaw:currentStandardAtomicWeight` | 0..1 | `shape:StandardAtomicWeightDeclaration` | Absent when the table gives no standard atomic weight. |
| Chemical element | `ciaaw:currentConventionalAtomicWeight` | 0..1 | `shape:ConventionalAtomicWeightDeclaration` |  |
| Chemical element | `ciaaw:hasDeclaration` | 0..* | `shape:StandardAtomicWeightDeclaration` or `shape:ConventionalAtomicWeightDeclaration` | All declarations including deprecated ones. |
| Chemical element | `ciaaw:standardAtomicWeightLower` | 0..1 | `xsd:decimal` | Derived shortcut copied from the current declaration. Never edited by hand. |
| Chemical element | `ciaaw:standardAtomicWeightUpper` | 0..1 | `xsd:decimal` | Derived shortcut. |
| Chemical element | `ciaaw:standardAtomicWeightValue` | 0..1 | `xsd:decimal` | Derived shortcut. |
| Chemical element | `ciaaw:standardAtomicWeightUncertainty` | 0..1 | `xsd:decimal` | Derived shortcut. |
| Standard atomic weight declaration | `ciaaw:ofElement` | 1 | `shape:Element` |  |
| Standard atomic weight declaration | `ciaaw:value` | 1 | `shape:IntervalValue` or `shape:ValueWithUncertainty` or `shape:SingleValue` |  |
| Conventional atomic weight declaration | `ciaaw:ofElement` | 1 | `shape:Element` |  |
| Conventional atomic weight declaration | `ciaaw:value` | 1 | `shape:SingleValue` | Not generated yet. The two source tables do not contain abridged values. |

## Isotopic abundance declarations

The representative isotopic composition of one isotope. It can be an interval, a value with an uncertainty, or a single value such as 1 for monoisotopic elements.

```mermaid
classDiagram
    direction TB
    class Element["chemrof:ChemicalElement"]
    class Isotope["chemrof:Isotope"]
    class IsotopicAbundanceDeclaration["ciaaw:IsotopicAbundanceDeclaration"]
    class AtomicMassDeclaration["ciaaw:AtomicMassDeclaration"]
    class IntervalValue["Interval"]
    class ValueWithUncertainty["Value with uncertainty"]
    class SingleValue["Single value"]
    Element --> "0..*" Isotope : ciaaw#58;hasIsotope
    Isotope --> "1" IsotopicAbundanceDeclaration : ciaaw#58;currentAbundance
    Isotope --> "1..*" IsotopicAbundanceDeclaration : ciaaw#58;hasDeclaration (one of)
    Isotope --> "1..*" AtomicMassDeclaration : ciaaw#58;hasDeclaration (one of)
    IsotopicAbundanceDeclaration --> "1" Isotope : ciaaw#58;ofIsotope
    IsotopicAbundanceDeclaration --> "1" IntervalValue : ciaaw#58;value (one of)
    IsotopicAbundanceDeclaration --> "1" ValueWithUncertainty : ciaaw#58;value (one of)
    IsotopicAbundanceDeclaration --> "1" SingleValue : ciaaw#58;value (one of)
```

| Shape | Property | Count | Value | Note |
| --- | --- | --- | --- | --- |
| Chemical element | `ciaaw:hasIsotope` | 0..* | `shape:Isotope` |  |
| Isotope | `ciaaw:currentAbundance` | 1 | `shape:IsotopicAbundanceDeclaration` |  |
| Isotope | `ciaaw:hasDeclaration` | 1..* | `shape:IsotopicAbundanceDeclaration` or `shape:AtomicMassDeclaration` | All declarations including deprecated ones. |
| Isotopic abundance declaration | `ciaaw:ofIsotope` | 1 | `shape:Isotope` |  |
| Isotopic abundance declaration | `ciaaw:value` | 1 | `shape:IntervalValue` or `shape:ValueWithUncertainty` or `shape:SingleValue` | Amount fraction between 0 and 1. |

## Atomic masses (planned)

Part of the draft vocabulary, but not generated yet because the two source tables do not contain atomic masses.

```mermaid
classDiagram
    direction TB
    class Isotope["chemrof:Isotope"]
    class AtomicMassDeclaration["ciaaw:AtomicMassDeclaration"]
    class IsotopicAbundanceDeclaration["ciaaw:IsotopicAbundanceDeclaration"]
    class MassValue["Mass with uncertainty"]
    Isotope --> "0..1" AtomicMassDeclaration : ciaaw#58;currentAtomicMass
    Isotope --> "1..*" IsotopicAbundanceDeclaration : ciaaw#58;hasDeclaration (one of)
    Isotope --> "1..*" AtomicMassDeclaration : ciaaw#58;hasDeclaration (one of)
    AtomicMassDeclaration --> "1" Isotope : ciaaw#58;ofIsotope
    AtomicMassDeclaration --> "1" MassValue : ciaaw#58;value
```

| Shape | Property | Count | Value | Note |
| --- | --- | --- | --- | --- |
| Isotope | `ciaaw:currentAtomicMass` | 0..1 | `shape:AtomicMassDeclaration` |  |
| Isotope | `ciaaw:hasDeclaration` | 1..* | `shape:IsotopicAbundanceDeclaration` or `shape:AtomicMassDeclaration` | All declarations including deprecated ones. |
| Atomic mass declaration | `ciaaw:ofIsotope` | 1 | `shape:Isotope` |  |
| Atomic mass declaration | `ciaaw:value` | 1 | `shape:MassValue` | Not generated yet. The two source tables do not contain atomic masses. |

## Quantity values

Numbers are qudt:QuantityValue nodes in one of a few closed forms. Significant figures are stored separately because xsd:decimal does not preserve trailing zeros.

```mermaid
classDiagram
    direction LR
    class StandardAtomicWeightDeclaration["ciaaw:StandardAtomicWeightDeclaration"]
    class IntervalValue["Interval"] {
        qudt:hasUnit : IRI [1]
        qudt:lowerBound : decimal [1]
        qudt:upperBound : decimal [1]
        ciaaw:significantFiguresLower : integer [0..1]
        ciaaw:significantFiguresUpper : integer [0..1]
    }
    class ValueWithUncertainty["Value with uncertainty"] {
        qudt:hasUnit : IRI [1]
        qudt:numericValue : decimal [1]
        qudt:standardUncertainty : decimal [1]
        ciaaw:significantFigures : integer [1]
        ciaaw:significantFiguresUncertainty : integer [1]
    }
    class SingleValue["Single value"] {
        qudt:hasUnit : IRI [1]
        qudt:numericValue : decimal [1]
        ciaaw:significantFigures : integer [0..1]
    }
    class ConventionalAtomicWeightDeclaration["ciaaw:ConventionalAtomicWeightDeclaration"]
    class IsotopicAbundanceDeclaration["ciaaw:IsotopicAbundanceDeclaration"]
    class AtomicMassDeclaration["ciaaw:AtomicMassDeclaration"]
    class MassValue["Mass with uncertainty"] {
        qudt:hasUnit : IRI [1]
        qudt:numericValue : decimal [1]
        qudt:standardUncertainty : decimal [1]
        ciaaw:significantFigures : integer [1]
        ciaaw:significantFiguresUncertainty : integer [1]
    }
    StandardAtomicWeightDeclaration --> "1" IntervalValue : ciaaw#58;value (one of)
    StandardAtomicWeightDeclaration --> "1" ValueWithUncertainty : ciaaw#58;value (one of)
    StandardAtomicWeightDeclaration --> "1" SingleValue : ciaaw#58;value (one of)
    ConventionalAtomicWeightDeclaration --> "1" SingleValue : ciaaw#58;value
    IsotopicAbundanceDeclaration --> "1" IntervalValue : ciaaw#58;value (one of)
    IsotopicAbundanceDeclaration --> "1" ValueWithUncertainty : ciaaw#58;value (one of)
    IsotopicAbundanceDeclaration --> "1" SingleValue : ciaaw#58;value (one of)
    AtomicMassDeclaration --> "1" MassValue : ciaaw#58;value
```

| Shape | Property | Count | Value | Note |
| --- | --- | --- | --- | --- |
| Standard atomic weight declaration | `ciaaw:value` | 1 | `shape:IntervalValue` or `shape:ValueWithUncertainty` or `shape:SingleValue` |  |
| Conventional atomic weight declaration | `ciaaw:value` | 1 | `shape:SingleValue` | Not generated yet. The two source tables do not contain abridged values. |
| Isotopic abundance declaration | `ciaaw:value` | 1 | `shape:IntervalValue` or `shape:ValueWithUncertainty` or `shape:SingleValue` | Amount fraction between 0 and 1. |
| Atomic mass declaration | `ciaaw:value` | 1 | `shape:MassValue` | Not generated yet. The two source tables do not contain atomic masses. |
| Interval | `qudt:hasUnit` | 1 | `IRI` |  |
| Interval | `qudt:lowerBound` | 1 | `xsd:decimal` |  |
| Interval | `qudt:upperBound` | 1 | `xsd:decimal` |  |
| Interval | `ciaaw:significantFiguresLower` | 0..1 | `xsd:integer` | Absent when the bound is zero. |
| Interval | `ciaaw:significantFiguresUpper` | 0..1 | `xsd:integer` |  |
| Value with uncertainty | `qudt:hasUnit` | 1 | `IRI` |  |
| Value with uncertainty | `qudt:numericValue` | 1 | `xsd:decimal` |  |
| Value with uncertainty | `qudt:standardUncertainty` | 1 | `xsd:decimal` | Scaled from the digits in brackets in the table. |
| Value with uncertainty | `ciaaw:significantFigures` | 1 | `xsd:integer` |  |
| Value with uncertainty | `ciaaw:significantFiguresUncertainty` | 1 | `xsd:integer` |  |
| Single value | `qudt:hasUnit` | 1 | `IRI` |  |
| Single value | `qudt:numericValue` | 1 | `xsd:decimal` | Stated without an uncertainty. |
| Single value | `ciaaw:significantFigures` | 0..1 | `xsd:integer` |  |
| Mass with uncertainty | `qudt:hasUnit` | 1 | `IRI` |  |
| Mass with uncertainty | `qudt:numericValue` | 1 | `xsd:decimal` |  |
| Mass with uncertainty | `qudt:standardUncertainty` | 1 | `xsd:decimal` |  |
| Mass with uncertainty | `ciaaw:significantFigures` | 1 | `xsd:integer` |  |
| Mass with uncertainty | `ciaaw:significantFiguresUncertainty` | 1 | `xsd:integer` |  |

## Footnotes

The g, m and r notes printed below the CIAAW tables are shared nodes that declarations refer to.

```mermaid
classDiagram
    direction LR
    class Declaration["Declaration"] {
        <<abstract>>
    }
    class Footnote["ciaaw:Footnote"] {
        skos:notation : string [1]
        skos:definition : langString [1]
    }
    Declaration --> "0..*" Footnote : ciaaw#58;footnote
```

| Shape | Property | Count | Value | Note |
| --- | --- | --- | --- | --- |
| Declaration | `ciaaw:footnote` | 0..* | `shape:Footnote` |  |
| Footnote | `skos:notation` | 1 | `xsd:string` |  |
| Footnote | `skos:definition` | 1 | `rdf:langString` | As printed below the CIAAW tables. |

## History and provenance

Declarations are never edited. A new value creates a new declaration, and the old one is kept, flagged as deprecated, and linked to its replacement.

```mermaid
classDiagram
    direction LR
    class Element["chemrof:ChemicalElement"]
    class NotDeprecated["Not deprecated"] {
        owl:deprecated : boolean [0..1]
    }
    class StandardAtomicWeightDeclaration["ciaaw:StandardAtomicWeightDeclaration"]
    class ConventionalAtomicWeightDeclaration["ciaaw:ConventionalAtomicWeightDeclaration"]
    class Isotope["chemrof:Isotope"]
    class IsotopicAbundanceDeclaration["ciaaw:IsotopicAbundanceDeclaration"]
    class AtomicMassDeclaration["ciaaw:AtomicMassDeclaration"]
    class Declaration["Declaration"] {
        <<abstract>>
        dcterms:issued : gYear [0..1]
        dcterms:source : IRI [0..*]
        owl:deprecated : boolean [0..1]
        adms:status : IRI [0..1]
    }
    Declaration <|-- StandardAtomicWeightDeclaration
    Declaration <|-- ConventionalAtomicWeightDeclaration
    Declaration <|-- IsotopicAbundanceDeclaration
    Declaration <|-- AtomicMassDeclaration
    Element --> "0..1" NotDeprecated : ciaaw#58;currentStandardAtomicWeight
    Element --> "0..1" NotDeprecated : ciaaw#58;currentConventionalAtomicWeight
    Element --> "0..*" StandardAtomicWeightDeclaration : ciaaw#58;hasDeclaration (one of)
    Element --> "0..*" ConventionalAtomicWeightDeclaration : ciaaw#58;hasDeclaration (one of)
    Isotope --> "1" NotDeprecated : ciaaw#58;currentAbundance
    Isotope --> "0..1" NotDeprecated : ciaaw#58;currentAtomicMass
    Isotope --> "1..*" IsotopicAbundanceDeclaration : ciaaw#58;hasDeclaration (one of)
    Isotope --> "1..*" AtomicMassDeclaration : ciaaw#58;hasDeclaration (one of)
    Declaration --> "0..1" Declaration : dcterms#58;isReplacedBy
    Declaration --> "0..1" Declaration : dcterms#58;replaces
```

| Shape | Property | Count | Value | Note |
| --- | --- | --- | --- | --- |
| Chemical element | `ciaaw:currentStandardAtomicWeight` | 0..1 | `shape:NotDeprecated` | A current pointer may never lead to a deprecated declaration. |
| Chemical element | `ciaaw:currentConventionalAtomicWeight` | 0..1 | `shape:NotDeprecated` | A current pointer may never lead to a deprecated declaration. |
| Chemical element | `ciaaw:hasDeclaration` | 0..* | `shape:StandardAtomicWeightDeclaration` or `shape:ConventionalAtomicWeightDeclaration` | All declarations including deprecated ones. |
| Isotope | `ciaaw:currentAbundance` | 1 | `shape:NotDeprecated` | A current pointer may never lead to a deprecated declaration. |
| Isotope | `ciaaw:currentAtomicMass` | 0..1 | `shape:NotDeprecated` | A current pointer may never lead to a deprecated declaration. |
| Isotope | `ciaaw:hasDeclaration` | 1..* | `shape:IsotopicAbundanceDeclaration` or `shape:AtomicMassDeclaration` | All declarations including deprecated ones. |
| Declaration | `dcterms:issued` | 0..1 | `xsd:gYear` | Year of the assigning report. |
| Declaration | `dcterms:source` | 0..* | `IRI` | DOI of the assigning report. |
| Declaration | `owl:deprecated` | 0..1 | `xsd:boolean` | True once a later declaration has replaced this one. |
| Declaration | `adms:status` | 0..1 | `IRI` | The ADMS status IRI still needs to be confirmed. |
| Declaration | `dcterms:isReplacedBy` | 0..1 | `shape:Declaration` |  |
| Declaration | `dcterms:replaces` | 0..1 | `shape:Declaration` |  |
| Not deprecated | `owl:deprecated` | 0..1 | `xsd:boolean` | Helper shape: owl:deprecated is absent or false. |

## Rules across nodes

These checks are defined in [rules.ttl](model/rules.ttl):

- Abundance is a fraction
- Abundances of an element sum to 1
- Bounds are in order
- Current declaration is part of the history
- Declaration points back to its subject
- Deprecation names a replacement and a status
- Derived shortcuts match the current declaration
- Isotope belongs to one element
- Replacement links run both ways
- Uncertainty is positive
