| 
1 | 1 | {  | 
2 |  | - "cells": [  | 
3 |  | -  {  | 
4 |  | -   "cell_type": "markdown",  | 
5 |  | -   "id": "edcc1fd6-2474-4d15-8355-084ef85bc748",  | 
6 |  | -   "metadata": {},  | 
7 |  | -   "source": [  | 
8 |  | -    "# Operations development"  | 
9 |  | -   ]  | 
10 |  | -  },  | 
11 |  | -  {  | 
12 |  | -   "cell_type": "markdown",  | 
13 |  | -   "id": "e191786a-786a-418e-886a-a4da0c2d741e",  | 
14 |  | -   "metadata": {},  | 
15 |  | -   "source": [  | 
16 |  | -    "SimPhoNy operations are actions (written in Python) that can be executed on\n",  | 
17 |  | -    "demand on any ontology individual belonging to the ontology class they\n",  | 
18 |  | -    "are defined for."  | 
19 |  | -   ]  | 
20 |  | -  },  | 
21 |  | -  {  | 
22 |  | -   "cell_type": "markdown",  | 
23 |  | -   "id": "7ea449f9-bc08-4ddc-a8a8-13c6d3ade2ef",  | 
24 |  | -   "metadata": {},  | 
25 |  | -   "source": [  | 
26 |  | -    "<div class=\"admonition important\">\n",  | 
27 |  | -    "<div class=\"admonition-title\" style=\"font-weight: bold\"><div style=\"display: inline-block\">Tip</div></div>\n",  | 
28 |  | -    "    \n",  | 
29 |  | -    "File uploads and downloads in SimPhoNy are an example of SimPhoNy operations.\n",  | 
30 |  | -    "Head to the [assertional knowledge](../usage/assertional_knowledge.html#Operations) section to see them in action.\n",  | 
31 |  | -    "    \n",  | 
32 |  | -    "</div>"  | 
33 |  | -   ]  | 
34 |  | -  },  | 
35 |  | -  {  | 
36 |  | -   "cell_type": "markdown",  | 
37 |  | -   "id": "ee275d73-f2ef-4418-bc94-cec8458c803c",  | 
38 |  | -   "metadata": {},  | 
39 |  | -   "source": [  | 
40 |  | -    "\n",  | 
41 |  | -    "SimPhoNy operations are distributed as (or as part of) Python packages. \n",  | 
42 |  | -    "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",  | 
43 |  | -    "\n",  | 
44 |  | -    "Then, define an `iri` attribute having as value the IRI of the ontology class that the\n",  | 
45 |  | -    "operation should be associated to. Every public method ([not starting with\n",  | 
46 |  | -    "an underscore](https://peps.python.org/pep-0008/#method-names-and-instance-variables)) defined on the implementation is automatically detected and\n",  | 
47 |  | -    "assigned as an operation to said ontology class. The\n",  | 
48 |  | -    "[ontology individual object](../usage/assertional_knowledge.ipynb#Ontology-individual-objects)\n",  | 
49 |  | -    "on which the operation is called is available as the private attribute\n",  | 
50 |  | -    "`_individual` on every instance of the implementation. For a specific \n",  | 
51 |  | -    "ontology individual, the implementation gets instantiated the first time that \n",  | 
52 |  | -    "any operation defined on it is called by the user.\n",  | 
53 |  | -    "\n",  | 
54 |  | -    "Finally, define an\n",  | 
55 |  | -    "[entry point](https://packaging.python.org/en/latest/specifications/entry-points/#entry-points-specification)\n",  | 
56 |  | -    "(or many if implementing operations for several ontology classes) under the\n",  | 
57 |  | -    "`simphony_osp.ontology.operations`\n",  | 
58 |  | -    "[group](https://packaging.python.org/en/latest/specifications/entry-points/#data-model)\n",  | 
59 |  | -    "that points to your\n",  | 
60 |  | -    "implementation of the `Operations` abstract class.\n",  | 
61 |  | -    "\n",  | 
62 |  | -    "An example implementation of an operation that takes advantage of\n",  | 
63 |  | -    "[geopy](https://pypi.org/project/geopy/) to compute the distance between \n",  | 
64 |  | -    "two points on Earth defined using the \n",  | 
65 |  | -    "[WGS84 Geo Positioning vocabulary](https://www.w3.org/2003/01/geo/wgs84_pos)\n",  | 
66 |  | -    "is shown below."  | 
67 |  | -   ]  | 
68 |  | -  },  | 
69 |  | -  {  | 
70 |  | -   "cell_type": "markdown",  | 
71 |  | -   "id": "0fffa052-186a-46b7-9076-8acfed6b1ee0",  | 
72 |  | -   "metadata": {},  | 
73 |  | -   "source": [  | 
74 |  | -    "```python\n",  | 
75 |  | -    "\"\"\"Operations for classes from the WGS84 Geo Positioning vocabulary.\"\"\"\n",  | 
76 |  | -    "\n",  | 
77 |  | -    "from geopy import distance\n",  | 
78 |  | -    "from simphony_osp.namespaces import wgs84_pos\n",  | 
79 |  | -    "from simphony_osp.ontology import OntologyIndividual\n",  | 
80 |  | -    "from simphony_osp.ontology.operations import Operations\n",  | 
81 |  | -    "\n",  | 
82 |  | -    "\n",  | 
83 |  | -    "class Wgs84Pos(Operations):\n",  | 
84 |  | -    "    \"\"\"Operations for the Point ontology class.\"\"\"\n",  | 
85 |  | -    "\n",  | 
86 |  | -    "    iri = wgs84_pos.Point.iri\n",  | 
87 |  | -    "\n",  | 
88 |  | -    "    def distance(self, other: OntologyIndividual) -> float:\n",  | 
89 |  | -    "        \"\"\"Compute the distance between two points on Earth.\n",  | 
90 |  | -    "        \n",  | 
91 |  | -    "        Args:\n",  | 
92 |  | -    "            other: Another point with respect to which the distance will be computed. \n",  | 
93 |  | -    "            \n",  | 
94 |  | -    "        Returns:\n",  | 
95 |  | -    "            The distance between this point and the given one in km.\n",  | 
96 |  | -    "        \"\"\"\n",  | 
97 |  | -    "        lat_self = float(self._individual[wgs84_pos.latitude].one())\n",  | 
98 |  | -    "        long_self = float(self._individual[wgs84_pos.longitude].one())\n",  | 
99 |  | -    "        lat_other = float(other[wgs84_pos.latitude].one())\n",  | 
100 |  | -    "        long_other = float(other[wgs84_pos.longitude].one())\n",  | 
101 |  | -    "        return distance.geodesic(\n",  | 
102 |  | -    "            (lat_self, long_self),\n",  | 
103 |  | -    "            (lat_other, long_other),\n",  | 
104 |  | -    "            ellipsoid=\"WGS-84\"\n",  | 
105 |  | -    "        ).km\n",  | 
106 |  | -    "\n",  | 
107 |  | -    "```"  | 
108 |  | -   ]  | 
109 |  | -  },  | 
110 |  | -  {  | 
111 |  | -   "cell_type": "markdown",  | 
112 |  | -   "id": "744e037f-aabe-4bdf-a994-8787f3f039b1",  | 
113 |  | -   "metadata": {},  | 
114 |  | -   "source": [  | 
115 |  | -    "<div class=\"admonition note\">\n",  | 
116 |  | -    "<div class=\"admonition-title\" style=\"font-weight: bold\"><div style=\"display: inline-block\">Note</div></div>\n",  | 
117 |  | -    "    \n",  | 
118 |  | -    "Remember that the implementation above is still not enough for the operation to\n",  | 
119 |  | -    "work: the corresponding \n",  | 
120 |  | -    "[entry point](https://packaging.python.org/en/latest/specifications/entry-points/#entry-points-specification)\n",  | 
121 |  | -    "for `Wgs84Pos` must have been defined and the `wgs84_pos` vocabulary needs to be installed using [pico](../usage/ontologies/pico.html).\n",  | 
122 |  | -    "    \n",  | 
123 |  | -    "</div>"  | 
124 |  | -   ]  | 
125 |  | -  },  | 
126 |  | -  {  | 
127 |  | -   "cell_type": "markdown",  | 
128 |  | -   "id": "d3db93d6-e26f-4831-b9a2-d9223cc4a51f",  | 
129 |  | -   "metadata": {},  | 
130 |  | -   "source": [  | 
131 |  | -    "The operation can be used as follows."  | 
132 |  | -   ]  | 
133 |  | -  },  | 
134 |  | -  {  | 
135 |  | -   "cell_type": "code",  | 
136 |  | -   "execution_count": 1,  | 
137 |  | -   "id": "40a97048-80ea-4d99-8711-3ecd6ab5598b",  | 
138 |  | -   "metadata": {},  | 
139 |  | -   "outputs": [  | 
 | 2 | +  "cells": [  | 
 | 3 | +    {  | 
 | 4 | +      "cell_type": "markdown",  | 
 | 5 | +      "id": "edcc1fd6-2474-4d15-8355-084ef85bc748",  | 
 | 6 | +      "metadata": {},  | 
 | 7 | +      "source": [  | 
 | 8 | +        "# Operations development"  | 
 | 9 | +      ]  | 
 | 10 | +    },  | 
 | 11 | +    {  | 
 | 12 | +      "cell_type": "markdown",  | 
 | 13 | +      "id": "e191786a-786a-418e-886a-a4da0c2d741e",  | 
 | 14 | +      "metadata": {},  | 
 | 15 | +      "source": [  | 
 | 16 | +        "SimPhoNy operations are actions (written in Python) that can be executed on\n",  | 
 | 17 | +        "demand on any ontology individual belonging to the ontology class they\n",  | 
 | 18 | +        "are defined for."  | 
 | 19 | +      ]  | 
 | 20 | +    },  | 
140 | 21 |     {  | 
141 |  | -     "data": {  | 
142 |  | -      "text/plain": [  | 
143 |  | -       "417.4695920611045"  | 
 | 22 | +      "cell_type": "markdown",  | 
 | 23 | +      "id": "7ea449f9-bc08-4ddc-a8a8-13c6d3ade2ef",  | 
 | 24 | +      "metadata": {},  | 
 | 25 | +      "source": [  | 
 | 26 | +        "<div class=\"admonition important\">\n",  | 
 | 27 | +        "<div class=\"admonition-title\" style=\"font-weight: bold\"><div style=\"display: inline-block\">Tip</div></div>\n",  | 
 | 28 | +        "    \n",  | 
 | 29 | +        "File uploads and downloads in SimPhoNy are an example of SimPhoNy operations.\n",  | 
 | 30 | +        "Head to the [assertional knowledge](../usage/assertional_knowledge.html#Operations) section to see them in action.\n",  | 
 | 31 | +        "    \n",  | 
 | 32 | +        "</div>"  | 
144 | 33 |       ]  | 
145 |  | -     },  | 
146 |  | -     "execution_count": 1,  | 
147 |  | -     "metadata": {},  | 
148 |  | -     "output_type": "execute_result"  | 
 | 34 | +    },  | 
 | 35 | +    {  | 
 | 36 | +      "cell_type": "markdown",  | 
 | 37 | +      "id": "ee275d73-f2ef-4418-bc94-cec8458c803c",  | 
 | 38 | +      "metadata": {},  | 
 | 39 | +      "source": [  | 
 | 40 | +        "\n",  | 
 | 41 | +        "SimPhoNy operations are distributed as (or as part of) Python packages. \n",  | 
 | 42 | +        "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",  | 
 | 43 | +        "\n",  | 
 | 44 | +        "Then, define an `iri` attribute having as value the IRI of the ontology class that the\n",  | 
 | 45 | +        "operation should be associated to. Every public method ([not starting with\n",  | 
 | 46 | +        "an underscore](https://peps.python.org/pep-0008/#method-names-and-instance-variables)) defined on the implementation is automatically detected and\n",  | 
 | 47 | +        "assigned as an operation to said ontology class. The\n",  | 
 | 48 | +        "[ontology individual object](../usage/assertional_knowledge.ipynb#Ontology-individual-objects)\n",  | 
 | 49 | +        "on which the operation is called is available as the private attribute\n",  | 
 | 50 | +        "`_individual` on every instance of the implementation. For a specific \n",  | 
 | 51 | +        "ontology individual, the implementation gets instantiated the first time that \n",  | 
 | 52 | +        "any operation defined on it is called by the user.\n",  | 
 | 53 | +        "\n",  | 
 | 54 | +        "Finally, define an\n",  | 
 | 55 | +        "[entry point](https://packaging.python.org/en/latest/specifications/entry-points/#entry-points-specification)\n",  | 
 | 56 | +        "(or many if implementing operations for several ontology classes) under the\n",  | 
 | 57 | +        "`simphony_osp.ontology.operations`\n",  | 
 | 58 | +        "[group](https://packaging.python.org/en/latest/specifications/entry-points/#data-model)\n",  | 
 | 59 | +        "that points to your\n",  | 
 | 60 | +        "implementation of the `Operations` abstract class.\n",  | 
 | 61 | +        "\n",  | 
 | 62 | +        "An example implementation of an operation that takes advantage of\n",  | 
 | 63 | +        "[geopy](https://pypi.org/project/geopy/) to compute the distance between \n",  | 
 | 64 | +        "two points on Earth defined using the \n",  | 
 | 65 | +        "[WGS84 Geo Positioning vocabulary](https://www.w3.org/2003/01/geo/wgs84_pos)\n",  | 
 | 66 | +        "is shown below."  | 
 | 67 | +      ]  | 
 | 68 | +    },  | 
 | 69 | +    {  | 
 | 70 | +      "cell_type": "markdown",  | 
 | 71 | +      "id": "0fffa052-186a-46b7-9076-8acfed6b1ee0",  | 
 | 72 | +      "metadata": {},  | 
 | 73 | +      "source": [  | 
 | 74 | +        "```python\n",  | 
 | 75 | +        "\"\"\"Operations for classes from the WGS84 Geo Positioning vocabulary.\"\"\"\n",  | 
 | 76 | +        "\n",  | 
 | 77 | +        "from geopy import distance\n",  | 
 | 78 | +        "from simphony_osp.namespaces import wgs84_pos\n",  | 
 | 79 | +        "from simphony_osp.ontology import OntologyIndividual\n",  | 
 | 80 | +        "from simphony_osp.ontology.operations import Operations\n",  | 
 | 81 | +        "\n",  | 
 | 82 | +        "\n",  | 
 | 83 | +        "class Wgs84Pos(Operations):\n",  | 
 | 84 | +        "    \"\"\"Operations for the Point ontology class.\"\"\"\n",  | 
 | 85 | +        "\n",  | 
 | 86 | +        "    iri = wgs84_pos.Point.iri\n",  | 
 | 87 | +        "\n",  | 
 | 88 | +        "    def distance(self, other: OntologyIndividual) -> float:\n",  | 
 | 89 | +        "        \"\"\"Compute the distance between two points on Earth.\n",  | 
 | 90 | +        "        \n",  | 
 | 91 | +        "        Args:\n",  | 
 | 92 | +        "            other: Another point with respect to which the distance will be computed. \n",  | 
 | 93 | +        "            \n",  | 
 | 94 | +        "        Returns:\n",  | 
 | 95 | +        "            The distance between this point and the given one in km.\n",  | 
 | 96 | +        "        \"\"\"\n",  | 
 | 97 | +        "        lat_self = float(self._individual[wgs84_pos.latitude].one())\n",  | 
 | 98 | +        "        long_self = float(self._individual[wgs84_pos.longitude].one())\n",  | 
 | 99 | +        "        lat_other = float(other[wgs84_pos.latitude].one())\n",  | 
 | 100 | +        "        long_other = float(other[wgs84_pos.longitude].one())\n",  | 
 | 101 | +        "        return distance.geodesic(\n",  | 
 | 102 | +        "            (lat_self, long_self),\n",  | 
 | 103 | +        "            (lat_other, long_other),\n",  | 
 | 104 | +        "            ellipsoid=\"WGS-84\"\n",  | 
 | 105 | +        "        ).km\n",  | 
 | 106 | +        "\n",  | 
 | 107 | +        "```"  | 
 | 108 | +      ]  | 
 | 109 | +    },  | 
 | 110 | +    {  | 
 | 111 | +      "cell_type": "markdown",  | 
 | 112 | +      "id": "744e037f-aabe-4bdf-a994-8787f3f039b1",  | 
 | 113 | +      "metadata": {},  | 
 | 114 | +      "source": [  | 
 | 115 | +        "<div class=\"admonition note\">\n",  | 
 | 116 | +        "<div class=\"admonition-title\" style=\"font-weight: bold\"><div style=\"display: inline-block\">Note</div></div>\n",  | 
 | 117 | +        "    \n",  | 
 | 118 | +        "Remember that the implementation above is still not enough for the operation to\n",  | 
 | 119 | +        "work: the corresponding \n",  | 
 | 120 | +        "[entry point](https://packaging.python.org/en/latest/specifications/entry-points/#entry-points-specification)\n",  | 
 | 121 | +        "for `Wgs84Pos` must have been defined and the `wgs84_pos` vocabulary needs to be installed using [pico](../usage/ontologies/pico.html).\n",  | 
 | 122 | +        "    \n",  | 
 | 123 | +        "</div>"  | 
 | 124 | +      ]  | 
 | 125 | +    },  | 
 | 126 | +    {  | 
 | 127 | +      "cell_type": "markdown",  | 
 | 128 | +      "id": "d3db93d6-e26f-4831-b9a2-d9223cc4a51f",  | 
 | 129 | +      "metadata": {},  | 
 | 130 | +      "source": [  | 
 | 131 | +        "The operation can be used as follows."  | 
 | 132 | +      ]  | 
 | 133 | +    },  | 
 | 134 | +    {  | 
 | 135 | +      "cell_type": "code",  | 
 | 136 | +      "execution_count": 1,  | 
 | 137 | +      "id": "40a97048-80ea-4d99-8711-3ecd6ab5598b",  | 
 | 138 | +      "metadata": {},  | 
 | 139 | +      "outputs": [  | 
 | 140 | +        {  | 
 | 141 | +          "data": {  | 
 | 142 | +            "text/plain": [  | 
 | 143 | +              "417.4695920611045"  | 
 | 144 | +            ]  | 
 | 145 | +          },  | 
 | 146 | +          "execution_count": 1,  | 
 | 147 | +          "metadata": {},  | 
 | 148 | +          "output_type": "execute_result"  | 
 | 149 | +        }  | 
 | 150 | +      ],  | 
 | 151 | +      "source": [  | 
 | 152 | +        "from simphony_osp.namespaces import wgs84_pos\n",  | 
 | 153 | +        "\n",  | 
 | 154 | +        "location_freiburg = wgs84_pos.Point()\n",  | 
 | 155 | +        "location_freiburg[wgs84_pos.latitude] = 47.997791\n",  | 
 | 156 | +        "location_freiburg[wgs84_pos.longitude] = 7.842609\n",  | 
 | 157 | +        "\n",  | 
 | 158 | +        "location_paris = wgs84_pos.Point()\n",  | 
 | 159 | +        "location_paris[wgs84_pos.latitude] = 48.85333\n",  | 
 | 160 | +        "location_paris[wgs84_pos.longitude] = 2.34885\n",  | 
 | 161 | +        "\n",  | 
 | 162 | +        "location_freiburg.operations.distance(location_paris)"  | 
 | 163 | +      ]  | 
 | 164 | +    }  | 
 | 165 | +  ],  | 
 | 166 | +  "metadata": {  | 
 | 167 | +    "kernelspec": {  | 
 | 168 | +      "display_name": "Python 3",  | 
 | 169 | +      "language": "python",  | 
 | 170 | +      "name": "python3"  | 
 | 171 | +    },  | 
 | 172 | +    "language_info": {  | 
 | 173 | +      "codemirror_mode": {  | 
 | 174 | +        "name": "ipython",  | 
 | 175 | +        "version": 3  | 
 | 176 | +      },  | 
 | 177 | +      "file_extension": ".py",  | 
 | 178 | +      "mimetype": "text/x-python",  | 
 | 179 | +      "name": "python",  | 
 | 180 | +      "nbconvert_exporter": "python",  | 
 | 181 | +      "pygments_lexer": "ipython3",  | 
 | 182 | +      "version": "3.8.12"  | 
149 | 183 |     }  | 
150 |  | -   ],  | 
151 |  | -   "source": [  | 
152 |  | -    "from simphony_osp.namespaces import wgs84_pos\n",  | 
153 |  | -    "\n",  | 
154 |  | -    "location_freiburg = wgs84_pos.Point()\n",  | 
155 |  | -    "location_freiburg[wgs84_pos.latitude] = 47.997791\n",  | 
156 |  | -    "location_freiburg[wgs84_pos.longitude] = 7.842609\n",  | 
157 |  | -    "\n",  | 
158 |  | -    "location_paris = wgs84_pos.Point()\n",  | 
159 |  | -    "location_paris[wgs84_pos.latitude] = 48.85333\n",  | 
160 |  | -    "location_paris[wgs84_pos.longitude] = 2.34885\n",  | 
161 |  | -    "\n",  | 
162 |  | -    "location_freiburg.operations.distance(location_paris)"  | 
163 |  | -   ]  | 
164 |  | -  }  | 
165 |  | - ],  | 
166 |  | - "metadata": {  | 
167 |  | -  "kernelspec": {  | 
168 |  | -   "display_name": "Python 3",  | 
169 |  | -   "language": "python",  | 
170 |  | -   "name": "python3"  | 
171 | 184 |   },  | 
172 |  | -  "language_info": {  | 
173 |  | -   "codemirror_mode": {  | 
174 |  | -    "name": "ipython",  | 
175 |  | -    "version": 3  | 
176 |  | -   },  | 
177 |  | -   "file_extension": ".py",  | 
178 |  | -   "mimetype": "text/x-python",  | 
179 |  | -   "name": "python",  | 
180 |  | -   "nbconvert_exporter": "python",  | 
181 |  | -   "pygments_lexer": "ipython3",  | 
182 |  | -   "version": "3.8.12"  | 
183 |  | -  }  | 
184 |  | - },  | 
185 |  | - "nbformat": 4,  | 
186 |  | - "nbformat_minor": 5  | 
 | 185 | +  "nbformat": 4,  | 
 | 186 | +  "nbformat_minor": 5  | 
187 | 187 | }  | 
0 commit comments