diff --git a/.github/issue-branch.yml b/.github/issue-branch.yml new file mode 100644 index 0000000..91a382d --- /dev/null +++ b/.github/issue-branch.yml @@ -0,0 +1 @@ +mode: chatops \ No newline at end of file diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..7ad7a60 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,27 @@ +name: Test build + +on: pull_request + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v2 + - name: Set up Python 3.7 + uses: actions/setup-python@v2 + with: + python-version: 3.7 + - name: Install OS dependencies + run: | + sudo apt-get update + sudo apt-get install pandoc latexmk + sudo apt-get install texlive-fonts-recommended texlive-latex-recommended texlive-latex-extra + - name: Install python dependencies + run: | + python -m pip install --upgrade pip + pip install wheel + pip install -r requirements.txt + - name: Build docs + run: python setup.py install diff --git a/README.md b/README.md index 1fd3f45..29e99fe 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,9 @@ +## Build Status +**latest** - [![Documentation latest](https://readthedocs.org/projects/simphony/badge/?version=latest)](https://simphony.readthedocs.io/en/latest/?badge=latest) +**dev** - [![Documentation dev](https://readthedocs.org/projects/simphony/badge/?version=dev)](https://simphony.readthedocs.io/en/latest/?badge=dev) # SimPhoNy docs -To access the documentation, please visit: https://simphony-docs.readthedocs.io/en/latest/ +To access the documentation, please visit: https://simphony.readthedocs.io/en/latest/ If you find any error or problem with the documentation, please [create an issue](https://github.com/simphony/docs/issues) diff --git a/docs/source/_static/img/ontology2dot.png b/docs/source/_static/img/ontology2dot.png index fefe49b..4149025 100644 Binary files a/docs/source/_static/img/ontology2dot.png and b/docs/source/_static/img/ontology2dot.png differ diff --git a/docs/source/about.md b/docs/source/about.md index 38ac27e..32b2f09 100644 --- a/docs/source/about.md +++ b/docs/source/about.md @@ -1,6 +1,7 @@ # About + SimPhoNy is an ontology-based framework that promotes and enables interoperability between any 3rd-party software tool. -Its latest version is soon to become an open-source python project. +Its [core functionality](https://github.com/simphony/osp-core) is an open-source python project. The name ‘SimPhoNy’ stems from the SimPhoNy EU-project in which it was originally developed (See more details [here](https://www.simphony-project.eu/)). One of SimPhoNy’s main tasks is to convert *opaque* data, meaning data whose semantics are hidden, to *transparent* data, that is data whose semantics is understood and easily accessible. @@ -8,14 +9,12 @@ One of SimPhoNy’s main tasks is to convert *opaque* data, meaning data whose s This project aims to clarify the purpose and usage of the SimPhoNy platform through simple, short examples. In particular, this guide will try to expose the main concepts and components. -_Contact:_ [Pablo de Andres](mailto:pablo.de.andres@iwm.fraunhofer.de), -[Matthias Urban](mailto:matthias.urban@iwm.fraunhofer.de) and -[Yoav Nahshon](mailto:yoav.nahshon@iwm.fraunhofer.de) from -the Materials Data Science and Informatics team, Fraunhofer IWM. +All the tutorials in this documentation are Jupyter notebooks that can be downloaded +by clicking on the "Edit on Github" button on the top right of the page. # License -BSD 3-Clause -Copyright 2020 SimPhoNy OSP-core developers +BSD 3-Clause +Copyright 2020 SimPhoNy OSP-core developers. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: @@ -44,7 +43,7 @@ These are some of the terms used in the following sections: 1. `individual`: an instance of a class. E.g., an instance of the class 'City' can be used to represent the city of Freiburg in which case it would have the attribute 'name' with the value 'Freiburg'. 1. `relationship`: a type of a way in which one individual relates to another. E.g., 'Has-A' which could use to form the relationship 'Freiburg (City) Has-A Dreisam (River)'. 1. `entity`: a general term that can refer to a class, a relationship, attribute, or an individual. E.g., 'City', 'name', 'Has-A', the Freiburg individual are all entities. - 1. `namespace`: an ontology identifier. E.g., 'CITY_ONTOLOGY' which could be used as a namespace for the ontology that consists of the entities 'City', 'name' and 'Has-A'. + 1. `namespace`: an ontology identifier. E.g., 'city_ontology' which could be used as a namespace for the ontology that consists of the entities 'City', 'name' and 'Has-A'. - Each entity is uniquely identified by its name and the namespace it is contained in. We call \.\ the `qualified entity name`. 1. `CUDS`: Common Universal Data Structure. A data structure that is used to uniformly represent ontology concepts in programming code. - CUDS exposes an API that provides CRUD (Create, Read, Update and Delete) functionalities. diff --git a/docs/source/conf.py b/docs/source/conf.py index 88bf52c..d6522b6 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -27,6 +27,7 @@ 'nbsphinx', # Jupyter 'IPython.sphinxext.ipython_console_highlighting', # Jupyter - Syntax highlight workaround 'sphinx.ext.autosectionlabel', # Auto-generate section labels. + 'sphinx-jsonschema' # Generate JSON schema for serialized CUDS ] master_doc = 'index' @@ -75,3 +76,6 @@ def setup(app): # 'enable_auto_doc_ref': True, }, True) app.add_transform(AutoStructify) + + +nbsphinx_allow_errors = True diff --git a/docs/source/contact.md b/docs/source/contact.md new file mode 100644 index 0000000..4293900 --- /dev/null +++ b/docs/source/contact.md @@ -0,0 +1,8 @@ +# Contact +If you see something wrong, missing, or in need of clarification, you can directly +create an issue in [here](https://github.com/simphony/docs/issues). + +Any other questions, issues or comments can be directed to [Pablo de Andres](mailto:pablo.de.andres@iwm.fraunhofer.de), +[Matthias Urban](mailto:matthias.urban@iwm.fraunhofer.de) and +[Yoav Nahshon](mailto:yoav.nahshon@iwm.fraunhofer.de) +from the Materials Data Science and Informatics team, Fraunhofer IWM. \ No newline at end of file diff --git a/docs/source/detailed_design.md b/docs/source/detailed_design.md index f761c24..cdcb7dc 100644 --- a/docs/source/detailed_design.md +++ b/docs/source/detailed_design.md @@ -6,125 +6,143 @@ For a more general overview, go to [getting started](./getting_started.md#genera ```eval_rst .. uml:: - :caption: Standard design - :align: center - - allow_mixing - actor User - - rectangle SemanticLayer { - - class Cuds { - Session session - UUID uuid - CUBA cuba_key - -- - add() : Cuds - get() : Cuds - remove() : void - update() : void - iter() : Iterator - } - } - - rectangle InteroperabilityLayer { - - class Registry { - } - - abstract class Session { - Registry : registry - -- - store() : void - load() : Cuds - sync() : void - } - - class SomeWrapperSession implements Session { - List added - List updated - List removed - SyntacticLayer syntactic - -- - } - } + :caption: Standard design + :align: center + + allow_mixing + actor User + + circle pico + + rectangle SemanticLayer { + class Cuds { + Session session + UUID uuid + OntologyEntity oclass + -- + add() : Cuds + get() : Cuds + remove() : void + update() : void + iter() : Iterator + } + + abstract class OntologyEntity { + String name + URIRef iri + String tblname + OntologyNamespace namespace + Set direct_superclasses + Set direct_subclasses + Set superclasses + Set subclasses + String description + -- + get_triples() : triple + is_superclass_of() : bool + is_subclass_of() : bool + } + class OntologyClass implements OntologyEntity { + Dict attributes + Dict own_attributes + } + + class OntologyRelationship implements OntologyEntity { + OntologyRelationship inverse + } + + class OntologyAttribute implements OntologyEntity { + URIRef datatype + -- + convert_to_datatype() : Any + convert_to_basic_type() : Any + } + + class OntologyNamespace { + -- + get_iri() : URIRef + get_default_rel() : OntologyRelationship + get() : OntologyEntity + + } + + class NamespaceRegistry { + -- + get() : OntologyNamespace + update_namespaces() : void + from_iri() : OntologyEntity + clear() : Graph + store() : void + load() : void + } + } - rectangle SyntacticLayer { - class SyntacticLayer { + rectangle InteroperabilityLayer { + class Registry { + } + + abstract class Session { + Registry : registry + -- + store() : void + load() : Cuds + sync() : void + } + + class SomeWrapperSession implements Session { + List added + List updated + List removed + SyntacticLayer syntactic + -- + } } - } - database backend + rectangle SyntacticLayer { + class SyntacticLayer { + } + } + database backend - ' ----------------------- - ' ------ RELATIONS ------ - ' ----------------------- - User -> Cuds : interacts_with + ' ----------------------- + ' ------ RELATIONS ------ + ' ----------------------- + User -up-> OntologyClass : interacts_with + Cuds -left> OntologyClass : instance_of + OntologyEntity -> OntologyNamespace : part_of + OntologyNamespace -> NamespaceRegistry : contained_in + OntologyClass -left> OntologyAttribute : has - Cuds -> Session : has_a - Session -> Registry : manages + pico -> NamespaceRegistry : manages - SomeWrapperSession -> SyntacticLayer : manages + Cuds -> Session : has_a + Session -> Registry : manages - SyntacticLayer -> backend : acts_on + SomeWrapperSession -> SyntacticLayer : manages - ' ----------------------- - ' -------- NOTES -------- - ' ----------------------- - note top of Cuds - This will be shallow structure with - the uuids of the contained elements: - { - Relation1: {uid1: cuba_key, uid2: cuba_key}, - Relation2: {uid4: cuba_key}, - Relation3: {uid3: cuba_key, uid5: cuba_key}, - } - end note - - note top of Session - Provides the info requested to Cuds - end note - - note top of SomeWrapperSession - Updates the registry with information - from the backend and vice versa. - end note - - note top of Registry - Flat structure that contains all the - objects accessible through their uid: - { - uid1: object1, - uid2: object2, - uid3: object3, - } - end note + SyntacticLayer -> backend : acts_on - note top of SyntacticLayer - Connects to the engine and - knows its specific API - end note + OntologyRelationship -[hidden]> OntologyAttribute ``` - ## Semantic layer The semantic layer is the representation of the classes of the ontology in a programming language. When the user installs an ontology through `pico`, -all ontology classes are saved in a pickle file in the site-packages of the python environment. +all ontology concepts are saved in a graph in `~/.osp_ontologies`. The procedure is as follows: - The `OntologyInstallationManager` receives a list of yml files with ontologies to install. - It instantiates a `Parser`. - The parser goes through the ontologies and creates an `OntologyClass` per entity. - All the oclasses of the same namespace are grouped in an `OntologyNamespace`. -- All the registries are collected in the `NamespaceRegistry`. This object will be pickled. +- All the registries are collected in the `NamespaceRegistry`. -Installing new ontologies loads the pickle and adds new namespaces or modifies the existing ones. +Installing new ontologies loads the graph and adds new namespaces or modifies the existing ones. When a class is instantiated, an individual is created. -The pickled file is read, and an instance of the [Cuds](#cuds) class with the ontology information is created. +The graph is read, and an instance of the [Cuds](#cuds) class with the ontology information is created. Through the Cuds they realise the [Cuds API](#cuds-api) which enables the user to work with them in a generic, simple way. @@ -133,7 +151,7 @@ _Location:_ `osp.core.cuds` It is the base class for all instances. Besides whatever might have been defined in the ontology, they all have 3 basic attributes: - - uid: instance of `uuid.UUID`, it serves to uniquely identify an instance + - uid: instance of `uuid.UUID`, it serves to uniquely identify an instance. - session: this is the link to the interoperability layer. By default all objects are in the `CoreSession`, unless they are in a wrapper. - oclass: indicates the ontology class they originate from. @@ -141,7 +159,7 @@ Besides whatever might have been defined in the ontology, they all have 3 basic #### Cuds structure Each cuds object contains the uids and oclass of the directly related entities, as well as the relationship that connects them. -The actual related objects are kept in the [registry](#registry) +The actual related objects are kept in the [registry](#registry). ``` a_cuds_object := { Relation1: {uid1: oclass, uid2: oclass}, @@ -149,8 +167,12 @@ The actual related objects are kept in the [registry](#registry) Relation3: {uid3: oclass, uid5: oclass}, } ``` -_Note:_ This is an abstraction to show the general structure. -The actual implementation is a bit more complex. + +```eval_rst +.. note:: + This is an abstraction to show the general structure. + The actual implementation is a bit more complex. +``` #### Cuds API The governing idea behind the API design was to simplify as much as possible the usage. @@ -159,14 +181,13 @@ This CRUD API is defined by 6 methods: ##### Create ```python -from osp.core import SOME_NAMESPACE -# from osp.core import some_namespace # lowercase works as well! +from osp.core.namespaces import some_namespace -ontology_class = SOME_NAMESPACE.ONTOLOGY_CLASS -# ontology_class = some_namespace.MyOntologyClass # CamelCase works as well! -relationship = SOME_NAMESPACE.RELATIONSHIP +ontology_class = some_namespace.OntologyClass -cuds_obj = SOME_NAMESPACE.ONTOLOGY_CLASS() +relationship = some_namespace.relationship + +cuds_obj = some_namespace.OntologyClass() ``` ##### Add @@ -363,12 +384,17 @@ cuds_obj = SOME_NAMESPACE.ONTOLOGY_CLASS() ``` First the uids of all the objects to be iterated are gathered, and then they are yielded like a generator + +```eval_rst +.. hint:: + There is also an :code:`is_a` method for checking oclass inheritance. +``` -_Note (I):_ Be aware that the sequence diagrams shown represent simple use cases, -and more complex scenarios are also possible (e.g. adding an object with children). - -_Note (II):_ There is also an `is_a` method for checking oclass inheritance. - +```eval_rst +.. note:: + Be aware that the sequence diagrams shown represent simple use cases, + and more complex scenarios are also possible (e.g. adding an object with children). +``` ## Interoperability layer The interoperability layer takes care of the connection and translation between the semantic and syntactic parts. It also contains the storage of all the objects that share a session. @@ -497,7 +523,11 @@ To simplify and group functionality, we built an inheritance scheme: } @enduml ``` -_Note:_ This is a reduced version and does not represent the entirety of the contained functions. + +```eval_rst +.. note:: + This is a reduced version and does not represent the entirety of the contained functions. +``` The simplest session, called `CoreSession`, is the default one for entities created in a python workspace and has no backend. It just accesses the registry to manage the operations made by users. @@ -508,6 +538,14 @@ This will define which methods have to be implemented and `_engine` as the acces `SimWrapperSession` and `DbWrapperSession` further specify the behaviour of wrappers, defining the methods that trigger an action on the backend (`run` and `commit`, respectively). +```eval_rst +.. note:: + You might have noticed that the semantic layer defines :code:`remove` in the API, + but in the session and registry we use :code:`delete`. The different between them + is conceptual: :code:`remove` is interpreted as detachment i.e. removal of edges, + while :code:`delete` implies the erasure of the note itself. +``` + #### Buffers Session classes under `WrapperSession` share 3 types of buffers, namely `added`, `updated` and `deleted`. The previous buffers are repeated twice, first for the user and then for the engine, diff --git a/docs/source/getting_started.md b/docs/source/getting_started.md index 0049d08..1212794 100644 --- a/docs/source/getting_started.md +++ b/docs/source/getting_started.md @@ -98,60 +98,93 @@ The abstraction is replaced by specificity when you move towards the backend. For a full explanation on the architecture and design, go to [detailed design](./detailed_design.md). ## OSP-core -[OSP-core](https://gitlab.cc-asp.fraunhofer.de/simphony/osp-core) is the main component of the SimPhoNy framework. +[OSP-core](https://github.com/simphony/osp-core) is the main component of the SimPhoNy framework. It is independent of any backend and provides the basic ontology based data structures for the seamless exchange of data between wrappers. - ### Ontology file OSP-core requires an ontology file to create the appropriate CUDS classes. -Said ontology must be in a YAML format as defined by [our specification](yaml.md). +Said ontology must be either in a YAML format as defined by [our specification](yaml.md) +or [one of the supported owl ontologies](owl.md).
- Ontology sample + YAML Ontology sample + The following is an excerpt from the `city.ontology.yml` in osp-core. ```yaml - version: "0.0.1" - namespace: "CUBA" + --- + version: "0.0.3" + + namespace: "city" ontology: - ENTITY: - description: The root of the ontology. - subclass_of: [] - NOTHING: - description: A class without any individuals. + encloses: subclass_of: - - CUBA.ENTITY - - ################ + - cuba.activeRelationship + inverse: city.isEnclosedBy - RELATIONSHIP: - description: The root of all relationships. + isEnclosedBy: subclass_of: - - CUBA.ENTITY + - cuba.passiveRelationship + inverse: city.encloses - ACTIVE_RELATIONSHIP: - description: The root of all active relationships. Active relationships express that one cuds object is in the container of another. + hasInhabitant: subclass_of: - - CUBA.RELATIONSHIP + - city.encloses ################ - WRAPPER: - description: The root of all wrappers. These are the bridge to simulation engines and databases. + CityWrapper: subclass_of: - - CUBA.ENTITY + - cuba.Wrapper + - city.hasPart: + range: city.City + cardinality: 1+ + exclusive: false + + ################ - ATTRIBUTE: - description: The root of all attributes. + City: subclass_of: - - CUBA.ENTITY + - city.PopulatedPlace + - city.hasPart: + range: city.Neighborhood + cardinality: many + exclusive: true + - city.isPartOf: + range: city.CityWrapper + cardinality: 0-1 + exclusive: true + - city.hasMajor: + range: city.Citizen + cardinality: 0-1 + exclusive: true + + Building: + subclass_of: + - city.ArchitecturalStructure + - city.hasPart: + range: city.Address + cardinality: 1 + exclusive: false + - city.hasPart: + range: city.Floor + cardinality: many + exclusive: false + - city.isPartOf: + range: city.Street + cardinality: 1 + exclusive: true + + Citizen: + subclass_of: + - city.Person ```
-OSP-core can also be used with EMMO (European Materials and Modelling Ontology). -Tools for converting EMMO from the OWL format to YAML are provided. See more [here](working_with_emmo.md). +OSP-core can be used with EMMO (European Materials and Modelling Ontology) out of the box. +See more [here](ontologies_included.md). ### Python classes Upon installation of OSP-core, each ontology class (except from attributes and relationships) becomes a python class. @@ -159,14 +192,15 @@ Upon installation of OSP-core, each ontology class (except from attributes and r Since each ontology has a namespace, it can be used to import the classes and create cuds objects: ```py -from osp.core import cuba, another_namespace +from osp.core.namespaces import cuba, another_namespace entity = cuba.Entity() other_entity = another_namespace.SomeOtherEntity() ``` ### Sessions -The sessions are the interoperability classes that connect to where the data is stored. In the case of wrappers, they take care of keeping consistency between the backends (e.g. databases) and the internal registry. +The sessions are the interoperability classes that connect to where the data is stored. +In the case of wrappers, they take care of keeping consistency between the backends (e.g. databases) and the internal registry. When you add an object to a wrapper, a copy of the object is created in the registry belonging to the session of the wrapper. @@ -250,70 +284,3 @@ we suggest going through the different available [repositories](https://gitlab.c For more technical information regarding wrappers, particularly for wrapper developers, we recommend visiting [wrapper development](./wrapper_development.md). - -# Installation -For the installation and usage of the framework, -we *highly* encourage the use of a [virtual environment](https://docs.python.org/3/tutorial/venv.html): - -```shell -~/test$ python3 -m venv SimPhoNy -~/test$ source SimPhoNy/bin/activate -(SimPhoNy) ~/test$ -``` - -## OSP-core installation -First, the repository must be cloned: - -```shell -git clone git@gitlab.cc-asp.fraunhofer.de:simphony/osp-core.git -``` - -Once available locally, the project must be installed. The default installation is: - -```shell -cd osp-core -python3 setup.py install -``` - -After installing OSP-core, you can install an ontology file using -[**pico**](./utils.md#pico-installs-cuds-ontologies): - -```shell -pico install -``` - -## Wrapper installation -The installation of a wrapper is similar. First, the repository is cloned: - -```shell -git clone git@gitlab.cc-asp.fraunhofer.de:simphony/wrappers/.git -cd some-wrapper -``` -### Local wrapper installation -With OSP-core installed, if the wrapper has its own ontology, it *must* be installed: - -```shell -pico install -``` - -For the wrappers that require the installation of a backend, a `install_engine.sh` script is provided. -It will automatically call `install_engine_requirements.sh`, where the engine specific requirements are installed. - -```shell -./install_engine.sh -``` - -Now the wrapper can be installed: - -```shell -python3 setup.py install -``` - -### Wrapper Docker image -Some wrappers also provided a [Dockerfile](https://docs.docker.com/engine/reference/builder/) -for an automatic installation in a container. -Simply run the `docker_install.sh` script. No need to install OSP-core either. - -```shell -./docker_install.sh -``` diff --git a/docs/source/index.md b/docs/source/index.md index 2fb38d8..5110152 100644 --- a/docs/source/index.md +++ b/docs/source/index.md @@ -5,7 +5,7 @@ Here you can browse though the general documentation of SimPhoNy. ```eval_rst ============= ========== - SymPhoNy docs OSP-core + SimPhoNy docs OSP-core ============= ========== 2.3.x 3.4.0-beta 2.2.x 3.3.5-beta @@ -15,43 +15,46 @@ Here you can browse though the general documentation of SimPhoNy. ```eval_rst .. toctree:: - :caption: Basics + :caption: Introduction :maxdepth: 2 about.md motivation.md getting_started.md + installation.md + jupyter/cuds-api.ipynb + jupyter/sessions_and_vars.ipynb + detailed_design.md + utils.md .. toctree:: :caption: Ontology :maxdepth: 2 + ontology_intro.md + ontologies_included.md yaml.md owl.md + jupyter/ontology-interface.ipynb -.. toctree:: - :caption: Further information - - detailed_design.md - wrapper_development.md - utils.md .. toctree:: - :caption: DIY - :maxdepth: 2 + :caption: Wrappers - jupyter/cuds-api.ipynb - jupyter/ontology-interface.ipynb - jupyter/sessions_and_vars.ipynb jupyter/multiple-wrappers.ipynb jupyter/simlammps.ipynb jupyter/quantum-espresso.ipynb + wrapper_development.md + jupyter/wrapper_development.ipynb + .. toctree:: :caption: Additional :maxdepth: 2 api_ref.md + json.md links.md + contact.md ``` diff --git a/docs/source/installation.md b/docs/source/installation.md new file mode 100644 index 0000000..37b6fcf --- /dev/null +++ b/docs/source/installation.md @@ -0,0 +1,93 @@ +# Installation +For the installation and usage of the framework Python 3.6 or higher is needed. +We *highly* encourage the use of a [virtual environment](https://docs.python.org/3/tutorial/venv.html) +or a [conda](https://docs.conda.io/en/latest/) environment: + +```shell +# virtual environment +~/test$ python3 -m venv SimPhoNy +~/test$ source SimPhoNy/bin/activate +(SimPhoNy) ~/test$ +``` + +```shell +# conda +~/test$ conda create -n +~/test$ conda activate +``` + + +## OSP-core installation +First, the repository must be cloned: + +```shell +git clone git@github.com:simphony/osp-core.git +cd osp-core +``` + +The installation is based on setuptools: + +```sh +# build and install (recommended) +pip install . + +# alternative +python3 setup.py install +``` + +or: + +```sh +# build for in-place development (recommended) +pip install -e . + +# alternative +python3 setup.py develop +``` + +After installing OSP-core, you can install your ontology namespaces. +We provide the tool [`pico`](./utils.md#pico-installs-cuds-ontologies) +(**p**ico **i**nstalls **c**uds **o**ntologies) for that purpose. + +```sh +pico install + +# If you have issues using pico directly, you can use +python -m osp.core.pico install +``` + +## Wrapper installation +The installation of a wrapper is similar. First, the repository is cloned: + +```shell +git clone git@github.com:simphony/.git +cd some-wrapper +``` +### Local wrapper installation +With OSP-core installed, if the wrapper has its own ontology, it *must* be installed: + +```shell +pico install +``` + +For the wrappers that require the installation of a backend, a `install_engine.sh` script is provided. +It will automatically call `install_engine_requirements.sh`, where the engine specific requirements are installed. + +```shell +./install_engine.sh +``` + +Now the wrapper can be installed: + +```shell +python3 setup.py install +``` + +### Wrapper Docker image +Some wrappers also provided a [Dockerfile](https://docs.docker.com/engine/reference/builder/) +for an automatic installation in a container. +Simply run the `docker_install.sh` script. There is no need to install OSP-core either. + +```shell +./docker_install.sh +``` diff --git a/docs/source/json.md b/docs/source/json.md new file mode 100644 index 0000000..2f0095e --- /dev/null +++ b/docs/source/json.md @@ -0,0 +1,16 @@ + + +# Serialization JSON schema of CUDS objects + +When you serialize a CUDS object using the +[`serialize()` method in the utils module](api_ref.html#osp.core.utils.general.serialize), +you will get a json document as a result. +The method will traverse the hierarchical datastructure +using Depth First Traversal. +Therefore, its result is a json array composed of several flat CUDS objects. + +This array can later be deserialized using the opposite +[`deserialize`](api_ref.html#osp.core.utils.general.deserialize). + +The serialization is done via [JSON-LD](https://json-ld.org/), +with the schema used for the [OSP API in Marketplace](https://gitlab.cc-asp.fraunhofer.de/MarketPlace/osp-api). diff --git a/docs/source/json_schema/serialized_cuds.json b/docs/source/json_schema/serialized_cuds.json new file mode 100644 index 0000000..e18f669 --- /dev/null +++ b/docs/source/json_schema/serialized_cuds.json @@ -0,0 +1,102 @@ + { + "cuds_array": { + "title": "Array of flat CUDS objects", + "description": "This schema shows how the method `osp.core.utils.serialize()`\n\nwill serialize a CUDS object to JSON. The result is a flat list,\n\nwhere ich element references its neighbors by UUID.", + "type": "array", + "items": { + "$ref": "#/definitions/cuds" + } + }, + "definitions": { + "cuds": { + "title": "Flat CUDS object", + "description": "A representation of a single non-hierarchical CUDS object", + "type": "object", + "$$target": "#/definitions/cuds", + "properties": { + "uid": { + "$ref": "#/definitions/uuid" + }, + "oclass": { + "$ref": "#/definitions/entity" + }, + "attributes": { + "$ref": "#/definitions/attributes" + }, + "relationships": { + "$ref": "#/definitions/relationships" + } + }, + "required": [ + "uid", + "oclass" + ], + "example": { + "uid": "0ed73819-a095-423f-a444-e7e21e600957", + "oclass": "onto.WaterMolecule", + "attributes": { + "onto.velocity": 7 + }, + "relationships": { + "onto.hasPart": { + "b22fc8f5-2fdf-40f1-955c-96d6e2c278d8": "onto.Oxygen", + "ee901cdc-307e-4ca7-837e-074ba14996d6": "onto.Hydrogen", + "1e8f75f6-29d5-450f-a991-fc0dc2890075": "onto.Hydrogen" + } + } + } + }, + "entity": { + "title": "Name of an ontology entity", + "type": "string", + "description": "An ontology entity", + "format": "oclass", + "example": "onto.SimulationCuds", + "$$target": "#/definitions/entity", + "pattern": "([a-zA-Z])([a-zA-Z]|[0-9]|_)*\\.([a-zA-Z])([a-zA-Z]|[0-9]|_)*" + }, + "uuid": { + "title": "Universal unique identifier", + "type": "string", + "format": "uuid", + "description": "The unique identifier of a CUDS", + "example": "9053ed01-b301-473d-b59d-c184d4e772a1", + "$$target": "#/definitions/uuid" + }, + "attributes": { + "title": "Attributes of the CUDS objects", + "description": "**The key is a `entity`:** A mapping from the **ontology attribute** to its **values**", + "type": "object", + "additionalProperties": true, + "$$target": "#/definitions/attributes", + "example": { + "onto.Foo": 42, + "onto.Bar": [ + 1, + 2, + 3 + ] + } + }, + "relationships": { + "title": "Relationships of the CUDS objects", + "type": "object", + "$$target": "#/definitions/relationships", + "description": "**The key is a `entity`:** A mapping from the **ontology relationship** to the related cuds objects' **UUIDs and ontology classes**.", + "additionalProperties": { + "type": "object", + "description": "**The key is a `uuid`:** A mapping from the **uuid** to the **ontology class** of the related cuds objects", + "additionalProperties": { + "$ref": "#/definitions/entity" + } + }, + "example": { + "onto.hasPart": { + "b22fc8f5-2fdf-40f1-955c-96d6e2c278d8": "onto.Oxygen", + "ee901cdc-307e-4ca7-837e-074ba14996d6": "onto.Hydrogen", + "1e8f75f6-29d5-450f-a991-fc0dc2890075": "onto.Hydrogen" + } + } + } + } + } \ No newline at end of file diff --git a/docs/source/jupyter/.ipynb_checkpoints/quantum-espresso-checkpoint.ipynb b/docs/source/jupyter/.ipynb_checkpoints/quantum-espresso-checkpoint.ipynb new file mode 100644 index 0000000..accde3b --- /dev/null +++ b/docs/source/jupyter/.ipynb_checkpoints/quantum-espresso-checkpoint.ipynb @@ -0,0 +1,338 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tutorial 06: Quantum Espresso Wrapper\n", + "\n", + "In this tutorial we will go through a simple example of how to use the wrapper for the Quantum Espresso simulation engine. You can find the wrapper [here](https://github.com/simphony/quantum-espresso-wrapper).\n", + "## Background\n", + "This is an example of a slightly different design based upon the input-output functionality of certain simulation engines such as Quantum Espresso and Gromacs.\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Let's get hands-on\n", + "### Installation\n", + "To run the local installation of Quantum Espresso, simply run `./install_engine.sh`. This should check for the prerequisites and compile the code for Quantum Espresso for you.\n", + "\n", + "If the script runs into an error finding openmpi-bin or something like that, try running `apt-get update` and try again. \n", + "Once the installation has completed, try running `pw.x` to see if the installation has succeeded. If this does not work, then try adding `export PATH=$PATH:/home/username/qe-6.1/bin/` at the end of `.bashrc` located at your home folder. \n", + " \n", + "Once you have verified that `pw.x` works, install the ontology via `pico install ontology.simlammps.yml`, and make sure to run `python3 setup.py` located in the root of the quantum espresso wrapper folder. \n", + "\n", + "Note that the installation of the ontology requires version 3.4.0 of osp-core to be installed (see [dev branch](https://github.com/simphony/osp-core/tree/v3.4.0-dev))\n", + "\n", + "That should be all needed to use Quantum Espresso!\n", + "\n", + "### Simple example\n", + "\n", + "This is an adaptation of quantum-espresso-wrapper/examples/Simple.py. As usual, we need to import the necessary components:" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'osp.wrappers.quantumespresso.qe_utilsv2'", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mModuleNotFoundError\u001b[0m Traceback (most recent call last)", + "\u001b[0;32m\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mosp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcore\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mnamespaces\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mQE\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mosp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcore\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutils\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mpretty_print\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0;32mfrom\u001b[0m \u001b[0mosp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwrappers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mquantumespresso\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mqe_session\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mqeSession\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m", + "\u001b[0;32m~/miniconda3/envs/osp/lib/python3.8/site-packages/quantum_espresso-0.1-py3.8.egg/osp/wrappers/quantumespresso/qe_session.py\u001b[0m in \u001b[0;36m\u001b[0;34m\u001b[0m\n\u001b[1;32m 3\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mosp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwrappers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mquantumespresso\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mqe_engine\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mSimulationEngine\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 4\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mosp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwrappers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mquantumespresso\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mqe_utils\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0mqeUtils\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 5\u001b[0;31m \u001b[0;32mimport\u001b[0m \u001b[0mosp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mwrappers\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mquantumespresso\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mqe_utilsv2\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m\u001b[1;32m 6\u001b[0m \u001b[0;32mfrom\u001b[0m \u001b[0mosp\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mcore\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mutils\u001b[0m \u001b[0;32mimport\u001b[0m \u001b[0msimple_search\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 7\u001b[0m \u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mModuleNotFoundError\u001b[0m: No module named 'osp.wrappers.quantumespresso.qe_utilsv2'" + ] + } + ], + "source": [ + "import numpy as np \n", + "\n", + "from osp.core.namespaces import QE\n", + "from osp.core.utils import pretty_print\n", + "from osp.wrappers.quantumespresso.qe_session import qeSession" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we create simulation and its K points, which determine at what points it samples the cell" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sim = QE.Simulation()\n", + "k = QE.K_POINTS(vector = (7, 7, 7), unit = \"\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we create a cell, the element Silicon, a pseudopotential, an atom and the cell parameters. Note that the pseudopotential files should ALWAYS be located inside of a folder named `$PSEUDO_DIR` inside of wherever you are running the simulation." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SiCell = QE.Cell()\n", + "Si = QE.Element(name = \"Si\")\n", + "SiPseudo = QE.PSEUDOPOTENTIAL(name = \"Si.pbe-n-kjpaw_psl.1.0.0.UPF\")\n", + "Si1 = QE.Atom()\n", + "SiParams = QE.CellParams()\n", + "celldm1 = QE.Celldm1(value = 5.43070, unit = \"au\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we connect these all to each other using the `add` method." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Si.add(SiPseudo, Si1)\n", + "Si.add(QE.Mass(value = 28.085, unit = \"amu\"))\n", + "SiCell.add(Si1, SiParams)\n", + "Si1.add(QE.Position(vector = (0, 0, 0), unit = \"\"))\n", + "SiCell.add(celldm1)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "We specify the cell parameters:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SiParams.add(QE.CellParameterX(vector = (0.5, 0.5, 0), unit = \"\"),\n", + " QE.CellParameterY(vector = (0.5, 0, 0.5), unit = \"\"),\n", + " QE.CellParameterZ(vector = (0, 0.5, 0.5), unit = \"\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "And then we add everything created so far to the simulation:\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sim.add(SiCell)\n", + "sim.add(Si)\n", + "sim.add(k)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "While we're add it, let's add some variables to the simulation which we can check to see if they have been updated. They will not be taken into account when simulating, so they're there for control purposes.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "sim.add(QE.Pressure(value = 100, unit = \"kbar\"))\n", + "sim.add(QE.StressTensor(tensor2 = np.zeros((3, 3)), unit = \"kbar\"))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's check out what this simulation looks like now with the `pretty_print` function:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pretty_print(sim)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now, it's time to get the simulation running:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "session = qeSession(root = \"\")\n", + "quantum_espresso_wrapper = QE.QEWrapper(session = session)\n", + "quantum_espresso_wrapper.add(sim)\n", + "print(\"Running calculation...\")\n", + "\n", + "quantum_espresso_wrapper.session._run(prefix = \"si\", command_type = \"pw.x\", calculation_type = \"scf\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now let's check the results of our calculation:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pretty_print(sim)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "As you can see, the original part of the cuds tree is still there, with everything mostly the same. The new parts are:\n", + "\n", + "- The qe.PwOut cuds object. This is the output file of the simulation, in case there is something that the wrapper does not parse but that you would still like to see.\n", + "- The qe.TotalEnergy cuds object. This was parsed from the qe.PwOut file itself.\n", + "- The qe.Force cuds object. This represents the force exerted on the atom(s).\n", + "\n", + "The updated parts are:\n", + "\n", + "- The qe.Pressure cuds object, having changed in value from 100 kbar to 5723.64 kbar.\n", + "- The qe.StressTensor cuds object, which is no longer zero." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's see if we can do better and calculate some bands structures:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "quantum_espresso_wrapper.session._run(prefix = \"si\", command_type = \"pw.x\", calculation_type = \"bands\")\n", + "quantum_espresso_wrapper.session._run(prefix = \"si\", command_type = \"bands.x\", calculation_type = \"\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Although the cuds structure won't have changed much by this, the data is there in the folder.\n", + "\n", + "Now let's try to relax this cell. While it isn't a real cell, we can still perform the calculations to relax it to know what the movement of the atoms would be like if it were a real cell (warning, perform vc-relax type calculations with caution. These examples are designed to be lightweight and non-indicative of real-world applications)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "quantum_espresso_wrapper.session._run(prefix = \"si\", command_type = \"pw.x\", calculation_type = \"relax\", IONS = {'ion_dynamics': \"'bfgs'\"})" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "pretty_print(sim)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "In this example, the position hasn't changed. So let's spice things up a little bit and add another atom, and then relax:" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "Si2 = QE.Atom()\n", + "Si2.add(QE.Position(vector = (0.25, 0.25, 0.26), unit = \"\"))\n", + "SiCell.add(Si)\n", + "Si.add(Si2)\n", + "pretty_print(sim)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "quantum_espresso_wrapper.session._run(prefix = \"si\", command_type = \"pw.x\", calculation_type = \"relax\", IONS = {'ion_dynamics': \"'bfgs'\"})\n", + "pretty_print(sim)" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.8.0" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/docs/source/jupyter/cuds-api.ipynb b/docs/source/jupyter/cuds-api.ipynb index 6ac7e5f..7eb35a9 100644 --- a/docs/source/jupyter/cuds-api.ipynb +++ b/docs/source/jupyter/cuds-api.ipynb @@ -4,10 +4,10 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Tutorial 01: CUDS API\n", + "# Tutorial: CUDS API\n", "\n", "This tutorial introduces the CUDS API.\n", - "The code given here is based on [this](https://gitlab.cc-asp.fraunhofer.de/simphony/osp-core/blob/master/examples/api_example.py) example." + "The code given here is based on [this](https://github.com/simphony/osp-core/blob/master/examples/api_example.py) example." ] }, { @@ -21,10 +21,12 @@ "Conceptually, we consider CUDS objects as containers. The content of a CUDS object consists of other CUDS objects. This means that a CUDS is a [recursive data structure](https://en.wikipedia.org/wiki/Recursive_data_type). There are various types of relationships between a container and its contained objects. We will see this later on.\n", "\n", "As a data structure, CUDS exposes an API that provides the functionalities *Create*, *Read*, *Update* and *Delete* (or simply [CRUD](https://en.wikipedia.org/wiki/Create,_read,_update_and_delete)).\n", - "Except *Create*, all the other functionalities are supported by the methods `add`, `get`, `remove`, `update` and `iter`, that are defined in the class `Cuds`. Here, we cover all of the methods except `update` since it is used to synchronize between two or more data sources, and in this tutorial we will only use one, that is the data we will create through our python code on the fly. Check out the [wrapper tutorial](./multiple-wrappers.ipynb) to see the `update` method in action.\n", + "Except *Create*, all the other functionalities are supported by the methods `add`, `get`, `remove`, `update` and `iter`, that are defined in the class `Cuds`. Here, we cover all of the methods except `update` since it is used to synchronize between two or more data sources, and in this tutorial we will only use one, that is the data we will create through our python code on the fly. Check out the [wrapper tutorial](multiple-wrappers.ipynb) to see the `update` method in action.\n", "\n", - "Every CUDS object is related to an ontological concept via the ontological `is a` relation. In the python implementation of OSP-core, all ontological concepts are instances of the `OntologyEntity` class. The ontological concept that can be used to *Create* CUDS objects are instances of `OntologyClass`, a subclass of `OntologyEntity`. The ontological\n", - "concepts are organized in namespaces.\n" + "Every CUDS object is related to an ontological concept via the ontological `is a` relation.\n", + "In the python implementation of OSP-core, all ontological concepts are instances of the `OntologyEntity` class.\n", + "The ontological concept that can be used to *Create* CUDS objects are instances of `OntologyClass`, a subclass of `OntologyEntity`.\n", + "The ontological concepts are organized in namespaces." ] }, { @@ -32,21 +34,45 @@ "metadata": {}, "source": [ "## Let's get hands on\n", - "We start by importing the example namespace from osp-core. It consists of concepts that were automatically generated from the [dummy city ontology](https://gitlab.cc-asp.fraunhofer.de/simphony/osp-core/blob/cuds-3.0/cuds/ontology/ontology.city.yml). There is [another tutorial](#) on the ontology YAML file. However, it is not important for the purposes of this tutorial. " + "We start by importing the example namespace from OSP-core. It consists of concepts that were automatically generated from the [dummy city ontology](https://github.com/simphony/osp-core/blob/master/osp/core/ontology/docs/city.ontology.yml). There is [another tutorial](#) on the ontology YAML file. However, it is not important for the purposes of this tutorial.\n", + "\n", + "Before we can start, you have to install the city ontology. Use out tool pico for this:" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 1, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": "INFO 2020-08-06 08:03:23,850 [osp.core.ontology.installation]: Will install the following namespaces: ['city']\nINFO 2020-08-06 08:03:23,880 [osp.core.ontology.yml.yml_parser]: Parsing YAML ontology file /mnt/c/Users/urba/Desktop/repos/osp-core/osp/core/ontology/docs/city.ontology.yml\nINFO 2020-08-06 08:03:23,892 [osp.core.ontology.yml.yml_parser]: You can now use `from osp.core.namespaces import city`.\nINFO 2020-08-06 08:03:23,892 [osp.core.ontology.parser]: Loaded 367 ontology triples in total\nINFO 2020-08-06 08:03:23,927 [osp.core.ontology.installation]: Installation successful\n" + } + ], + "source": [ + "!pico install city" + ] + }, + { + "cell_type": "markdown", "metadata": {}, + "source": [ + "Now you can start coding:" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "# If you did not install the CITY ontology (pico install city), you have to execute these commands first:\n", - "# from osp.core import Parser\n", - "# p = Parser()\n", - "# p.parse(\"city\")\n", - "\n", - "from osp.core import CITY" + "# If you just installed the ontology from within this notebook and this line doesn't work, please restart the kernel and run this cell again.\n", + "from osp.core.namespaces import city" ] }, { @@ -58,18 +84,18 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ - "c = CITY.CITY(name=\"Freiburg\", coordinates=[47, 7])" + "c = city.City(name=\"Freiburg\", coordinates=[47, 7])" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "The variable `c` is assigned with a newly created CUDS object. This object was initialized with a name (Freiburg) and coordinates ([47, 7]). To understand why these two arguments were necessary, we'll have to take a look at the ontology. This will be explained in another tutorial." + "The variable `c` is assigned with a newly created CUDS object. This object was initialized with a name (Freiburg) and coordinates (\\[47, 7\\]). To understand why these two arguments were necessary, we'll have to take a look at the ontology. This will be explained in another tutorial." ] }, { @@ -81,9 +107,17 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 4, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": "uid of c: 34ffc443-9287-46de-b2aa-477a57f68a2f\n" + } + ], "source": [ "print(\"uid of c: \" + str(c.uid))" ] @@ -97,15 +131,15 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": {}, + "execution_count": 5, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", - "text": [ - "type of c: CITY.CITY\n" - ] + "name": "stdout", + "text": "type of c: city.City\n" } ], "source": [ @@ -121,25 +155,23 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { + "output_type": "execute_result", "data": { - "text/plain": [ - "" - ] + "text/plain": "" }, - "execution_count": 5, "metadata": {}, - "output_type": "execute_result" + "execution_count": 6 } ], "source": [ - "p1 = CITY.CITIZEN(name=\"Peter\")\n", - "p2 = CITY.CITIZEN(name=\"Anne\")\n", - "c.add(p1, rel=CITY.HAS_INHABITANT)\n", - "c.add(p2, rel=CITY.HAS_INHABITANT)" + "p1 = city.Citizen(name=\"Peter\")\n", + "p2 = city.Citizen(name=\"Anne\")\n", + "c.add(p1, rel=city.hasInhabitant)\n", + "c.add(p2, rel=city.hasInhabitant)" ] }, { @@ -158,16 +190,15 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": {}, + "execution_count": 7, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", - "text": [ - "uid: f34cb649-d25a-46fe-8e43-c35e2746f8cf\n", - "uid: 192b50d6-9235-4214-91a8-f0669ac7ac18\n" - ] + "name": "stdout", + "text": "uid: 703ec4ba-e89b-4e79-8985-5b6d31223328\nuid: 088c08f9-7961-4586-b908-23170fb0f059\n" } ], "source": [ @@ -184,15 +215,15 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, + "execution_count": 8, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", - "text": [ - "CITY.CITIZEN: f34cb649-d25a-46fe-8e43-c35e2746f8cf\n" - ] + "name": "stdout", + "text": "city.Citizen: 703ec4ba-e89b-4e79-8985-5b6d31223328\n" } ], "source": [ @@ -208,19 +239,19 @@ }, { "cell_type": "code", - "execution_count": 8, - "metadata": {}, + "execution_count": 9, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", - "text": [ - "[, ]\n" - ] + "name": "stdout", + "text": "[, ]\n" } ], "source": [ - "print(c.get(oclass=CITY.CITIZEN))" + "print(c.get(oclass=city.Citizen))" ] }, { @@ -232,7 +263,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -249,41 +280,16 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ "for i in range(6):\n", - " c.add(CITY.NEIGHBOURHOOD(name=\"neighbourhood %s\" % i))" + " c.add(city.Neighborhood(name=\"neighbourhood %s\" % i))" ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.0" - } - }, + "metadata": {}, "nbformat": 4, "nbformat_minor": 2 } \ No newline at end of file diff --git a/docs/source/jupyter/multiple-wrappers.ipynb b/docs/source/jupyter/multiple-wrappers.ipynb index ec33b20..881309a 100644 --- a/docs/source/jupyter/multiple-wrappers.ipynb +++ b/docs/source/jupyter/multiple-wrappers.ipynb @@ -4,15 +4,19 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Tutorial 04: Multiple wrappers\n", - "This tutorial introduces the use of multiple data sources, and shows how can one exchange information between them. The code given here is based on [this example](https://gitlab.cc-asp.fraunhofer.de/simphony/osp-core/blob/master/examples/multiple_wrappers_example.py) and builds on the [introduction on the CUDS API](./cuds-api.ipynb).\n", + "# Tutorial: Multiple wrappers\n", + "This tutorial introduces the use of multiple data sources, and shows how can one exchange information between them. The code given here is based on [this example](https://github.com/simphony/osp-core/blob/master/examples/multiple_wrappers_example.py) and builds on the [introduction on the CUDS API](./cuds-api.ipynb).\n", "\n", "## Background\n", - "One of the main strengths of CUDS objects is their ability to share information between different underlying data sources interchangeably. Using OSP-core's innerworkings a data source can be represented as a CUDS object. A data source can be in turn a database, a simulation engine, or any other software package, which is able to either generate or store information.\n", + "One of the main strengths of CUDS objects is their ability to share information between different underlying data sources interchangeably.\n", + "Using OSP-core's innerworkings a data source can be represented as a CUDS object.\n", + "A data source can be in turn a database, a simulation engine, or any other software package, which is able to either generate or store information.\n", "\n", - "We refer to a CUDS object, which represents an underlying data source as a **wrapper**, as it wraps around the data source. Wrappers use the CUDS API with the addition to some wrapper-specific methods, which will be discussed later on in this tutorial.\n", + "We refer to a CUDS object, which represents an underlying data source as a **wrapper**, as it wraps around the data source.\n", + "Wrappers use the CUDS API with the addition to some wrapper-specific methods, which will be discussed later on in this tutorial.\n", "\n", - "For a wrapper to be initialized, one needs some context for the underlying data source (e.g. location, credentials, etc.) for this we introduce an object called **session**. Conceptually a session can be thought as an interoperability level, or in simple terms it handles the transition from the user-friendly CUDS API to the more task-specific syntax data sources tend to have." + "For a wrapper to be initialized, one needs some context for the underlying data source (e.g. location, credentials, etc.) for this we introduce an object called **session**.\n", + "Conceptually a session can be thought as an interoperability level, or in simple terms it handles the transition from the user-friendly CUDS API to the more task-specific syntax data sources tend to have." ] }, { @@ -20,21 +24,39 @@ "metadata": {}, "source": [ "## Let's get hands on\n", - "We start by importing the example namespace of osp-core" + "We start by importing the example namespace of OSP-core. If you haven't already, you should install the city ontology before:" ] }, { "cell_type": "code", "execution_count": 1, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "INFO 2020-12-02 11:54:26,244 [osp.core.ontology.installation]: Will install the following namespaces: ['city']\n", + "INFO 2020-12-02 11:54:26,280 [osp.core.ontology.yml.yml_parser]: Parsing YAML ontology file /mnt/c/Users/dea/Documents/Projects/simphony/osp-core/osp/core/ontology/docs/city.ontology.yml\n", + "INFO 2020-12-02 11:54:26,331 [osp.core.ontology.yml.yml_parser]: You can now use `from osp.core.namespaces import city`.\n", + "INFO 2020-12-02 11:54:26,333 [osp.core.ontology.parser]: Loaded 403 ontology triples in total\n", + "INFO 2020-12-02 11:54:26,374 [osp.core.ontology.installation]: Installation successful\n" + ] + } + ], + "source": [ + "!pico install city" + ] + }, + { + "cell_type": "code", + "execution_count": 2, "metadata": {}, "outputs": [], "source": [ - "# If you did not install the CITY ontology (pico install city), you have to execute these commands first:\n", - "# from osp.core import Parser\n", - "# p = Parser()\n", - "# p.parse(\"city\")\n", - "\n", - "from osp.core import CITY" + "from osp.core.namespaces import city" ] }, { @@ -46,7 +68,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -62,7 +84,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [], "source": [ @@ -79,36 +101,29 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [], "source": [ - "try:\n", - " from osp.wrappers.sqlalchemy_wrapper_session import \\\n", - " SqlAlchemyWrapperSession\n", - "except ImportError as e:\n", - " raise ImportError(\"For this example, the SQLAlchemy \"\n", - " \"wrapper for SimPhoNy is required!\") from e" + "from osp.wrappers.sqlalchemy import SqlAlchemySession" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ - "Next we import a session object, which will provide the context to a simple simulation engine we developed for demonstrational purposes. To install it refer to this [repo](https://gitlab.cc-asp.fraunhofer.de/simphony/wrappers/dummy-simulation-wrapper)." + "Next we import a session object, which will provide the context to a simple simulation engine we developed for demonstrational purposes. It is already included in OSP-core." ] }, { "cell_type": "code", - "execution_count": 5, - "metadata": {}, + "execution_count": 6, + "metadata": { + "tags": [] + }, "outputs": [], "source": [ - "try:\n", - " from osp.wrappers.dummy_simulation_wrapper import DummySimWrapperSession\n", - "except ImportError as e:\n", - " raise ImportError(\"For this example, the dummy simulation \"\n", - " \"wrapper for SimPhoNy is required!\") from e" + "from osp.wrappers.simdummy import SimDummySession" ] }, { @@ -122,19 +137,16 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": {}, + "execution_count": 7, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ - "Input data to connect to Postgres table!\n", - "User: postgres\n", - "Password: ········\n", - "Database name: osp_core\n", - "Host: 127.0.0.1\n", - "Port [5432]: \n" + "Input data to connect to Postgres table!\n" ] } ], @@ -152,38 +164,38 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In the next lines we create our small ontology-loving [**EMMO town** example](https://emmc.info/emmo-info/). Please pay a closer attention to the fourth line ([this](https://gitlab.cc-asp.fraunhofer.de/simphony/osp-core/blob/master/examples/multiple_wrappers_example.py#L30) line in the `multiple_wrappers_example.py` file) as there you can see the power of the `add` method and how with one statement one can add multiple `CITIZEN` CUDS objects simultaneously." + "In the next lines we create our small ontology-loving [**EMMO town** example](https://emmc.info/emmo-info/). Please pay a closer attention to the fourth line as there you can see the power of the `add` method and how with one statement one can add multiple `CITIZEN` CUDS objects simultaneously." ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [ { + "output_type": "execute_result", "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 7, "metadata": {}, - "output_type": "execute_result" + "execution_count": 8 } ], "source": [ - "emmo_town = CITY.CITY(name='EMMO town')\n", + "emmo_town = city.City(name='EMMO town')\n", "\n", - "emmo_town.add(CITY.CITIZEN(name='Emanuele Ghedini'), rel=CITY.HAS_INHABITANT)\n", - "emmo_town.add(CITY.CITIZEN(name='Adham Hashibon'), rel=CITY.HAS_INHABITANT)\n", - "emmo_town.add(CITY.CITIZEN(name='Jesper Friis'),\n", - " CITY.CITIZEN(name='Gerhard Goldbeck'),\n", - " CITY.CITIZEN(name='Georg Schmitz'),\n", - " CITY.CITIZEN(name='Anne de Baas'),\n", - " rel=CITY.HAS_INHABITANT)\n", + "emmo_town.add(city.Citizen(name='Emanuele Ghedini'), rel=city.hasInhabitant)\n", + "emmo_town.add(city.Citizen(name='Adham Hashibon'), rel=city.hasInhabitant)\n", + "emmo_town.add(city.Citizen(name='Jesper Friis'),\n", + " city.Citizen(name='Gerhard Goldbeck'),\n", + " city.Citizen(name='Georg Schmitz'),\n", + " city.Citizen(name='Anne de Baas'),\n", + " rel=city.hasInhabitant)\n", "\n", - "emmo_town.add(CITY.NEIGHBOURHOOD(name=\"Ontology\"))\n", - "emmo_town.add(CITY.NEIGHBOURHOOD(name=\"User cases\"))" + "emmo_town.add(city.Neighborhood(name=\"Ontology\"))\n", + "emmo_town.add(city.Neighborhood(name=\"User cases\"))" ] }, { @@ -195,16 +207,16 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "ontology_uid = None\n", - "for neighbourhood in emmo_town.get(oclass=CITY.NEIGHBOURHOOD):\n", + "for neighbourhood in emmo_town.get(oclass=city.Neighborhood):\n", " if neighbourhood.name == \"Ontology\":\n", " ontology_uid = neighbourhood.uid\n", - " neighbourhood.add(CITY.STREET(name=\"Relationships\"), rel=CITY.HAS_PART)\n", - " neighbourhood.add(CITY.STREET(name=\"Entities\"), rel=CITY.HAS_PART)" + " neighbourhood.add(city.Street(name=\"Relationships\"), rel=city.hasPart)\n", + " neighbourhood.add(city.Street(name=\"Entities\"), rel=city.hasPart)" ] }, { @@ -216,12 +228,14 @@ }, { "cell_type": "code", - "execution_count": 9, - "metadata": {}, + "execution_count": 10, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ "EMMO town is my city!\n" ] @@ -229,7 +243,7 @@ ], "source": [ "onto = emmo_town.get(ontology_uid)\n", - "print(onto.get(rel=CITY.IS_PART_OF)[0].name + ' is my city!')" + "print(onto.get(rel=city.isPartOf)[0].name + ' is my city!')" ] }, { @@ -245,12 +259,12 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ - "with SqlAlchemyWrapperSession(postgres_url) as session:\n", - " wrapper = CITY.CITY_WRAPPER(session=session)\n", + "with SqlAlchemySession(postgres_url) as session:\n", + " wrapper = city.CityWrapper(session=session)\n", " wrapper.add(emmo_town)\n", " session.commit()" ] @@ -270,79 +284,29 @@ }, { "cell_type": "code", - "execution_count": 11, - "metadata": {}, + "execution_count": 12, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", - "text": [ - "The database contains the following information about the city:\n", - "- Cuds object named :\n", - " uuid: 3954ba3f-27db-4cff-9453-619d2ee6435f\n", - " type: CITY.CITY\n", - " superclasses: CITY.CITY, CITY.POPULATED_PLACE, CITY.GEOGRAPHICAL_PLACE, CUBA.ENTITY\n", - " values: coordinates: [0. 0.]\n", - " description: \n", - " To Be Determined\n", - "\n", - " |_Relationship CITY.HAS_INHABITANT:\n", - " | - CITY.CITIZEN cuds object named :\n", - " | . uuid: 89deb6b7-eaac-4db1-a573-53beb132a183\n", - " | . age: 25\n", - " | - CITY.CITIZEN cuds object named :\n", - " | . uuid: 121e73f3-35a9-4b49-8b32-6a58fd1375f1\n", - " | . age: 25\n", - " | - CITY.CITIZEN cuds object named :\n", - " | . uuid: d077246d-105d-429f-b041-27dfb170ae31\n", - " | . age: 25\n", - " | - CITY.CITIZEN cuds object named :\n", - " | . uuid: 0c1e5ca6-1279-465c-ab0a-701eee118343\n", - " | . age: 25\n", - " | - CITY.CITIZEN cuds object named :\n", - " | . uuid: 0d7630f0-6965-4ff0-a40b-c1851f354308\n", - " | . age: 25\n", - " | - CITY.CITIZEN cuds object named :\n", - " | uuid: adc48ce9-264a-49cf-813d-377825228c49\n", - " | age: 25\n", - " |_Relationship CITY.HAS_PART:\n", - " - CITY.NEIGHBOURHOOD cuds object named :\n", - " . uuid: d8e6cf00-0747-42c9-8c54-f09a532df7e0\n", - " . coordinates: [0. 0.]\n", - " . |_Relationship CITY.HAS_PART:\n", - " . - CITY.STREET cuds object named :\n", - " . . uuid: a54f76dc-1b2c-4899-9ae3-ca48ddb05811\n", - " . . coordinates: [0. 0.]\n", - " . - CITY.STREET cuds object named :\n", - " . uuid: 092d17b5-37f1-4f54-ad71-d208218a1851\n", - " . coordinates: [0. 0.]\n", - " - CITY.NEIGHBOURHOOD cuds object named :\n", - " uuid: bee623d8-fba2-4106-bfd4-c6a659950966\n", - " coordinates: [0. 0.]\n", - "The city has a new inhabitant:\n", - "- Cuds object named :\n", - " uuid: c8d11136-d88b-4cff-9508-240678947ce2\n", - " type: CITY.CITIZEN\n", - " superclasses: CITY.CITIZEN, CITY.PERSON, CITY.LIVING_BEING, CUBA.ENTITY\n", - " values: age: 32\n", - " description: \n", - " To Be Determined\n", - "\n" - ] + "name": "stdout", + "text": "The database contains the following information about the city:\n- Cuds object named :\n uuid: 96a2f49c-8009-456a-ad69-1cb1dea7f128\n type: city.City\n superclasses: city.City, city.GeographicalPlace, city.PopulatedPlace, cuba.Entity\n values: coordinates: [0 0]\n description: \n To Be Determined\n\n |_Relationship city.hasInhabitant:\n | - city.Citizen cuds object named :\n | . uuid: 08e05374-0187-4114-a114-085431aeebde\n | . age: 25\n | - city.Citizen cuds object named :\n | . uuid: a084c4ba-c054-4afd-b194-b4e983743706\n | . age: 25\n | - city.Citizen cuds object named :\n | . uuid: 209926bc-6bcd-466c-a86a-807780e4789c\n | . age: 25\n | - city.Citizen cuds object named :\n | . uuid: 0a0a8488-7400-4f4e-9e44-dbf56782cd3c\n | . age: 25\n | - city.Citizen cuds object named :\n | . uuid: cdfe72ec-fc15-4a14-a516-88b576bf0a27\n | . age: 25\n | - city.Citizen cuds object named :\n | uuid: 4ec1b1af-341f-4aa5-845d-fb3f9c502c9c\n | age: 25\n |_Relationship city.hasPart:\n - city.Neighborhood cuds object named :\n . uuid: e1632cf5-24e3-4afb-b72b-757ef62d5bef\n . coordinates: [0 0]\n . |_Relationship city.hasPart:\n . - city.Street cuds object named :\n . . uuid: 19a6a5a4-c22c-4be7-98c4-c69b3ee613d2\n . . coordinates: [0 0]\n . - city.Street cuds object named :\n . uuid: 681f7441-e711-4375-ab70-074234206faa\n . coordinates: [0 0]\n - city.Neighborhood cuds object named :\n uuid: 574e4a68-92c8-4b0e-b41f-e0341b42b00b\n coordinates: [0 0]\nThe city has a new inhabitant:\n- Cuds object named :\n uuid: 7a263d53-9c4d-47ac-bb31-fa54d7920bcd\n type: city.Citizen\n superclasses: city.Citizen, city.LivingBeing, city.Person, cuba.Entity\n values: age: 32\n description: \n To Be Determined\n\n" } ], "source": [ - "with SqlAlchemyWrapperSession(postgres_url) as db_session:\n", - " db_wrapper = CITY.CITY_WRAPPER(session=db_session)\n", + "with SqlAlchemySession(postgres_url) as db_session:\n", + " db_wrapper = city.CityWrapper(session=db_session)\n", " db_emmo_town = db_wrapper.get(emmo_town.uid)\n", " print(\"The database contains the following information about the city:\")\n", " pretty_print(db_emmo_town)\n", "\n", " # Working with a Simulation wrapper\n", - " with DummySimWrapperSession() as sim_session:\n", - " sim_wrapper = CITY.CITY_SIM_WRAPPER(num_steps=1,\n", - " session=sim_session)\n", - " new_inhabitant = CITY.PERSON(age=31, name=\"Peter\")\n", + " with SimDummySession() as sim_session:\n", + " sim_wrapper = city.CitySimWrapper(numSteps=1,\n", + " session=sim_session)\n", + " new_inhabitant = city.Person(age=31, name=\"Peter\")\n", " sim_emmo_town, _ = sim_wrapper.add(db_emmo_town, new_inhabitant)\n", " sim_session.run()\n", " print(\"The city has a new inhabitant:\")\n", @@ -362,64 +326,20 @@ }, { "cell_type": "code", - "execution_count": 12, - "metadata": {}, + "execution_count": 13, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", - "text": [ - "The database contains the following information about the city:\n", - "- Cuds object named :\n", - " uuid: 3954ba3f-27db-4cff-9453-619d2ee6435f\n", - " type: CITY.CITY\n", - " superclasses: CITY.CITY, CITY.POPULATED_PLACE, CITY.GEOGRAPHICAL_PLACE, CUBA.ENTITY\n", - " values: coordinates: [0. 0.]\n", - " description: \n", - " To Be Determined\n", - "\n", - " |_Relationship CITY.HAS_INHABITANT:\n", - " | - CITY.CITIZEN cuds object named :\n", - " | . uuid: 89deb6b7-eaac-4db1-a573-53beb132a183\n", - " | . age: 25\n", - " | - CITY.CITIZEN cuds object named :\n", - " | . uuid: 121e73f3-35a9-4b49-8b32-6a58fd1375f1\n", - " | . age: 25\n", - " | - CITY.CITIZEN cuds object named :\n", - " | . uuid: d077246d-105d-429f-b041-27dfb170ae31\n", - " | . age: 25\n", - " | - CITY.CITIZEN cuds object named :\n", - " | . uuid: 0c1e5ca6-1279-465c-ab0a-701eee118343\n", - " | . age: 25\n", - " | - CITY.CITIZEN cuds object named :\n", - " | . uuid: 0d7630f0-6965-4ff0-a40b-c1851f354308\n", - " | . age: 25\n", - " | - CITY.CITIZEN cuds object named :\n", - " | . uuid: adc48ce9-264a-49cf-813d-377825228c49\n", - " | . age: 25\n", - " | - CITY.CITIZEN cuds object named :\n", - " | uuid: c8d11136-d88b-4cff-9508-240678947ce2\n", - " | age: 32\n", - " |_Relationship CITY.HAS_PART:\n", - " - CITY.NEIGHBOURHOOD cuds object named :\n", - " . uuid: d8e6cf00-0747-42c9-8c54-f09a532df7e0\n", - " . coordinates: [0. 0.]\n", - " . |_Relationship CITY.HAS_PART:\n", - " . - CITY.STREET cuds object named :\n", - " . . uuid: a54f76dc-1b2c-4899-9ae3-ca48ddb05811\n", - " . . coordinates: [0. 0.]\n", - " . - CITY.STREET cuds object named :\n", - " . uuid: 092d17b5-37f1-4f54-ad71-d208218a1851\n", - " . coordinates: [0. 0.]\n", - " - CITY.NEIGHBOURHOOD cuds object named :\n", - " uuid: bee623d8-fba2-4106-bfd4-c6a659950966\n", - " coordinates: [0. 0.]\n" - ] + "name": "stdout", + "text": "The database contains the following information about the city:\n- Cuds object named :\n uuid: 96a2f49c-8009-456a-ad69-1cb1dea7f128\n type: city.City\n superclasses: city.City, city.GeographicalPlace, city.PopulatedPlace, cuba.Entity\n values: coordinates: [0 0]\n description: \n To Be Determined\n\n |_Relationship city.hasInhabitant:\n | - city.Citizen cuds object named :\n | . uuid: 08e05374-0187-4114-a114-085431aeebde\n | . age: 25\n | - city.Citizen cuds object named :\n | . uuid: a084c4ba-c054-4afd-b194-b4e983743706\n | . age: 25\n | - city.Citizen cuds object named :\n | . uuid: 209926bc-6bcd-466c-a86a-807780e4789c\n | . age: 25\n | - city.Citizen cuds object named :\n | . uuid: 0a0a8488-7400-4f4e-9e44-dbf56782cd3c\n | . age: 25\n | - city.Citizen cuds object named :\n | . uuid: cdfe72ec-fc15-4a14-a516-88b576bf0a27\n | . age: 25\n | - city.Citizen cuds object named :\n | . uuid: 4ec1b1af-341f-4aa5-845d-fb3f9c502c9c\n | . age: 25\n | - city.Citizen cuds object named :\n | uuid: 7a263d53-9c4d-47ac-bb31-fa54d7920bcd\n | age: 32\n |_Relationship city.hasPart:\n - city.Neighborhood cuds object named :\n . uuid: e1632cf5-24e3-4afb-b72b-757ef62d5bef\n . coordinates: [0 0]\n . |_Relationship city.hasPart:\n . - city.Street cuds object named :\n . . uuid: 19a6a5a4-c22c-4be7-98c4-c69b3ee613d2\n . . coordinates: [0 0]\n . - city.Street cuds object named :\n . uuid: 681f7441-e711-4375-ab70-074234206faa\n . coordinates: [0 0]\n - city.Neighborhood cuds object named :\n uuid: 574e4a68-92c8-4b0e-b41f-e0341b42b00b\n coordinates: [0 0]\n" } ], "source": [ - "with SqlAlchemyWrapperSession(postgres_url) as db_session:\n", - " db_wrapper = CITY.CITY_WRAPPER(session=db_session)\n", + "with SqlAlchemySession(postgres_url) as db_session:\n", + " db_wrapper = city.CityWrapper(session=db_session)\n", " db_emmo_town = db_wrapper.get(emmo_town.uid)\n", " print(\"The database contains the following information about the city:\")\n", " pretty_print(db_emmo_town)" @@ -434,29 +354,15 @@ } ], "metadata": { - "file_extension": ".py", "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.0" - }, - "mimetype": "text/x-python", - "name": "python", - "npconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": 3 + "name": "python3", + "display_name": "Python 3.7.5 64-bit", + "metadata": { + "interpreter": { + "hash": "6b8ae71b8e061ba9b211c188436d81117d4fa8435b658f808f738c6c9c6d5c29" + } + } + } }, "nbformat": 4, "nbformat_minor": 2 diff --git a/docs/source/jupyter/ontology-interface.ipynb b/docs/source/jupyter/ontology-interface.ipynb index 8dd3bf3..e3845ed 100644 --- a/docs/source/jupyter/ontology-interface.ipynb +++ b/docs/source/jupyter/ontology-interface.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Tutorial 02: Ontology Interface\n", + "# Tutorial: Ontology Interface\n", "\n", "This tutorial introduces the interface to the installed ontologies. The code presented is based on [this example](#). If you want to create your own ontology please refer to [this guide](../yaml.md)." ] @@ -20,7 +20,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "In the previous tutorial we have discussed the CUDS API. CUDS objects correspond to ontology individuals. In this tutorial we present the API of all other entities: ontology classes, relationships and attributes. These are defined in an ontology file in [YAML format](../yaml.md). With the presented API you can access the entities and navigate within an ontology." + "In the previous tutorial we have discussed the CUDS API. CUDS objects correspond to ontology individuals. In this tutorial we present the API of all other entities: ontology classes, relationships and attributes. These are defined in an ontology file in [YAML](../yaml.md) or [OWL](../owl.md) format. With the presented API you can access the entities and navigate within an ontology." ] }, { @@ -32,15 +32,26 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "execution_count": 1, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": [ + "INFO 2020-12-02 13:53:47,242 [osp.core.ontology.installation]: Will install the following namespaces: ['city']\n", + "INFO 2020-12-02 13:53:47,288 [osp.core.ontology.yml.yml_parser]: Parsing YAML ontology file /mnt/c/Users/dea/Documents/Projects/simphony/osp-core/osp/core/ontology/docs/city.ontology.yml\n", + "INFO 2020-12-02 13:53:47,357 [osp.core.ontology.yml.yml_parser]: You can now use `from osp.core.namespaces import city`.\n", + "INFO 2020-12-02 13:53:47,358 [osp.core.ontology.parser]: Loaded 403 ontology triples in total\n", + "INFO 2020-12-02 13:53:47,397 [osp.core.ontology.installation]: Installation successful\n" + ] + } + ], "source": [ - "# If you did not install the CITY ontology\n", - "# you have to execute these commands first:\n", - "from osp.core import Parser\n", - "p = Parser()\n", - "p.parse(\"city\")" + "# Install the ontology\n", + "!pico install city" ] }, { @@ -55,59 +66,69 @@ "---\n", "version: \"0.0.3\"\n", "\n", - "namespace: \"CITY\"\n", + "namespace: \"city\"\n", "\n", "ontology:\n", " ...\n", "```\n", "\n", - "Knowing the name of the namespace, we can import it in python. With the namespace python object we can access the entities within the namespace:" + "Alternatively you can use pico to see the installed namespaces:" ] }, { "cell_type": "code", - "execution_count": 1, - "metadata": {}, + "execution_count": 2, + "metadata": { + "tags": [] + }, "outputs": [ { + "output_type": "stream", "name": "stdout", + "text": [ + "Packages:\n\t- simlammps_ontology\n\t- city\nNamespaces:\n\t- xml\n\t- rdf\n\t- rdfs\n\t- xsd\n\t- cuba\n\t- ns1\n\t- owl\n\t- simlammps_ontology\n\t- city\n" + ] + } + ], + "source": [ + "!pico list" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Knowing the name of the namespace, we can import it in python. With the namespace python object we can access the entities within the namespace:" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "tags": [] + }, + "outputs": [ + { "output_type": "stream", + "name": "stdout", "text": [ - "\n", - "You can use UPPERCASE and lowercase to access a namespace\n", - "True\n", - "\n", - "You can use the namespace to access its entities\n", - "CITY.LIVING_BEING\n", - "\n", - "You can use UPPERCASE, lowercase or CamelCase to access entities\n", - "True\n", - "\n", - "You can also use index notation\n", - "True\n", - "\n", - "You can access the namespace of an entity\n", - "True\n" + "\nYou can use the namespace to access its entities\ncity.LivingBeing\n\nYou can also use index notation. For owl ontologies, this queries the entities by rdf.label.It returns a list of all entities with the same label\nTrue\n\nYou can access the namespace of an entity\nFalse\n" ] } ], "source": [ - "from osp.core import city, CITY # This imports the namespace city\n", - "\n", - "print(\"\\nYou can use UPPERCASE and lowercase to access a namespace\")\n", - "print(city is CITY)\n", + "from osp.core.namespaces import city\n", "\n", "print(\"\\nYou can use the namespace to access its entities\")\n", - "print(city.living_being)\n", + "print(city.LivingBeing)\n", "\n", - "print(\"\\nYou can use UPPERCASE, lowercase or CamelCase to access entities\")\n", - "print(city.living_being is city.LIVING_BEING is city.LivingBeing)\n", - "\n", - "print(\"\\nYou can also use index notation\")\n", - "print(city.living_being is city[\"living_being\"])\n", + "print(\"\\nYou can also use index notation. \"\n", + " \"For owl ontologies, this queries the entities by rdf.label.\"\n", + " \"It returns a list of all entities with the same label\")\n", + "print(city.LivingBeing == city[\"LivingBeing\"][0])\n", "\n", "print(\"\\nYou can access the namespace of an entity\")\n", - "print(city is city.LivingBeing.namespace)" + "print(city is city.LivingBeing.namespace)\n" ] }, { @@ -121,28 +142,16 @@ }, { "cell_type": "code", - "execution_count": 2, - "metadata": {}, + "execution_count": 4, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ - "\n", - "You can access the superclasses and the subclasses\n", - "[, ]\n", - "[, , ]\n", - "\n", - "You can access the direct superclasses and subclasses\n", - "[]\n", - "[]\n", - "\n", - "You can access a description of the entities\n", - "A being that lives\n", - "\n", - "You can test if one entity is a subclass / superclass of another\n", - "True\n", - "True\n" + "\nYou can access the superclasses and the subclasses\n{, }\n{, , }\n\nYou can access the direct superclasses and subclasses\n{}\n{}\n\nYou can access a description of the entities\nA being that lives\n\nYou can test if one entity is a subclass / superclass of another\nTrue\nTrue\n" ] } ], @@ -174,26 +183,25 @@ }, { "cell_type": "code", - "execution_count": 3, - "metadata": {}, + "execution_count": 5, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ - "\n", - "You can get an entity from a string\n", - "CITY.LIVING_BEING\n", - "True\n" + "\nYou can get an entity with a string\ncity.LivingBeing\nTrue\n" ] } ], "source": [ - "from osp.core import get_entity # noqa: E402\n", + "from osp.core.namespaces import get_entity # noqa: E402\n", "\n", - "print(\"\\nYou can get an entity from a string\")\n", + "print(\"\\nYou can get an entity with a string\")\n", "print(get_entity(\"city.LivingBeing\"))\n", - "print(get_entity(\"city.LivingBeing\") is city.LivingBeing)" + "print(get_entity(\"city.LivingBeing\") == city.LivingBeing)" ] }, { @@ -207,53 +215,43 @@ }, { "cell_type": "code", - "execution_count": 4, - "metadata": {}, + "execution_count": 6, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ - "\n", - "You can test if an entity is a class\n", - "True\n", - "True\n", - "\n", - "You can test if an entity is a relationship\n", - "True\n", - "True\n", - "\n", - "You can test if an entity is an attribute\n", - "True\n", - "True\n" + "\nYou can test if an entity is a class\nTrue\nTrue\n\nYou can test if an entity is a relationship\nTrue\nTrue\n\nYou can test if an entity is a attribute\nTrue\nTrue\n" ] } ], "source": [ - "# CUBA namespace\n", - "# This is the main namespace that is always available\n", - "from osp.core import cuba # noqa: E402\n", + "from osp.core.namespaces import cuba # noqa: E402\n", "\n", "# These are the classes for the ontology entities\n", "from osp.core.ontology import ( # noqa: F401, E402\n", - " OntologyEntity,\n", - " OntologyClass,\n", - " OntologyRelationship,\n", - " OntologyAttribute\n", + " OntologyEntity,\n", + " OntologyClass,\n", + " OntologyRelationship,\n", + " OntologyAttribute\n", ")\n", "\n", "print(\"\\nYou can test if an entity is a class\")\n", "print(isinstance(city.LivingBeing, OntologyClass))\n", - "print(not city.LivingBeing.is_subclass_of(cuba.Relationship)\n", - " and not city.LivingBeing.is_subclass_of(cuba.Attribute))\n", + "print(not city.LivingBeing.is_subclass_of(cuba.relationship)\n", + " and not city.LivingBeing.is_subclass_of(cuba.attribute))\n", "\n", "print(\"\\nYou can test if an entity is a relationship\")\n", - "print(isinstance(city.HasInhabitant, OntologyRelationship))\n", - "print(city.HasInhabitant.is_subclass_of(cuba.Relationship))\n", + "print(isinstance(city.hasInhabitant, OntologyRelationship))\n", + "print(city.hasInhabitant.is_subclass_of(cuba.relationship))\n", "\n", - "print(\"\\nYou can test if an entity is an attribute\")\n", - "print(isinstance(city.Name, OntologyAttribute))\n", - "print(city.Name.is_subclass_of(cuba.Attribute))\n" + "print(\"\\nYou can test if an entity is a attribute\")\n", + "print(isinstance(city.name, OntologyAttribute))\n", + "print(city.name.is_subclass_of(cuba.attribute))\n", + "\n" ] }, { @@ -267,27 +265,16 @@ }, { "cell_type": "code", - "execution_count": 5, - "metadata": {}, + "execution_count": 7, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ - "\n", - "You can get the attributes of an ontology class and their defaults\n", - "{: 'John Smith', : 25}\n", - "\n", - "You can get the non-inherited attributes and their defaults\n", - "{: 'John Smith', : 25}\n", - "\n", - "Further interesting properties:\n", - "\n", - "Subclass of: ['CUBA.ENTITY', 'CITY.IS_CHILD_OF 0-2 CITY.LIVING_BEING']\n", - "\n", - "Equivalent to: []\n", - "\n", - "Disjoint with: []\n" + "\nYou can get the attributes of an ontology class and their defaults\n{: (rdflib.term.Literal('John Smith'), False, None), : (rdflib.term.Literal('25', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer')), False, None)}\n\nYou can get the non-inherited attributes and their defaults\n{}\n{: (rdflib.term.Literal('John Smith'), False, None), : (rdflib.term.Literal('25', datatype=rdflib.term.URIRef('http://www.w3.org/2001/XMLSchema#integer')), False, None)}\n" ] } ], @@ -296,13 +283,8 @@ "print(city.Citizen.attributes)\n", "\n", "print(\"\\nYou can get the non-inherited attributes and their defaults\")\n", - "print(city.LivingBeing.own_attributes)\n", - "\n", - "print(\"\\nFurther interesting properties:\")\n", - "print(\"\\nSubclass of:\",\n", - " list(map(str, city.LivingBeing.subclass_of_expressions)))\n", - "print(\"\\nEquivalent to:\", city.LivingBeing.equivalent_to_expressions) # empty\n", - "print(\"\\nDisjoint with:\", city.LivingBeing.disjoint_with_expressions) # empty" + "print(city.Citizen.own_attributes)\n", + "print(city.LivingBeing.own_attributes)" ] }, { @@ -316,36 +298,22 @@ }, { "cell_type": "code", - "execution_count": 6, - "metadata": {}, + "execution_count": 8, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ - "\n", - "You can get the inverse of a relationship\n", - "CITY.IS_INHABITANT_OF\n", - "\n", - "You can get the characteristics of a relationship\n", - "['transitive']\n", - "\n", - "You can get the domain and range of a relationship\n", - "[]\n", - "[]\n" + "\nYou can get the inverse of a relationship\ncity.INVERSE_OF_hasInhabitant\n" ] } ], "source": [ "print(\"\\nYou can get the inverse of a relationship\")\n", - "print(city.HasInhabitant.inverse)\n", - "\n", - "print(\"\\nYou can get the characteristics of a relationship\")\n", - "print(city.HasPart.characteristics)\n", - "\n", - "print(\"\\nYou can get the domain and range of a relationship\")\n", - "print(city.HasPart.domain_expressions) # empty\n", - "print(city.HasPart.range_expressions) # empty" + "print(city.hasInhabitant.inverse)" ] }, { @@ -359,36 +327,30 @@ }, { "cell_type": "code", - "execution_count": 7, - "metadata": {}, + "execution_count": 9, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", + "name": "stdout", "text": [ - "\n", - "You can get the argument name of an attribute. The argument name is used when instantiating CUDS objects\n", - "age\n", - "\n", - "You can get the datatype of attributes\n", - "INT\n", - "\n", - "You can use the attribute to convert values to the datatype of the attribute\n", - "10\n" + "\nYou can get the argument name of an attribute. The argument name is used when instantiating CUDS objects\nage\n\nYou can get the datatype of attributes\nhttp://www.w3.org/2001/XMLSchema#integer\n\nYou can use the attribute to convert values to the datatype of the attribute\n10\n" ] } ], "source": [ "print(\"\\nYou can get the argument name of an attribute. \"\n", " \"The argument name is used when instantiating CUDS objects\")\n", - "print(city.Age.argname)\n", + "print(city.age.argname)\n", "\n", "print(\"\\nYou can get the datatype of attributes\")\n", - "print(city.Age.datatype)\n", + "print(city.age.datatype)\n", "\n", "print(\"\\nYou can use the attribute to convert values \"\n", " \"to the datatype of the attribute\")\n", - "print(city.Age(\"10\"))" + "print(city.age.convert_to_datatype(\"10\"))" ] }, { @@ -402,25 +364,15 @@ }, { "cell_type": "code", - "execution_count": 8, - "metadata": {}, + "execution_count": 11, + "metadata": { + "tags": [] + }, "outputs": [ { - "name": "stdout", "output_type": "stream", - "text": [ - "\n", - "You can instantiate CUDS objects using ontology classes\n", - "CITY.CITIZEN: b42eaaaa-8c05-4769-8362-3494bed82e30\n", - "Take a look at api_example.py for a description of the CUDS API\n", - "\n", - "You can check if a CUDS object is an instace of a ontology class\n", - "True\n", - "True\n", - "\n", - "You can get the ontology class of a CUDS object.\n", - "CITY.CITIZEN\n" - ] + "name": "stdout", + "text": "\nYou can instantiate CUDS objects using ontology classes\ncity.Citizen: 1714a778-5943-4611-af3a-e3b0cb32693d\nTake a look at api_example.py for a description of the CUDS API\n\nYou can check if a CUDS object is an instace of a ontology class\nTrue\nTrue\n\nYou can get the ontology class of a CUDS object.\ncity.Citizen\n" } ], "source": [ @@ -436,46 +388,6 @@ "print(city.Citizen(name=\"Test Person\", age=42).oclass)\n" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Namespace registry\n", - "\n", - "All namespaces are stored in a namespace registry (singleton). With the namespace registry, you can access the individual namespaces, using index or dot notation." - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "\n", - "All namespaces are stored in the namespace registry\n", - "\n", - "\n", - "You can access the namespaces using dot or index notation\n", - "\n", - "\n" - ] - } - ], - "source": [ - "# NAMESPACE_REGISTRY\n", - "from osp.core import ONTOLOGY_NAMESPACE_REGISTRY as namespace_reg # noqa: E402\n", - "\n", - "print(\"\\nAll namespaces are stored in the namespace registry\")\n", - "print(namespace_reg)\n", - "\n", - "print(\"\\nYou can access the namespaces using dot or index notation\")\n", - "print(namespace_reg.city)\n", - "print(namespace_reg[\"city\"])\n" - ] - }, { "cell_type": "code", "execution_count": null, @@ -486,21 +398,13 @@ ], "metadata": { "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.8.0" + "name": "python3", + "display_name": "Python 3.7.5 64-bit", + "metadata": { + "interpreter": { + "hash": "6b8ae71b8e061ba9b211c188436d81117d4fa8435b658f808f738c6c9c6d5c29" + } + } } }, "nbformat": 4, diff --git a/docs/source/jupyter/quantum-espresso.ipynb b/docs/source/jupyter/quantum-espresso.ipynb index bd30ba4..fc6ff58 100644 --- a/docs/source/jupyter/quantum-espresso.ipynb +++ b/docs/source/jupyter/quantum-espresso.ipynb @@ -25,8 +25,11 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Tutorial 06: Quantum Espresso Wrapper\n", - "In this tutorial we will go through a simple example of how to use the wrapper for the Quantum Espresso simulation engine. You can find the wrapper [here](https://github.com/simphony/quantum-espresso-wrapper).\n", + "# Tutorial: Quantum Espresso Wrapper\n", + "\n", + "In this tutorial we will go through a simple example of how to use the wrapper for the Quantum Espresso simulation engine.\n", + "You can find the wrapper [here](https://github.com/simphony/quantum-espresso-wrapper).\n", + "\n", "## Background\n", "This is an example of a slightly different design based upon the input-output functionality of certain simulation engines such as Quantum Espresso and Gromacs.\n" ] @@ -44,8 +47,6 @@ " \n", "Once you have verified that `pw.x` works, install the ontology via `pico install ontology.simlammps.yml`, and make sure to run `python3 setup.py` located in the root of the quantum espresso wrapper folder. \n", "\n", - "Note that the installation of the ontology requires version 3.4.0 of osp-core to be installed (see [dev branch](https://github.com/simphony/osp-core/tree/v3.4.0-dev))\n", - "\n", "That should be all needed to use Quantum Espresso!\n", "\n", "### Simple example\n", @@ -439,5 +440,8 @@ "pretty_print(sim)" ] } - ] + ], + "metadata": {}, + "nbformat": 4, + "nbformat_minor": 2 } \ No newline at end of file diff --git a/docs/source/jupyter/sessions_and_vars.ipynb b/docs/source/jupyter/sessions_and_vars.ipynb index be12f5d..f7b42eb 100644 --- a/docs/source/jupyter/sessions_and_vars.ipynb +++ b/docs/source/jupyter/sessions_and_vars.ipynb @@ -4,19 +4,19 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Tutorial 03: Sessions and variables\n", + "# Tutorial: Sessions and variables\n", "In this tutorial we will explain how objects and the variables assigned to them behave with different sessions.\n", "\n", "## Background\n", "Some use cases of OSP-core, like coupling and linking, require interaction between multiple sessions. Even using just one wrapper usually means working with the default CoreSession initially, and then the wrapper session.\n", "\n", - "When an object from one session is added to a different one, a deepcopy of the object is carried out. This means that both objects are technically the same at that point (same uid, oclas, relationships...), but reside in different memory areas and can theoretically differ in the future. The purpose of this behaviour is to allow selective synching and enable different sessions to have different states of an instance.\n", + "When an object from one session is added to a different one, a deepcopy of the object is carried out. This means that both objects are technically the same at that point (same uid, oclass, relationships...), but reside in different memory areas and can theoretically differ in the future. The purpose of this behaviour is to allow selective synching and enable different sessions to have different states of an instance.\n", "\n", "Variables that point to an object in the origin session will keep pointing to it (and not to the added session) unless explicitedly updated.\n", "\n", "Here we will try to explain said behaviour with simple illustrative examples.\n", "\n", - "_Note:_ This tutorial is not meant to be run like the others. The session classes and ontology entities are not real implementations. However, the behaviour shown will be the same as that of a real setup." + "**Note:** This tutorial is not meant to be run like the others. The session classes and ontology entities are not real implementations. However, the behaviour shown will be the same as that of a real setup." ] }, { @@ -33,7 +33,7 @@ "metadata": {}, "outputs": [], "source": [ - "from osp.core import namespace\n", + "from osp.core.namespaces import namespace\n", "from osp.wrappers.wrapper_x import SessionX\n", "from osp.wrappers.wrapper_y import SessionY" ] @@ -186,31 +186,7 @@ ] } ], - "metadata": { - "file_extension": ".py", - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.7.5-final" - }, - "mimetype": "text/x-python", - "name": "python", - "npconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": 3 - }, + "metadata": {}, "nbformat": 4, "nbformat_minor": 2 } \ No newline at end of file diff --git a/docs/source/jupyter/simlammps.ipynb b/docs/source/jupyter/simlammps.ipynb index a7a517f..27b20af 100644 --- a/docs/source/jupyter/simlammps.ipynb +++ b/docs/source/jupyter/simlammps.ipynb @@ -4,7 +4,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Tutorial 05: Simlammps wrapper\n", + "# Tutorial: Simlammps wrapper\n", "In this tutorial we will go through a simple example of how to use the wrapper for the LAMMPS simulation engine.\n", "You can find the wrapper [here](https://gitlab.cc-asp.fraunhofer.de/simphony/wrappers/simlammps).\n", "\n", @@ -25,7 +25,7 @@ "Like we explain in the [wrapper development section](../wrapper_development.md#engine-installation), there are two options:\n", "\n", "- Using Docker: run `./docker_install.sh`.\n", - "- Local installation: remember that you must have a compatible version of [osp-core installed](../getting_started#osp-core-installation).\n", + "- Local installation: remember that you must have a compatible version of [OSP-core installed](../installation.md#osp-core-installation).\n", " \n", " Install the ontology via `pico install ontology.simlammps.yml.`\n", " \n", @@ -40,7 +40,7 @@ "That should be all needed to use simlammps!\n", "\n", "### Simple example\n", - "This is an adaptation of simlammps/examples/simple.py.\n", + "This is an adaptation of simlammps/examples/small.py.\n", "As usual, we start importing the necessary components:" ] }, diff --git a/docs/source/jupyter/wrapper_development.ipynb b/docs/source/jupyter/wrapper_development.ipynb new file mode 100644 index 0000000..53460c3 --- /dev/null +++ b/docs/source/jupyter/wrapper_development.ipynb @@ -0,0 +1,417 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Tutorial: Simple Wrapper development\n", + "In this tutorial we will implement a very simple simulation wrapper.\n", + "It can be used to understand which methods need to be implemented, and how.\n", + "\n", + "The source files can be found [here](https://github.com/simphony/wrapper-development).\n", + "\n", + "## Background\n", + "Wrappers are the way to extend SimPhoNy to support other back-ends. For an in-depth explanation, you can go to the [wrapper development section](../wrapper_development.md) of the documentation. Here we will explain with more detail what has to be implemented.\n", + "\n", + "## Requirements\n", + "In order to run this code, you need to have the simple_ontology available [here](https://github.com/simphony/wrapper-development/blob/master/osp/wrappers/simple_simulation/simple_ontology.ontology.yml).\n", + "\n", + "Remember that once you have OSP-core installed and the ontology file locally, you can simply run `pico install `" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Let's get hands on\n", + "### Syntactic layer\n", + "As you know, SimPhoNy consists of 3 layers, with the wrappers being relevant in the last 2 (interoperability and syntactic layers).\n", + "The syntactic layer talks directly to the back-end in a way that it can be understood.\n", + "\n", + "Since this wrapper aims to be as minimalistic as possible (while still being meaningfull),\n", + "we have created a dummy syntactic layer that emulates talking to a simulation tool.\n", + "\n", + "_Note:_ In order to reduce the amount of code, the docstrings hav been erased. You can refer to the [source file](https://github.com/simphony/wrapper-development/blob/master/osp/wrappers/simple_simulation/simulation_engine.py) for the complete information." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": {}, + "outputs": [], + "source": [ + "# This is the representation of an atom in the \"engine\"\n", + "class Atom():\n", + "\n", + " def __init__(self, position, velocity):\n", + " self.position = position\n", + " self.velocity = velocity" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The engine only works with atoms, setting and getting their position and velocities" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [], + "source": [ + "class SimulationEngine:\n", + " def __init__(self):\n", + " self.atoms = list()\n", + " print(\"Engine instantiated!\")\n", + "\n", + " def __str__(self):\n", + " return \"Some Engine Connection\"\n", + "\n", + " def run(self, timesteps=1):\n", + " print(\"Now the engine is running\")\n", + " for atom in self.atoms:\n", + " atom.position += atom.velocity * timesteps\n", + "\n", + " def add_atom(self, position, velocity):\n", + " print(\"Add atom %s with position %s and velocity %s\"\n", + " % (len(self.atoms), position, velocity))\n", + " self.atoms.append(Atom(position, velocity))\n", + "\n", + " def update_position(self, idx, position):\n", + " print(\"Update atom %s. Setting position to %s\"\n", + " % (idx, position))\n", + " self.atoms[idx].position = position\n", + "\n", + " def update_velocity(self, idx, velocity):\n", + " print(\"Update atom %s. Setting velocity to %s\"\n", + " % (idx, velocity))\n", + " self.atoms[idx].velocity = velocity\n", + "\n", + " def get_velocity(self, idx):\n", + " return self.atoms[idx].velocity\n", + "\n", + " def get_position(self, idx):\n", + " return self.atoms[idx].position\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### Interoperability layer\n", + "Since a lot of 3rd-party tools come with a syntactic layer, the bulk of the work when developping a wrapper for SimPhoNy is here.\n", + "\n", + "We will explain step by step all the code required." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "First, we import the parent Simulation Wrapper Session and the namespace (ontology).\n", + "The engine is not necessary since it is in the previous codebock." + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [], + "source": [ + "from osp.core.session import SimWrapperSession\n", + "# from osp.wrappers.simple_simulation import SimulationEngine\n", + "from osp.core.namespaces import simple_ontology " + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next, we will go through each of the methods. \n", + "\n", + "_Note:_ to be able to break the class into multiple blocks, we will use inheritance, to add a method each time.\n", + "In truth, all the definitions should go under one same `class` definition." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The first method is the `__init__`. This method is called when a new object is instantiated.\n", + "Here we will call the `__init__` method of the parent class and initialise the necessary elements.\n", + "\n", + "Most simulation engines will have an internal way to keep track of, for example, particles.\n", + "To make sure that the entities in the semantic layer are properly synched, we usually use a _mapper_.\n", + "This could be anything from a list or dictionary to a more complex and sofisticated data structure." + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": {}, + "outputs": [], + "source": [ + "class SimpleSimulationSession(SimWrapperSession):\n", + "\n", + " def __init__(self, engine=None, **kwargs):\n", + " super().__init__(engine or SimulationEngine(), **kwargs)\n", + " self.mapper = dict() # maps uuid to index in the backend\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Next comes the output to the `str()` method.\n", + "It will be a string returned in `__str__(self)`." + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": {}, + "outputs": [], + "source": [ + "class SimpleSimulationSession(SimpleSimulationSession):\n", + "\n", + " def __str__(self):\n", + " return \"Simple sample Wrapper Session\"\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "When the `run()` or `commit()` method is called on the session, all the objects that have been added since the last run have to be sent to the back end.\n", + "This is done through `_apply_added`.\n", + "The method should iterate through all the entities in the buffer and trigger different actions depending on which type of entity it is.\n", + "\n", + "Remember that we can check the type using the `is_a` method, or querying for the `oclass` attribute of an entity.\n", + "\n", + "In this example, we will only contact the back end if an atom has been added.\n", + "However, normal wrappers will have a lot more comparisons (`if` and `elif`) to determine which entity it is and act accordingly" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "class SimpleSimulationSession(SimpleSimulationSession):\n", + "\n", + " # OVERRIDE\n", + " def _apply_added(self, root_obj, buffer):\n", + " \"\"\"Adds the added cuds to the engine.\"\"\"\n", + " for obj in buffer.values():\n", + " if obj.is_a(simple_ontology.Atom):\n", + " # Add the atom to the mapper\n", + " self.mapper[obj.uid] = len(self.mapper)\n", + " pos = obj.get(oclass=simple_ontology.Position)[0].value\n", + " vel = obj.get(oclass=simple_ontology.Velocity)[0].value\n", + " self._engine.add_atom(pos, vel)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Just like `_apply_added` is used to modify the engine with the new objects, `_apply_updated` changes the existing ones." + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "class SimpleSimulationSession(SimpleSimulationSession):\n", + "\n", + " # OVERRIDE\n", + " def _apply_updated(self, root_obj, buffer):\n", + " \"\"\"Updates the updated cuds in the engine.\"\"\"\n", + " for obj in buffer.values():\n", + "\n", + " # case 1: we change the velocity\n", + " if obj.is_a(simple_ontology.Velocity):\n", + " atom = obj.get(rel=simple_ontology.isPartOf)[0]\n", + " idx = self.mapper[atom.uid]\n", + " self._engine.update_velocity(idx, obj.value)\n", + "\n", + " # case 2: we change the position\n", + " elif obj.is_a(simple_ontology.Position):\n", + " atom = obj.get(rel=simple_ontology.isPartOf)[0]\n", + " idx = self.mapper[atom.uid]\n", + " self._engine.update_position(idx, obj.value)\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Similarly to the previous methods, `_apply_deleted` should remove entities from the engine.\n", + "In this specific case we left it empty to simplify the code (both in the session and the engine classes)." + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "class SimpleSimulationSession(SimpleSimulationSession):\n", + " # OVERRIDE\n", + " def _apply_deleted(self, root_obj, buffer):\n", + " \"\"\"Deletes the deleted cuds from the engine.\"\"\"" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The previous methods synchronise the engine with the cuds, i.e. the communication is from the semantic layer towards the syntactic.\n", + "The way to update the cuds with the latest information from the engine is `_load_from_backend`.\n", + "\n", + "It is most often called when the user calls the `get` on a cuds object that has potentially been changed by the engine.\n", + "\n", + "When `_load_from_backend` is called for a given cuds object (through its uid), the method should:\n", + " - Check if any of the attributes of the object has changed (like the _value_ for a _position_).\n", + " - Check if any new children cuds objects have been created (like a static _atom_ that gets a new _velocity_ when another bumps into it).\n", + "\n", + "However, it does not have to be recursive and check for more than itself. This is because if the user queries any of the contained elements, that will trigger another call to `_load_from_backend`.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "class SimpleSimulationSession(SimpleSimulationSession):\n", + "\n", + " # OVERRIDE\n", + " def _load_from_backend(self, uids, expired=None):\n", + " \"\"\"Loads the cuds object from the simulation engine\"\"\"\n", + " for uid in uids:\n", + " if uid in self._registry:\n", + " obj = self._registry.get(uid)\n", + "\n", + " # check whether user wants to load a position\n", + " if obj.is_a(simple_ontology.Position):\n", + " atom = obj.get(rel=simple_ontology.isPartOf)[0]\n", + " idx = self.mapper[atom.uid]\n", + " pos = self._engine.get_position(idx)\n", + " obj.value = pos\n", + "\n", + " # check whether user wants to load a velocity\n", + " elif obj.is_a(simple_ontology.Velocity):\n", + " atom = obj.get(rel=simple_ontology.isPartOf)[0]\n", + " idx = self.mapper[atom.uid]\n", + " vel = self._engine.get_velocity(idx)\n", + " obj.value = vel\n", + "\n", + " yield obj" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "The last method that needs to be overridden is `_run`. It simply has to call the `run` method of the engine.\n", + "This could also need to send some information, like the number of steps.\n", + "For that reason, the `root_cuds_object` is available for query." + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [], + "source": [ + "class SimpleSimulationSession(SimpleSimulationSession):\n", + "\n", + " # OVERRIDE\n", + " def _run(self, root_cuds_object):\n", + " \"\"\"Call the run command of the engine.\"\"\"\n", + " self._engine.run()\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Now we can run an example:" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "tags": [] + }, + "outputs": [ + { + "output_type": "stream", + "name": "stdout", + "text": "Engine instantiated!\nAdd atom 0 with position [0. 0. 0.] and velocity [0.63000616 0.38951439 0.12717548]\nAdd atom 1 with position [1. 1. 1.] and velocity [0.80816851 0.04562681 0.44983098]\nAdd atom 2 with position [2. 2. 2.] and velocity [0.3849223 0.50767213 0.82963311]\nNow the engine is running\n- Cuds object:\n uuid: a0a97dbe-584d-4764-b085-7b597e323d20\n type: simple_ontology.Material\n superclasses: cuba.Entity, simple_ontology.Material\n description: \n To Be Determined\n\n |_Relationship simple_ontology.hasPart:\n - simple_ontology.Atom cuds object:\n . uuid: 221a1793-c54a-4e42-bdeb-08921617fbac\n . |_Relationship simple_ontology.hasPart:\n . - simple_ontology.Position cuds object:\n . . uuid: db17082e-d9d3-4a48-bce1-9402d4315200\n . . unit: m\n . . value: [0.63000616 0.38951439 0.12717548]\n . - simple_ontology.Velocity cuds object:\n . uuid: fc7d778d-b18a-4b60-a6ab-ba855a2c2874\n . value: [0.63000616 0.38951439 0.12717548]\n . unit: m/s\n - simple_ontology.Atom cuds object:\n . uuid: 222df5d0-c0fe-435b-b5e2-0d5f7ebd32a9\n . |_Relationship simple_ontology.hasPart:\n . - simple_ontology.Position cuds object:\n . . uuid: f0eb08c4-88a3-40de-893f-89473cd194e8\n . . value: [1.80816851 1.04562681 1.44983098]\n . . unit: m\n . - simple_ontology.Velocity cuds object:\n . uuid: d3e7b5ce-3409-4a4e-bbdb-13a2addaee1c\n . value: [0.80816851 0.04562681 0.44983098]\n . unit: m/s\n - simple_ontology.Atom cuds object:\n uuid: 13bfe4ee-32e8-4fbe-bad5-f98f46aa297a\n |_Relationship simple_ontology.hasPart:\n - simple_ontology.Position cuds object:\n . uuid: da5c35f0-afe5-4b56-b5fa-631b72ee32ad\n . value: [2.3849223 2.50767213 2.82963311]\n . unit: m\n - simple_ontology.Velocity cuds object:\n uuid: 9b6c2c1c-3e63-4144-b7c9-d6223c0b79f7\n value: [0.3849223 0.50767213 0.82963311]\n unit: m/s\nUpdate atom 0. Setting velocity to [0. 0. 0.]\nUpdate atom 1. Setting velocity to [0. 0. 0.]\nUpdate atom 2. Setting velocity to [0. 0. 0.]\nNow the engine is running\n- Cuds object:\n uuid: a0a97dbe-584d-4764-b085-7b597e323d20\n type: simple_ontology.Material\n superclasses: cuba.Entity, simple_ontology.Material\n description: \n To Be Determined\n\n |_Relationship simple_ontology.hasPart:\n - simple_ontology.Atom cuds object:\n . uuid: 221a1793-c54a-4e42-bdeb-08921617fbac\n . |_Relationship simple_ontology.hasPart:\n . - simple_ontology.Position cuds object:\n . . uuid: db17082e-d9d3-4a48-bce1-9402d4315200\n . . unit: m\n . . value: [0.63000616 0.38951439 0.12717548]\n . - simple_ontology.Velocity cuds object:\n . uuid: fc7d778d-b18a-4b60-a6ab-ba855a2c2874\n . value: [0. 0. 0.]\n . unit: m/s\n - simple_ontology.Atom cuds object:\n . uuid: 222df5d0-c0fe-435b-b5e2-0d5f7ebd32a9\n . |_Relationship simple_ontology.hasPart:\n . - simple_ontology.Position cuds object:\n . . uuid: f0eb08c4-88a3-40de-893f-89473cd194e8\n . . value: [1.80816851 1.04562681 1.44983098]\n . . unit: m\n . - simple_ontology.Velocity cuds object:\n . uuid: d3e7b5ce-3409-4a4e-bbdb-13a2addaee1c\n . unit: m/s\n . value: [0. 0. 0.]\n - simple_ontology.Atom cuds object:\n uuid: 13bfe4ee-32e8-4fbe-bad5-f98f46aa297a\n |_Relationship simple_ontology.hasPart:\n - simple_ontology.Position cuds object:\n . uuid: da5c35f0-afe5-4b56-b5fa-631b72ee32ad\n . value: [2.3849223 2.50767213 2.82963311]\n . unit: m\n - simple_ontology.Velocity cuds object:\n uuid: 9b6c2c1c-3e63-4144-b7c9-d6223c0b79f7\n value: [0. 0. 0.]\n unit: m/s\n" + } + ], + "source": [ + "from osp.core.utils import pretty_print\n", + "import numpy as np\n", + "\n", + "m = simple_ontology.Material()\n", + "for i in range(3):\n", + " a = m.add(simple_ontology.Atom())\n", + " a.add(\n", + " simple_ontology.Position(value=[i, i, i], unit=\"m\"),\n", + " simple_ontology.Velocity(value=np.random.random(3), unit=\"m/s\")\n", + " )\n", + "\n", + "# Run a simulation\n", + "with SimpleSimulationSession() as session:\n", + " w = simple_ontology.Wrapper(session=session)\n", + " m = w.add(m)\n", + " w.session.run()\n", + "\n", + " pretty_print(m)\n", + "\n", + " for atom in m.get(rel=simple_ontology.hasPart):\n", + " atom.get(oclass=simple_ontology.Velocity)[0].value = [0, 0, 0]\n", + " w.session.run()\n", + "\n", + " pretty_print(m)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [] + } + ], + "metadata": { + "language_info": { + "name": "python", + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "version": "3.7.5-final" + }, + "orig_nbformat": 2, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "npconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": 3, + "kernelspec": { + "name": "python37564bitvenvvenvbd0fd6573f5f4e40af04d1a32ae4ddbe", + "display_name": "Python 3.7.5 64-bit ('venv': venv)" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} \ No newline at end of file diff --git a/docs/source/links.md b/docs/source/links.md index 2ec177f..46335bf 100644 --- a/docs/source/links.md +++ b/docs/source/links.md @@ -1,8 +1,10 @@ # Related links Here are links to other projects relevant for this documentation. + SimPhoNy: -- [SimPhoNy group](https://gitlab.cc-asp.fraunhofer.de/simphony) -- [OSP-core](https://gitlab.cc-asp.fraunhofer.de/simphony/osp-core) +- [GitLab's SimPhoNy group](https://gitlab.cc-asp.fraunhofer.de/simphony) +- [GitHub's SimPhoNy group](https://github.com/simphony) +- [OSP-core](https://github.com/simphony/osp-core) - [wrappers](https://gitlab.cc-asp.fraunhofer.de/simphony/wrappers) - [wrapper development](https://gitlab.cc-asp.fraunhofer.de/simphony/wrappers/wrapper-development/) diff --git a/docs/source/motivation.md b/docs/source/motivation.md index 950fc9f..2493742 100644 --- a/docs/source/motivation.md +++ b/docs/source/motivation.md @@ -55,7 +55,7 @@ Based on how tools communicate with other tools, we can define 3 levels of opera To continue with our language simile, `A` would be a translator that speaks the languages of `B`, `C` and `D`. If `B` wants to talk to `C`, they must first relay the message to `A`, - and `A` will convert it to a format that `C` understands + and `A` will convert it to a format that `C` understands. #### Interoperability ```eval_rst @@ -86,7 +86,7 @@ Interoperability between software tools is one of the most important objectives ### Abstraction and generalisation -Once a certain degree of interoperability has been reached, other interesting concepts and details that arise +Once a certain degree of interoperability has been reached, other interesting concepts and details that arise: #### Semantic vs. syntactic In our day to day life we use a series of sounds, symbols and rules to communicate. In its simplest level, words have a syntactic side, a role in the sentence they make up, and a explicit meaning. diff --git a/docs/source/ontologies_included.md b/docs/source/ontologies_included.md new file mode 100644 index 0000000..99214dc --- /dev/null +++ b/docs/source/ontologies_included.md @@ -0,0 +1,56 @@ +# Included ontologies + +## The City ontology + +OSP core currently ships with two ontologies. +The first one, called `city` is a simple example ontology. +You can use it to play around and get familiar with OSP-core. +We will also use it a lot in this documentation as an example. + +The city ontology provides the concepts to describe people and +buildings in a city. In this graph we show the different entities in the +ontology. We used [Ontology2Dot](utils.md#ontology2dot) for that: + +![ontology2dot sample image](./_static/img/ontology2dot.png) + +eval_rst +To use the city ontology you have to install it using the tool [Pico](utils.md#pico-installs-cuds-ontologies): + +```sh +pico install city +``` + +Take a look at our [examples](jupyter/cuds-api.md) to see how you can build your own city! + +## Working with EMMO using OSP-core + +The second ontology that is ready to be used out of the box is the European +Materials Modelling Ontology, or EMMO in short. This ontology is an effort +to develop an ontology for applied sciences. It is based on physics, +analytical philosophy and information and communication technologies. +Its source code is open and [available on Github](https://github.com/emmo-repo/EMMO). +If you want to develop an emmo compliant ontology, see [the documentation](https://ontology.pages.fraunhofer.de/documentation/latest/). + +You can install EMMO using [Pico](utils.md#pico-installs-cuds-ontologies). + +```sh +pico install emmo +``` + +Start creating cuds objects: + +```py +>>> from osp.core.namespaces import math +>>> math.Numerical.attributes +{: None} +>>> x = math.Numerical(hasNumericalData=12) +>>> x + +>>> x.hasNumericalData +12 +``` + +## More ontologies + +To create you own or use an existing ontology, see the upcoming sections. +Contact us, if you want your ontology to be shipped with SimPhoNy. diff --git a/docs/source/ontology_intro.md b/docs/source/ontology_intro.md new file mode 100644 index 0000000..5957b20 --- /dev/null +++ b/docs/source/ontology_intro.md @@ -0,0 +1,13 @@ +# Introduction on ontologies + +What is an ontology? + +An ontology defines a set of representational primitives with which to +model a domain of knowledge or discourse. The representational +primitives are typically classes (or sets), attributes (or properties), +and relationships (or relations among class members). The definitions of +the representational primitives include information about their meaning +and constraints on their logically consistent application. (Source: +) + +TODO extend \ No newline at end of file diff --git a/docs/source/owl.md b/docs/source/owl.md index 1550822..f203926 100644 --- a/docs/source/owl.md +++ b/docs/source/owl.md @@ -1,17 +1,95 @@ -# Here comes the information about owl +# How to work with owl ontologies +To install owl ontologies in OSP-core, you have to create a configuration yaml file similar +to the following one: -## Working with EMMO using OSP-core +```yaml +identifier: emmo +ontology_file: https://raw.githubusercontent.com/emmo-repo/EMMO/master/emmo-inferred.owl +reference_by_label: True +namespaces: + mereotopology: http://emmo.info/emmo/top/mereotopology + physical: http://emmo.info/emmo/top/physical + top: http://emmo.info/emmo/top + semiotics: http://emmo.info/emmo/top/semiotics + perceptual: http://emmo.info/emmo/middle/perceptual + reductionistic: http://emmo.info/emmo/middle/reductionistic + holistic: http://emmo.info/emmo/middle/holistic + physicalistic: http://emmo.info/emmo/middle/physicalistic + math: http://emmo.info/emmo/middle/math + properties: http://emmo.info/emmo/middle/properties + materials: http://emmo.info/emmo/middle/materials + metrology: http://emmo.info/emmo/middle/metrology + models: http://emmo.info/emmo/middle/models + manufacturing: http://emmo.info/emmo/middle/manufacturing + isq: http://emmo.info/emmo/middle/isq + siunits: http://emmo.info/emmo/middle/siunits +active_relationships: + - http://emmo.info/emmo/top/mereotopology#EMMO_8c898653_1118_4682_9bbf_6cc334d16a99 + - http://emmo.info/emmo/top/semiotics#EMMO_60577dea_9019_4537_ac41_80b0fb563d41 +default_relationship: http://emmo.info/emmo/top/mereotopology#EMMO_17e27c22_37e1_468c_9dd7_95e137f73e7f +``` +## Keywords - ```sh - pico install emmo - ``` +**identifier**: Can be any alphanumerical string. It is the name of the package +that contains multiple namespaces. Will be used for uninstallation: `pico uninstall emmo`. +(In YAML ontologies this package name or identifier is the same as the namespace name). -Start creating cuds objects. Check the getting-started repository in the SimPhoNy group. +**ontology_file**: Path to the inferred owl ontology. That means you should +have executed a reasoner on your ontology, e.g. by using the `Export inferred axioms` +functionality of [Protégé](https://protege.stanford.edu/). +We support all the formats that [RDFLib](https://rdflib.readthedocs.io/) supports: +RDF/XML, N3, NTriples, N-Quads, Turtle, TriX, RDFa and Microdata. - ```py - >>> from osp.core.namespaces import emmo - >>> n = emmo.Number(value=1) - >>> ... - ``` \ No newline at end of file +**reference_by_label** (default False): Whether the label should be used or the IRI suffix to reference +entity from within OSP-core. In case of EMMO it is true, because IRI suffixes are not +human friendly. In this case all labels should be unique and not contain whitespaces. +If False, use dot notation to get by IRI square brackets (`__getitem__`) to get by label. +The latter will return a list of all entities with the same label. + +**namespaces**: mapping from namespace name (used to import the namespace) to iri prefix. +If IRI doesn't end with "/" or "#", "#" will be added. + +**active relationships**: +List of iris of active relationships. + +**default relationship**: +The default relationship. + +## Installation + +Name the yaml file as you would any yaml file `.yml`, where `` should be replaced by a user defined name. + +Then you can use pico to install the tool [Pico](utils.md#pico-installs-cuds-ontologies) +to install the ontology: + +```sh +pico install +``` + +## Limitations + +At the moment, only the most basic predicates of owl ontologies are used: + +- `RDF.type` to determine the type of the entities. +- `RDFS.label` to get the entities by label. +- `RDFS.isDefinedBy` to get a descriptions for the entities. +- `RDFS.subClassOf` / `RDFS.subPropertyOf` for subclasses. +- `OWL.inverseOf` for inverse relationships. +- `RDFS.range` to determine the datatype of `DataProperties`. These are the supported + datatypes: + - `XSD.boolean` + - `XSD.integer` + - `XSD.float` + - `XSD.string` +- To get the attributes of an owl class, we use + - The `RDFS.domain` of the `DatatypeProperties`, if it is a simple class. + - Restrictions on the ontology classes. + - Furthermore, all DataProperties are considered functional, see [this issue](https://github.com/simphony/osp-core/issues/416). + +No reasoner is included. We plan to include a reasoner in the +future. + +We try to extend this list over time and support more of the +OWL DL standard. diff --git a/docs/source/utils.md b/docs/source/utils.md index 00c6a0d..f219ded 100644 --- a/docs/source/utils.md +++ b/docs/source/utils.md @@ -8,8 +8,8 @@ It is a recursive acronym that stands for _Pico Installs Cuds Ontologies_. There are 3 main things that can be done with pico: - Install ontologies. -- List the install ontologies. -- Removed installed ontologies. +- List the installed ontologies. +- Remove installed ontologies. There are different possible levels of log available, and they can be set via `--log-level `. The default value is `INFO`. @@ -20,44 +20,70 @@ _Usage:_ `pico install |city|cuba` _Behaviour:_ - The ontology file is parsed, and the entities mapped to python objects. - The python classes can be imported via their namespace - `from osp.core import namespace` + `from osp.core.namespaces import namespace` _Example:_ ```console (venv) user@PC:~$ pico install city INFO [osp.core.ontology.installation]: Will install the following namespaces: ['city'] -INFO [osp.core.ontology.parser]: Parsing file city -INFO [osp.core.ontology.installation]: Installation successful! +INFO [osp.core.ontology.yml.yml_parser]: Parsing YAML ontology file /.../osp-core/osp/core/ontology/docs/city.ontology.yml +INFO [osp.core.ontology.yml.yml_parser]: You can now use `from osp.core.namespaces import city`. +INFO [osp.core.ontology.parser]: Loaded 367 ontology triples in total +INFO [osp.core.ontology.installation]: Installation successful ``` ### Pico lists _Usage:_ `pico list` _Behaviour:_ -- The installed namespaces are printed out +- The installed namespaces and packages are printed out. A package can be +uninstalled and can contain many namespaces. A namespace can be imported in code. _Example:_ ```console -(venv) user@PC:~$ pico list -CUBA -CITY +Packages: + - qe + - city +Namespaces: + - xml + - rdf + - rdfs + - xsd + - cuba + - owl + - qe + - city ``` ### Pico uninstalls -_Usage:_ `pico uninstall |"*"` -Note that to select all the namespaces, `"*"` must be quoted. +_Usage:_ `pico uninstall |all`. +Note that to select all the packages, `all` must be quoted. _Behaviour:_ -- All installed namespaces are uninstalled. -- All namespaces except from the uninstalled one are re-installed. +- All installed packages / namespaces are uninstalled. +- All namespaces except the uninstalled ones are re-installed. _Example:_ ```console -(venv) user@PC:~$ pico uninstall city -INFO [osp.core.ontology.installation]: Uninstalling namespace city. -INFO [osp.core.ontology.installation]: Will install the following namespaces: ['cuba'] -INFO [osp.core.ontology.parser]: Parsing file /some/path/ontology.cuba.yml -INFO [osp.core.ontology.installation]: Uninstallation successful! +INFO [osp.core.ontology.installation]: Will install the following namespaces: ['qe'] +INFO [osp.core.ontology.yml.yml_parser]: Parsing YAML ontology file /home//.osp_ontologies/qe.yml +INFO [osp.core.ontology.yml.yml_parser]: You can now use `from osp.core.namespaces import qe`. +INFO [osp.core.ontology.parser]: Loaded 205 ontology triples in total +INFO [osp.core.ontology.installation]: Uninstallation successful +``` + +### Conflicts with other "pico" installations +Some Operating Systems might have a pre-existing tool called _pico_. +In most cases, the previous commands should work, but if any problem arises, +you can use the following alternative: + +```shell +python -m osp.core.pico +``` + +For example: +```shell +python -m osp.core.pico install city ``` ## Tips and tricks @@ -78,7 +104,10 @@ and another one as a [dot](https://www.graphviz.org/pdf/dotguide.pdf) graph ([cu Another useful dot graph visualisation tool called [ontology2dot](#ontology2dot) is available for ontology YML files. -_Note:_ the graphic visualisation tools that generate a dot file require Graphviz to be installed in the system. +```eval_rst +.. warning:: + The graphic visualisation tools that generate a dot file require Graphviz to be installed in the system. +``` ### Pretty print _Location:_ `from osp.core.utils import pretty_print`. @@ -96,43 +125,43 @@ _Example:_ >>> pretty_print(emmo_town) Cuds object named : uuid: 06b01f5a-e8c1-44a5-962d-ea0c726e97d0 - type: CITY.CITY - superclasses: CITY.CITY, CITY.POPULATED_PLACE, CITY.GEOGRAPHICAL_PLACE, CUBA.ENTITY + type: city.City + superclasses: city.City, city.PopulatedPlace, city.GeographicalPlace, cuba.Entity values: coordinates: [42 42] description: To Be Determined - |_Relationship CITY.HAS_INHABITANT: - | - CITY.CITIZEN cuds object named : + |_Relationship city.hasInhabitant: + | - city.Citizen cuds object named : | . uuid: f1bd9143-6472-4b24-94b5-1c5fc4c6e5b6 | . age: 25 - | - CITY.CITIZEN cuds object named : + | - city.Citizen cuds object named : | . uuid: 3b774c96-1a0c-403b-b0d0-05d6cd38c52c | . age: 25 - | - CITY.CITIZEN cuds object named : + | - city.Citizen cuds object named : | . uuid: 40d2335c-a335-4d07-b142-fb2b9b7581a7 | . age: 25 - | - CITY.CITIZEN cuds object named : + | - city.Citizen cuds object named : | . uuid: a5b9282a-ec10-462d-9aa1-9671d8bbe236 | . age: 25 - | - CITY.CITIZEN cuds object named : + | - city.Citizen cuds object named : | . uuid: c7c87209-660f-4a54-9c37-7e50c3164bc9 | . age: 25 - | - CITY.CITIZEN cuds object named : + | - city.Citizen cuds object named : | uuid: d74cfbae-9699-4998-a1e2-8f495a874ced | age: 25 - |_Relationship CITY.HAS_PART: - - CITY.NEIGHBOURHOOD cuds object named : + |_Relationship city.hasPart: + - city.Neighborhood cuds object named : . uuid: 26c4767d-c0ea-4abb-b7b7-7e8702de5de3 . coordinates: [0 0] - . |_Relationship CITY.HAS_PART: - . - CITY.STREET cuds object named : + . |_Relationship city.hasPart: + . - city.Street cuds object named : . . uuid: 23b0ba0d-1601-4824-b6c7-7eb3fdc05a91 . . coordinates: [0 0] - . - CITY.STREET cuds object named : + . - city.Street cuds object named : . uuid: b69d40d0-b919-4df8-8334-b898e4beda83 . coordinates: [0 0] - - CITY.NEIGHBOURHOOD cuds object named : + - city.Neighborhood cuds object named : uuid: 79a214f6-4eb1-4a3b-8908-306129583da1 coordinates: [0 0] @@ -200,7 +229,7 @@ _Examples:_ queried_name = 'Pablo' search.find_cuds_object(criterion = lambda x: queried_name in x.name, root=city_cuds, - rel=CITY.HAS_INHABITANT, + rel=city.hasInhabitant, find_all=True) ``` @@ -210,7 +239,7 @@ _Examples:_ queried_uid = uuid.uuid4() search.find_cuds_object_by_uid(uid=queried_uid, root=city_cuds, - rel=CITY.DEFAULT_REL) + rel=city.get_default_rel()) ``` - To find all the streets that are part of a city: @@ -218,7 +247,7 @@ _Examples:_ ```py search.find_cuds_objects_by_oclass(oclass=city.Street, root=city_cuds, - rel=CITY.HAS_PART) + rel=city.hasPart) ``` - To find all the inhabitants with an attribute `age` with value `26`: @@ -227,5 +256,5 @@ _Examples:_ search.find_cuds_objects_by_attribute(attribute='age', value=26, root=city_cuds, - rel=CITY.HAS_INHABITANT) + rel=city.hasInhabitant) ``` diff --git a/docs/source/wrapper_development.md b/docs/source/wrapper_development.md index fdee97a..f41cb33 100644 --- a/docs/source/wrapper_development.md +++ b/docs/source/wrapper_development.md @@ -1,5 +1,6 @@ # Wrapper development -For an skeleton structure of a wrapper, you can visit the [wrapper development repo](https://gitlab.cc-asp.fraunhofer.de/simphony/wrappers/wrapper-development/). +For an skeleton structure of a wrapper, you can visit the [wrapper development repo](https://github.com/simphony/wrapper-development). +For a tutorial on creating a simple wrapper, there is a [jupyter notebook](jupyter/wrapper_development.md) available. ## Ontology The end goal is to build one, unique and standard ontology with all the relevant entities and relationships. This ontology could use modules where the entities regarding a certain domain are present. @@ -11,11 +12,11 @@ of a correct ontology can be done, and should not require major changes in the c These are the requirements for a minimal wrapper ontology: - Should contain an entity representing the wrapper. - Said entity should inherit from (subclass, is_a) `CUBA.WRAPPER`. -- All attributes should subclass `CUBA.ATTRIBUTE`. -- Top level entities should subclass `CUBA.ENTITY` -- Active relationships should subclass `CUBA.ACTIVE_RELATIONSHIP` -- Passive relationships should subclass `CUBA.PASSIVE_RELATIONSHIP` + Said entity should inherit from (subclass, is_a) `cuba.Wrapper`. +- All attributes should subclass `cuba.attribute`. +- Top level entities should subclass `cuba.Entity` +- Active relationships should subclass `cuba.ActiveRelationship` +- Passive relationships should subclass `cuba.PassiveRelationship`
Dummy ontology sample @@ -26,36 +27,36 @@ These are the requirements for a minimal wrapper ontology: author: Parmenides - namespace: SOME_NEW_WRAPPER_ONTOLOGY + namespace: some_new_wrapper_ontology ontology: - A_RELATIONSHIP: + aRelationship: description: "default relationship" subclass_of: - - CUBA.ACTIVE_RELATIONSHIP - inverse: SOME_NEW_WRAPPER_ONTOLOGY.PIHSNOITALER_A + - cuba.activeRelationship + inverse: some_new_wrapper_ontology.pihsnoitalerA default_rel: true - PIHSNOITALER_A: + pihsnoitalerA: description: "inverse of the default relationship" subclass_of: - - CUBA.PASSIVE_RELATIONSHIP - inverse: SOME_NEW_WRAPPER_ONTOLOGY.A_RELATIONSHIP + - cuba.passiveRelationship + inverse: some_new_wrapper_ontology.aRelationship ################ - SOME_NEW_WRAPPER: + SomeNewWrapper: subclass_of: - - CUBA.WRAPPER + - cuba.Wrapper - VALUE: + value: subclass_of: - - CUBA.ATTRIBUTE + - cuba.attribute - SOME_ENTITY: + SomeEntity: subclass_of: - - CUBA.ENTITY + - cuba.Entity ```
@@ -68,6 +69,7 @@ This allows us to group and clearly define which components should and which one - [Semantic layer](./detailed_design.md#semantic-layer): Requires no work. + As presented in the previous section, only an entity representing the wrapper has to be present in the ontology. - [Interoperability layer](./detailed_design.md#interoperability-layer): - [Session class](./detailed_design.md#session): @@ -93,7 +95,6 @@ This allows us to group and clearly define which components should and which one - [Syntactic layer](./detailed_design.md#syntactic-layer): If none is available, one must be developed. - Only needs an entity representing the wrapper, as presented in the previous section. ## Engine installation Most engines will require some sort of compilation or installation before being able to use them through Python. @@ -214,12 +215,14 @@ The `Dockerfile` for the Container Registry image will be very similar to the on However, here it might be useful to install other libraries like flake8 for style checks. ## Utility functions for wrapper development -We have developed some functions that will probably come in handy when developing a wrapper. You can find them in [osp.core.utils.wrapper_development](https://gitlab.cc-asp.fraunhofer.de/simphony/osp-core/blob/master/osp/core/utils/wrapper_development.py). +We have developed some functions that will probably come in handy when developing a wrapper. +You can find them in [osp.core.utils.wrapper_development](https://github.com/simphony/osp-core/blob/master/osp/core/utils/wrapper_development.py). ## Wrapper Examples Some wrappers we are developing are: - [SQLAlchemy](https://gitlab.cc-asp.fraunhofer.de/simphony/wrappers/sqlalchemy-wrapper) -- [SQLite](https://gitlab.cc-asp.fraunhofer.de/simphony/wrappers/sqlite-wrapper) +- [SQLite](https://github.com/simphony/osp-core/tree/master/osp/wrappers/sqlite) - [SimLammps](https://gitlab.cc-asp.fraunhofer.de/simphony/wrappers/simlammps) - [SimGromacs](https://gitlab.cc-asp.fraunhofer.de/simphony/wrappers/simgromacs) -- [SimOpenFoam](https://gitlab.cc-asp.fraunhofer.de/simphony/wrappers/simopenfoam) \ No newline at end of file +- [SimOpenFoam](https://gitlab.cc-asp.fraunhofer.de/simphony/wrappers/simopenfoam) +- [Quantum Espresso](https://github.com/simphony/quantum-espresso-wrapper) \ No newline at end of file diff --git a/docs/source/yaml.md b/docs/source/yaml.md index 188a9ac..6c659b6 100644 --- a/docs/source/yaml.md +++ b/docs/source/yaml.md @@ -1,13 +1,13 @@ # Description of YAML format Specification -This file describes the ontology format that is used by OSP-core. +This file describes how you can create ontologies using YAML. -## Info - -Contact: [Matthias Urban](mailto:matthias.urban@iwm.fraunhofer.de) and [Pablo de Andres](mailto:pablo.de.andres@iwm.fraunhofer.de) from the -Material Informatics team, Fraunhofer IWM. - -Version: 3.0 pending approval +```eval_rst +.. tip:: + If you have an ontology where all entity names are in ALL_UPPERCASE, + you can use the commandline tool `yaml2camelcase` that is shipped with + OSP-core to transform it to an ontology with CamelCase entity names. +``` ## Introduction @@ -16,19 +16,16 @@ represented in a yaml file format and how to interpret such files. For simplicity reasons in the following we will give examples from the **\* example ontology \*** file which can be found in osp/core/ontology/yml/ontology.city.yml. -What is an ontology? +## Naming of the files and installation -An ontology defines a set of representational primitives with which to -model a domain of knowledge or discourse. The representational -primitives are typically classes (or sets), attributes (or properties), -and relationships (or relations among class members). The definitions of -the representational primitives include information about their meaning -and constraints on their logically consistent application. (Source: -) +Name any ontology `.ontology.yml`, where `` should be replaced by a user defined name. -## Naming of the files +Then you can use pico to install the tool [Pico](#pico-installs-cuds-ontologies) +to install the ontology: -Name any ontolgy `ontology..yml`, where `` should be replaced by a user defined name. +```sh +pico install
+``` ## Syntax of the .yml ontology @@ -43,7 +40,7 @@ Name any ontolgy `ontology..yml`, where `` should be replaced by a u `namespace`: string > Defines the namespace of the current file. We recommend to use - ALL_UPPERCASE for the namespace name, with underscore as separation. + all_lowercase for the namespace name, with underscore as separation. All entities defined in this file will live in the namespace defined here. `requirements`: List[string] @@ -58,7 +55,12 @@ Name any ontolgy `ontology..yml`, where `` should be replaced by a u > Contains individual declarations for ontology entities as a mapping. > Each key of the mapping is the name of an ontology entity. -> The key should be ALL_UPPERCASE, with underscore as separation. +> The key can contain letters, numbers and underscore. +> By convention, they should be in CamelCase. The name of ontology classes +> should start with an uppercase latter, while the name of relationships +> and attributes should start with a lower case letter. +> This key is later used the reference the entity from within OSP-core +> in a case sensitive manner. > The value of the mapping is a mapping whose format is detailed in the > [Ontology entities format](#ontology-entities-format). @@ -76,7 +78,7 @@ Every declaration of an ontology entity must have the following keys: > > The subclass keyword expresses an **ontological is-a** > relation. MUST be a list of a fully qualified strings referring to another entity. -> Only the entity `ENTITY` is allowed to have no superclass. See [CUBA namespace](#the-cuba-namespace). +> Only the entity `cuba.entity` is allowed to have no superclass. See [CUBA namespace](#the-cuba-namespace). > > If entity A is a subclass of B and B is subclass of C, > then A is also subclass of C. @@ -95,31 +97,30 @@ For attributes, these keys are described in The CUBA namespace contains a set of Common Universal Basic entities, that have special meaning in OSP-core. The CUBA namespace is always installed in OSP-core. -`CUBA.ENTITY` -> The entity is the root of the ontology. It is the only entity which does not have a superclass. -> Every other entity is a subclass of `ENTITY`. +`cuba.Entity` +> The root for all ontology classes. Does not have a superclass. -`CUBA.NOTHING` +`cuba.Nothing` > An ontology class, that is not allowed to have individuals. -`CUBA.RELATIONSHIP` -> The root of all relationships. Its direct superclass is `ENTITY`. +`cuba.relationship` +> The root of all relationships. Does not have a superclass. -`CUBA.ATTRIBUTE` -> The root of all attributes. Its direct superclass is `ENTITY`. +`cuba.attribute` +> The root of all attributes. Does not have a superclass. -`CUBA.WRAPPER` +`cuba.Wrapper` > The root of all wrappers. These are the bridge to simulation engines and databases. See the examples in examples/. -`CUBA.ACTIVE_RELATIONSHIP` +`cuba.activeRelationship` > The root of all active relationships. Active relationships express that one cuds object is in the container of another. -`CUBA.PASSIVE_RELATIONSHIP` -> The inverse of `CUBA.ACTIVE_RELATIONSHIP`. +`cuba.passiveRelationship` +> The inverse of `cuba.activeRelationship`. ## Attribute format -Every attribute is a subclass of `ATTRIBUTE`. +Every attribute is a subclass of `cuba.attribute`. The declaration of an attribute is a special case of the declaration of an entity. It must have the keys described in [Ontology entities format](#ontology-entities-format). It can additionally have the following keys: @@ -143,6 +144,7 @@ It can additionally have the following keys: > characters). > - `VECTOR:datatype:D1:D2:...:Dn`: a vector of the given dimensions > (D1 x D2 x ... x Dn) and the given datatype. +> The dimensions are always fixed. > > For example, a VECTOR:INT:4:2:1 would be: \ > { [(a), (b)], [(c), (d)], [(e), (f)], [(g), (h)] } \ @@ -153,7 +155,13 @@ It can additionally have the following keys: > In case a datatype is not specified the default datatype is assumed to > be STRING > -> For example: The datatype of entity NUMBER_OF_OCCURRENCES is INT. +> For example: The datatype of entity numberOfOccurrences is INT. + +> ```eval_rst +>.. note:: +> The implementation of the vectors is experimental and will be updated as soon as +> EMMO has established an appropriate wait of representing them +> ``` ## Class expressions @@ -166,9 +174,9 @@ They can be either: - Requirements on the individual's relationships. For example: ```yaml - CITY.HAS_INHABITANT: + city.hasInhabitant: cardinality: 1+ - range: CITY.CITIZEN + range: city.Citizen exclusive: false ``` @@ -196,8 +204,8 @@ They can be either: ```yaml or: - - CITY.CITY - - CITY.NEIGHBOURHOOD + - city.City + - city.Neighborhood ``` This is the union of all individuals that are a city or a neighbourhood. @@ -209,10 +217,10 @@ The definition of class expressions is recursive. For example: ```yaml or: - - CITY.CITY - - CITY.HAS_PART: + - city.City + - city.hasPart: cardinality: 1+ - range: CITY.NEIGHBOURHOOD + range: city.Neighborhood exclusive: false ``` @@ -226,14 +234,14 @@ It can contain further information: `attributes`: Dict[**\`\`qualified entity name\`\`**, default_value] > Expects a mapping from the **\`\`qualified entity name\`\`** of an attribute to its default. -> Each key must correspond to a subclass of `ATTRIBUTE`. For example: +> Each key must correspond to a subclass of `attribute`. For example: > > ```yaml -> ADDRESS: +> Address: > ... > attributes: -> CITY.NAME: "Street" -> CITY.NUMBER: +> city.name: "Street" +> city.number: > ``` > > Here, an address has a name and a number. @@ -246,12 +254,12 @@ It can contain further information: > individuals are allowed that are in the intersection of the class expressions. For example: > > ```yaml -> POPULATED_PLACE: +> PopulatedPlace: > description: > subclass_of: -> - CITY.GEOGRAPHICAL_PLACE -> - CITY.HAS_INHABITANT: -> range: CITY.CITIZEN +> - city.GeographicalPlace +> - city.hasInhabitant: +> range: city.Citizen > cardinality: many > exclusive: true > ``` @@ -265,12 +273,12 @@ It can contain further information: > A list of class expressions who contain the same individuals as the cuds entity. For example: > > ```yaml -> POPULATED_PLACE: +> PopulatedPlace: > description: > equivalent_to: -> - CITY.GEOGRAPHICAL_PLACE -> - CITY.HAS_INHABITANT: -> range: CITY.CITIZEN +> - city.GeographicalPlace +> - city.hasInhabitant: +> range: city.Citizen > cardinality: many > exclusive: true > ``` @@ -279,16 +287,16 @@ It can contain further information: ## Relationship format -Every relationship is a subclass of `RELATIONSHIP`. +Every relationship is a subclass of `cuba.relationship`. The declaration of a relationship is a special case of the declaration of an entity. It must have the keys described in [Ontology entities format](#ontology-entities-format). Furthermore, it can contain the following information: `inverse`: **\`\`qualified entity name\`\`** or empty (None) -> If CUDS object A is related to CUDS object B via relationship REL, then B is related -> with A via the inverse of REL. +> If CUDS object A is related to CUDS object B via relationship `rel`, then B is related +> with A via the inverse of `rel`. > -> For example: The inverse of HAS\_PART is IS\_PART\_OF. +> For example: The inverse of `hasPart` is `isPartOf`. > > If no inverse is given, OSP-core will automatically create one. @@ -312,3 +320,8 @@ Furthermore, it can contain the following information: > - inversefunctional A subclass of a relationship is called a sub-relationship. + +## Limitations + +`Class expressions`, `domain`, `range`, `characteristics`, `equivalent_to`, `disjoint_with` +are currently not parsed by OSP core. diff --git a/requirements.txt b/requirements.txt index c3eae7d..30c4683 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,7 +1,11 @@ git+https://github.com/simphony/osp-core.git#egg=osp-core sphinx recommonmark +sphinx_rtd_theme sphinxcontrib-plantuml nbsphinx sphinx-copybutton ipython +jupyter +sphinx-jsonschema + diff --git a/setup.py b/setup.py index 3b8e84a..d791c82 100644 --- a/setup.py +++ b/setup.py @@ -29,18 +29,6 @@ def run(self): description='The SimPhoNy documentation', keywords='simphony, documentation, sphinx, cuds, Fraunhofer IWM', long_description=README_TEXT, - install_requires=[ - 'osp-core>=' + OSP_CORE_MIN + ', <' + OSP_CORE_MAX, - 'sphinx', - 'recommonmark', - 'sphinxcontrib-plantuml', - 'nbsphinx', - 'sphinx-copybutton', - 'ipython', - ], - setup_requires=[ - 'sphinx', - ], cmdclass={'install': CustomBuild}, command_options={ 'install': {