{ "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": [ { "data": { "text/plain": [ "417.4695920611045" ] }, "execution_count": 1, "metadata": {}, "output_type": "execute_result" } ], "source": [ "from simphony_osp.namespaces import wgs84_pos\n", "\n", "location_freiburg = wgs84_pos.Point()\n", "location_freiburg[wgs84_pos.latitude] = 47.997791\n", "location_freiburg[wgs84_pos.longitude] = 7.842609\n", "\n", "location_paris = wgs84_pos.Point()\n", "location_paris[wgs84_pos.latitude] = 48.85333\n", "location_paris[wgs84_pos.longitude] = 2.34885\n", "\n", "location_freiburg.operations.distance(location_paris)" ] } ], "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": 5 }