Repository: SINTEF/dlite (language: python)

Issue:
Serialise as EMMO datasets
# Description
This PR implements a new `dlite.dataset` module for serialisation of DLite datamodels and instances to an RDF representation based on EMMO following the representation shown in the figure below.

The main interface is exposed by four new functions:
- `add_dataset()`: stores datamodel+mappings to a triplestore
- `add_data()`: stores an instance (or datamodel) to a triplestore
- `get_dataset()`: loads datamodel+mappings from a triplestore
- `get_data()`: loads an instance (or datamodel) from a triplestore

**Question**: Is the naming of these functions understandable? The term *dataset* comes from EMMO, but as a user of DLite it may be confusing. Maybe `save_datamodel()`, `save_instance()`, `load_datamodel()`, `load_instance()` would be more intuitive?

Two tests are added using a datamodel matching what is shown in the figure.
- [test_dataset1_dave.py](https://github.com/SINTEF/dlite/blob/652-serialise-data-models-to-tbox/bindings/python/tests/test_dataset1_save.py) loads first a [`FluidData`]( https://github.com/SINTEF/dlite/blob/652-serialise-data-models-to-tbox/bindings/python/tests/entities/FluidData.json) datamodel and documents it semantically with the following mappings
  ```python
  mappings = [
    (FLUID,                  EMMO.isDescriptionFor, EMMO.Fluid),
    (FLUID.LJPotential,      MAP.mapsTo,            EMMO.String),
    (FLUID.LJPotential,      EMMO.isDescriptionFor, EMMO.MolecularEntity),
    (FLUID.TemperatureField, MAP.mapsTo,            EMMO.ThermodynamicTemperature),
    (FLUID.ntimes,           MAP.mapsTo,            EMMO.Time),
    (FLUID.npositions,       MAP.mapsTo,            EMMO.Position),
  ]
  ```
  Note the use of `emmo:isDescriptionFor` relations in the mappings. They are stored as-is in the triplestore.
  The `map:mapsTo` are translated to `rdfs:subClassOf` when serialised to the triplestore.

  Then it uses the `add_dataset()` function in the new `dlite.dataset` module and stores it as RDF in a local triplestore. The content of the triplestore corresponds now to the figure below.

  Then it creates two `FluidData` instances and store them (using the `add_data()` function) as RDF in a local triplestore as well. The instances are represented as an individual with a rdf:JSON data property containing the instance data. 

  Finally the triplestore is serialised to a turtle file. 

- [test_dataset2_load.py](https://github.com/SINTEF/dlite/blob/652-serialise-data-models-to-tbox/bindings/python/tests/test_dataset2_load.py) loads the turtle file into a local triplestore and reconstruct the `FluidData` datamodel as well as the mappings using the `get_dataset()` function. 

  Using the `get_hash()` method, it is checked that the reconstruct the `FluidData` datamodel is exactly equal to the original datamodel.

  Finally it loads the two instances using the `get_data()` function and check that they are exactly equal to the two original instances.

![](https://raw.githubusercontent.com/SINTEF/dlite/652-serialise-data-models-to-tbox/doc/_static/dataset-v2.svg)





## Type of change
- [ ] Bug fix & code cleanup
- [x] New feature
- [ ] Documentation update
- [x] Test update

## Checklist for the reviewer
This checklist should be used as a help for the reviewer.

- [ ] Is the change limited to one issue?
- [ ] Does this PR close the issue?
- [ ] Is the code easy to read and understand?
- [ ] Do all new feature have an accompanying new test?
- [ ] Has the documentation been updated as necessary?



Discussion / hints:

Fix patch:
diff --git a/examples/dataset/README.md b/examples/dataset/README.md
index 29611ee82..c0cb01a33 100644
--- a/examples/dataset/README.md
+++ b/examples/dataset/README.md
@@ -27,6 +27,9 @@ properties:
     description: Array of measured temperatures.
 ```
 
+A DLite datamodel is represented with an emmo:DataSet, and its properties are represented with emmo:Datum as illustrated in the figure above.
+It shows how a simple [`FluidData`] datamodel is represented.
+
 The datamodel is semantically enhanced using the following mappings
   ```python
   mappings = [
@@ -45,5 +48,4 @@ Some comments:
 - The `map:mapsTo` are translated to `rdfs:subClassOf` when serialised to the triplestore.
 
 
-
 [`FluidData`]: https://github.com/SINTEF/dlite/blob/652-serialise-data-models-to-tbox/examples/dataset/datamodels/FluidData.json


Test patch:
diff --git a/bindings/python/tests/test_dataset1_save.py b/bindings/python/tests/test_dataset1_save.py
index 6862cd698..13174bcf8 100644
--- a/bindings/python/tests/test_dataset1_save.py
+++ b/bindings/python/tests/test_dataset1_save.py
@@ -45,7 +45,6 @@
 #assert get_unit_iri("mm") == "https://w3id.org/emmo#MilliMetre"
 
 
-
 # Test serialising Metadata as an EMMO dataset
 # ============================================
 Fluid = dlite.get_instance("http://onto-ns.org/meta/dlite/0.1/FluidData")
diff --git a/storages/python/tests-python/test_redis.py b/storages/python/tests-python/test_redis.py
index 11d900499..6ff8d7713 100644
--- a/storages/python/tests-python/test_redis.py
+++ b/storages/python/tests-python/test_redis.py
@@ -22,8 +22,8 @@
 meta = inst1.meta
 
 save0 = meta.asdict()
-save1 = inst1.asdict()
-save2 = inst2.asdict()
+save1 = inst1.asdict(single=True, uuid=True)
+save2 = inst2.asdict(single=True, uuid=True)
 
 
 # Test storing to Redis