{ "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", "[![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/simphony/docs/v4.0.0?filepath=docs%2Fintroduction%2Fquickstart.ipynb \"Click to run this tutorial yourself!\")\n", " \n", "
\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" ] } ], "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", "\n", "SimPhoNy semantic2dot\n", "\n", "\n", "\n", "https___www.simphony-project.eu_entity#b9074f9e-6bd4-4eef-b8ae-78fd4d1d86cb\n", "\n", "My Atom's position\n", "classes: Position (simlammps)\n", "Vector: [1 0 3]\n", "session: 0x55899b8cab40\n", "\n", "\n", "\n", "https___www.simphony-project.eu_entity#63f477ea-dfc5-48c7-8227-60b71cc65cb6\n", "\n", "My Atom\n", "classes: Atom (simlammps)\n", "session: 0x55899b8cab40\n", "\n", "\n", "\n", "https___www.simphony-project.eu_entity#63f477ea-dfc5-48c7-8227-60b71cc65cb6->https___www.simphony-project.eu_entity#b9074f9e-6bd4-4eef-b8ae-78fd4d1d86cb\n", "\n", "\n", "has part (simlammps)\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." ] } ], "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 }