diff --git a/docs/developers/operations.ipynb b/docs/developers/operations.ipynb
index a64f244..678ff11 100644
--- a/docs/developers/operations.ipynb
+++ b/docs/developers/operations.ipynb
@@ -1,187 +1,187 @@
{
- "cells": [
- {
- "cell_type": "markdown",
- "id": "edcc1fd6-2474-4d15-8355-084ef85bc748",
- "metadata": {},
- "source": [
- "# Operations development"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e191786a-786a-418e-886a-a4da0c2d741e",
- "metadata": {},
- "source": [
- "SimPhoNy operations are actions (written in Python) that can be executed on\n",
- "demand on any ontology individual belonging to the ontology class they\n",
- "are defined for."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7ea449f9-bc08-4ddc-a8a8-13c6d3ade2ef",
- "metadata": {},
- "source": [
- "
\n",
- "
Tip
\n",
- " \n",
- "File uploads and downloads in SimPhoNy are an example of SimPhoNy operations.\n",
- "Head to the [assertional knowledge](../usage/assertional_knowledge.html#Operations) section to see them in action.\n",
- " \n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ee275d73-f2ef-4418-bc94-cec8458c803c",
- "metadata": {},
- "source": [
- "\n",
- "SimPhoNy operations are distributed as (or as part of) Python packages. \n",
- "Developing operations for an ontology class is fairly simple. To do so, import the [Operations abstract class](../api_reference.md#simphony_osp.development.Operations) from the `simphony_osp.development` module, and create an implementation by subclassing it.\n",
- "\n",
- "Then, define an `iri` attribute having as value the IRI of the ontology class that the\n",
- "operation should be associated to. Every public method ([not starting with\n",
- "an underscore](https://peps.python.org/pep-0008/#method-names-and-instance-variables)) defined on the implementation is automatically detected and\n",
- "assigned as an operation to said ontology class. The\n",
- "[ontology individual object](../usage/assertional_knowledge.ipynb#Ontology-individual-objects)\n",
- "on which the operation is called is available as the private attribute\n",
- "`_individual` on every instance of the implementation. For a specific \n",
- "ontology individual, the implementation gets instantiated the first time that \n",
- "any operation defined on it is called by the user.\n",
- "\n",
- "Finally, define an\n",
- "[entry point](https://packaging.python.org/en/latest/specifications/entry-points/#entry-points-specification)\n",
- "(or many if implementing operations for several ontology classes) under the\n",
- "`simphony_osp.ontology.operations`\n",
- "[group](https://packaging.python.org/en/latest/specifications/entry-points/#data-model)\n",
- "that points to your\n",
- "implementation of the `Operations` abstract class.\n",
- "\n",
- "An example implementation of an operation that takes advantage of\n",
- "[geopy](https://pypi.org/project/geopy/) to compute the distance between \n",
- "two points on Earth defined using the \n",
- "[WGS84 Geo Positioning vocabulary](https://www.w3.org/2003/01/geo/wgs84_pos)\n",
- "is shown below."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0fffa052-186a-46b7-9076-8acfed6b1ee0",
- "metadata": {},
- "source": [
- "```python\n",
- "\"\"\"Operations for classes from the WGS84 Geo Positioning vocabulary.\"\"\"\n",
- "\n",
- "from geopy import distance\n",
- "from simphony_osp.namespaces import wgs84_pos\n",
- "from simphony_osp.ontology import OntologyIndividual\n",
- "from simphony_osp.ontology.operations import Operations\n",
- "\n",
- "\n",
- "class Wgs84Pos(Operations):\n",
- " \"\"\"Operations for the Point ontology class.\"\"\"\n",
- "\n",
- " iri = wgs84_pos.Point.iri\n",
- "\n",
- " def distance(self, other: OntologyIndividual) -> float:\n",
- " \"\"\"Compute the distance between two points on Earth.\n",
- " \n",
- " Args:\n",
- " other: Another point with respect to which the distance will be computed. \n",
- " \n",
- " Returns:\n",
- " The distance between this point and the given one in km.\n",
- " \"\"\"\n",
- " lat_self = float(self._individual[wgs84_pos.latitude].one())\n",
- " long_self = float(self._individual[wgs84_pos.longitude].one())\n",
- " lat_other = float(other[wgs84_pos.latitude].one())\n",
- " long_other = float(other[wgs84_pos.longitude].one())\n",
- " return distance.geodesic(\n",
- " (lat_self, long_self),\n",
- " (lat_other, long_other),\n",
- " ellipsoid=\"WGS-84\"\n",
- " ).km\n",
- "\n",
- "```"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "744e037f-aabe-4bdf-a994-8787f3f039b1",
- "metadata": {},
- "source": [
- "
\n",
- "
Note
\n",
- " \n",
- "Remember that the implementation above is still not enough for the operation to\n",
- "work: the corresponding \n",
- "[entry point](https://packaging.python.org/en/latest/specifications/entry-points/#entry-points-specification)\n",
- "for `Wgs84Pos` must have been defined and the `wgs84_pos` vocabulary needs to be installed using [pico](../usage/ontologies/pico.html).\n",
- " \n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "d3db93d6-e26f-4831-b9a2-d9223cc4a51f",
- "metadata": {},
- "source": [
- "The operation can be used as follows."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "40a97048-80ea-4d99-8711-3ecd6ab5598b",
- "metadata": {},
- "outputs": [
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "edcc1fd6-2474-4d15-8355-084ef85bc748",
+ "metadata": {},
+ "source": [
+ "# Operations development"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e191786a-786a-418e-886a-a4da0c2d741e",
+ "metadata": {},
+ "source": [
+ "SimPhoNy operations are actions (written in Python) that can be executed on\n",
+ "demand on any ontology individual belonging to the ontology class they\n",
+ "are defined for."
+ ]
+ },
{
- "data": {
- "text/plain": [
- "417.4695920611045"
+ "cell_type": "markdown",
+ "id": "7ea449f9-bc08-4ddc-a8a8-13c6d3ade2ef",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Tip
\n",
+ " \n",
+ "File uploads and downloads in SimPhoNy are an example of SimPhoNy operations.\n",
+ "Head to the [assertional knowledge](../usage/assertional_knowledge.html#Operations) section to see them in action.\n",
+ " \n",
+ "
"
]
- },
- "execution_count": 1,
- "metadata": {},
- "output_type": "execute_result"
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ee275d73-f2ef-4418-bc94-cec8458c803c",
+ "metadata": {},
+ "source": [
+ "\n",
+ "SimPhoNy operations are distributed as (or as part of) Python packages. \n",
+ "Developing operations for an ontology class is fairly simple. To do so, import the [Operations abstract class](../api_reference.md#simphony_osp.development.Operations) from the `simphony_osp.development` module, and create an implementation by subclassing it.\n",
+ "\n",
+ "Then, define an `iri` attribute having as value the IRI of the ontology class that the\n",
+ "operation should be associated to. Every public method ([not starting with\n",
+ "an underscore](https://peps.python.org/pep-0008/#method-names-and-instance-variables)) defined on the implementation is automatically detected and\n",
+ "assigned as an operation to said ontology class. The\n",
+ "[ontology individual object](../usage/assertional_knowledge.ipynb#Ontology-individual-objects)\n",
+ "on which the operation is called is available as the private attribute\n",
+ "`_individual` on every instance of the implementation. For a specific \n",
+ "ontology individual, the implementation gets instantiated the first time that \n",
+ "any operation defined on it is called by the user.\n",
+ "\n",
+ "Finally, define an\n",
+ "[entry point](https://packaging.python.org/en/latest/specifications/entry-points/#entry-points-specification)\n",
+ "(or many if implementing operations for several ontology classes) under the\n",
+ "`simphony_osp.ontology.operations`\n",
+ "[group](https://packaging.python.org/en/latest/specifications/entry-points/#data-model)\n",
+ "that points to your\n",
+ "implementation of the `Operations` abstract class.\n",
+ "\n",
+ "An example implementation of an operation that takes advantage of\n",
+ "[geopy](https://pypi.org/project/geopy/) to compute the distance between \n",
+ "two points on Earth defined using the \n",
+ "[WGS84 Geo Positioning vocabulary](https://www.w3.org/2003/01/geo/wgs84_pos)\n",
+ "is shown below."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0fffa052-186a-46b7-9076-8acfed6b1ee0",
+ "metadata": {},
+ "source": [
+ "```python\n",
+ "\"\"\"Operations for classes from the WGS84 Geo Positioning vocabulary.\"\"\"\n",
+ "\n",
+ "from geopy import distance\n",
+ "from simphony_osp.namespaces import wgs84_pos\n",
+ "from simphony_osp.ontology import OntologyIndividual\n",
+ "from simphony_osp.ontology.operations import Operations\n",
+ "\n",
+ "\n",
+ "class Wgs84Pos(Operations):\n",
+ " \"\"\"Operations for the Point ontology class.\"\"\"\n",
+ "\n",
+ " iri = wgs84_pos.Point.iri\n",
+ "\n",
+ " def distance(self, other: OntologyIndividual) -> float:\n",
+ " \"\"\"Compute the distance between two points on Earth.\n",
+ " \n",
+ " Args:\n",
+ " other: Another point with respect to which the distance will be computed. \n",
+ " \n",
+ " Returns:\n",
+ " The distance between this point and the given one in km.\n",
+ " \"\"\"\n",
+ " lat_self = float(self._individual[wgs84_pos.latitude].one())\n",
+ " long_self = float(self._individual[wgs84_pos.longitude].one())\n",
+ " lat_other = float(other[wgs84_pos.latitude].one())\n",
+ " long_other = float(other[wgs84_pos.longitude].one())\n",
+ " return distance.geodesic(\n",
+ " (lat_self, long_self),\n",
+ " (lat_other, long_other),\n",
+ " ellipsoid=\"WGS-84\"\n",
+ " ).km\n",
+ "\n",
+ "```"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "744e037f-aabe-4bdf-a994-8787f3f039b1",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Note
\n",
+ " \n",
+ "Remember that the implementation above is still not enough for the operation to\n",
+ "work: the corresponding \n",
+ "[entry point](https://packaging.python.org/en/latest/specifications/entry-points/#entry-points-specification)\n",
+ "for `Wgs84Pos` must have been defined and the `wgs84_pos` vocabulary needs to be installed using [pico](../usage/ontologies/pico.html).\n",
+ " \n",
+ "
\n",
- " \n",
- "Using the button above, you can launch a Jupyter notebook to follow this tutorial without even having to install SimPhoNy.\n",
- " \n",
- "
\n",
- "\n",
- "\n",
- "This tutorial offers a quick first-contact with SimPhoNy. The learning objectives are:\n",
- "\n",
- "- Convey the purpose of SimPhoNy\n",
- "- Manage the installed ontologies\n",
- "- Use the installed ontologies to instantiate ontology individuals\n",
- "- Demonstrate the usage of wrappers to achieve interoperability\n",
- "\n",
- "Following the tutorial on your own machine requires the installation of [SimPhoNy](../installation.md#installation) and the [SimLAMMPS](https://github.com/simphony/simphony-osp-simlammps) wrapper. We recommend that you use the button above to follow the tutorial online using Binder."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "648d8664-4cac-404d-9580-3ae9cd0a6b5c",
- "metadata": {},
- "source": [
- "## Ontologies"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "8d7e260f-ecb6-487b-b550-47677d2821c1",
- "metadata": {},
- "source": [
- "SimPhoNy enables you to manage data that is based on ontologies. This means that all information is represented in terms of _ontology individuals_. Individuals belong to a specific _ontology class_, have specific _attributes_ and can be connected to other individuals through _relationships_. Classes, attributes and relationships are defined in ontologies. Therefore, in order for SimPhoNy to be able to properly interpret the data, such ontologies need to be installed. For that purpose, SimPhoNy includes an ontology management tool called _pico_."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "415d9ee0-6672-482a-a8d7-f0a2f77ed124",
- "metadata": {},
- "source": [
- "In this tutorial, you will work, among others, with the SimLAMMPS wrapper. This wrapper only understands data based on the SimLAMMPS ontology, which is included with it. Therefore, you will start by installing such ontology."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "98b3f4e3-2943-46dc-8c30-41870e2e2183",
- "metadata": {},
- "source": [
- "_pico_ works with so-called \"ontology packages\". Ontology packages are just a pointer to an ontology file with some additional metadata defined on it, such as the namespaces that the ontology includes or a name for the package. You can learn to create your own packages here."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "00fcc98d-b3a7-4c1d-9b9f-af3edebd9c01",
- "metadata": {},
- "source": [
- "To install the desired ontology use the command `pico install` and provide the path to the ontology package."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "5a9b1ce4-e9bb-4c59-afd6-0e4e733a0bd3",
- "metadata": {},
- "outputs": [],
- "source": [
- "# if you are running the tutorial online using Binder, then the simlammps\n",
- "# ontology is already pre-installed\n",
- "\n",
- "# otherwise, download `simlammps.ttl` and `simlammps.yml` from \n",
- "# https://github.com/simphony/simlammps/tree/v4.0.0/simphony_osp_simlammps\n",
- "# and run\n",
- "\n",
- "#!pico install simlammps.yml"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "bd1bd1a5-8cdf-4a46-b86a-f58eb44573ab",
- "metadata": {},
- "source": [
- "_pico_ will install the ontology. After the installation is complete, it is listed among the installed ontology packages when running the `pico list` command."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "320f4159-f306-4755-a1e2-c1b5ff97e7ae",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Packages:\n",
- "\t- simlammps\n",
- "Namespaces:\n",
- "\t- simphony\n",
- "\t- owl\n",
- "\t- rdfs\n",
- "\t- simlammps\n"
- ]
- }
- ],
- "source": [
- "!pico list"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "489d9c00-fd53-4751-a389-b2bffe9c9517",
- "metadata": {},
- "source": [
- "That's all! Everything is ready to start using SimPhoNy. "
- ]
- },
- {
- "cell_type": "markdown",
- "id": "7501ee0c-23f5-40c4-962d-2f7cdb392466",
- "metadata": {},
- "source": [
- "## Data and sessions"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "ede3e762-ce82-477f-aa9f-4a300020de4d",
- "metadata": {},
- "source": [
- "The simplest way to start working with some data is the following.\n",
- "\n",
- "1. Import an installed _ontology namespace_. Namespaces agglomerate the ontology classes, relationships, and attributes included in an ontology. Namespaces come bundled with ontology packages, so that one ontology package can provide several namespaces.\n",
- "2. Retrieve a class from the namespace and use it to create an ontology individual.\n",
- "3. Assign attributes or connect the individual with others.\n",
- "\n",
- "In the example below, first the `simlammps` namespace from the previously installed ontology is imported, then two ontology individuals of classes _Atom_ and _Position_ are created. After that, the individual of class Atom is linked to the individual of class Position through the relationship _hasPart_, and finally some coordinates are assigned to the individual of class Position."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "d81a8471-2c97-48d3-b2ca-50c7cdf5a780",
- "metadata": {},
- "outputs": [],
- "source": [
- "from simphony_osp.namespaces import simlammps\n",
- "\n",
- "atom, position = simlammps.Atom(), simlammps.Position(vector=[1, 0, 3])\n",
- "atom[simlammps.hasPart] = position\n",
- "\n",
- "atom.label = \"My Atom\"\n",
- "position.label = \"My Atom's position\""
- ]
- },
- {
- "cell_type": "markdown",
- "id": "586d7063-5034-4cb2-b210-97b8b235ad14",
- "metadata": {},
- "source": [
- "SimPhoNy includes a visualization tool that can draw a graph containing any ontology individuals you desire, their attributes, and the relationships connecting them. Using it, the dataset that has just been created may be visualized."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "f214d5c7-85e2-4396-8183-b32202e39968",
- "metadata": {
- "tags": []
- },
- "outputs": [
- {
- "data": {
- "image/svg+xml": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "803ff440-2093-4455-96ba-214d9fc0f91b",
+ "metadata": {},
+ "source": [
+ "# Quickstart"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1921410c-6d62-4322-abe9-8f0390368168",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "
\n",
+ "
Tip
\n",
+ " \n",
+ "Using the button above, you can launch a Jupyter notebook to follow this tutorial without even having to install SimPhoNy.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "\n",
+ "This tutorial offers a quick first-contact with SimPhoNy. The learning objectives are:\n",
+ "\n",
+ "- Convey the purpose of SimPhoNy\n",
+ "- Manage the installed ontologies\n",
+ "- Use the installed ontologies to instantiate ontology individuals\n",
+ "- Demonstrate the usage of wrappers to achieve interoperability\n",
+ "\n",
+ "Following the tutorial on your own machine requires the installation of [SimPhoNy](../installation.md#installation) and the [SimLAMMPS](https://github.com/simphony/simphony-osp-simlammps) wrapper. We recommend that you use the button above to follow the tutorial online using Binder."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "648d8664-4cac-404d-9580-3ae9cd0a6b5c",
+ "metadata": {},
+ "source": [
+ "## Ontologies"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8d7e260f-ecb6-487b-b550-47677d2821c1",
+ "metadata": {},
+ "source": [
+ "SimPhoNy enables you to manage data that is based on ontologies. This means that all information is represented in terms of _ontology individuals_. Individuals belong to a specific _ontology class_, have specific _attributes_ and can be connected to other individuals through _relationships_. Classes, attributes and relationships are defined in ontologies. Therefore, in order for SimPhoNy to be able to properly interpret the data, such ontologies need to be installed. For that purpose, SimPhoNy includes an ontology management tool called _pico_."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "415d9ee0-6672-482a-a8d7-f0a2f77ed124",
+ "metadata": {},
+ "source": [
+ "In this tutorial, you will work, among others, with the SimLAMMPS wrapper. This wrapper only understands data based on the SimLAMMPS ontology, which is included with it. Therefore, you will start by installing such ontology."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "98b3f4e3-2943-46dc-8c30-41870e2e2183",
+ "metadata": {},
+ "source": [
+ "_pico_ works with so-called \"ontology packages\". Ontology packages are just a pointer to an ontology file with some additional metadata defined on it, such as the namespaces that the ontology includes or a name for the package. You can learn to create your own packages here."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "00fcc98d-b3a7-4c1d-9b9f-af3edebd9c01",
+ "metadata": {},
+ "source": [
+ "To install the desired ontology use the command `pico install` and provide the path to the ontology package."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "5a9b1ce4-e9bb-4c59-afd6-0e4e733a0bd3",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# if you are running the tutorial online using Binder, then the simlammps\n",
+ "# ontology is already pre-installed\n",
+ "\n",
+ "# otherwise, download `simlammps.ttl` and `simlammps.yml` from \n",
+ "# https://github.com/simphony/simlammps/tree/v4.0.0/simphony_osp_simlammps\n",
+ "# and run\n",
+ "\n",
+ "#!pico install simlammps.yml"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bd1bd1a5-8cdf-4a46-b86a-f58eb44573ab",
+ "metadata": {},
+ "source": [
+ "_pico_ will install the ontology. After the installation is complete, it is listed among the installed ontology packages when running the `pico list` command."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "320f4159-f306-4755-a1e2-c1b5ff97e7ae",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Packages:\n",
+ "\t- simlammps\n",
+ "Namespaces:\n",
+ "\t- simphony\n",
+ "\t- owl\n",
+ "\t- rdfs\n",
+ "\t- simlammps\n"
+ ]
+ }
],
- "text/plain": [
- ""
+ "source": [
+ "!pico list"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "489d9c00-fd53-4751-a389-b2bffe9c9517",
+ "metadata": {},
+ "source": [
+ "That's all! Everything is ready to start using SimPhoNy. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "7501ee0c-23f5-40c4-962d-2f7cdb392466",
+ "metadata": {},
+ "source": [
+ "## Data and sessions"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "ede3e762-ce82-477f-aa9f-4a300020de4d",
+ "metadata": {},
+ "source": [
+ "The simplest way to start working with some data is the following.\n",
+ "\n",
+ "1. Import an installed _ontology namespace_. Namespaces agglomerate the ontology classes, relationships, and attributes included in an ontology. Namespaces come bundled with ontology packages, so that one ontology package can provide several namespaces.\n",
+ "2. Retrieve a class from the namespace and use it to create an ontology individual.\n",
+ "3. Assign attributes or connect the individual with others.\n",
+ "\n",
+ "In the example below, first the `simlammps` namespace from the previously installed ontology is imported, then two ontology individuals of classes _Atom_ and _Position_ are created. After that, the individual of class Atom is linked to the individual of class Position through the relationship _hasPart_, and finally some coordinates are assigned to the individual of class Position."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "d81a8471-2c97-48d3-b2ca-50c7cdf5a780",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from simphony_osp.namespaces import simlammps\n",
+ "\n",
+ "atom, position = simlammps.Atom(), simlammps.Position(vector=[1, 0, 3])\n",
+ "atom[simlammps.hasPart] = position\n",
+ "\n",
+ "atom.label = \"My Atom\"\n",
+ "position.label = \"My Atom's position\""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "586d7063-5034-4cb2-b210-97b8b235ad14",
+ "metadata": {},
+ "source": [
+ "SimPhoNy includes a visualization tool that can draw a graph containing any ontology individuals you desire, their attributes, and the relationships connecting them. Using it, the dataset that has just been created may be visualized."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "f214d5c7-85e2-4396-8183-b32202e39968",
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from simphony_osp.tools import semantic2dot\n",
+ "\n",
+ "semantic2dot(atom, position)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "2cf6770f-8708-4d2a-acc3-b346fea9e826",
+ "metadata": {},
+ "source": [
+ "But... Where are actually the atom and the position stored? If a new atom is created running `atom = simlammps.Atom()` again, what happens to the old atom, how can it be retrieved?"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d57e226b-f906-4be7-b434-953c26dae804",
+ "metadata": {},
+ "source": [
+ "SimPhoNy stores data in the so-called _sessions_. You may think of a session as a \"box\" were ontology idividuals can be placed. The magic lies within the fact that sessions can provide _views_ into different data sources and software products, thanks to the SimPhoNy Wrapper mechanism. This means that you see a \"box\" containing ontology entitites, but behind the scenes, SimPhoNy is translating this information so that it can be used by the underlying data source or software."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "9bb30c91-98df-4a0b-81a0-0d92fe7ae14c",
+ "metadata": {},
+ "source": [
+ "But still, this does not clarify the issue. To which session did the atom and the position go? When you do not specify any session, objects are created by default on the so-called _Core Session_, which is the default session of SimPhoNy. You may access the default session at any time by importing it."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "b7ff9d9d-faf1-4681-afab-8e34905df95b",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[,\n",
+ " ]"
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from simphony_osp.session import core_session\n",
+ "\n",
+ "list(core_session)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "0fd68c98-022d-46a8-a50d-8676d81c5f66",
+ "metadata": {},
+ "source": [
+ "Now it is clear that the atom and its position are stored on the Core Session. Be aware that the Core Session is only meant to serve as a way to quickly test SimPhoNy or be a transient place to store information, as all of its contents are **lost** when you close the Python shell."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "bb7edb1c-a729-4654-abf7-bdab60b09659",
+ "metadata": {},
+ "source": [
+ "## Wrappers"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "b26c880d-2ec5-4d49-991e-1dc7bad2ba82",
+ "metadata": {},
+ "source": [
+ "Wrappers are sessions that are connected to data sources or other software. When you use then, you see a \"box\" filled with ontology entitites, but behind the scenes, they do the necessary computations to store your data on said data sources or transfer it to the software."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6019dc3e-fb81-48af-b120-e767c3e11af5",
+ "metadata": {},
+ "source": [
+ "In this example, the SQLite (included with SimPhoNy) and [SimLAMMPS](https://github.com/simphony/simphony-osp-simlammps) wrappers are used."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "f0fbd5ce-3d2f-4004-a391-a84afae50ed6",
+ "metadata": {},
+ "source": [
+ "First, start by creating an SQLite session. In this session, create three atoms, with their respective positions and velocities, and then commit the changes."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "5e467ea3-2e9f-4bf3-a143-eed224e46da9",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from simphony_osp.wrappers import SQLite\n",
+ "\n",
+ "with SQLite('atoms.db', create=True) as session:\n",
+ " \n",
+ " atom = simlammps.Atom(); atom.label = 'Atom 0'\n",
+ " position = simlammps.Position(vector=[1, 0, 0]); position.label = 'Position 0'\n",
+ " velocity = simlammps.Velocity(vector=[0, 1, 0]); velocity.label = 'Velocity 0'\n",
+ " atom[simlammps.hasPart] = {position, velocity}\n",
+ " \n",
+ " atom = simlammps.Atom(); atom.label = 'Atom 1'\n",
+ " position = simlammps.Position(vector=[1, 0, 1]); position.label = 'Position 1'\n",
+ " velocity = simlammps.Velocity(vector=[3, 1, 0]); velocity.label = 'Velocity 1'\n",
+ " atom[simlammps.hasPart] = {position, velocity}\n",
+ " \n",
+ " atom = simlammps.Atom(); atom.label = 'Atom 2'\n",
+ " position = simlammps.Position(vector=[1, 1, 0]); position.label = 'Position 2'\n",
+ " velocity = simlammps.Velocity(vector=[0, 1, 2]); velocity.label = 'Velocity 2'\n",
+ " atom[simlammps.hasPart] = {position, velocity}\n",
+ " \n",
+ " session.commit()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "6546b0e8-8d72-4ff7-9789-72776aa99d7f",
+ "metadata": {},
+ "source": [
+ "When the session is opened again, the atoms are still there!"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "54b46e51-8843-42b6-93f9-00e02fa045ec",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "[, , , , , , , , ]\n"
+ ]
+ }
+ ],
+ "source": [
+ "with SQLite('atoms.db', create=False) as session:\n",
+ " print(list(session))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1467b0af-4741-469d-be57-e52b1548d0d2",
+ "metadata": {},
+ "source": [
+ "The next step is to copy these atoms to a SimLAMMPS session and run a simulation."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "6ba94bf5-4094-455a-82ed-a41cc96916fe",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "LAMMPS output is captured by PyLammps wrapper\n",
+ "LAMMPS (23 Jun 2022 - Update 1)\n",
+ "OMP_NUM_THREADS environment is not set. Defaulting to 1 thread. (src/comm.cpp:98)\n",
+ " using 1 OpenMP thread(s) per MPI task\n"
+ ]
+ },
+ {
+ "name": "stderr",
+ "output_type": "stream",
+ "text": [
+ "--------------------------------------------------------------------------\n",
+ "The library attempted to open the following supporting CUDA libraries,\n",
+ "but each of them failed. CUDA-aware support is disabled.\n",
+ "libcuda.so.1: cannot open shared object file: No such file or directory\n",
+ "libcuda.dylib: cannot open shared object file: No such file or directory\n",
+ "/usr/lib64/libcuda.so.1: cannot open shared object file: No such file or directory\n",
+ "/usr/lib64/libcuda.dylib: cannot open shared object file: No such file or directory\n",
+ "If you are not interested in CUDA-aware support, then run with\n",
+ "--mca opal_warn_on_missing_libcuda 0 to suppress this message. If you are interested\n",
+ "in CUDA-aware support, then try setting LD_LIBRARY_PATH to the location\n",
+ "of libcuda.so.1 to get passed this issue.\n",
+ "--------------------------------------------------------------------------\n"
+ ]
+ }
+ ],
+ "source": [
+ "from simphony_osp.wrappers import SimLAMMPS\n",
+ "\n",
+ "# open the SQLite database and create a new SimLAMMPS session\n",
+ "sqlite_session = SQLite('atoms.db', create=False)\n",
+ "simlammps_session = SimLAMMPS()\n",
+ "\n",
+ "# prevent closing the sessions when leaving the contexts after \n",
+ "# using the `with` statement\n",
+ "sqlite_session.locked = True\n",
+ "simlammps_session.locked = True\n",
+ "\n",
+ "# copy the individuals from the SQLite session to the SimLAMMPS session\n",
+ "ontology_individuals_from_database = list(sqlite_session)\n",
+ "simlammps_session.add(ontology_individuals_from_database);"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "id": "38e1c393-4b09-4fb6-8c84-0d9bc3065a24",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "with simlammps_session:\n",
+ " # a few additional entities that were omitted before for brevity\n",
+ " # are needed to configure the simulation and are created now\n",
+ " \n",
+ " # material\n",
+ " mass = simlammps.Mass(value=0.2)\n",
+ " material = simlammps.Material()\n",
+ " material[simlammps.hasPart] += mass\n",
+ " for atom in simlammps_session.get(oclass=simlammps.Atom):\n",
+ " atom[simlammps.hasPart] += material\n",
+ " \n",
+ " # simulation box\n",
+ " box = simlammps.SimulationBox()\n",
+ " face_x = simlammps.FaceX(vector=(10, 0, 0))\n",
+ " face_x[simlammps.hasPart] += simlammps.Periodic()\n",
+ " face_y = simlammps.FaceY(vector=(0, 10, 0))\n",
+ " face_y[simlammps.hasPart] += simlammps.Periodic()\n",
+ " face_z = simlammps.FaceZ(vector=(0, 0, 10))\n",
+ " face_z[simlammps.hasPart] += simlammps.Periodic()\n",
+ " box[simlammps.hasPart] += {face_x, face_y, face_z}\n",
+ " \n",
+ " # molecular dynamics model\n",
+ " md_nve = simlammps.MolecularDynamics()\n",
+ "\n",
+ " # solver component\n",
+ " sp = simlammps.SolverParameter()\n",
+ "\n",
+ " # integration time\n",
+ " steps = 100\n",
+ " itime = simlammps.IntegrationTime(steps=steps)\n",
+ " sp[simlammps.hasPart] += itime\n",
+ " \n",
+ " # verlet\n",
+ " verlet = simlammps.Verlet()\n",
+ " sp[simlammps.hasPart] += verlet\n",
+ "\n",
+ " # define the interatomic force as material relation\n",
+ " lj = simlammps.LennardJones612(\n",
+ " cutoffDistance=2.5, energyWellDepth=1.0, vanDerWaalsRadius=1.0\n",
+ " )\n",
+ " lj[simlammps.hasPart] += material"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "id": "f7dd7981-da6f-4e78-9cc9-fda4902d1796",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# the simulation is now ready to be run\n",
+ "simlammps_session.compute()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "894eeb42-b253-4fb0-8618-b97e6211fe09",
+ "metadata": {},
+ "source": [
+ "After running the simulation, the data in the SQLite database can be overwritten with the new data."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "id": "e658666c-7e3b-497f-b224-eefa929526ce",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# finally, the data in the sqlite database can be overwritten\n",
+ "# with the new data\n",
+ "sqlite_session.add(\n",
+ " simlammps_session,\n",
+ " exists_ok = True,\n",
+ " merge = False, # overwrite an entity if it already exists\n",
+ ")\n",
+ "sqlite_session.commit()\n",
+ "\n",
+ "# and both sessions can be closed\n",
+ "sqlite_session.close(), simlammps_session.close();"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "1b98fc6a-2b22-4b1a-b589-d154c6edb83a",
+ "metadata": {},
+ "source": [
+ "As expected, if the saved atoms are now examined, their positions and velicities have changed."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "id": "b135c220-b089-4459-a0fa-8253905ee4ba",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Atom 0:\n",
+ " - Position [1.09604332 9.98007699 9.56039398]\n",
+ " - Velocity [ 0.36107337 0.40331728 -0.30807669]\n",
+ "Atom 1:\n",
+ " - Position [2.23711536 0.99949841 1.09814967]\n",
+ " - Velocity [ 2.68929927 1.9921991 -0.5872734 ]\n",
+ "Atom 2:\n",
+ " - Position [1.16684132 1.5204246 1.34145635]\n",
+ " - Velocity [-0.05037264 0.60448362 2.89535009]\n"
+ ]
+ }
+ ],
+ "source": [
+ "with SQLite('atoms.db', create=False) as session:\n",
+ " for i, atom in enumerate(session.get(oclass=simlammps.Atom)):\n",
+ " velocity = atom.get(oclass=simlammps.Velocity).one()\n",
+ " position = atom.get(oclass=simlammps.Position).one()\n",
+ " print(\n",
+ " f\"{atom.label}:\\n\"\n",
+ " f\" - Position {position.vector}\\n\"\n",
+ " f\" - Velocity {velocity.vector}\"\n",
+ " )"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "98746142-b5ea-449e-bdd0-92d67f43be0b",
+ "metadata": {},
+ "source": [
+ "That's all! This was just a quick overview of the usage and purpose of SimPhoNy. Keep reading the documentation to learn more."
]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from simphony_osp.tools import semantic2dot\n",
- "\n",
- "semantic2dot(atom, position)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "2cf6770f-8708-4d2a-acc3-b346fea9e826",
- "metadata": {},
- "source": [
- "But... Where are actually the atom and the position stored? If a new atom is created running `atom = simlammps.Atom()` again, what happens to the old atom, how can it be retrieved?"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "d57e226b-f906-4be7-b434-953c26dae804",
- "metadata": {},
- "source": [
- "SimPhoNy stores data in the so-called _sessions_. You may think of a session as a \"box\" were ontology idividuals can be placed. The magic lies within the fact that sessions can provide _views_ into different data sources and software products, thanks to the SimPhoNy Wrapper mechanism. This means that you see a \"box\" containing ontology entitites, but behind the scenes, SimPhoNy is translating this information so that it can be used by the underlying data source or software."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "9bb30c91-98df-4a0b-81a0-0d92fe7ae14c",
- "metadata": {},
- "source": [
- "But still, this does not clarify the issue. To which session did the atom and the position go? When you do not specify any session, objects are created by default on the so-called _Core Session_, which is the default session of SimPhoNy. You may access the default session at any time by importing it."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "b7ff9d9d-faf1-4681-afab-8e34905df95b",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "[,\n",
- " ]"
- ]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from simphony_osp.session import core_session\n",
- "\n",
- "list(core_session)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "0fd68c98-022d-46a8-a50d-8676d81c5f66",
- "metadata": {},
- "source": [
- "Now it is clear that the atom and its position are stored on the Core Session. Be aware that the Core Session is only meant to serve as a way to quickly test SimPhoNy or be a transient place to store information, as all of its contents are **lost** when you close the Python shell."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "bb7edb1c-a729-4654-abf7-bdab60b09659",
- "metadata": {},
- "source": [
- "## Wrappers"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "b26c880d-2ec5-4d49-991e-1dc7bad2ba82",
- "metadata": {},
- "source": [
- "Wrappers are sessions that are connected to data sources or other software. When you use then, you see a \"box\" filled with ontology entitites, but behind the scenes, they do the necessary computations to store your data on said data sources or transfer it to the software."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6019dc3e-fb81-48af-b120-e767c3e11af5",
- "metadata": {},
- "source": [
- "In this example, the SQLite (included with SimPhoNy) and [SimLAMMPS](https://github.com/simphony/simphony-osp-simlammps) wrappers are used."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "f0fbd5ce-3d2f-4004-a391-a84afae50ed6",
- "metadata": {},
- "source": [
- "First, start by creating an SQLite session. In this session, create three atoms, with their respective positions and velocities, and then commit the changes."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "id": "5e467ea3-2e9f-4bf3-a143-eed224e46da9",
- "metadata": {},
- "outputs": [],
- "source": [
- "from simphony_osp.wrappers import SQLite\n",
- "\n",
- "with SQLite('atoms.db', create=True) as session:\n",
- " \n",
- " atom = simlammps.Atom(); atom.label = 'Atom 0'\n",
- " position = simlammps.Position(vector=[1, 0, 0]); position.label = 'Position 0'\n",
- " velocity = simlammps.Velocity(vector=[0, 1, 0]); velocity.label = 'Velocity 0'\n",
- " atom[simlammps.hasPart] = {position, velocity}\n",
- " \n",
- " atom = simlammps.Atom(); atom.label = 'Atom 1'\n",
- " position = simlammps.Position(vector=[1, 0, 1]); position.label = 'Position 1'\n",
- " velocity = simlammps.Velocity(vector=[3, 1, 0]); velocity.label = 'Velocity 1'\n",
- " atom[simlammps.hasPart] = {position, velocity}\n",
- " \n",
- " atom = simlammps.Atom(); atom.label = 'Atom 2'\n",
- " position = simlammps.Position(vector=[1, 1, 0]); position.label = 'Position 2'\n",
- " velocity = simlammps.Velocity(vector=[0, 1, 2]); velocity.label = 'Velocity 2'\n",
- " atom[simlammps.hasPart] = {position, velocity}\n",
- " \n",
- " session.commit()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "6546b0e8-8d72-4ff7-9789-72776aa99d7f",
- "metadata": {},
- "source": [
- "When the session is opened again, the atoms are still there!"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "id": "54b46e51-8843-42b6-93f9-00e02fa045ec",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "[, , , , , , , , ]\n"
- ]
- }
- ],
- "source": [
- "with SQLite('atoms.db', create=False) as session:\n",
- " print(list(session))"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "1467b0af-4741-469d-be57-e52b1548d0d2",
- "metadata": {},
- "source": [
- "The next step is to copy these atoms to a SimLAMMPS session and run a simulation."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "id": "6ba94bf5-4094-455a-82ed-a41cc96916fe",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "LAMMPS output is captured by PyLammps wrapper\n",
- "LAMMPS (23 Jun 2022 - Update 1)\n",
- "OMP_NUM_THREADS environment is not set. Defaulting to 1 thread. (src/comm.cpp:98)\n",
- " using 1 OpenMP thread(s) per MPI task\n"
- ]
- },
- {
- "name": "stderr",
- "output_type": "stream",
- "text": [
- "--------------------------------------------------------------------------\n",
- "The library attempted to open the following supporting CUDA libraries,\n",
- "but each of them failed. CUDA-aware support is disabled.\n",
- "libcuda.so.1: cannot open shared object file: No such file or directory\n",
- "libcuda.dylib: cannot open shared object file: No such file or directory\n",
- "/usr/lib64/libcuda.so.1: cannot open shared object file: No such file or directory\n",
- "/usr/lib64/libcuda.dylib: cannot open shared object file: No such file or directory\n",
- "If you are not interested in CUDA-aware support, then run with\n",
- "--mca opal_warn_on_missing_libcuda 0 to suppress this message. If you are interested\n",
- "in CUDA-aware support, then try setting LD_LIBRARY_PATH to the location\n",
- "of libcuda.so.1 to get passed this issue.\n",
- "--------------------------------------------------------------------------\n"
- ]
}
- ],
- "source": [
- "from simphony_osp.wrappers import SimLAMMPS\n",
- "\n",
- "# open the SQLite database and create a new SimLAMMPS session\n",
- "sqlite_session = SQLite('atoms.db', create=False)\n",
- "simlammps_session = SimLAMMPS()\n",
- "\n",
- "# prevent closing the sessions when leaving the contexts after \n",
- "# using the `with` statement\n",
- "sqlite_session.locked = True\n",
- "simlammps_session.locked = True\n",
- "\n",
- "# copy the individuals from the SQLite session to the SimLAMMPS session\n",
- "ontology_individuals_from_database = list(sqlite_session)\n",
- "simlammps_session.add(ontology_individuals_from_database);"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "id": "38e1c393-4b09-4fb6-8c84-0d9bc3065a24",
- "metadata": {},
- "outputs": [],
- "source": [
- "with simlammps_session:\n",
- " # a few additional entities that were omitted before for brevity\n",
- " # are needed to configure the simulation and are created now\n",
- " \n",
- " # material\n",
- " mass = simlammps.Mass(value=0.2)\n",
- " material = simlammps.Material()\n",
- " material[simlammps.hasPart] += mass\n",
- " for atom in simlammps_session.get(oclass=simlammps.Atom):\n",
- " atom[simlammps.hasPart] += material\n",
- " \n",
- " # simulation box\n",
- " box = simlammps.SimulationBox()\n",
- " face_x = simlammps.FaceX(vector=(10, 0, 0))\n",
- " face_x[simlammps.hasPart] += simlammps.Periodic()\n",
- " face_y = simlammps.FaceY(vector=(0, 10, 0))\n",
- " face_y[simlammps.hasPart] += simlammps.Periodic()\n",
- " face_z = simlammps.FaceZ(vector=(0, 0, 10))\n",
- " face_z[simlammps.hasPart] += simlammps.Periodic()\n",
- " box[simlammps.hasPart] += {face_x, face_y, face_z}\n",
- " \n",
- " # molecular dynamics model\n",
- " md_nve = simlammps.MolecularDynamics()\n",
- "\n",
- " # solver component\n",
- " sp = simlammps.SolverParameter()\n",
- "\n",
- " # integration time\n",
- " steps = 100\n",
- " itime = simlammps.IntegrationTime(steps=steps)\n",
- " sp[simlammps.hasPart] += itime\n",
- " \n",
- " # verlet\n",
- " verlet = simlammps.Verlet()\n",
- " sp[simlammps.hasPart] += verlet\n",
- "\n",
- " # define the interatomic force as material relation\n",
- " lj = simlammps.LennardJones612(\n",
- " cutoffDistance=2.5, energyWellDepth=1.0, vanDerWaalsRadius=1.0\n",
- " )\n",
- " lj[simlammps.hasPart] += material"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "id": "f7dd7981-da6f-4e78-9cc9-fda4902d1796",
- "metadata": {},
- "outputs": [],
- "source": [
- "# the simulation is now ready to be run\n",
- "simlammps_session.compute()"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "894eeb42-b253-4fb0-8618-b97e6211fe09",
- "metadata": {},
- "source": [
- "After running the simulation, the data in the SQLite database can be overwritten with the new data."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "id": "e658666c-7e3b-497f-b224-eefa929526ce",
- "metadata": {},
- "outputs": [],
- "source": [
- "# finally, the data in the sqlite database can be overwritten\n",
- "# with the new data\n",
- "sqlite_session.add(\n",
- " simlammps_session,\n",
- " exists_ok = True,\n",
- " merge = False, # overwrite an entity if it already exists\n",
- ")\n",
- "sqlite_session.commit()\n",
- "\n",
- "# and both sessions can be closed\n",
- "sqlite_session.close(), simlammps_session.close();"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "1b98fc6a-2b22-4b1a-b589-d154c6edb83a",
- "metadata": {},
- "source": [
- "As expected, if the saved atoms are now examined, their positions and velicities have changed."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "id": "b135c220-b089-4459-a0fa-8253905ee4ba",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Atom 0:\n",
- " - Position [1.09604332 9.98007699 9.56039398]\n",
- " - Velocity [ 0.36107337 0.40331728 -0.30807669]\n",
- "Atom 1:\n",
- " - Position [2.23711536 0.99949841 1.09814967]\n",
- " - Velocity [ 2.68929927 1.9921991 -0.5872734 ]\n",
- "Atom 2:\n",
- " - Position [1.16684132 1.5204246 1.34145635]\n",
- " - Velocity [-0.05037264 0.60448362 2.89535009]\n"
- ]
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "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.10.7"
}
- ],
- "source": [
- "with SQLite('atoms.db', create=False) as session:\n",
- " for i, atom in enumerate(session.get(oclass=simlammps.Atom)):\n",
- " velocity = atom.get(oclass=simlammps.Velocity).one()\n",
- " position = atom.get(oclass=simlammps.Position).one()\n",
- " print(\n",
- " f\"{atom.label}:\\n\"\n",
- " f\" - Position {position.vector}\\n\"\n",
- " f\" - Velocity {velocity.vector}\"\n",
- " )"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "98746142-b5ea-449e-bdd0-92d67f43be0b",
- "metadata": {},
- "source": [
- "That's all! This was just a quick overview of the usage and purpose of SimPhoNy. Keep reading the documentation to learn more."
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3 (ipykernel)",
- "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.10.7"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
+ "nbformat": 4,
+ "nbformat_minor": 5
}
diff --git a/docs/usage/assertional_knowledge.ipynb b/docs/usage/assertional_knowledge.ipynb
index de64e29..ecfd1d2 100644
--- a/docs/usage/assertional_knowledge.ipynb
+++ b/docs/usage/assertional_knowledge.ipynb
@@ -1,1170 +1,1170 @@
{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Assertional knowledge\n",
- "\n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "In an ontological framework, ontology entities are used as a knowledge representation form. Those can be further categorized in two groups: ontology individuals ([assertional knowledge](https://en.wikipedia.org/wiki/Abox)), and ontology classes, relationships, attributes and annotations ([terminological knowledge](https://en.wikipedia.org/wiki/Tbox)). This page **focuses on** how to access, edit and navigate the **assertional knowledge** of an ontology using SimPhoNy."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Such functionality is presented in the form of a tutorial, in which the city namespace from SimPhoNy’s example City ontology, the emmo namespace from the Elementary Multiperspective Material Ontology (EMMO) are used as examples. If you want to follow the tutorial along, please make sure that both ontologies are installed. If it is not the case, you can install them by running the command below."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "# Install the ontologies\n",
- "!pico install city emmo"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Moreover, this tutorial concentrates on how to interact with [ontology individual objects](../api_reference.md#simphony_osp.ontology.OntologyIndividual). Each ontology individual object represents a single individual in the ontology."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## Instantiating ontology individuals"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "On this page, examples are based **exclusively on newly created ontology individuals**. You can learn how to retrieve existing ontology individuals from a data source in the next sections."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To instantiate a new ontology individual, just call an ontology class object as shown below. If the words \"ontology class object\" sound new to you, please read the [previous section](terminological_knowledge.ipynb). "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Certain attributes of the ontology individual can already be set at creation time by passing their values as keyword arguments, where the keyword is any of the attribute labels or its namespace suffix. Such attributes are, specifically, the ones returned by the [attributes property](../api_reference.md#simphony_osp.ontology.OntologyClass.attributes) and the [optional attributes property](../api_reference.md#simphony_osp.ontology.OntologyClass.optional_attributes) of the ontology class being called."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {
- "tags": []
- },
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "The following attributes of a new Citizen individual can be set using keyword arguments:\n",
- " - name\n",
- " - age\n"
- ]
- },
- {
- "data": {
- "text/plain": [
- ""
- ]
- },
- "execution_count": 2,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from simphony_osp.namespaces import city, emmo, owl, rdfs, simphony\n",
- "\n",
- "print(\n",
- " f'The following attributes of a new {city.Citizen} '\n",
- " f'individual can be set using keyword arguments:'\n",
- ")\n",
- "for attribute in set(city.Citizen.attributes) | city.Citizen.optional_attributes:\n",
- " print(f' - {attribute}')\n",
- "\n",
- "city.Citizen(name=\"Test Person\", age=42)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "In fact, if any of the attributes is defined in the ontology as _mandatory_ using [ontology axioms](terminological_knowledge.ipynb#Operations-specific-to-ontology-axioms), you will be forced to provide them in the function call (otherwise an exception will be raised)."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "
\n",
- "
Tip
\n",
- " \n",
- "In Python, you can pass keyword arguments with spaces or other characters not typically allowed in keyword arguments by unpacking a dictionary in the function call: `city.Citizen(name=\"Test Person\", **{\"age\": 42})`.\n",
- " \n",
- "
\n",
- "\n",
- "At the moment, it is not possible to instantiate multi-class individuals. We [are aware of this issue](https://github.com/simphony/simphony-osp/issues/669), and planning to include this functionality in a future minor release.\n",
- "\n",
- "Until this is fixed, the suggested workaround is to instantiate an ontology individual of any class and change the classes _a posteriori_, just as shown below.\n",
- " \n",
- "```python\n",
- "person = owl.Thing()\n",
- "\n",
- "person.classes = city.Citizen, emmo.Cogniser\n",
- "```\n",
- " \n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "By default, new ontology individuals are assigned a random IRI from the _simphony-osp.eu_ domain."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "rdflib.term.URIRef('https://www.simphony-osp.eu/entity#6b7cf472-9dbe-4d9e-93e2-0f56ee308d27')"
- ]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "city.Citizen(name=\"Test Person\", age=42).identifier"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "However, it is possible to fix the identifier using the `iri` keyword argument."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "rdflib.term.URIRef('http://example.org/entity#test_person')"
- ]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "city.Citizen(\n",
- " name=\"Test Person\", age=42,\n",
- " iri='http://example.org/entity#test_person'\n",
- ").identifier"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "An individual can also be instantiated in a session different from the default one using the `session` keyword argument (see the sessions section)."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "## [Ontology individual objects](../api_reference.md#simphony_osp.ontology.OntologyIndividual)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Ontology individuals are a special type of ontology entities, and thus, the ontology individual objects inherit from [ontology entity objects](terminological_knowledge.ipynb#Ontology-entity-objects), meaning that they share their functionality.\n",
- "\n",
- "In SimPhoNy, an ontology individual is characterized by\n",
- "\n",
- "- the information about the ontology individual itself such as the classes it belongs to, its label and its attributes;\n",
- "- the connections to other ontology individuals.\n",
- "\n",
- "Moreover, such information is stored on a so-called _session_ (see [next section](sessions.ipynb))."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "As said, ontology individual objects inherit from [ontology entity objects](terminological_knowledge.ipynb#Ontology-entity-objects). Therefore, it is also possible to access their label, identifier, namespace and super- or subclasses. Below you can find an example. Head to the [terminological knowledge](terminological_knowledge.ipynb#Ontology-entity-objects) section for more details. "
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "
\n",
- "
Note
\n",
- " \n",
- "Even though ontology individual objects share the functionality of [ontology entity objects](terminological_knowledge.ipynb#Ontology-entity-objects), there are some slight differences to consider:\n",
- "\n",
- "- The [namespace property](../api_reference.md#simphony_osp.ontology.OntologyEntity.namespace) tipically returns `None`, regardless of the IRI of the ontology individual. This happens because in order to belong to a namespace, an ontology entity needs not only to have an IRI that contains the namespace IRI, but also to belong to the same session. Ontologies installed with [pico](ontology/pico.md) live in their own, separate session.\n",
- "- The [superclasses](../api_reference.md#simphony_osp.ontology.OntologyEntity.superclasses), [direct_superclasses](../api_reference.md#simphony_osp.ontology.OntologyEntity.direct_superclasses), [subclasses](../api_reference.md#simphony_osp.ontology.OntologyEntity.subclasses) and [direct_subclasses](../api_reference.md#simphony_osp.ontology.OntologyEntity.direct_subclasses) properties, as well as the [is_subclass_of](../api_reference.md#simphony_osp.ontology.OntologyEntity.is_subclass_of) method refer to the superclasses and subclasses of all the classes the ontology individual belongs to, as illustrated in the example.\n",
- "- The properties [label](../api_reference.md#simphony_osp.ontology.OntologyEntity.label), [label_lang](../api_reference.md#simphony_osp.ontology.OntologyEntity.label_lang), [label_literal](../api_reference.md#simphony_osp.ontology.OntologyEntity.label_literal) and [session](../api_reference.md#simphony_osp.ontology.OntologyEntity.session) are **writable**. This means that both the [main label](terminological_knowledge.ipynb#Accessing-an-entity%E2%80%99s-label) of ontology individuals can be changed and the individuals themselves may be moved from one session to another by changing the value of such properties.\n",
- " \n",
- "
"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Label: My neighbor (en)\n",
- "\n",
- "Label literal: rdflib.term.Literal('My neighbor', lang='en')\n",
- "\n",
- "List of labels: [rdflib.term.Literal('My neighbor', lang='en')]\n",
- "\n",
- "Identifier: rdflib.term.URIRef('https://www.simphony-osp.eu/entity#03659fa1-5c91-44a0-a73c-f475d3b328fe')\n",
- "\n",
- "Namespace: None\n",
- "\n",
- "Superclasses: frozenset({, , , , , , , , , })\n",
- "\n",
- "Subclasses: frozenset({})\n",
- "\n",
- "Direct superclasses: frozenset({})\n",
- "\n",
- "Direct subclasses: frozenset()\n",
- "\n",
- "Does any of the classes of the individual belong the \"Semiotics\" branch of EMMO? True\n",
- "\n",
- "Is the entity an individual? True\n"
- ]
- }
- ],
- "source": [
- "person = emmo.Cogniser()\n",
- "# Instantiate an ontology individual of class Cogniser. According to the EMMO's\n",
- "# documentation, a Cogniser is defined as:\n",
- "# > An interpreter who establish the connection between an icon an an object \n",
- "# > recognizing their resemblance (e.g. logical, pictorial)\n",
- "# The following example for a Cogniser is provided:\n",
- "# > The scientist that connects an equation to a physical phenomenon.\n",
- "\n",
- "person.label, person.label_lang = \"My neighbor\", \"en\"\n",
- "\n",
- "print(\"Label:\", f\"{person.label} ({person.label_lang})\", end='\\n'*2)\n",
- "print(\"Label literal:\", person.label_literal.__repr__(), end='\\n'*2)\n",
- "print(\"List of labels:\", list(person.iter_labels()).__repr__(), end='\\n'*2)\n",
- "print(\"Identifier:\", person.identifier.__repr__(), end='\\n'*2)\n",
- "print(\"Namespace:\", person.namespace.__repr__(), end='\\n'*2)\n",
- "\n",
- "print('Superclasses:', person.superclasses, end='\\n'*2)\n",
- "print('Subclasses:', person.subclasses, end='\\n'*2)\n",
- "print('Direct superclasses:', person.direct_superclasses, end='\\n'*2)\n",
- "print('Direct subclasses:', person.direct_subclasses, end='\\n'*2)\n",
- "\n",
- "print(\"Does any of the classes of the individual belong the \\\"Semiotics\\\" branch of EMMO?\", person.is_subclass_of(emmo.Semiotics))\n",
- "\n",
- "from simphony_osp.ontology import OntologyIndividual\n",
- "print(\"\\nIs the entity an individual?\", isinstance(person, OntologyIndividual))"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "In addition, ontology individuals have extra functionality that is specific to them."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "For example, there is an extra method to verify whether they are an instance of a specific ontology class (which is just an alias for [is_subclass_of](..#api_reference.md#simphony_osp.ontology.OntologyEntity.is_subclass_of))."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "True"
- ]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "person.is_a(emmo.Semiotics)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "It is also is possible not only to verify the classes that the individual belongs to,"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "frozenset({})"
- ]
- },
- "execution_count": 7,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "person.classes"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "but also to **change** them."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "frozenset({,\n",
- " })"
- ]
- },
- "execution_count": 8,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "person.classes = city.Citizen, emmo.Cogniser\n",
- "\n",
- "person.classes"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To get the [session](sessions.ipynb) an individual belongs to, use the [session property](../api_reference.md#simphony_osp.ontology.OntologyEntity.session). Remember that this property can be also changed in order to transfer the individual from one session to another."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- ""
- ]
- },
- "execution_count": 9,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "person.session"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Managing attributes, relationships and annotations"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### Using the index operator `[]`"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "SimPhoNy features a single, unified syntax based on the Python index `[]` operator to manage the relationships between ontology individuals, the values of the attributes of an individual, and the values of ontology annotations."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "For example, assume one wants to create a city with several neighborhoods and inhabitants. The first step is to instantiate the ontology individuals that represent such elements."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [],
- "source": [
- "freiburg = city.City(name=\"Freiburg\", coordinates=[47.997791, 7.842609])\n",
- "\n",
- "neighborhoods = {\n",
- " city.Neighborhood(name=name, coordinates=coordinates)\n",
- " for name, coordinates in [\n",
- " ('Altstadt', [47.99525, 7.84726]),\n",
- " ('Stühlinger', [47.99888, 7.83774]),\n",
- " ('Neuburg', [48.00021, 7.86084]),\n",
- " ('Herdern', [48.00779, 7.86268]),\n",
- " ('Brühl', [48.01684, 7.843]),\n",
- " ]\n",
- "}\n",
- "\n",
- "citizen_1 = city.Citizen(name='Nikola', age=35)\n",
- "citizen_2 = city.Citizen(name='Lena', age=70)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The next step is connecting them, modifying the values of their attributes and adding annotations.\n",
- "\n",
- "Let's start trying to declare that the neighborhoods are part of the city and that the citizens are inhabitants of the city using the `city.hasPart` and `city.hasInhabitant` relationships.\n",
- "\n",
- "The individuals that are already connected to the city through this relationship can be consulted as follows."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 11,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "set() "
- ]
- },
- "execution_count": 11,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "freiburg[city.hasPart]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The above statement yields a [relationship set object](../api_reference.md#simphony_osp.ontology.RelationshipSet). Relationship sets are [set-like](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableSet) objects that manage the ontology individuals that are linked to the given individual and relationship (in this example, `freiburg` and `city.hasPart`). You will notice in the following examples, that relationship set objects have a few extra capabilities that [Python sets](https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset) do not have that make the interaction with them more natural."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "
\n",
- "
Note
\n",
- "\n",
- "Set-like objects are objects compatible with the standard Python sets, meaning that all the methods and functionality from Python sets are available for set-like objects.\n",
- "\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "In order to attach items through the given relationship, all that is needed is an **in-place** set union."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 12,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "set()\n",
- "{, , , , }\n"
- ]
- }
- ],
- "source": [
- "freiburg[city.hasPart] | neighborhoods # does not attach the neighborhoods\n",
- "print(freiburg[city.hasPart])\n",
- "freiburg[city.hasPart] |= neighborhoods # attaches the neighborhoods (in-place union)\n",
- "print(freiburg[city.hasPart])\n",
- "\n",
- "freiburg[city.hasInhabitant] += citizen_1, citizen_2 # attaches the citizens\n",
- "# the '+=` operator is not available in standard Python sets and is a shorthand for\n",
- "# the following operations:\n",
- "# - `+= citizen_1, citizen_2` is equivalent to `|= {citizen_1, citizen_2}`\n",
- "# - `+= {citizen_1, citizen_2}` is equivalent to `|= {citizen_1, citizen_2}`\n",
- "# - `+= [citizen_1, citizen_2]` raises a TypeError (this shortcut only works for tuples and set-like objects)\n",
- "# - `+= citizen_3` is equivalent to `|= {citizen_3}\n",
- "# the `-=` operator is avilable in standard Python sets, but has been extended\n",
- "# to work like in the above examples when used together with non set-like objects."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Exactly in the same way, when ontology attributes or ontology annotations are passed to the index operator `[]`, [attribute sets](../api_reference.md#simphony_osp.ontology.AttributeSet) and [annotation sets](../api_reference.md#simphony_osp.ontology.AnnotationSet) are spawned, which behave similarly to relationship sets."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 13,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "{'Lena', 'Helena'} \n",
- "\n",
- "{70} \n",
- "{55} \n",
- "{'Lena was born in Berlin, but moved to Freiburg when she was 28 years old.', 'She likes to go into the woods and get lost in her thoughts.'} \n"
- ]
- }
- ],
- "source": [
- "# ATTRIBUTES\n",
- "# - assign one more name to Lena\n",
- "citizen_2[city['name']] += 'Helena'\n",
- "print(citizen_2[city['name']].__repr__(), end='\\n'*2)\n",
- "\n",
- "# - change the age of Lena (`=` replaces all the values of the attribute)\n",
- "print(citizen_2[city.age].__repr__())\n",
- "citizen_2[city.age] = 55\n",
- "print(citizen_2[city.age].__repr__())\n",
- "\n",
- "# ANNOTATIONS\n",
- "citizen_1[rdfs.comment] = (\n",
- " 'Lena was born in Berlin, but moved to Freiburg when she was 28 years old.',\n",
- " 'She likes to go into the woods and get lost in her thoughts.'\n",
- ")\n",
- "print(citizen_1[rdfs.comment].__repr__())"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "
\n",
- "
Note
\n",
- "\n",
- "In SimPhoNy, relationships, attributes and annotations are treated in an ontological sense. This means that when using the corresponding Python object to access or modify them, one is referring not only to such ontology entity, but also to all of its subclasses. You can verify this fact noting that `freiburg[owl.topObjectProperty]` returns all individuals attached to `freiburg`, as all relationships are a subclass of `owl:topObjectProperty`.\n",
- "\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Strings can also be used with the index notation `[]` as a shorthand in certain cases"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "- to access the [attributes of any of the classes](terminological_knowledge.ipynb#Ontology-class-objects) that the individual belongs to, or other attributes that have already been assigned to the individual,\n",
- "- to access relationships that have already been used to link the inidividual to others,\n",
- "- to access annotations whose value has been already assigned."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 14,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "{, } "
- ]
- },
- "execution_count": 14,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "freiburg[\"hasInhabitant\"]"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 15,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "{35} "
- ]
- },
- "execution_count": 15,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "citizen_1[\"age\"]"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Therefore the most relevant use-case of passing strings is accessing information from existing individuals, rather than constructing new ones."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "
\n",
- "
Tip
\n",
- " \n",
- "The index notation `[]` supports IPython autocompletion for strings. When working on a Jupyter notebook, it is possible to get suggestions for the strings that will work for that specific individual by writing `individual[\"` and pressing TAB.\n",
- "\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Even though in this example only a few possibilities of the relationship-, attribute- and annotation sets have been covered, remember that they are compatible with standard Python sets. So hopefully, this introduction should be enough to consider the remaining possibilities on your own: remove elements with `-=`, check if a certain relationship is being used `if freiburg[city.hasInhabitant]:`, loop over elements `for connected_individual in freiburg[city.hasInhabitant]:`, etc.\n",
- "\n",
- "`del freiburg[city.hasInhabitant]` and `freiburg[city.hasInhabitant] = None` can also be used and are equivalent to `freiburg[city.hasInhabitant] = set()`."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "When it comes to **accessing single values** from a relationship-, attribute- or annotation set, there are three built-in shortcuts to make it easier than iterating over them:\n",
- "\n",
- "- `any()` returns an element from the set in a non-deterministic way. Returns `None` if the set is empty.\n",
- "- `one()` returns the single element in the set. If the set is empty or has multiple elements, thein the exceptions [ResultEmptyError](../api_reference.md#simphony_osp.ontology.ResultEmptyError) or [MultipleResultsError](../api_reference.md#simphony_osp.ontology.MultipleResultsError) are respectively raised.\n",
- "- `all()` returns the set itself, and is therefore redundant. Can be used to improve code readability if needed."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 16,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "Nikola\n",
- "{'Nikola'}\n",
- "None\n",
- "set() \n"
- ]
- }
- ],
- "source": [
- "# print(citizen_2['name'].one()) # Raises `MultipleResultsError`, as Lena has multiple names.\n",
- "print(citizen_1['name'].any())\n",
- "print(citizen_1['name'].all())\n",
- "\n",
- "# print(citizen_2[city.hasChild].one()) # Raises `ResultEmptyError`, as Nikola has not been declared to have children.\n",
- "print(citizen_2[city.hasChild].any())\n",
- "print(citizen_2[city.hasChild].all().__repr__())"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Finally, if it is needed to find individuals that are connected through an _inverse relationship_, the `.inverse` attribute of the relationship sets can be used."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 17,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "'Freiburg'"
- ]
- },
- "execution_count": 17,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "citizen_1[city.hasInhabitant].inverse.one()['name'].one()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### Using the Python dot notation (attributes only)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The Python dot notation can be used to access and set the attributes of individuals in all cases when both strings can be passed to the index notation `[]` and the string is compatible with the Python syntax (e.g. it contains no spaces). See the [previous section for more details](#Using-the-index-operator-[])."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 18,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "('Nikola', 35)"
- ]
- },
- "execution_count": 18,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "citizen_1.name, citizen_1.age"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 19,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "34"
- ]
- },
- "execution_count": 19,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "citizen_1.age = 34\n",
- "citizen_1.age"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 20,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "mappingproxy({: frozenset({'Nikola'}),\n",
- " : frozenset({34})})"
- ]
- },
- "execution_count": 20,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "citizen_1.attributes"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "
\n",
- "
Tip
\n",
- " \n",
- "The dot notation also supports IPython autocompletion.\n",
- "\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The dot notation is limited to attributes with a single value. When several values are assigned to the same attribute, a `RuntimeError` is raised."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "It is possible to get a dictionary with all the attributes of an individual and its values using the `attributes` attribute."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 21,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "mappingproxy({: frozenset({'Helena',\n",
- " 'Lena'}),\n",
- " : frozenset({55})})"
- ]
- },
- "execution_count": 21,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "citizen_2.attributes"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "#### Using the `get`, `iter`, `connect`, and `disconnect` methods (relationships only)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The method [connect](../api_reference.md#simphony_osp.ontology.OntologyIndividual.connect) connects individuals using the given relationship."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 22,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "set() \n",
- "{, } \n"
- ]
- }
- ],
- "source": [
- "# remove the existing connections between Freiburg and its citizens\n",
- "del freiburg[city.hasInhabitant]\n",
- "print(freiburg[city.hasInhabitant].__repr__())\n",
- "\n",
- "# use the connect method to restore them\n",
- "freiburg.connect(citizen_1, citizen_2, rel=city.hasInhabitant)\n",
- "print(freiburg[city.hasInhabitant].__repr__())"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The method [disconnect](../api_reference.md#simphony_osp.ontology.OntologyIndividual.disconnect) disconnects ontology individuals. Optionally a relationship and class filter can be given."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 23,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "{}\n",
- "set()\n",
- "{}\n",
- "{}\n",
- "set()\n"
- ]
- }
- ],
- "source": [
- "citizen_3 = city.Citizen(name='Lukas', age=2)\n",
- "citizen_1.connect(citizen_3, rel=city.hasChild)\n",
- "print(citizen_1[city.hasChild])\n",
- "\n",
- "citizen_1.disconnect(citizen_3) # disconnects citizen_3\n",
- "print(citizen_1[city.hasChild])\n",
- "\n",
- "citizen_1.connect(citizen_3, rel=city.hasChild)\n",
- "\n",
- "citizen_1.disconnect(rel=city.worksIn) # does not disconnect citizen_3, as the relationship does not match the filter\n",
- "print(citizen_1[city.hasChild])\n",
- "citizen_1.disconnect(rel=city.hasChild, oclass=city.Building) # does not disconnect citizen_3, as the its class does not match the filter\n",
- "print(citizen_1[city.hasChild])\n",
- "citizen_1.disconnect(citizen_3, oclass=city.Citizen) # disconnect works, as the filters match now\n",
- "print(citizen_1[city.hasChild])"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The method [get](../api_reference.md#simphony_osp.ontology.OntologyIndividual.get) is used to obtain the individuals linked through a given relationship. Filters to restrict the results only to specific individuals, relationships and classes, as well as any combination of them can optinally be provided. The [iter](../api_reference.md#simphony_osp.ontology.OntologyIndividual.iter) method behaves similarly, but returns an interator instead."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 24,
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "{, , , , , , } \n",
- "\n",
- "{, } \n",
- "\n",
- "{, } \n",
- "\n",
- "\n",
- "(, )\n",
- "\n",
- "None\n",
- "None\n",
- "\n",
- "None\n"
- ]
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Assertional knowledge\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In an ontological framework, ontology entities are used as a knowledge representation form. Those can be further categorized in two groups: ontology individuals ([assertional knowledge](https://en.wikipedia.org/wiki/Abox)), and ontology classes, relationships, attributes and annotations ([terminological knowledge](https://en.wikipedia.org/wiki/Tbox)). This page **focuses on** how to access, edit and navigate the **assertional knowledge** of an ontology using SimPhoNy."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Such functionality is presented in the form of a tutorial, in which the city namespace from SimPhoNy\u2019s example City ontology, the emmo namespace from the Elementary Multiperspective Material Ontology (EMMO) are used as examples. If you want to follow the tutorial along, please make sure that both ontologies are installed. If it is not the case, you can install them by running the command below."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "# Install the ontologies\n",
+ "!pico install city emmo"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Moreover, this tutorial concentrates on how to interact with [ontology individual objects](../api_reference.md#simphony_osp.ontology.OntologyIndividual). Each ontology individual object represents a single individual in the ontology."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## Instantiating ontology individuals"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "On this page, examples are based **exclusively on newly created ontology individuals**. You can learn how to retrieve existing ontology individuals from a data source in the next sections."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To instantiate a new ontology individual, just call an ontology class object as shown below. If the words \"ontology class object\" sound new to you, please read the [previous section](terminological_knowledge.ipynb). "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Certain attributes of the ontology individual can already be set at creation time by passing their values as keyword arguments, where the keyword is any of the attribute labels or its namespace suffix. Such attributes are, specifically, the ones returned by the [attributes property](../api_reference.md#simphony_osp.ontology.OntologyClass.attributes) and the [optional attributes property](../api_reference.md#simphony_osp.ontology.OntologyClass.optional_attributes) of the ontology class being called."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {
+ "tags": []
+ },
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "The following attributes of a new Citizen individual can be set using keyword arguments:\n",
+ " - name\n",
+ " - age\n"
+ ]
+ },
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from simphony_osp.namespaces import city, emmo, owl, rdfs, simphony\n",
+ "\n",
+ "print(\n",
+ " f'The following attributes of a new {city.Citizen} '\n",
+ " f'individual can be set using keyword arguments:'\n",
+ ")\n",
+ "for attribute in set(city.Citizen.attributes) | city.Citizen.optional_attributes:\n",
+ " print(f' - {attribute}')\n",
+ "\n",
+ "city.Citizen(name=\"Test Person\", age=42)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In fact, if any of the attributes is defined in the ontology as _mandatory_ using [ontology axioms](terminological_knowledge.ipynb#Operations-specific-to-ontology-axioms), you will be forced to provide them in the function call (otherwise an exception will be raised)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Tip
\n",
+ " \n",
+ "In Python, you can pass keyword arguments with spaces or other characters not typically allowed in keyword arguments by unpacking a dictionary in the function call: `city.Citizen(name=\"Test Person\", **{\"age\": 42})`.\n",
+ " \n",
+ "
\n",
+ "\n",
+ "At the moment, it is not possible to instantiate multi-class individuals. We [are aware of this issue](https://github.com/simphony/simphony-osp/issues/669), and planning to include this functionality in a future minor release.\n",
+ "\n",
+ "Until this is fixed, the suggested workaround is to instantiate an ontology individual of any class and change the classes _a posteriori_, just as shown below.\n",
+ " \n",
+ "```python\n",
+ "person = owl.Thing()\n",
+ "\n",
+ "person.classes = city.Citizen, emmo.Cogniser\n",
+ "```\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "By default, new ontology individuals are assigned a random IRI from the _simphony-osp.eu_ domain."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "rdflib.term.URIRef('https://www.simphony-osp.eu/entity#6b7cf472-9dbe-4d9e-93e2-0f56ee308d27')"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "city.Citizen(name=\"Test Person\", age=42).identifier"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "However, it is possible to fix the identifier using the `iri` keyword argument."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "rdflib.term.URIRef('http://example.org/entity#test_person')"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "city.Citizen(\n",
+ " name=\"Test Person\", age=42,\n",
+ " iri='http://example.org/entity#test_person'\n",
+ ").identifier"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "An individual can also be instantiated in a session different from the default one using the `session` keyword argument (see the sessions section)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "## [Ontology individual objects](../api_reference.md#simphony_osp.ontology.OntologyIndividual)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Ontology individuals are a special type of ontology entities, and thus, the ontology individual objects inherit from [ontology entity objects](terminological_knowledge.ipynb#Ontology-entity-objects), meaning that they share their functionality.\n",
+ "\n",
+ "In SimPhoNy, an ontology individual is characterized by\n",
+ "\n",
+ "- the information about the ontology individual itself such as the classes it belongs to, its label and its attributes;\n",
+ "- the connections to other ontology individuals.\n",
+ "\n",
+ "Moreover, such information is stored on a so-called _session_ (see [next section](sessions.ipynb))."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "As said, ontology individual objects inherit from [ontology entity objects](terminological_knowledge.ipynb#Ontology-entity-objects). Therefore, it is also possible to access their label, identifier, namespace and super- or subclasses. Below you can find an example. Head to the [terminological knowledge](terminological_knowledge.ipynb#Ontology-entity-objects) section for more details. "
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Note
\n",
+ " \n",
+ "Even though ontology individual objects share the functionality of [ontology entity objects](terminological_knowledge.ipynb#Ontology-entity-objects), there are some slight differences to consider:\n",
+ "\n",
+ "- The [namespace property](../api_reference.md#simphony_osp.ontology.OntologyEntity.namespace) tipically returns `None`, regardless of the IRI of the ontology individual. This happens because in order to belong to a namespace, an ontology entity needs not only to have an IRI that contains the namespace IRI, but also to belong to the same session. Ontologies installed with [pico](ontology/pico.md) live in their own, separate session.\n",
+ "- The [superclasses](../api_reference.md#simphony_osp.ontology.OntologyEntity.superclasses), [direct_superclasses](../api_reference.md#simphony_osp.ontology.OntologyEntity.direct_superclasses), [subclasses](../api_reference.md#simphony_osp.ontology.OntologyEntity.subclasses) and [direct_subclasses](../api_reference.md#simphony_osp.ontology.OntologyEntity.direct_subclasses) properties, as well as the [is_subclass_of](../api_reference.md#simphony_osp.ontology.OntologyEntity.is_subclass_of) method refer to the superclasses and subclasses of all the classes the ontology individual belongs to, as illustrated in the example.\n",
+ "- The properties [label](../api_reference.md#simphony_osp.ontology.OntologyEntity.label), [label_lang](../api_reference.md#simphony_osp.ontology.OntologyEntity.label_lang), [label_literal](../api_reference.md#simphony_osp.ontology.OntologyEntity.label_literal) and [session](../api_reference.md#simphony_osp.ontology.OntologyEntity.session) are **writable**. This means that both the [main label](terminological_knowledge.ipynb#Accessing-an-entity%E2%80%99s-label) of ontology individuals can be changed and the individuals themselves may be moved from one session to another by changing the value of such properties.\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Label: My neighbor (en)\n",
+ "\n",
+ "Label literal: rdflib.term.Literal('My neighbor', lang='en')\n",
+ "\n",
+ "List of labels: [rdflib.term.Literal('My neighbor', lang='en')]\n",
+ "\n",
+ "Identifier: rdflib.term.URIRef('https://www.simphony-osp.eu/entity#03659fa1-5c91-44a0-a73c-f475d3b328fe')\n",
+ "\n",
+ "Namespace: None\n",
+ "\n",
+ "Superclasses: frozenset({, , , , , , , , , })\n",
+ "\n",
+ "Subclasses: frozenset({})\n",
+ "\n",
+ "Direct superclasses: frozenset({})\n",
+ "\n",
+ "Direct subclasses: frozenset()\n",
+ "\n",
+ "Does any of the classes of the individual belong the \"Semiotics\" branch of EMMO? True\n",
+ "\n",
+ "Is the entity an individual? True\n"
+ ]
+ }
+ ],
+ "source": [
+ "person = emmo.Cogniser()\n",
+ "# Instantiate an ontology individual of class Cogniser. According to the EMMO's\n",
+ "# documentation, a Cogniser is defined as:\n",
+ "# > An interpreter who establish the connection between an icon an an object \n",
+ "# > recognizing their resemblance (e.g. logical, pictorial)\n",
+ "# The following example for a Cogniser is provided:\n",
+ "# > The scientist that connects an equation to a physical phenomenon.\n",
+ "\n",
+ "person.label, person.label_lang = \"My neighbor\", \"en\"\n",
+ "\n",
+ "print(\"Label:\", f\"{person.label} ({person.label_lang})\", end='\\n'*2)\n",
+ "print(\"Label literal:\", person.label_literal.__repr__(), end='\\n'*2)\n",
+ "print(\"List of labels:\", list(person.iter_labels()).__repr__(), end='\\n'*2)\n",
+ "print(\"Identifier:\", person.identifier.__repr__(), end='\\n'*2)\n",
+ "print(\"Namespace:\", person.namespace.__repr__(), end='\\n'*2)\n",
+ "\n",
+ "print('Superclasses:', person.superclasses, end='\\n'*2)\n",
+ "print('Subclasses:', person.subclasses, end='\\n'*2)\n",
+ "print('Direct superclasses:', person.direct_superclasses, end='\\n'*2)\n",
+ "print('Direct subclasses:', person.direct_subclasses, end='\\n'*2)\n",
+ "\n",
+ "print(\"Does any of the classes of the individual belong the \\\"Semiotics\\\" branch of EMMO?\", person.is_subclass_of(emmo.Semiotics))\n",
+ "\n",
+ "from simphony_osp.ontology import OntologyIndividual\n",
+ "print(\"\\nIs the entity an individual?\", isinstance(person, OntologyIndividual))"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In addition, ontology individuals have extra functionality that is specific to them."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "For example, there is an extra method to verify whether they are an instance of a specific ontology class (which is just an alias for [is_subclass_of](..#api_reference.md#simphony_osp.ontology.OntologyEntity.is_subclass_of))."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "True"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "person.is_a(emmo.Semiotics)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "It is also is possible not only to verify the classes that the individual belongs to,"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "frozenset({})"
+ ]
+ },
+ "execution_count": 7,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "person.classes"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "but also to **change** them."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "frozenset({,\n",
+ " })"
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "person.classes = city.Citizen, emmo.Cogniser\n",
+ "\n",
+ "person.classes"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To get the [session](sessions.ipynb) an individual belongs to, use the [session property](../api_reference.md#simphony_osp.ontology.OntologyEntity.session). Remember that this property can be also changed in order to transfer the individual from one session to another."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 9,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "person.session"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Managing attributes, relationships and annotations"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Using the index operator `[]`"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "SimPhoNy features a single, unified syntax based on the Python index `[]` operator to manage the relationships between ontology individuals, the values of the attributes of an individual, and the values of ontology annotations."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "For example, assume one wants to create a city with several neighborhoods and inhabitants. The first step is to instantiate the ontology individuals that represent such elements."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "freiburg = city.City(name=\"Freiburg\", coordinates=[47.997791, 7.842609])\n",
+ "\n",
+ "neighborhoods = {\n",
+ " city.Neighborhood(name=name, coordinates=coordinates)\n",
+ " for name, coordinates in [\n",
+ " ('Altstadt', [47.99525, 7.84726]),\n",
+ " ('St\u00fchlinger', [47.99888, 7.83774]),\n",
+ " ('Neuburg', [48.00021, 7.86084]),\n",
+ " ('Herdern', [48.00779, 7.86268]),\n",
+ " ('Br\u00fchl', [48.01684, 7.843]),\n",
+ " ]\n",
+ "}\n",
+ "\n",
+ "citizen_1 = city.Citizen(name='Nikola', age=35)\n",
+ "citizen_2 = city.Citizen(name='Lena', age=70)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The next step is connecting them, modifying the values of their attributes and adding annotations.\n",
+ "\n",
+ "Let's start trying to declare that the neighborhoods are part of the city and that the citizens are inhabitants of the city using the `city.hasPart` and `city.hasInhabitant` relationships.\n",
+ "\n",
+ "The individuals that are already connected to the city through this relationship can be consulted as follows."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 11,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "set() "
+ ]
+ },
+ "execution_count": 11,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "freiburg[city.hasPart]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The above statement yields a [relationship set object](../api_reference.md#simphony_osp.ontology.RelationshipSet). Relationship sets are [set-like](https://docs.python.org/3/library/collections.abc.html#collections.abc.MutableSet) objects that manage the ontology individuals that are linked to the given individual and relationship (in this example, `freiburg` and `city.hasPart`). You will notice in the following examples, that relationship set objects have a few extra capabilities that [Python sets](https://docs.python.org/3/library/stdtypes.html#set-types-set-frozenset) do not have that make the interaction with them more natural."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Note
\n",
+ "\n",
+ "Set-like objects are objects compatible with the standard Python sets, meaning that all the methods and functionality from Python sets are available for set-like objects.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In order to attach items through the given relationship, all that is needed is an **in-place** set union."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 12,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "set()\n",
+ "{, , , , }\n"
+ ]
+ }
+ ],
+ "source": [
+ "freiburg[city.hasPart] | neighborhoods # does not attach the neighborhoods\n",
+ "print(freiburg[city.hasPart])\n",
+ "freiburg[city.hasPart] |= neighborhoods # attaches the neighborhoods (in-place union)\n",
+ "print(freiburg[city.hasPart])\n",
+ "\n",
+ "freiburg[city.hasInhabitant] += citizen_1, citizen_2 # attaches the citizens\n",
+ "# the '+=` operator is not available in standard Python sets and is a shorthand for\n",
+ "# the following operations:\n",
+ "# - `+= citizen_1, citizen_2` is equivalent to `|= {citizen_1, citizen_2}`\n",
+ "# - `+= {citizen_1, citizen_2}` is equivalent to `|= {citizen_1, citizen_2}`\n",
+ "# - `+= [citizen_1, citizen_2]` raises a TypeError (this shortcut only works for tuples and set-like objects)\n",
+ "# - `+= citizen_3` is equivalent to `|= {citizen_3}\n",
+ "# the `-=` operator is avilable in standard Python sets, but has been extended\n",
+ "# to work like in the above examples when used together with non set-like objects."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Exactly in the same way, when ontology attributes or ontology annotations are passed to the index operator `[]`, [attribute sets](../api_reference.md#simphony_osp.ontology.AttributeSet) and [annotation sets](../api_reference.md#simphony_osp.ontology.AnnotationSet) are spawned, which behave similarly to relationship sets."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 13,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{'Lena', 'Helena'} \n",
+ "\n",
+ "{70} \n",
+ "{55} \n",
+ "{'Lena was born in Berlin, but moved to Freiburg when she was 28 years old.', 'She likes to go into the woods and get lost in her thoughts.'} \n"
+ ]
+ }
+ ],
+ "source": [
+ "# ATTRIBUTES\n",
+ "# - assign one more name to Lena\n",
+ "citizen_2[city['name']] += 'Helena'\n",
+ "print(citizen_2[city['name']].__repr__(), end='\\n'*2)\n",
+ "\n",
+ "# - change the age of Lena (`=` replaces all the values of the attribute)\n",
+ "print(citizen_2[city.age].__repr__())\n",
+ "citizen_2[city.age] = 55\n",
+ "print(citizen_2[city.age].__repr__())\n",
+ "\n",
+ "# ANNOTATIONS\n",
+ "citizen_1[rdfs.comment] = (\n",
+ " 'Lena was born in Berlin, but moved to Freiburg when she was 28 years old.',\n",
+ " 'She likes to go into the woods and get lost in her thoughts.'\n",
+ ")\n",
+ "print(citizen_1[rdfs.comment].__repr__())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Note
\n",
+ "\n",
+ "In SimPhoNy, relationships, attributes and annotations are treated in an ontological sense. This means that when using the corresponding Python object to access or modify them, one is referring not only to such ontology entity, but also to all of its subclasses. You can verify this fact noting that `freiburg[owl.topObjectProperty]` returns all individuals attached to `freiburg`, as all relationships are a subclass of `owl:topObjectProperty`.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Strings can also be used with the index notation `[]` as a shorthand in certain cases"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "- to access the [attributes of any of the classes](terminological_knowledge.ipynb#Ontology-class-objects) that the individual belongs to, or other attributes that have already been assigned to the individual,\n",
+ "- to access relationships that have already been used to link the inidividual to others,\n",
+ "- to access annotations whose value has been already assigned."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 14,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{, } "
+ ]
+ },
+ "execution_count": 14,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "freiburg[\"hasInhabitant\"]"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 15,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{35} "
+ ]
+ },
+ "execution_count": 15,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "citizen_1[\"age\"]"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Therefore the most relevant use-case of passing strings is accessing information from existing individuals, rather than constructing new ones."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Tip
\n",
+ " \n",
+ "The index notation `[]` supports IPython autocompletion for strings. When working on a Jupyter notebook, it is possible to get suggestions for the strings that will work for that specific individual by writing `individual[\"` and pressing TAB.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Even though in this example only a few possibilities of the relationship-, attribute- and annotation sets have been covered, remember that they are compatible with standard Python sets. So hopefully, this introduction should be enough to consider the remaining possibilities on your own: remove elements with `-=`, check if a certain relationship is being used `if freiburg[city.hasInhabitant]:`, loop over elements `for connected_individual in freiburg[city.hasInhabitant]:`, etc.\n",
+ "\n",
+ "`del freiburg[city.hasInhabitant]` and `freiburg[city.hasInhabitant] = None` can also be used and are equivalent to `freiburg[city.hasInhabitant] = set()`."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "When it comes to **accessing single values** from a relationship-, attribute- or annotation set, there are three built-in shortcuts to make it easier than iterating over them:\n",
+ "\n",
+ "- `any()` returns an element from the set in a non-deterministic way. Returns `None` if the set is empty.\n",
+ "- `one()` returns the single element in the set. If the set is empty or has multiple elements, thein the exceptions [ResultEmptyError](../api_reference.md#simphony_osp.ontology.ResultEmptyError) or [MultipleResultsError](../api_reference.md#simphony_osp.ontology.MultipleResultsError) are respectively raised.\n",
+ "- `all()` returns the set itself, and is therefore redundant. Can be used to improve code readability if needed."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 16,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "Nikola\n",
+ "{'Nikola'}\n",
+ "None\n",
+ "set() \n"
+ ]
+ }
+ ],
+ "source": [
+ "# print(citizen_2['name'].one()) # Raises `MultipleResultsError`, as Lena has multiple names.\n",
+ "print(citizen_1['name'].any())\n",
+ "print(citizen_1['name'].all())\n",
+ "\n",
+ "# print(citizen_2[city.hasChild].one()) # Raises `ResultEmptyError`, as Nikola has not been declared to have children.\n",
+ "print(citizen_2[city.hasChild].any())\n",
+ "print(citizen_2[city.hasChild].all().__repr__())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Finally, if it is needed to find individuals that are connected through an _inverse relationship_, the `.inverse` attribute of the relationship sets can be used."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 17,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "'Freiburg'"
+ ]
+ },
+ "execution_count": 17,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "citizen_1[city.hasInhabitant].inverse.one()['name'].one()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Using the Python dot notation (attributes only)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The Python dot notation can be used to access and set the attributes of individuals in all cases when both strings can be passed to the index notation `[]` and the string is compatible with the Python syntax (e.g. it contains no spaces). See the [previous section for more details](#Using-the-index-operator-[])."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 18,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "('Nikola', 35)"
+ ]
+ },
+ "execution_count": 18,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "citizen_1.name, citizen_1.age"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 19,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "34"
+ ]
+ },
+ "execution_count": 19,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "citizen_1.age = 34\n",
+ "citizen_1.age"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 20,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "mappingproxy({: frozenset({'Nikola'}),\n",
+ " : frozenset({34})})"
+ ]
+ },
+ "execution_count": 20,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "citizen_1.attributes"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Tip
\n",
+ " \n",
+ "The dot notation also supports IPython autocompletion.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The dot notation is limited to attributes with a single value. When several values are assigned to the same attribute, a `RuntimeError` is raised."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "It is possible to get a dictionary with all the attributes of an individual and its values using the `attributes` attribute."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 21,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "mappingproxy({: frozenset({'Helena',\n",
+ " 'Lena'}),\n",
+ " : frozenset({55})})"
+ ]
+ },
+ "execution_count": 21,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "citizen_2.attributes"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "#### Using the `get`, `iter`, `connect`, and `disconnect` methods (relationships only)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The method [connect](../api_reference.md#simphony_osp.ontology.OntologyIndividual.connect) connects individuals using the given relationship."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 22,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "set() \n",
+ "{, } \n"
+ ]
+ }
+ ],
+ "source": [
+ "# remove the existing connections between Freiburg and its citizens\n",
+ "del freiburg[city.hasInhabitant]\n",
+ "print(freiburg[city.hasInhabitant].__repr__())\n",
+ "\n",
+ "# use the connect method to restore them\n",
+ "freiburg.connect(citizen_1, citizen_2, rel=city.hasInhabitant)\n",
+ "print(freiburg[city.hasInhabitant].__repr__())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The method [disconnect](../api_reference.md#simphony_osp.ontology.OntologyIndividual.disconnect) disconnects ontology individuals. Optionally a relationship and class filter can be given."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 23,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{}\n",
+ "set()\n",
+ "{}\n",
+ "{}\n",
+ "set()\n"
+ ]
+ }
+ ],
+ "source": [
+ "citizen_3 = city.Citizen(name='Lukas', age=2)\n",
+ "citizen_1.connect(citizen_3, rel=city.hasChild)\n",
+ "print(citizen_1[city.hasChild])\n",
+ "\n",
+ "citizen_1.disconnect(citizen_3) # disconnects citizen_3\n",
+ "print(citizen_1[city.hasChild])\n",
+ "\n",
+ "citizen_1.connect(citizen_3, rel=city.hasChild)\n",
+ "\n",
+ "citizen_1.disconnect(rel=city.worksIn) # does not disconnect citizen_3, as the relationship does not match the filter\n",
+ "print(citizen_1[city.hasChild])\n",
+ "citizen_1.disconnect(rel=city.hasChild, oclass=city.Building) # does not disconnect citizen_3, as the its class does not match the filter\n",
+ "print(citizen_1[city.hasChild])\n",
+ "citizen_1.disconnect(citizen_3, oclass=city.Citizen) # disconnect works, as the filters match now\n",
+ "print(citizen_1[city.hasChild])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The method [get](../api_reference.md#simphony_osp.ontology.OntologyIndividual.get) is used to obtain the individuals linked through a given relationship. Filters to restrict the results only to specific individuals, relationships and classes, as well as any combination of them can optinally be provided. The [iter](../api_reference.md#simphony_osp.ontology.OntologyIndividual.iter) method behaves similarly, but returns an interator instead."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 24,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "{, , , , , , } \n",
+ "\n",
+ "{, } \n",
+ "\n",
+ "{, } \n",
+ "\n",
+ "\n",
+ "(, )\n",
+ "\n",
+ "None\n",
+ "None\n",
+ "\n",
+ "None\n"
+ ]
+ }
+ ],
+ "source": [
+ "print(freiburg.get().__repr__(), end='\\n'*2) # returns everything attached to Freiburg (a relationship set)\n",
+ "\n",
+ "print(freiburg.get(rel=city.hasInhabitant).__repr__(), end='\\n'*2) # returns only the citizens (a relationship set)\n",
+ "\n",
+ "print(freiburg.get(oclass=city.Citizen).__repr__(), end='\\n'*2) # also returns only the citizens (a relationship set)\n",
+ "\n",
+ "# filtering specific individuals (can be combined with class and relationship filters)\n",
+ "print(freiburg.get(citizen_1).__repr__())\n",
+ "print(freiburg.get(citizen_1, citizen_2).__repr__())\n",
+ "print(freiburg.get(citizen_1.identifier).__repr__())\n",
+ "print(freiburg.get('https://example.org/city#unknown_citizen').__repr__())\n",
+ "print(freiburg.get(citizen_1, rel=city.hasChild).__repr__())\n",
+ "print(freiburg.get(citizen_1, rel=city.hasInhabitant).__repr__())\n",
+ "print(freiburg.get(citizen_1, rel=city.hasInhabitant, oclass=city.Building).__repr__())"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Using the `get` and `iter` methods, it is also possible to discover the specific relationships that connect two individuals when a superclass of them is given."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 25,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "((,\n",
+ " ),\n",
+ " (,\n",
+ " ),\n",
+ " (,\n",
+ " ),\n",
+ " (,\n",
+ " ),\n",
+ " (,\n",
+ " ),\n",
+ " (,\n",
+ " ),\n",
+ " (,\n",
+ " ))"
+ ]
+ },
+ "execution_count": 25,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "freiburg.get(rel=owl.topObjectProperty, return_rel=True)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "### Operations"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Operations are actions (written in Python) that can be executed on instances of specific ontology classes that they are defined for."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "A great example of the applications of operations is the interaction with file objects in SimPhoNy wrappers that support it, for example, the included dataspace wrapper."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 26,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from pathlib import Path\n",
+ "from tempfile import TemporaryDirectory\n",
+ "from urllib import request\n",
+ "\n",
+ "from IPython.display import Image\n",
+ "\n",
+ "from simphony_osp.wrappers import Dataspace\n",
+ "\n",
+ "dataspace_directory = TemporaryDirectory()\n",
+ "example_directory = TemporaryDirectory()\n",
+ "\n",
+ "# Download a picture of Freiburg using urllib\n",
+ "# from _Visit Freiburg_ - https://visit.freiburg.de\n",
+ "url = (\n",
+ " \"https://visit.freiburg.de/extension/portal-freiburg\"\n",
+ " \"/var/storage/images/media/bibliothek/teaser-bilder-startseite\"\n",
+ " \"/freiburg-kunst-kultur-copyright-fwtm-polkowski/225780-1-ger-DE\"\n",
+ " \"/freiburg-kunst-kultur-copyright-fwtm-polkowski_grid_medium.jpg\"\n",
+ ")\n",
+ "file, response = request.urlretrieve(url)\n",
+ "\n",
+ "# Open a dataspace session in a temporary directory\n",
+ "with Dataspace(dataspace_directory.name, True) as session:\n",
+ " # Create an individual belonging to SimPhoNy's file class\n",
+ " picture = simphony.File(\n",
+ " iri='http://example.org/freiburg#my_picture'\n",
+ " )\n",
+ " \n",
+ " # Use the `upload` operation to assign data to the file object\n",
+ " picture.operations.upload(file)\n",
+ " \n",
+ " # Commit the changes\n",
+ " session.commit()\n",
+ "\n",
+ "# Access the saved data and retrieve the Picture using the `download` operation\n",
+ "with Dataspace(dataspace_directory.name, True) as session:\n",
+ " picture = session.from_identifier('http://example.org/freiburg#my_picture')\n",
+ " download_path = Path(example_directory.name) / 'my_picture.jpg'\n",
+ " picture.operations.download(download_path)\n",
+ " \n",
+ "# Uncomment this line to show the downloaded picture\n",
+ "# (you can do so by running the tutorial yourself using Binder)\n",
+ "# Image(download_path)"
+ ]
}
- ],
- "source": [
- "print(freiburg.get().__repr__(), end='\\n'*2) # returns everything attached to Freiburg (a relationship set)\n",
- "\n",
- "print(freiburg.get(rel=city.hasInhabitant).__repr__(), end='\\n'*2) # returns only the citizens (a relationship set)\n",
- "\n",
- "print(freiburg.get(oclass=city.Citizen).__repr__(), end='\\n'*2) # also returns only the citizens (a relationship set)\n",
- "\n",
- "# filtering specific individuals (can be combined with class and relationship filters)\n",
- "print(freiburg.get(citizen_1).__repr__())\n",
- "print(freiburg.get(citizen_1, citizen_2).__repr__())\n",
- "print(freiburg.get(citizen_1.identifier).__repr__())\n",
- "print(freiburg.get('https://example.org/city#unknown_citizen').__repr__())\n",
- "print(freiburg.get(citizen_1, rel=city.hasChild).__repr__())\n",
- "print(freiburg.get(citizen_1, rel=city.hasInhabitant).__repr__())\n",
- "print(freiburg.get(citizen_1, rel=city.hasInhabitant, oclass=city.Building).__repr__())"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Using the `get` and `iter` methods, it is also possible to discover the specific relationships that connect two individuals when a superclass of them is given."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 25,
- "metadata": {},
- "outputs": [
- {
- "data": {
- "text/plain": [
- "((,\n",
- " ),\n",
- " (,\n",
- " ),\n",
- " (,\n",
- " ),\n",
- " (,\n",
- " ),\n",
- " (,\n",
- " ),\n",
- " (,\n",
- " ),\n",
- " (,\n",
- " ))"
- ]
- },
- "execution_count": 25,
- "metadata": {},
- "output_type": "execute_result"
+ ],
+ "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.12"
}
- ],
- "source": [
- "freiburg.get(rel=owl.topObjectProperty, return_rel=True)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "### Operations"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Operations are actions (written in Python) that can be executed on instances of specific ontology classes that they are defined for."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "A great example of the applications of operations is the interaction with file objects in SimPhoNy wrappers that support it, for example, the included dataspace wrapper."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 26,
- "metadata": {},
- "outputs": [],
- "source": [
- "from pathlib import Path\n",
- "from tempfile import TemporaryDirectory\n",
- "from urllib import request\n",
- "\n",
- "from IPython.display import Image\n",
- "\n",
- "from simphony_osp.wrappers import Dataspace\n",
- "\n",
- "dataspace_directory = TemporaryDirectory()\n",
- "example_directory = TemporaryDirectory()\n",
- "\n",
- "# Download a picture of Freiburg using urllib\n",
- "# from _Visit Freiburg_ - https://visit.freiburg.de\n",
- "url = (\n",
- " \"https://visit.freiburg.de/extension/portal-freiburg\"\n",
- " \"/var/storage/images/media/bibliothek/teaser-bilder-startseite\"\n",
- " \"/freiburg-kunst-kultur-copyright-fwtm-polkowski/225780-1-ger-DE\"\n",
- " \"/freiburg-kunst-kultur-copyright-fwtm-polkowski_grid_medium.jpg\"\n",
- ")\n",
- "file, response = request.urlretrieve(url)\n",
- "\n",
- "# Open a dataspace session in a temporary directory\n",
- "with Dataspace(dataspace_directory.name, True) as session:\n",
- " # Create an individual belonging to SimPhoNy's file class\n",
- " picture = simphony.File(\n",
- " iri='http://example.org/freiburg#my_picture'\n",
- " )\n",
- " \n",
- " # Use the `upload` operation to assign data to the file object\n",
- " picture.operations.upload(file)\n",
- " \n",
- " # Commit the changes\n",
- " session.commit()\n",
- "\n",
- "# Access the saved data and retrieve the Picture using the `download` operation\n",
- "with Dataspace(dataspace_directory.name, True) as session:\n",
- " picture = session.from_identifier('http://example.org/freiburg#my_picture')\n",
- " download_path = Path(example_directory.name) / 'my_picture.jpg'\n",
- " picture.operations.download(download_path)\n",
- " \n",
- "# Uncomment this line to show the downloaded picture\n",
- "# (you can do so by running the tutorial yourself using Binder)\n",
- "# Image(download_path)"
- ]
- }
- ],
- "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.12"
- }
- },
- "nbformat": 4,
- "nbformat_minor": 4
+ "nbformat": 4,
+ "nbformat_minor": 4
}
diff --git a/docs/usage/sessions/import_export.ipynb b/docs/usage/sessions/import_export.ipynb
index f49d728..530e719 100644
--- a/docs/usage/sessions/import_export.ipynb
+++ b/docs/usage/sessions/import_export.ipynb
@@ -1,515 +1,515 @@
{
- "cells": [
- {
- "cell_type": "markdown",
- "id": "boxed-professional",
- "metadata": {},
- "source": [
- "# RDF Import and export"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "operational-honey",
- "metadata": {},
- "source": [
- "\n",
- "\n",
- "SimPhoNy sessions store the ontology individual information using the [RDF standard](https://www.w3.org/TR/rdf-concepts/) in an [RDF graph object](https://rdflib.readthedocs.io/en/stable/intro_to_graphs.html) from the [RDFLib](https://github.com/RDFLib/rdflib) library. Exporting such RDF graph is possible using the functions [import_file](../../api_reference.md#simphony_osp.tools.import_file) and [export_file](../../api_reference.md#simphony_osp.tools.export_file)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "id": "94ca2509-eabd-4311-b531-1fd2269d27ad",
- "metadata": {},
- "outputs": [],
- "source": [
- "from simphony_osp.tools import import_file, export_file"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "qualified-works",
- "metadata": {},
- "source": [
- "
\n",
- "
Tip
\n",
- " \n",
- "The full API specifications of the import and export functions can be found on the\n",
- "[API reference page](../../api_reference.md).\n",
- " \n",
- "
\n"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "driving-injury",
- "metadata": {},
- "source": [
- "In the examples on this page, the [city ontology](../ontologies/ontologies_included.md#the-city-ontology) is used. Make sure the city ontology is installed. If not, run the following command:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "id": "dying-accreditation",
- "metadata": {},
- "outputs": [],
- "source": [
- "!pico install city"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "lonely-listening",
- "metadata": {},
- "source": [
- "Then create a few ontology individuals"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "id": "considered-leonard",
- "metadata": {},
- "outputs": [],
- "source": [
- "from simphony_osp.namespaces import city\n",
- "\n",
- "freiburg = city.City(name=\"Freiburg\", coordinates=[47.997791, 7.842609])\n",
- "peter = city.Citizen(name=\"Peter\", age=30)\n",
- "anne = city.Citizen(name=\"Anne\", age=20)\n",
- "freiburg[city.hasInhabitant] += peter, anne"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e15dc482-63aa-4eae-9682-2f32f363bb4c",
- "metadata": {},
- "source": [
- "## Exporting individuals"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "worth-province",
- "metadata": {},
- "source": [
- "The `export_file` function allows to export either all the contents of a session, or select a few ontology individuals to be exported."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "cf167dfe-aa6d-4b12-955f-edf3d64cf9b0",
- "metadata": {},
- "source": [
- "For example, exporting Freiburg and Peter"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "id": "monthly-anxiety",
- "metadata": {},
- "outputs": [],
- "source": [
- "export_file({freiburg, peter}, file='./data.ttl', format='turtle')"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "795aea94-ded2-43e0-8037-07412a9b93b0",
- "metadata": {},
- "source": [
- "creates the file `data.ttl` with the following content."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "id": "outstanding-wound",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "@prefix ns1: .\n",
- "@prefix xsd: .\n",
- "\n",
- " a ns1:City ;\n",
- " ns1:coordinates \"13YFp0RR93AD@t&xBo{#)k4YS)LtJz\"^^ ;\n",
- " ns1:hasInhabitant ;\n",
- " ns1:name \"Freiburg\"^^xsd:string .\n",
- "\n",
- " a ns1:Citizen ;\n",
- " ns1:age 30 ;\n",
- " ns1:name \"Peter\"^^xsd:string .\n",
- "\n"
- ]
- }
- ],
- "source": [
- "from sys import platform\n",
- "\n",
- "if platform == 'win32':\n",
- " !more data.ttl\n",
- "else:\n",
- " !cat data.ttl"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e10d2793-7763-4929-b017-e5e66087b09a",
- "metadata": {},
- "source": [
- "Note that when individuals that are connected are **exported together**, their connections are kept in the exported file."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "afd633af-b85c-449b-94c7-2ff99a097150",
- "metadata": {},
- "source": [
- "If instead, you wish to export all the individuals in a session, then pass the session object to be exported."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "id": "7eb2c80b-42ad-447b-9b46-47365a639cbc",
- "metadata": {},
- "outputs": [
- {
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "@prefix city: .\n",
- "@prefix xsd: .\n",
- "\n",
- " a city:City ;\n",
- " city:coordinates \"13YFp0RR93AD@t&xBo{#)k4YS)LtJz\"^^ ;\n",
- " city:hasInhabitant ,\n",
- " ;\n",
- " city:name \"Freiburg\"^^xsd:string .\n",
- "\n",
- " a city:Citizen ;\n",
- " city:age 30 ;\n",
- " city:name \"Peter\"^^xsd:string .\n",
- "\n",
- " a city:Citizen ;\n",
- " city:age 20 ;\n",
- " city:name \"Anne\"^^xsd:string .\n",
- "\n"
- ]
- }
- ],
- "source": [
- "from simphony_osp.session import core_session\n",
- "\n",
- "export_file(core_session, file='./data.ttl', format='turtle')\n",
- "\n",
- "if platform == 'win32':\n",
- " !more data.ttl\n",
- "else:\n",
- " !cat data.ttl"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "offshore-cotton",
- "metadata": {},
- "source": [
- "You can change the output format by entering a different value for the parameter `format`. A list of supported formats is available on [this page](../ontologies/supported_formats.html#supported-formats)."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "601d4d0d-b00d-4680-9b9f-1c80899cdc03",
- "metadata": {},
- "source": [
- "## Importing individuals"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "derived-advancement",
- "metadata": {},
- "source": [
- "To import data, use the `import_file` method. Let's assume we wish to import the data from the previous example in a new session. The following code will help us achieve our aim:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "id": "stable-session",
- "metadata": {},
- "outputs": [],
- "source": [
- "from simphony_osp.session import Session\n",
- "from simphony_osp.tools import import_file\n",
- "\n",
- "session = Session(); session.locked = True\n",
- "\n",
- "with session:\n",
- " import_file('./data.ttl')"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "virgin-river",
- "metadata": {},
- "source": [
- "
\n",
- "
Note
\n",
- " \n",
- "The format is automatically inferred from the file extension. To specify it explicitly, you can add the `format` parameter, like so: `import_file('./data.ttl', format='turtle')`.\n",
- " \n",
- "
\n",
- " \n",
- "A `session` keyword argument can be optionally provided. When not specified, data is imported to the default sesion. You can specify the session explicitly like so: `import_file('./data.ttl', session=session)`.\n",
- " \n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "higher-short",
- "metadata": {},
- "source": [
- "Now we can verify the data was indeed imported:"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "id": "suspended-albert",
- "metadata": {},
- "outputs": [
- {
- "data": {
- "image/svg+xml": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "id": "boxed-professional",
+ "metadata": {},
+ "source": [
+ "# RDF Import and export"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "operational-honey",
+ "metadata": {},
+ "source": [
+ "\n",
+ "\n",
+ "SimPhoNy sessions store the ontology individual information using the [RDF standard](https://www.w3.org/TR/rdf-concepts/) in an [RDF graph object](https://rdflib.readthedocs.io/en/stable/intro_to_graphs.html) from the [RDFLib](https://github.com/RDFLib/rdflib) library. Exporting such RDF graph is possible using the functions [import_file](../../api_reference.md#simphony_osp.tools.import_file) and [export_file](../../api_reference.md#simphony_osp.tools.export_file)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 1,
+ "id": "94ca2509-eabd-4311-b531-1fd2269d27ad",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from simphony_osp.tools import import_file, export_file"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "qualified-works",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Tip
\n",
+ " \n",
+ "The full API specifications of the import and export functions can be found on the\n",
+ "[API reference page](../../api_reference.md).\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "driving-injury",
+ "metadata": {},
+ "source": [
+ "In the examples on this page, the [city ontology](../ontologies/ontologies_included.md#the-city-ontology) is used. Make sure the city ontology is installed. If not, run the following command:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "id": "dying-accreditation",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "!pico install city"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "lonely-listening",
+ "metadata": {},
+ "source": [
+ "Then create a few ontology individuals"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "id": "considered-leonard",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from simphony_osp.namespaces import city\n",
+ "\n",
+ "freiburg = city.City(name=\"Freiburg\", coordinates=[47.997791, 7.842609])\n",
+ "peter = city.Citizen(name=\"Peter\", age=30)\n",
+ "anne = city.Citizen(name=\"Anne\", age=20)\n",
+ "freiburg[city.hasInhabitant] += peter, anne"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e15dc482-63aa-4eae-9682-2f32f363bb4c",
+ "metadata": {},
+ "source": [
+ "## Exporting individuals"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "worth-province",
+ "metadata": {},
+ "source": [
+ "The `export_file` function allows to export either all the contents of a session, or select a few ontology individuals to be exported."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "cf167dfe-aa6d-4b12-955f-edf3d64cf9b0",
+ "metadata": {},
+ "source": [
+ "For example, exporting Freiburg and Peter"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "id": "monthly-anxiety",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "export_file({freiburg, peter}, file='./data.ttl', format='turtle')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "795aea94-ded2-43e0-8037-07412a9b93b0",
+ "metadata": {},
+ "source": [
+ "creates the file `data.ttl` with the following content."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "id": "outstanding-wound",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "@prefix ns1: .\n",
+ "@prefix xsd: .\n",
+ "\n",
+ " a ns1:City ;\n",
+ " ns1:coordinates \"13YFp0RR93AD@t&xBo{#)k4YS)LtJz\"^^ ;\n",
+ " ns1:hasInhabitant ;\n",
+ " ns1:name \"Freiburg\"^^xsd:string .\n",
+ "\n",
+ " a ns1:Citizen ;\n",
+ " ns1:age 30 ;\n",
+ " ns1:name \"Peter\"^^xsd:string .\n",
+ "\n"
+ ]
+ }
+ ],
+ "source": [
+ "from sys import platform\n",
+ "\n",
+ "if platform == 'win32':\n",
+ " !more data.ttl\n",
+ "else:\n",
+ " !cat data.ttl"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e10d2793-7763-4929-b017-e5e66087b09a",
+ "metadata": {},
+ "source": [
+ "Note that when individuals that are connected are **exported together**, their connections are kept in the exported file."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "afd633af-b85c-449b-94c7-2ff99a097150",
+ "metadata": {},
+ "source": [
+ "If instead, you wish to export all the individuals in a session, then pass the session object to be exported."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "id": "7eb2c80b-42ad-447b-9b46-47365a639cbc",
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "@prefix city: .\n",
+ "@prefix xsd: .\n",
+ "\n",
+ " a city:City ;\n",
+ " city:coordinates \"13YFp0RR93AD@t&xBo{#)k4YS)LtJz\"^^ ;\n",
+ " city:hasInhabitant ,\n",
+ " ;\n",
+ " city:name \"Freiburg\"^^xsd:string .\n",
+ "\n",
+ " a city:Citizen ;\n",
+ " city:age 30 ;\n",
+ " city:name \"Peter\"^^xsd:string .\n",
+ "\n",
+ " a city:Citizen ;\n",
+ " city:age 20 ;\n",
+ " city:name \"Anne\"^^xsd:string .\n",
+ "\n"
+ ]
+ }
],
- "text/plain": [
- ""
+ "source": [
+ "from simphony_osp.session import core_session\n",
+ "\n",
+ "export_file(core_session, file='./data.ttl', format='turtle')\n",
+ "\n",
+ "if platform == 'win32':\n",
+ " !more data.ttl\n",
+ "else:\n",
+ " !cat data.ttl"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "offshore-cotton",
+ "metadata": {},
+ "source": [
+ "You can change the output format by entering a different value for the parameter `format`. A list of supported formats is available on [this page](../ontologies/supported_formats.html#supported-formats)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "601d4d0d-b00d-4680-9b9f-1c80899cdc03",
+ "metadata": {},
+ "source": [
+ "## Importing individuals"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "derived-advancement",
+ "metadata": {},
+ "source": [
+ "To import data, use the `import_file` method. Let's assume we wish to import the data from the previous example in a new session. The following code will help us achieve our aim:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "id": "stable-session",
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from simphony_osp.session import Session\n",
+ "from simphony_osp.tools import import_file\n",
+ "\n",
+ "session = Session(); session.locked = True\n",
+ "\n",
+ "with session:\n",
+ " import_file('./data.ttl')"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "virgin-river",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Note
\n",
+ " \n",
+ "The format is automatically inferred from the file extension. To specify it explicitly, you can add the `format` parameter, like so: `import_file('./data.ttl', format='turtle')`.\n",
+ " \n",
+ "
\n",
+ " \n",
+ "A `session` keyword argument can be optionally provided. When not specified, data is imported to the default sesion. You can specify the session explicitly like so: `import_file('./data.ttl', session=session)`.\n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "higher-short",
+ "metadata": {},
+ "source": [
+ "Now we can verify the data was indeed imported:"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "id": "suspended-albert",
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 8,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from simphony_osp.tools import semantic2dot\n",
+ "\n",
+ "semantic2dot(session)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "8b84a2b7-0bd9-4cf4-aa09-a1b2138ba43e",
+ "metadata": {},
+ "source": [
+ "## Interpretation of RDF files"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "81211841-d564-4974-b0a7-eef4982fa3e4",
+ "metadata": {},
+ "source": [
+ "The [ontology languages supported by SimPhoNy](../ontologies/supported_formats.md) can be serialized as RDF files, but the [RDF standard](https://www.w3.org/TR/rdf-concepts/) can store data that does not necessarily have anything to do with an ontology. Moreover, as described in the [introduction to sessions](introduction.ipynb), SimPhoNy sessions have been designed to exlusively store assertional knowledge (ontology individuals). \n",
+ "\n",
+ "Due to these factors, SimPhoNy enforces a few constraints when importing and exporting individuals from/to RDF files, that can, however, **also be disabled if desired**.\n",
+ "\n",
+ "1. No terminological knowledge can be present in the file. Any RDF triple with predicate `rdf:type` and one of `owl:Class`, `rdfs:Class`, `owl:AnnotationProperty`, `rdf:Property`, `owl:DatatypeProperty`, `owl:ObjectProperty`, `owl:Restriction` as object raises an exception.\n",
+ "\n",
+ "2. The subjects of any RDF triple with predicate `rdf:type` and an IRI not listed above as object are considered to be the identifiers of ontology individuals. Therefore, SymPhoNy will look into its installed ontologies for a class matching the object of the triple. If this lookup fails, an exception is raised. This behavior is meant to prevent you from making the mistake of importing data for which you have not installed the corresponding ontology.\n",
+ "\n",
+ "3. If an RDF triple where the subject has been succesfully identified as an ontology individual has a predicate different from `rdf:type` that cannot be recognized as an annotation, relationship nor an attribute, an exception will be raised.\n",
+ "\n",
+ "4. If an RDF triple where the subject has been succesfully identified as an ontology individual has a predicate that can be recognized as a relationship, but has an object that cannot be recognized as an ontology individual (for example, because no `rdf:type` has been defined for it), then an exception will be raised.\n",
+ "\n",
+ "5. If an RDF triple where the subject has been succesfully identified as an ontology individual has a predicate that can be recognized as a relationship, but has a literal as an object, an exception will be raised.\n",
+ "\n",
+ "6. If an RDF triple where the subject has been succesfully identified as an ontology individual has a predicate that can be recognized as an attribute, but has a IRI as an object, an exception will be raised.\n",
+ "\n",
+ "7. Any triples whose subject cannot be identified as terminological knowledge, as ontology individuals, or for which (2) does not apply are **not imported**. No warning nor exception of any kind is raised for such triples."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "97478c07-c469-4f64-b219-ff1d12e3b322",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Warning
\n",
+ " \n",
+ "Point (7) implies that using the default options, you can lose data that was originally in the source, **without** warnings nor errors to notify you about it. Keep reading to learn how to prevent it. \n",
+ " \n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "29fbacc8-3c05-4f4c-a7e2-f8836c1c7535",
+ "metadata": {},
+ "source": [
+ "There are two keyword arguments that can be passed to the import and export functions to bypass these checks.\n",
+ "\n",
+ "- `all_triples`: When set to `True`, no exceptions will be raised for points (2)*, (3), (4), (5), (6). Warnings will still be emitted.\n",
+ "- `all_statements`: When set to `True`, none of the points above apply. All RDF triples are imported, and **no information is lost**. No warnings are emitted."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "e3208b1d-bc73-4a8c-a541-dd30f0a970f8",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Note
\n",
+ " \n",
+ "\\* To be recognized as an ontology individual, at least one of the types of the subject need to be defined in the [installed ontologies](../ontologies/pico.md). If you use `all_triples=True` when none of the types are defined in the installed ontologies, then (7) applies to such subject (its information is lost).\n",
+ " \n",
+ "
\n",
+ " \n",
+ "Be careful when using `all_triples` and especially, when using `all_statements`. SimPhoNy's sessions have been designed to work only with ontology individuals. If you use `all_statements=True`, then also classes, relationships, annotations and attributes will be imported to the session, but as SimPhoNy is not ready to deal with this situation, this may lead to errors.\n",
+ " \n",
+ "
\n"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "00cbc181-d4b3-4c12-847e-5b3c97f88579",
+ "metadata": {},
+ "source": [
+ "Below there is sample RDF graph that helps understanding all the cases."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "96b841a5-80fa-4a9b-9a07-44bde08c31c0",
+ "metadata": {},
+ "source": [
+ "![Sample RDF graph exemplifying cases where the constraints above apply](../../_static/importexport_graph.png)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "id": "d8a3156b-c999-4097-8478-b003f6a357f6",
+ "metadata": {},
+ "source": [
+ "1. The triple (`example:Skaters`, `rdf:type`, `owl:Class`) would trigger this case, because it defines terminological knowledge.\n",
+ "2. The triple (`example:Marco`, `rdf:type`, `foaf:Person`) matches this case, because the namespace `foaf` is not installed.\n",
+ "3. The triple (`example:Klaus`, `foaf:knows`, `example:Lena`) raises an exception, because the namespace `foaf` is not installed.\n",
+ "4. The triple (`example:Freiburg`, `city:hasInhabitant`, `example:Rob`) triggers this case, because `example:Rob` does not have any type assigned and therefore, it is not identified as an ontology individual.\n",
+ "5. The triple (`example:Freiburg`, `city:hasWorker`, `Lena (xsd:string)`) matches this case, as \"has worker\" is a relationship, but the object is a literal.\n",
+ "6. The triple (`example:Freiburg`, `city:coordinates`, ``) raises an exception, because \"coordinates\" is an attribute, but the object is an IRI.\n",
+ "7. The triple (`example:Something`, `example:predicate`, `example:Thing`) fits into this case."
]
- },
- "execution_count": 8,
- "metadata": {},
- "output_type": "execute_result"
}
- ],
- "source": [
- "from simphony_osp.tools import semantic2dot\n",
- "\n",
- "semantic2dot(session)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "8b84a2b7-0bd9-4cf4-aa09-a1b2138ba43e",
- "metadata": {},
- "source": [
- "## Interpretation of RDF files"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "81211841-d564-4974-b0a7-eef4982fa3e4",
- "metadata": {},
- "source": [
- "The [ontology languages supported by SimPhoNy](../ontologies/supported_formats.md) can be serialized as RDF files, but the [RDF standard](https://www.w3.org/TR/rdf-concepts/) can store data that does not necessarily have anything to do with an ontology. Moreover, as described in the [introduction to sessions](introduction.ipynb), SimPhoNy sessions have been designed to exlusively store assertional knowledge (ontology individuals). \n",
- "\n",
- "Due to these factors, SimPhoNy enforces a few constraints when importing and exporting individuals from/to RDF files, that can, however, **also be disabled if desired**.\n",
- "\n",
- "1. No terminological knowledge can be present in the file. Any RDF triple with predicate `rdf:type` and one of `owl:Class`, `rdfs:Class`, `owl:AnnotationProperty`, `rdf:Property`, `owl:DatatypeProperty`, `owl:ObjectProperty`, `owl:Restriction` as object raises an exception.\n",
- "\n",
- "2. The subjects of any RDF triple with predicate `rdf:type` and an IRI not listed above as object are considered to be the identifiers of ontology individuals. Therefore, SymPhoNy will look into its installed ontologies for a class matching the object of the triple. If this lookup fails, an exception is raised. This behavior is meant to prevent you from making the mistake of importing data for which you have not installed the corresponding ontology.\n",
- "\n",
- "3. If an RDF triple where the subject has been succesfully identified as an ontology individual has a predicate different from `rdf:type` that cannot be recognized as an annotation, relationship nor an attribute, an exception will be raised.\n",
- "\n",
- "4. If an RDF triple where the subject has been succesfully identified as an ontology individual has a predicate that can be recognized as a relationship, but has an object that cannot be recognized as an ontology individual (for example, because no `rdf:type` has been defined for it), then an exception will be raised.\n",
- "\n",
- "5. If an RDF triple where the subject has been succesfully identified as an ontology individual has a predicate that can be recognized as a relationship, but has a literal as an object, an exception will be raised.\n",
- "\n",
- "6. If an RDF triple where the subject has been succesfully identified as an ontology individual has a predicate that can be recognized as an attribute, but has a IRI as an object, an exception will be raised.\n",
- "\n",
- "7. Any triples whose subject cannot be identified as terminological knowledge, as ontology individuals, or for which (2) does not apply are **not imported**. No warning nor exception of any kind is raised for such triples."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "97478c07-c469-4f64-b219-ff1d12e3b322",
- "metadata": {},
- "source": [
- "
\n",
- "
Warning
\n",
- " \n",
- "Point (7) implies that using the default options, you can lose data that was originally in the source, **without** warnings nor errors to notify you about it. Keep reading to learn how to prevent it. \n",
- " \n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "29fbacc8-3c05-4f4c-a7e2-f8836c1c7535",
- "metadata": {},
- "source": [
- "There are two keyword arguments that can be passed to the import and export functions to bypass these checks.\n",
- "\n",
- "- `all_triples`: When set to `True`, no exceptions will be raised for points (2)*, (3), (4), (5), (6). Warnings will still be emitted.\n",
- "- `all_statements`: When set to `True`, none of the points above apply. All RDF triples are imported, and **no information is lost**. No warnings are emitted."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "e3208b1d-bc73-4a8c-a541-dd30f0a970f8",
- "metadata": {},
- "source": [
- "
\n",
- "
Note
\n",
- " \n",
- "\\* To be recognized as an ontology individual, at least one of the types of the subject need to be defined in the [installed ontologies](../ontologies/pico.md). If you use `all_triples=True` when none of the types are defined in the installed ontologies, then (7) applies to such subject (its information is lost).\n",
- " \n",
- "
\n",
- " \n",
- "Be careful when using `all_triples` and especially, when using `all_statements`. SimPhoNy's sessions have been designed to work only with ontology individuals. If you use `all_statements=True`, then also classes, relationships, annotations and attributes will be imported to the session, but as SimPhoNy is not ready to deal with this situation, this may lead to errors.\n",
- " \n",
- "
\n"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "00cbc181-d4b3-4c12-847e-5b3c97f88579",
- "metadata": {},
- "source": [
- "Below there is sample RDF graph that helps understanding all the cases."
- ]
- },
- {
- "cell_type": "markdown",
- "id": "96b841a5-80fa-4a9b-9a07-44bde08c31c0",
- "metadata": {},
- "source": [
- "![Sample RDF graph exemplifying cases where the constraints above apply](../../_static/importexport_graph.png)"
- ]
- },
- {
- "cell_type": "markdown",
- "id": "d8a3156b-c999-4097-8478-b003f6a357f6",
- "metadata": {},
- "source": [
- "1. The triple (`example:Skaters`, `rdf:type`, `owl:Class`) would trigger this case, because it defines terminological knowledge.\n",
- "2. The triple (`example:Marco`, `rdf:type`, `foaf:Person`) matches this case, because the namespace `foaf` is not installed.\n",
- "3. The triple (`example:Klaus`, `foaf:knows`, `example:Lena`) raises an exception, because the namespace `foaf` is not installed.\n",
- "4. The triple (`example:Freiburg`, `city:hasInhabitant`, `example:Rob`) triggers this case, because `example:Rob` does not have any type assigned and therefore, it is not identified as an ontology individual.\n",
- "5. The triple (`example:Freiburg`, `city:hasWorker`, `Lena (xsd:string)`) matches this case, as \"has worker\" is a relationship, but the object is a literal.\n",
- "6. The triple (`example:Freiburg`, `city:coordinates`, ``) raises an exception, because \"coordinates\" is an attribute, but the object is an IRI.\n",
- "7. The triple (`example:Something`, `example:predicate`, `example:Thing`) fits into this case."
- ]
- }
- ],
- "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.12"
- },
+ ],
"metadata": {
- "interpreter": {
- "hash": "301cd6007de04cbbf15bca26f0bc1cb48004d089278091d760363de622bdd0c8"
- }
- }
- },
- "nbformat": 4,
- "nbformat_minor": 5
+ "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.12"
+ },
+ "metadata": {
+ "interpreter": {
+ "hash": "301cd6007de04cbbf15bca26f0bc1cb48004d089278091d760363de622bdd0c8"
+ }
+ }
+ },
+ "nbformat": 4,
+ "nbformat_minor": 5
}
diff --git a/docs/usage/sessions/introduction.ipynb b/docs/usage/sessions/introduction.ipynb
index dff3fc8..4d188fe 100644
--- a/docs/usage/sessions/introduction.ipynb
+++ b/docs/usage/sessions/introduction.ipynb
@@ -1,216 +1,216 @@
{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Introduction\n",
- "\n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "In SimPhoNy, [assertional knowledge](../assertional_knowledge.ipynb) is stored in _sessions_. You may think of a session as a \"box\" were [ontology individuals](../assertional_knowledge.ipynb#Ontology-individual-objects) can be placed. But sessions go beyond just storing assertional knowledge. Sessions can be connected to [SimPhoNy Wrappers](../wrappers/index.md). Each wrapper is a piece of software that seamlessly translates the assertional knowledge to a form that is compatible with a specific simulation engine, database, data repository or file format.\n",
- "\n",
- "In order to keep things simple, this section focuses on sessions that are not connected to any wrapper. All the information stored in such sessions is stored in the computer's volatile memory and lost when the Python shell is closed. After having read this section, you can head to the [next one](../wrappers/index.md) to learn more about SimPhoNy Wrappers."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "All ontology individuals in SimPhoNy are stored in a session. The session where an individual is stored is always accesible through the [session](../../api_reference.md#simphony_osp.ontology.OntologyEntity.session) attribute, which is **writable**. In fact, changing this attribute is one of the several ways to transfer an ontology individual between sessions."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [
+ "cells": [
{
- "data": {
- "text/plain": [
- ""
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Introduction\n",
+ "\n",
+ ""
]
- },
- "execution_count": 1,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from simphony_osp.namespaces import city\n",
- "\n",
- "freiburg = city.City(name=\"Freiburg\", coordinates=[47.997791, 7.842609])\n",
- "freiburg.session"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "But where are newly created individuals stored? Indeed, when a new individual is created, it has to be stored in a session. It is possible to pass a [session object](../../api_reference.md#simphony_osp.session.Session) to the call using the `session` keyword argument to choose where the individual will be stored."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
+ },
{
- "data": {
- "text/plain": [
- "(, True, False)"
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In SimPhoNy, [assertional knowledge](../assertional_knowledge.ipynb) is stored in _sessions_. You may think of a session as a \"box\" were [ontology individuals](../assertional_knowledge.ipynb#Ontology-individual-objects) can be placed. But sessions go beyond just storing assertional knowledge. Sessions can be connected to [SimPhoNy Wrappers](../wrappers/index.md). Each wrapper is a piece of software that seamlessly translates the assertional knowledge to a form that is compatible with a specific simulation engine, database, data repository or file format.\n",
+ "\n",
+ "In order to keep things simple, this section focuses on sessions that are not connected to any wrapper. All the information stored in such sessions is stored in the computer's volatile memory and lost when the Python shell is closed. After having read this section, you can head to the [next one](../wrappers/index.md) to learn more about SimPhoNy Wrappers."
]
- },
- "execution_count": 2,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from simphony_osp.session import Session\n",
- "\n",
- "session_A = Session() # create a new session\n",
- "paris = city.City(\n",
- " name=\"Paris\", coordinates=[48.85333, 2.34885],\n",
- " session=session_A\n",
- ")\n",
- "session_A, paris in session_A, freiburg in session_A"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "But such argument is optional. When it is not specified, the individual is stored on the so-called _default session_. Every time you work with SimPhoNy in a Python shell, it creates a new session, called _Core Session_ and sets it as the default session. The default session can be changed later to any of your choice. The [Core Session](../../api_reference.md#simphony_osp.session.core_session) can be accessed at any time by importing it from the `simphony_osp.session` module."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [
+ },
{
- "data": {
- "text/plain": [
- "(, True, False)"
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "All ontology individuals in SimPhoNy are stored in a session. The session where an individual is stored is always accesible through the [session](../../api_reference.md#simphony_osp.ontology.OntologyEntity.session) attribute, which is **writable**. In fact, changing this attribute is one of the several ways to transfer an ontology individual between sessions."
]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from simphony_osp.session import core_session\n",
- "\n",
- "core_session, freiburg in core_session, paris in core_session"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "
\n",
- "
Note
\n",
- "\n",
- "The interface of the [session object](../api_reference.md#simphony_osp.session.Session) has been designed to interact exclusively with ontology individuals, and therefore, this page only shows you how to use sessions to deal with assertional knowledge.\n",
- " \n",
- "However, there is no technical reason for such limitation. Sessions can actually store any ontology entity (including terminological knowledge). As a curiosity, the entities from the ontologies that you install using [pico](ontologies/pico.md) are stored in a hidden session that is not meant to be directly accessed.\n",
- "\n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The default session can be temporarily changed using the `with` statement."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
+ },
{
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "True True\n",
- "False True\n"
- ]
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 1,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from simphony_osp.namespaces import city\n",
+ "\n",
+ "freiburg = city.City(name=\"Freiburg\", coordinates=[47.997791, 7.842609])\n",
+ "freiburg.session"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "But where are newly created individuals stored? Indeed, when a new individual is created, it has to be stored in a session. It is possible to pass a [session object](../../api_reference.md#simphony_osp.session.Session) to the call using the `session` keyword argument to choose where the individual will be stored."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(, True, False)"
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from simphony_osp.session import Session\n",
+ "\n",
+ "session_A = Session() # create a new session\n",
+ "paris = city.City(\n",
+ " name=\"Paris\", coordinates=[48.85333, 2.34885],\n",
+ " session=session_A\n",
+ ")\n",
+ "session_A, paris in session_A, freiburg in session_A"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "But such argument is optional. When it is not specified, the individual is stored on the so-called _default session_. Every time you work with SimPhoNy in a Python shell, it creates a new session, called _Core Session_ and sets it as the default session. The default session can be changed later to any of your choice. The [Core Session](../../api_reference.md#simphony_osp.session.core_session) can be accessed at any time by importing it from the `simphony_osp.session` module."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "(, True, False)"
+ ]
+ },
+ "execution_count": 3,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "from simphony_osp.session import core_session\n",
+ "\n",
+ "core_session, freiburg in core_session, paris in core_session"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Note
\n",
+ "\n",
+ "The interface of the [session object](../api_reference.md#simphony_osp.session.Session) has been designed to interact exclusively with ontology individuals, and therefore, this page only shows you how to use sessions to deal with assertional knowledge.\n",
+ " \n",
+ "However, there is no technical reason for such limitation. Sessions can actually store any ontology entity (including terminological knowledge). As a curiosity, the entities from the ontologies that you install using [pico](ontologies/pico.md) are stored in a hidden session that is not meant to be directly accessed.\n",
+ "\n",
+ "
"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The default session can be temporarily changed using the `with` statement."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "True True\n",
+ "False True\n"
+ ]
+ }
+ ],
+ "source": [
+ "session_B = Session()\n",
+ "\n",
+ "# this will be explained later\n",
+ "session_A.locked = True\n",
+ "session_B.locked = True\n",
+ "\n",
+ "with session_B:\n",
+ " london = city.City(name=\"London\", coordinates=[51.50737, -0.12767])\n",
+ " \n",
+ "print(paris in session_A, london in session_B)\n",
+ "\n",
+ "# Be careful when using the with statement with several session objects:\n",
+ "# keep in mind that the second will be the one set as default.\n",
+ "with session_A, session_B:\n",
+ " default_session = Session.get_default_session()\n",
+ " print(default_session is session_A, default_session is session_B)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Sessions actually work in a way similar to databases. To start using them, one first has to \"open\" or \"connect\" to them. After that, changes can be performed on the data they contain, but such changes are not made permanent until a \"commit\" is performed. When one finishes working with them, the connection should be \"closed\". Unconfirmed changes are lost when the connection is \"closed\".\n",
+ "\n",
+ "In SimPhoNy, all sessions are automatically \"opened\" when they are created. The \"commit\" and \"close\" operations are controlled manually.\n",
+ "\n",
+ "In spite of that general rule, for sessions that are not connected to a wrapper, which are the ones being illustrated in this page, the \"commit\" command actually does nothing, as confirmed changes have nowhere else to go and be made permanent. You can think of commits being automatic in this case. These sessions also do not implement the \"close\" command.\n",
+ "\n",
+ "Therefore, this general rule has just been introduced in order to present a useful mental model for working with _all_ sessions, which includes [sessions connected to a wrapper](../wrappers/index.md)."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Having said that, it is now simpler to understand the purpose of the [locked attribute of session objects](../../api_reference.md#simphony_osp.session.Session.locked) that appears in the last example. The `with` statement not only sets a session as the default, but also _closes_ it when leaving its context. _Locking a session_ with the [locked](../../api_reference.md#simphony_osp.session.Session.locked) attribute prevents the session from being closed if one intents to continue using it. To restore the original behavior, set it to `False`."
+ ]
}
- ],
- "source": [
- "session_B = Session()\n",
- "\n",
- "# this will be explained later\n",
- "session_A.locked = True\n",
- "session_B.locked = True\n",
- "\n",
- "with session_B:\n",
- " london = city.City(name=\"London\", coordinates=[51.50737, -0.12767])\n",
- " \n",
- "print(paris in session_A, london in session_B)\n",
- "\n",
- "# Be careful when using the with statement with several session objects:\n",
- "# keep in mind that the second will be the one set as default.\n",
- "with session_A, session_B:\n",
- " default_session = Session.get_default_session()\n",
- " print(default_session is session_A, default_session is session_B)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Sessions actually work in a way similar to databases. To start using them, one first has to \"open\" or \"connect\" to them. After that, changes can be performed on the data they contain, but such changes are not made permanent until a \"commit\" is performed. When one finishes working with them, the connection should be \"closed\". Unconfirmed changes are lost when the connection is \"closed\".\n",
- "\n",
- "In SimPhoNy, all sessions are automatically \"opened\" when they are created. The \"commit\" and \"close\" operations are controlled manually.\n",
- "\n",
- "In spite of that general rule, for sessions that are not connected to a wrapper, which are the ones being illustrated in this page, the \"commit\" command actually does nothing, as confirmed changes have nowhere else to go and be made permanent. You can think of commits being automatic in this case. These sessions also do not implement the \"close\" command.\n",
- "\n",
- "Therefore, this general rule has just been introduced in order to present a useful mental model for working with _all_ sessions, which includes [sessions connected to a wrapper](../wrappers/index.md)."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Having said that, it is now simpler to understand the purpose of the [locked attribute of session objects](../../api_reference.md#simphony_osp.session.Session.locked) that appears in the last example. The `with` statement not only sets a session as the default, but also _closes_ it when leaving its context. _Locking a session_ with the [locked](../../api_reference.md#simphony_osp.session.Session.locked) attribute prevents the session from being closed if one intents to continue using it. To restore the original behavior, set it to `False`."
- ]
- }
- ],
- "metadata": {
- "kernelspec": {
- "display_name": "Python 3 (ipykernel)",
- "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.10.7"
+ ],
+ "metadata": {
+ "kernelspec": {
+ "display_name": "Python 3 (ipykernel)",
+ "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.10.7"
+ },
+ "toc-showcode": false,
+ "toc-showtags": true
},
- "toc-showcode": false,
- "toc-showtags": true
- },
- "nbformat": 4,
- "nbformat_minor": 4
+ "nbformat": 4,
+ "nbformat_minor": 4
}
diff --git a/docs/usage/sessions/management.ipynb b/docs/usage/sessions/management.ipynb
index 1d6320e..a921a94 100644
--- a/docs/usage/sessions/management.ipynb
+++ b/docs/usage/sessions/management.ipynb
@@ -1,521 +1,521 @@
{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Managing the session contents\n",
- "\n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "As said, sessions can be though of as a \"box\" that stores ontology individuals. Consequently, adding and removing individuals are among the operations that can be performed on them. \n",
- "\n",
- "As described in [one of the previous sections](../assertional_knowledge.ipynb), in SimPhoNy, an ontology individual is characterized by\n",
- "\n",
- "- the information about the ontology individual itself such as the classes it belongs to, its label and its attributes;\n",
- "- the connections to other ontology individuals."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The methods [add](../../api_reference.md#simphony_osp.session.Session.add) and [delete](../../api_reference.md#simphony_osp.session.delete) try to accommodate this definition. To see how they work, consider a city example again."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "from simphony_osp.namespaces import city\n",
- "\n",
- "freiburg = city.City(name=\"Freiburg\", coordinates=[47.997791, 7.842609])\n",
- "\n",
- "neighborhoods = {\n",
- " city.Neighborhood(name=name, coordinates=coordinates)\n",
- " for name, coordinates in [\n",
- " ('Altstadt', [47.99525, 7.84726]),\n",
- " ('Stühlinger', [47.99888, 7.83774]),\n",
- " ('Neuburg', [48.00021, 7.86084]),\n",
- " ('Herdern', [48.00779, 7.86268]),\n",
- " ('Brühl', [48.01684, 7.843]),\n",
- " ]\n",
- "}\n",
- "\n",
- "citizen_1 = city.Citizen(name='Nikola', age=35)\n",
- "citizen_2 = city.Citizen(name='Lena', age=70)\n",
- "\n",
- "freiburg[city.hasPart] |= neighborhoods\n",
- "freiburg[city.hasInhabitant] += citizen_1, citizen_2"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 2,
- "metadata": {},
- "outputs": [
+ "cells": [
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Managing the session contents\n",
+ "\n",
+ ""
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "As said, sessions can be though of as a \"box\" that stores ontology individuals. Consequently, adding and removing individuals are among the operations that can be performed on them. \n",
+ "\n",
+ "As described in [one of the previous sections](../assertional_knowledge.ipynb), in SimPhoNy, an ontology individual is characterized by\n",
+ "\n",
+ "- the information about the ontology individual itself such as the classes it belongs to, its label and its attributes;\n",
+ "- the connections to other ontology individuals."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "The methods [add](../../api_reference.md#simphony_osp.session.Session.add) and [delete](../../api_reference.md#simphony_osp.session.delete) try to accommodate this definition. To see how they work, consider a city example again."
+ ]
+ },
{
- "data": {
- "image/svg+xml": [
- "\n",
- "\n",
- "\n",
- "\n",
- "\n"
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from simphony_osp.namespaces import city\n",
+ "\n",
+ "freiburg = city.City(name=\"Freiburg\", coordinates=[47.997791, 7.842609])\n",
+ "\n",
+ "neighborhoods = {\n",
+ " city.Neighborhood(name=name, coordinates=coordinates)\n",
+ " for name, coordinates in [\n",
+ " ('Altstadt', [47.99525, 7.84726]),\n",
+ " ('St\u00fchlinger', [47.99888, 7.83774]),\n",
+ " ('Neuburg', [48.00021, 7.86084]),\n",
+ " ('Herdern', [48.00779, 7.86268]),\n",
+ " ('Br\u00fchl', [48.01684, 7.843]),\n",
+ " ]\n",
+ "}\n",
+ "\n",
+ "citizen_1 = city.Citizen(name='Nikola', age=35)\n",
+ "citizen_2 = city.Citizen(name='Lena', age=70)\n",
+ "\n",
+ "freiburg[city.hasPart] |= neighborhoods\n",
+ "freiburg[city.hasInhabitant] += citizen_1, citizen_2"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 2,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "image/svg+xml": [
+ "\n",
+ "\n",
+ "\n",
+ "\n",
+ "\n"
+ ],
+ "text/plain": [
+ ""
+ ]
+ },
+ "execution_count": 2,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
],
- "text/plain": [
- ""
+ "source": [
+ "from simphony_osp.tools import semantic2dot # explained in a later section\n",
+ "\n",
+ "semantic2dot(freiburg, *neighborhoods, citizen_1, citizen_2)"
]
- },
- "execution_count": 2,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "from simphony_osp.tools import semantic2dot # explained in a later section\n",
- "\n",
- "semantic2dot(freiburg, *neighborhoods, citizen_1, citizen_2)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "
\n",
- "
Tip
\n",
- " \n",
- "On most web browsers (including mobile ones), you can right-click the picture above and then click \"open in new tab\" to see the picture in its full size.\n",
- " \n",
- "
"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Then create a new session to transfer individuals to."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [],
- "source": [
- "from simphony_osp.session import Session\n",
- "\n",
- "session = Session()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Passing any individual to the method [add](../../api_reference.md#simphony_osp.session.Session.add) of the new session creates a copy of it. The copy contained in the new session is assigned the same identifier as the original."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [
+ },
{
- "data": {
- "text/plain": [
- "([],\n",
- " 'Freiburg',\n",
- " ,\n",
- " set() )"
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "
\n",
+ "
Tip
\n",
+ " \n",
+ "On most web browsers (including mobile ones), you can right-click the picture above and then click \"open in new tab\" to see the picture in its full size.\n",
+ " \n",
+ "
"
]
- },
- "execution_count": 4,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "freiburg_copy = session.add(freiburg)\n",
- "list(session), freiburg_copy.name, freiburg_copy.coordinates, freiburg_copy.get()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "In the example above, the variable `freiburg` refers now to the individual in the Core Session, while `freiburg_copy` refers to the copy of the individual that has been created in the new session."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "As it can be inferred from the fact that the new session contains only one individual, only the _intrinsic_ information about the individual has been transferred, but not the connections to other ontology individuals nor any intrinsic information of the other ontology individuals themselves."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To keep the connection to another ontology individual, it is necessary to transfer **both of them together**."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
+ },
{
- "data": {
- "text/plain": [
- "{, , , , } "
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Then create a new session to transfer individuals to."
]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "session.clear() # this removes all individuals from the session\n",
- "\n",
- "copies = session.add(freiburg, neighborhoods) # note that Python iterables of individuals can also be passed to `add` (such as `neighborhoods`)\n",
- "freiburg_copy = copies[0] # the order in which individuals were added is respected\n",
- "freiburg_copy.get()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "As shown in the example, the [clear](../../api_reference.md#simphony_osp.session.Session.clear) method removes all ontology individuals from a session. The [delete](../../api_reference.md#simphony_osp.session.Session.delete) method allows to exactly select the individuals to remove. Both ontology individuals and identifiers can be passed to [delete](../../api_reference.md#simphony_osp.session.Session.delete)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [
+ },
{
- "data": {
- "text/plain": [
- "[]"
+ "cell_type": "code",
+ "execution_count": 3,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from simphony_osp.session import Session\n",
+ "\n",
+ "session = Session()"
]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "session.delete(freiburg.identifier, copies[1:])\n",
- "list(session)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "A special situation arises when one tries to add an ontology individual to a session that already contains an individual with the same identifier."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [],
- "source": [
- "session_A = Session(); session_A.locked = True\n",
- "with session_A:\n",
- " lena_A = city.Citizen(name='Lena', age=70,\n",
- " iri='https://example.org/entities#Lena')\n",
- "\n",
- "session_B = Session(); session_B.locked = True\n",
- "with session_B:\n",
- " lena_B = city.Citizen(name='Helena', age=31,\n",
- " iri='https://example.org/entities#Lena')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {
- "tags": [
- "raises-exception"
- ]
- },
- "outputs": [
+ },
{
- "ename": "RuntimeError",
- "evalue": "Some of the added entities already exist on the session.",
- "output_type": "error",
- "traceback": [
- "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
- "\u001b[0;31mRuntimeError\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 1\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mSession\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0msession\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0msession\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlena_A\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0msession\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlena_B\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# -> Fails, there is already an individual with the same identifier.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
- "\u001b[0;32m~/Dokumente/SimPhoNy/simphony-osp/simphony_osp/session/session.py\u001b[0m in \u001b[0;36madd\u001b[0;34m(self, merge, exists_ok, all_triples, *individuals)\u001b[0m\n\u001b[1;32m 808\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mexists_ok\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 809\u001b[0m ):\n\u001b[0;32m--> 810\u001b[0;31m raise RuntimeError(\n\u001b[0m\u001b[1;32m 811\u001b[0m \u001b[0;34m\"Some of the added entities already exist on the session.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 812\u001b[0m )\n",
- "\u001b[0;31mRuntimeError\u001b[0m: Some of the added entities already exist on the session."
- ]
- }
- ],
- "source": [
- "with Session() as session:\n",
- " session.add(lena_A)\n",
- " session.add(lena_B) # -> Fails, there is already an individual with the same identifier."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "When this happens, an exception is raised. It is still possible to copy the individual, but is necessary to decide whether:\n",
- "\n",
- "- the existing individual should be overwritten (default) or;\n",
- "- the new individual should be merged with the existing one."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To apply default action (overwrite), use the keyword argument `exists_ok=True`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 9,
- "metadata": {},
- "outputs": [
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Passing any individual to the method [add](../../api_reference.md#simphony_osp.session.Session.add) of the new session creates a copy of it. The copy contained in the new session is assigned the same identifier as the original."
+ ]
+ },
{
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "70 Lena\n",
- "31 Helena\n"
- ]
- }
- ],
- "source": [
- "with Session() as session:\n",
- " copy = session.add(lena_A)\n",
- " print(copy.age, copy.name)\n",
- " copy = session.add(lena_B, exists_ok=True)\n",
- " print(copy.age, copy.name)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Overwriting replaces the classes, attributes, attribute values and connections to other ontology individuals."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "To merge the new individual with the previous one, use `exists_ok=True, merge=True` instead."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 10,
- "metadata": {},
- "outputs": [
+ "cell_type": "code",
+ "execution_count": 4,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "([],\n",
+ " 'Freiburg',\n",
+ " ,\n",
+ " set() )"
+ ]
+ },
+ "execution_count": 4,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "freiburg_copy = session.add(freiburg)\n",
+ "list(session), freiburg_copy.name, freiburg_copy.coordinates, freiburg_copy.get()"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "In the example above, the variable `freiburg` refers now to the individual in the Core Session, while `freiburg_copy` refers to the copy of the individual that has been created in the new session."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "As it can be inferred from the fact that the new session contains only one individual, only the _intrinsic_ information about the individual has been transferred, but not the connections to other ontology individuals nor any intrinsic information of the other ontology individuals themselves."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To keep the connection to another ontology individual, it is necessary to transfer **both of them together**."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 5,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "{, , , , } "
+ ]
+ },
+ "execution_count": 5,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "session.clear() # this removes all individuals from the session\n",
+ "\n",
+ "copies = session.add(freiburg, neighborhoods) # note that Python iterables of individuals can also be passed to `add` (such as `neighborhoods`)\n",
+ "freiburg_copy = copies[0] # the order in which individuals were added is respected\n",
+ "freiburg_copy.get()"
+ ]
+ },
{
- "name": "stdout",
- "output_type": "stream",
- "text": [
- "70 Lena\n",
- "{70, 31} {'Helena', 'Lena'}\n"
- ]
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "As shown in the example, the [clear](../../api_reference.md#simphony_osp.session.Session.clear) method removes all ontology individuals from a session. The [delete](../../api_reference.md#simphony_osp.session.Session.delete) method allows to exactly select the individuals to remove. Both ontology individuals and identifiers can be passed to [delete](../../api_reference.md#simphony_osp.session.Session.delete)."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 6,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[]"
+ ]
+ },
+ "execution_count": 6,
+ "metadata": {},
+ "output_type": "execute_result"
+ }
+ ],
+ "source": [
+ "session.delete(freiburg.identifier, copies[1:])\n",
+ "list(session)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "A special situation arises when one tries to add an ontology individual to a session that already contains an individual with the same identifier."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 7,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "session_A = Session(); session_A.locked = True\n",
+ "with session_A:\n",
+ " lena_A = city.Citizen(name='Lena', age=70,\n",
+ " iri='https://example.org/entities#Lena')\n",
+ "\n",
+ "session_B = Session(); session_B.locked = True\n",
+ "with session_B:\n",
+ " lena_B = city.Citizen(name='Helena', age=31,\n",
+ " iri='https://example.org/entities#Lena')"
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {
+ "tags": [
+ "raises-exception"
+ ]
+ },
+ "outputs": [
+ {
+ "ename": "RuntimeError",
+ "evalue": "Some of the added entities already exist on the session.",
+ "output_type": "error",
+ "traceback": [
+ "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m",
+ "\u001b[0;31mRuntimeError\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 1\u001b[0m \u001b[0;32mwith\u001b[0m \u001b[0mSession\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;32mas\u001b[0m \u001b[0msession\u001b[0m\u001b[0;34m:\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 2\u001b[0m \u001b[0msession\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlena_A\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0;32m----> 3\u001b[0;31m \u001b[0msession\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0madd\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mlena_B\u001b[0m\u001b[0;34m)\u001b[0m \u001b[0;31m# -> Fails, there is already an individual with the same identifier.\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[0m",
+ "\u001b[0;32m~/Dokumente/SimPhoNy/simphony-osp/simphony_osp/session/session.py\u001b[0m in \u001b[0;36madd\u001b[0;34m(self, merge, exists_ok, all_triples, *individuals)\u001b[0m\n\u001b[1;32m 808\u001b[0m \u001b[0;32mand\u001b[0m \u001b[0mexists_ok\u001b[0m \u001b[0;32mis\u001b[0m \u001b[0;32mFalse\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 809\u001b[0m ):\n\u001b[0;32m--> 810\u001b[0;31m raise RuntimeError(\n\u001b[0m\u001b[1;32m 811\u001b[0m \u001b[0;34m\"Some of the added entities already exist on the session.\"\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n\u001b[1;32m 812\u001b[0m )\n",
+ "\u001b[0;31mRuntimeError\u001b[0m: Some of the added entities already exist on the session."
+ ]
+ }
+ ],
+ "source": [
+ "with Session() as session:\n",
+ " session.add(lena_A)\n",
+ " session.add(lena_B) # -> Fails, there is already an individual with the same identifier."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "When this happens, an exception is raised. It is still possible to copy the individual, but is necessary to decide whether:\n",
+ "\n",
+ "- the existing individual should be overwritten (default) or;\n",
+ "- the new individual should be merged with the existing one."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To apply default action (overwrite), use the keyword argument `exists_ok=True`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 9,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "70 Lena\n",
+ "31 Helena\n"
+ ]
+ }
+ ],
+ "source": [
+ "with Session() as session:\n",
+ " copy = session.add(lena_A)\n",
+ " print(copy.age, copy.name)\n",
+ " copy = session.add(lena_B, exists_ok=True)\n",
+ " print(copy.age, copy.name)"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Overwriting replaces the classes, attributes, attribute values and connections to other ontology individuals."
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "To merge the new individual with the previous one, use `exists_ok=True, merge=True` instead."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 10,
+ "metadata": {},
+ "outputs": [
+ {
+ "name": "stdout",
+ "output_type": "stream",
+ "text": [
+ "70 Lena\n",
+ "{70, 31} {'Helena', 'Lena'}\n"
+ ]
+ }
+ ],
+ "source": [
+ "with Session() as session:\n",
+ " copy = session.add(lena_A)\n",
+ " print(copy.age, copy.name)\n",
+ " copy = session.add(lena_B, exists_ok=True, merge=True)\n",
+ " print(copy['age'], copy['name'])"
+ ]
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Merging combines the classes, atrributes, attribute values and connections of the two individuals."
+ ]
}
- ],
- "source": [
- "with Session() as session:\n",
- " copy = session.add(lena_A)\n",
- " print(copy.age, copy.name)\n",
- " copy = session.add(lena_B, exists_ok=True, merge=True)\n",
- " print(copy['age'], copy['name'])"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Merging combines the classes, atrributes, attribute values and connections of the two individuals."
- ]
- }
- ],
- "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.12"
+ ],
+ "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.12"
+ },
+ "toc-showcode": false,
+ "toc-showtags": true
},
- "toc-showcode": false,
- "toc-showtags": true
- },
- "nbformat": 4,
- "nbformat_minor": 4
+ "nbformat": 4,
+ "nbformat_minor": 4
}
diff --git a/docs/usage/sessions/queries.ipynb b/docs/usage/sessions/queries.ipynb
index ad25146..e403d59 100644
--- a/docs/usage/sessions/queries.ipynb
+++ b/docs/usage/sessions/queries.ipynb
@@ -1,233 +1,233 @@
{
- "cells": [
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "# Queries: using the session object\n",
- "\n",
- ""
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "SimPhoNy's [session object](../../api_reference.md#simphony_osp.session.Session) implements methods that enable the retrieval of the ontology individuals it contains. The queries that can be run using such methods are extremely basic. If you need to run more advanced queries, head to the sections dealing with the [search module](search.ipynb) and [SPARQL](sparql.ipynb)."
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Consider a similar example from the city ontology again. Remember that by default, newly created individuals created are stored in the [Core Session](introduction.ipynb)."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 1,
- "metadata": {},
- "outputs": [],
- "source": [
- "from simphony_osp.namespaces import city, rdfs\n",
- "from simphony_osp.session import core_session\n",
- "\n",
- "freiburg = city.City(name=\"Freiburg\", coordinates=[47.997791, 7.842609])\n",
- "\n",
- "neighborhoods = {\n",
- " city.Neighborhood(name=name, coordinates=coordinates)\n",
- " for name, coordinates in [\n",
- " ('Altstadt', [47.99525, 7.84726]),\n",
- " ('Stühlinger', [47.99888, 7.83774]),\n",
- " ('Neuburg', [48.00021, 7.86084]),\n",
- " ('Herdern', [48.00779, 7.86268]),\n",
- " ('Brühl', [48.01684, 7.843]),\n",
- " ]\n",
- "}\n",
- "\n",
- "citizen_1 = city.Citizen(name='Nikola', age=35,\n",
- " iri='https://example.org/entities#Nikola')\n",
- "citizen_2 = city.Citizen(name='Lena', age=70,\n",
- " iri='https://example.org/entities#Lena')\n",
- "citizen_2[rdfs.label] = 'Helena'\n",
- "citizen_3 = city.Citizen(name='Marco', age=36,\n",
- " iri='https://example.org/entities#Marco')\n",
- "citizen_3[rdfs.label] = 'Marco'\n",
- "\n",
- "freiburg[city.hasPart] |= neighborhoods\n",
- "freiburg[city.hasInhabitant] += citizen_1, citizen_2"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "As shown in a [previous section](management.ipynb), the session object is iterable. This means that a simple method (althought very inefficient) to retrieve the individuals in the session is just iterating over the session object. It is also possible to know how many individuals are contained in a session using the Python built-in `len`."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 8,
- "metadata": {},
- "outputs": [
+ "cells": [
{
- "data": {
- "text/plain": [
- "[,\n",
- " ,\n",
- " ,\n",
- " ,\n",
- " ,\n",
- " ,\n",
- " ,\n",
- " ]"
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "# Queries: using the session object\n",
+ "\n",
+ ""
]
- },
- "execution_count": 8,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "list(core_session) # iterates over the session, very slow with big data"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 3,
- "metadata": {},
- "outputs": [
+ },
{
- "data": {
- "text/plain": [
- "9"
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "SimPhoNy's [session object](../../api_reference.md#simphony_osp.session.Session) implements methods that enable the retrieval of the ontology individuals it contains. The queries that can be run using such methods are extremely basic. If you need to run more advanced queries, head to the sections dealing with the [search module](search.ipynb) and [SPARQL](sparql.ipynb)."
]
- },
- "execution_count": 3,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "len(core_session)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "The session object also features a [get](../../api_reference.md#simphony_osp.session.Session.get) method that is similar to the [get method from ontology individuals](../assertional_knowledge.ipynb#Using-the-get,-iter,-connect,-and-disconnect-methods-(relationships-only)). It returns, in fact, a set-like object that manages the individuals contained in the session. Consequently, it is even possible to add and remove individuals from the session using in-place modifcations (although not very practical). The most common use case of the method is just retrieving ontology individuals."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 4,
- "metadata": {},
- "outputs": [],
- "source": [
- "core_session.get()"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Just like for the get method from ontology individuals, it is possible to filter the results to specific individuals (given their identifier is known or they are already available as objects) and classes, as well as any combination of both. "
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 5,
- "metadata": {},
- "outputs": [
+ },
{
- "data": {
- "text/plain": [
- ""
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "Consider a similar example from the city ontology again. Remember that by default, newly created individuals created are stored in the [Core Session](introduction.ipynb)."
]
- },
- "execution_count": 5,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "core_session.get('https://example.org/entities#Lena')"
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 6,
- "metadata": {},
- "outputs": [
+ },
{
- "data": {
- "text/plain": [
- "{, } "
+ "cell_type": "code",
+ "execution_count": 1,
+ "metadata": {},
+ "outputs": [],
+ "source": [
+ "from simphony_osp.namespaces import city, rdfs\n",
+ "from simphony_osp.session import core_session\n",
+ "\n",
+ "freiburg = city.City(name=\"Freiburg\", coordinates=[47.997791, 7.842609])\n",
+ "\n",
+ "neighborhoods = {\n",
+ " city.Neighborhood(name=name, coordinates=coordinates)\n",
+ " for name, coordinates in [\n",
+ " ('Altstadt', [47.99525, 7.84726]),\n",
+ " ('St\u00fchlinger', [47.99888, 7.83774]),\n",
+ " ('Neuburg', [48.00021, 7.86084]),\n",
+ " ('Herdern', [48.00779, 7.86268]),\n",
+ " ('Br\u00fchl', [48.01684, 7.843]),\n",
+ " ]\n",
+ "}\n",
+ "\n",
+ "citizen_1 = city.Citizen(name='Nikola', age=35,\n",
+ " iri='https://example.org/entities#Nikola')\n",
+ "citizen_2 = city.Citizen(name='Lena', age=70,\n",
+ " iri='https://example.org/entities#Lena')\n",
+ "citizen_2[rdfs.label] = 'Helena'\n",
+ "citizen_3 = city.Citizen(name='Marco', age=36,\n",
+ " iri='https://example.org/entities#Marco')\n",
+ "citizen_3[rdfs.label] = 'Marco'\n",
+ "\n",
+ "freiburg[city.hasPart] |= neighborhoods\n",
+ "freiburg[city.hasInhabitant] += citizen_1, citizen_2"
]
- },
- "execution_count": 6,
- "metadata": {},
- "output_type": "execute_result"
- }
- ],
- "source": [
- "core_session.get(oclass=city.Citizen)"
- ]
- },
- {
- "cell_type": "markdown",
- "metadata": {},
- "source": [
- "Finally, if a [label](../terminological_knowledge.ipynb#Accessing-an-entity%E2%80%99s-label) has been given to the individual, then it is also possible to use it as retrieval method."
- ]
- },
- {
- "cell_type": "code",
- "execution_count": 7,
- "metadata": {},
- "outputs": [
+ },
+ {
+ "cell_type": "markdown",
+ "metadata": {},
+ "source": [
+ "As shown in a [previous section](management.ipynb), the session object is iterable. This means that a simple method (althought very inefficient) to retrieve the individuals in the session is just iterating over the session object. It is also possible to know how many individuals are contained in a session using the Python built-in `len`."
+ ]
+ },
+ {
+ "cell_type": "code",
+ "execution_count": 8,
+ "metadata": {},
+ "outputs": [
+ {
+ "data": {
+ "text/plain": [
+ "[,\n",
+ " ,\n",
+ " ,\n",
+ " ,\n",
+ " ,\n",
+ "