From 318ae0c091824de45ace0caa30324e795f20ad9d Mon Sep 17 00:00:00 2001 From: candle Date: Wed, 25 Sep 2024 17:45:07 +0200 Subject: [PATCH 01/36] towards non-omm ase --- .../nanover-omni/src/nanover/omni/ase.py | 186 ++++++++++++++++++ .../nanover-omni/src/nanover/omni/ase_omm.py | 57 +++--- 2 files changed, 216 insertions(+), 27 deletions(-) create mode 100644 python-libraries/nanover-omni/src/nanover/omni/ase.py diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py new file mode 100644 index 00000000..0b0dfe07 --- /dev/null +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -0,0 +1,186 @@ +import warnings +from dataclasses import dataclass +from os import PathLike +from pathlib import Path +from typing import Optional, Any, Callable + +import numpy as np +from ase import units, Atoms +from ase.md import Langevin, MDLogger +from ase.md.md import MolecularDynamics +from ase.md.velocitydistribution import MaxwellBoltzmannDistribution +from openmm.app import Simulation + +from nanover.app import NanoverImdApplication +from nanover.ase import send_ase_frame +from nanover.ase.converter import EV_TO_KJMOL +from nanover.ase.imd_calculator import ImdCalculator +from nanover.ase.openmm import OpenMMCalculator +from nanover.ase.openmm.runner import openmm_ase_frame_adaptor +from nanover.ase.wall_constraint import VelocityWallConstraint +from nanover.openmm import serializer +from nanover.utilities.event import Event + + +CONSTRAINTS_UNSUPPORTED_MESSAGE = ( + "The simulation contains constraints which will be ignored by this runner!" +) + + +@dataclass +class InitialState: + positions: Any + velocities: Any + cell: Any + + +class ASESimulation: + """ + A wrapper for ASE simulations so they can be run inside the OmniRunner. + """ + + @classmethod + def from_dynamics( + cls, + dynamics: MolecularDynamics, + *, + name: Optional[str] = None, + frame_method=send_ase_frame, + ): + """ + Construct this from an existing ASE dynamics. + :param dynamics: An existing ASE Dynamics + :param name: An optional name for the simulation instead of default + :param frame_method: A + """ + sim = cls(name) + sim.dynamics = dynamics + sim.frame_method = frame_method + return sim + + @property + def atoms(self): + try: + return self.dynamics.atoms + except AttributeError: + return None + + def __init__(self, name: Optional[str] = None): + self.name = name or "Unnamed ASE OpenMM Simulation" + + self.app_server: Optional[NanoverImdApplication] = None + + self.on_reset_energy_exceeded = Event() + + self.verbose = False + self.use_walls = False + self.reset_energy: Optional[float] = None + self.time_step = 1 + self.frame_interval = 5 + self.include_velocities = False + self.include_forces = False + self.platform: Optional[str] = None + + self.dynamics: Optional[MolecularDynamics] = None + self.checkpoint: Optional[InitialState] = None + + self._frame_adapter: Optional[Callable] = None + + def load(self): + """ + Load and set up the simulation if it isn't done already. + """ + assert self.dynamics is not None + + if self.use_walls: + self.atoms.constraints.append(VelocityWallConstraint()) + + self.checkpoint = InitialState( + positions=self.atoms.get_positions(), + velocities=self.atoms.get_velocities(), + cell=self.atoms.get_cell(), + ) + + def reset(self, app_server: NanoverImdApplication): + """ + Reset the simulation to its initial conditions, reset IMD interactions, and reset frame stream to begin with + topology and continue. + :param app_server: The app server hosting the frame publisher and imd state + """ + assert ( + self.dynamics is not None + and self.atoms is not None + and self.checkpoint is not None + ) + + self.app_server = app_server + + self.atoms.calc = ImdCalculator( + self.app_server.imd, + self.atoms.calc, + dynamics=self.dynamics, + ) + + # remove previous frame adaptor and attach new one + if self._frame_adapter is not None: + remove_observer(self.dynamics, self._frame_adapter) + + self._frame_adapter = openmm_ase_frame_adaptor( + self.atoms, + self.app_server.frame_publisher, + include_velocities=self.include_velocities, + include_forces=self.include_forces, + ) + self.dynamics.attach(self._frame_adapter, interval=self.frame_interval) + + if self.verbose: + self.dynamics.attach( + MDLogger( + self.dynamics, + self.atoms, + "-", + header=True, + stress=False, + peratom=False, + ), + interval=100, + ) + + # reset atoms to initial state + self.atoms.set_positions(self.checkpoint.positions) + self.atoms.set_velocities(self.checkpoint.velocities) + self.atoms.set_cell(self.checkpoint.cell) + + def advance_by_one_step(self): + """ + Advance the simulation to the next point a frame should be reported, and send that frame. + """ + self.advance_to_next_report() + + def advance_by_seconds(self, dt: float): + """ + Advance playback time by some seconds, and advance the simulation to the next frame output. + :param dt: Time to advance playback by in seconds (ignored) + """ + self.advance_to_next_report() + + def advance_to_next_report(self): + """ + Step the simulation to the next point a frame should be reported. + """ + assert self.dynamics is not None + self.dynamics.run(self.frame_interval) + + if self.reset_energy is not None and self.app_server is not None: + energy = self.atoms.get_total_energy() * EV_TO_KJMOL + if not np.isfinite(energy) or energy > self.reset_energy: + self.on_reset_energy_exceeded.invoke() + self.reset(self.app_server) + + +def remove_observer(dynamics: MolecularDynamics, func: Callable): + entry = next(entry for entry in dynamics.observers if entry[0] == func) + try: + dynamics.observers.remove(entry) + except StopIteration: + pass diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index 2fe1f00e..fe7178ba 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -2,7 +2,7 @@ from dataclasses import dataclass from os import PathLike from pathlib import Path -from typing import Optional, Any +from typing import Optional, Any, Callable import numpy as np from ase import units, Atoms @@ -17,6 +17,7 @@ from nanover.ase.openmm import OpenMMCalculator from nanover.ase.openmm.runner import openmm_ase_frame_adaptor from nanover.ase.wall_constraint import VelocityWallConstraint +from nanover.omni.ase import InitialState, remove_observer from nanover.openmm import serializer from nanover.utilities.event import Event @@ -26,20 +27,18 @@ ) -@dataclass -class InitialState: - positions: Any - velocities: Any - cell: Any - - class ASEOpenMMSimulation: """ A wrapper for ASE OpenMM simulations so they can be run inside the OmniRunner. """ @classmethod - def from_simulation(cls, simulation: Simulation, *, name: Optional[str] = None): + def from_simulation( + cls, + simulation: Simulation, + *, + name: Optional[str] = None, + ): """ Construct this from an existing ASE OpenMM simulation. :param simulation: An existing ASE OpenMM Simulation @@ -83,6 +82,8 @@ def __init__(self, name: Optional[str] = None): self.openmm_calculator: Optional[OpenMMCalculator] = None self.checkpoint: Optional[InitialState] = None + self._frame_adapter: Optional[Callable] = None + def load(self): """ Load and set up the simulation if it isn't done already. @@ -128,16 +129,17 @@ def reset(self, app_server: NanoverImdApplication): if self.simulation.system.getNumConstraints() > 0: warnings.warn(CONSTRAINTS_UNSUPPORTED_MESSAGE) - # We do not remove the center of mass (fixcm=False). If the center of - # mass translations should be removed, then the removal should be added - # to the OpenMM system. - self.dynamics = Langevin( - atoms=self.atoms, - timestep=self.time_step * units.fs, - temperature_K=300, - friction=1e-2, - fixcm=False, - ) + if self.dynamics is None: + # We do not remove the center of mass (fixcm=False). If the center of + # mass translations should be removed, then the removal should be added + # to the OpenMM system. + self.dynamics = Langevin( + atoms=self.atoms, + timestep=self.time_step * units.fs, + temperature_K=300, + friction=1e-2, + fixcm=False, + ) self.atoms.calc = ImdCalculator( self.app_server.imd, @@ -145,15 +147,16 @@ def reset(self, app_server: NanoverImdApplication): dynamics=self.dynamics, ) - self.dynamics.attach( - openmm_ase_frame_adaptor( - self.atoms, - self.app_server.frame_publisher, - include_velocities=self.include_velocities, - include_forces=self.include_forces, - ), - interval=self.frame_interval, + if self._frame_adapter is not None: + remove_observer(self.dynamics, self._frame_adapter) + + self._frame_adapter = openmm_ase_frame_adaptor( + self.atoms, + self.app_server.frame_publisher, + include_velocities=self.include_velocities, + include_forces=self.include_forces, ) + self.dynamics.attach(self._frame_adapter, interval=self.frame_interval) if self.verbose: self.dynamics.attach( From 7af6611e30f4521abbc3c7274dd696823bf2c391 Mon Sep 17 00:00:00 2001 From: candle Date: Wed, 25 Sep 2024 17:48:17 +0200 Subject: [PATCH 02/36] cleanup --- python-libraries/nanover-omni/src/nanover/omni/ase.py | 10 +--------- .../nanover-omni/src/nanover/omni/ase_omm.py | 3 +-- 2 files changed, 2 insertions(+), 11 deletions(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 0b0dfe07..ace67f6d 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -1,24 +1,16 @@ -import warnings from dataclasses import dataclass -from os import PathLike -from pathlib import Path from typing import Optional, Any, Callable import numpy as np -from ase import units, Atoms -from ase.md import Langevin, MDLogger +from ase.md import MDLogger from ase.md.md import MolecularDynamics -from ase.md.velocitydistribution import MaxwellBoltzmannDistribution -from openmm.app import Simulation from nanover.app import NanoverImdApplication from nanover.ase import send_ase_frame from nanover.ase.converter import EV_TO_KJMOL from nanover.ase.imd_calculator import ImdCalculator -from nanover.ase.openmm import OpenMMCalculator from nanover.ase.openmm.runner import openmm_ase_frame_adaptor from nanover.ase.wall_constraint import VelocityWallConstraint -from nanover.openmm import serializer from nanover.utilities.event import Event diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index fe7178ba..438ee008 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -1,8 +1,7 @@ import warnings -from dataclasses import dataclass from os import PathLike from pathlib import Path -from typing import Optional, Any, Callable +from typing import Optional, Callable import numpy as np from ase import units, Atoms From b9ccada8c5f1b7253977113d1a6b6ea6afde0d24 Mon Sep 17 00:00:00 2001 From: candle Date: Thu, 26 Sep 2024 12:55:04 +0200 Subject: [PATCH 03/36] fixes + make basic_example work --- examples/ase/basic_example.ipynb | 1400 ++++++----------- .../nanover-omni/src/nanover/omni/ase.py | 3 +- 2 files changed, 515 insertions(+), 888 deletions(-) diff --git a/examples/ase/basic_example.ipynb b/examples/ase/basic_example.ipynb index 55949862..9bf5e023 100644 --- a/examples/ase/basic_example.ipynb +++ b/examples/ase/basic_example.ipynb @@ -63,7 +63,7 @@ " size=(size, size, size),\n", " pbc=True)\n", "# Describe the interatomic interactions with Effective Medium Theory\n", - "atoms.set_calculator(EMT())\n", + "atoms.calc = EMT()\n", "# Set the atomic momenta to 300 Kelvin. \n", "MaxwellBoltzmannDistribution(atoms, temperature_K=300 * units.kB)" ] @@ -132,7 +132,7 @@ { "data": { "text/plain": [ - "-0.18180820374102957" + "-0.18180819310664376" ] }, "execution_count": 5, @@ -144,6 +144,49 @@ "dyn.atoms.get_potential_energy()" ] }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [], + "source": [ + "from nanover.omni.ase import ASESimulation\n", + "\n", + "nanover_imd = ASESimulation.from_dynamics(dyn)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "Let's run a couple of steps to make sure it's working" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "pycharm": { + "is_executing": false + } + }, + "outputs": [ + { + "data": { + "text/plain": [ + "11" + ] + }, + "execution_count": 11, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "nanover_imd.advance_to_next_report()\n", + "nanover_imd.dynamics.nsteps" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -160,7 +203,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 12, "metadata": { "pycharm": { "is_executing": false @@ -168,8 +211,7 @@ }, "outputs": [], "source": [ - "from nanover.app import NanoverImdApplication\n", - "from nanover.ase import NanoverASEDynamics" + "from nanover.omni import OmniRunner" ] }, { @@ -181,7 +223,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 13, "metadata": { "pycharm": { "is_executing": false @@ -189,7 +231,7 @@ }, "outputs": [], "source": [ - "app_server = NanoverImdApplication.basic_server(port=0) #Try using Shift+TAB+TAB to see what you can set up here." + "runner = OmniRunner.with_basic_server(nanover_imd, port=0) #Try using Shift+TAB+TAB to see what you can set up here." ] }, { @@ -200,10 +242,10 @@ "\n", "```python\n", "try:\n", - " app_server.close()\n", + " runner.close()\n", "except NameError: # If the server hasn't been defined yet, there will be an error\n", " pass\n", - "app_server = NanoverImdApplication.basic_server(port=0)\n", + "runner = OmniRunner.with_basic_server(port=0)\n", "```" ] }, @@ -216,7 +258,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 14, "metadata": { "pycharm": { "is_executing": false @@ -227,12 +269,12 @@ "name": "stdout", "output_type": "stream", "text": [ - "jon: NanoVer iMD Server: Running at [::]:44973\n" + "ragzo: NanoVer iMD Server: Running at [::]:55943\n" ] } ], "source": [ - "print(f'{app_server.name}: Running at {app_server.address}:{app_server.port}')" + "print(f'{runner.app_server.name}: Running at {runner.app_server.address}:{runner.app_server.port}')" ] }, { @@ -246,45 +288,21 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "Now, let's attach it to the ASE simulation" + "Now, let's start the ASE simulation" ] }, { "cell_type": "code", - "execution_count": 9, - "metadata": { - "pycharm": { - "is_executing": false - } - }, - "outputs": [], - "source": [ - "nanover_imd = NanoverASEDynamics(app_server, dyn)" - ] - }, - { - "cell_type": "markdown", + "execution_count": 15, "metadata": {}, - "source": [ - "Let's run a couple of steps to make sure it's working" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "pycharm": { - "is_executing": false - } - }, "outputs": [], "source": [ - "nanover_imd.run(10, block=True)" + "runner.next()" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 17, "metadata": { "pycharm": { "is_executing": false @@ -292,18 +310,16 @@ }, "outputs": [ { - "data": { - "text/plain": [ - "11" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" + "name": "stdout", + "output_type": "stream", + "text": [ + "Simulation time: 18.859573993851, (192 steps)\n" + ] } ], "source": [ - "nanover_imd.dynamics.nsteps" + "# print the time to check dynamics is running\n", + "print(f'Simulation time: {nanover_imd.dynamics.get_time()}, ({nanover_imd.dynamics.nsteps} steps)')" ] }, { @@ -313,41 +329,6 @@ "Ok, it's working, so let's leave it running dynamics in background thread. This is what happens by default when you call `run`" ] }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "pycharm": { - "is_executing": false - } - }, - "outputs": [], - "source": [ - "nanover_imd.run()" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "pycharm": { - "is_executing": false - } - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Simulation time: 2.160992853462094, (22 steps)\n" - ] - } - ], - "source": [ - "# print the time to check dynamics is running\n", - "print(f'Simulation time: {nanover_imd.dynamics.get_time()}, ({nanover_imd.dynamics.nsteps} steps)')" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -360,7 +341,9 @@ { "cell_type": "markdown", "metadata": {}, - "source": "You can also visualize it live in the notebook, (check out this [example with NGLView](../basics/nanover_nglview.ipynb))." + "source": [ + "You can also visualize it live in the notebook, (check out this [example with NGLView](../basics/nanover_nglview.ipynb))." + ] }, { "cell_type": "markdown", @@ -378,7 +361,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 19, "metadata": { "pycharm": { "is_executing": false @@ -387,7 +370,7 @@ "outputs": [], "source": [ "from nanover.app import NanoverImdClient\n", - "client = NanoverImdClient.connect_to_single_server(port=app_server.port)" + "client = NanoverImdClient.connect_to_single_server(port=runner.app_server.port)" ] }, { @@ -399,7 +382,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 20, "metadata": {}, "outputs": [], "source": [ @@ -415,7 +398,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 21, "metadata": { "pycharm": { "is_executing": false @@ -429,7 +412,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 22, "metadata": { "pycharm": { "is_executing": false @@ -442,7 +425,7 @@ "32" ] }, - "execution_count": 17, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -460,7 +443,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": 23, "metadata": { "pycharm": { "is_executing": false @@ -474,7 +457,7 @@ "values {\n", " key: \"server.timestamp\"\n", " value {\n", - " number_value: 61981.883366045\n", + " number_value: 91197.171\n", " }\n", "}\n", "values {\n", @@ -492,13 +475,13 @@ "values {\n", " key: \"energy.potential\"\n", " value {\n", - " number_value: -17.531668290927588\n", + " number_value: -17.531048553386476\n", " }\n", "}\n", "values {\n", " key: \"energy.kinetic\"\n", " value {\n", - " number_value: 0.011534119468729485\n", + " number_value: 0.0095670517563931166\n", " }\n", "}\n", "values {\n", @@ -590,102 +573,102 @@ " key: \"particle.positions\"\n", " value {\n", " float_values {\n", - " values: 3.28507781e-06\n", - " values: 6.92371e-05\n", - " values: -0.00012874922\n", - " values: 0.180514857\n", - " values: 0.180455193\n", - " values: -3.49673828e-05\n", - " values: 0.180406049\n", - " values: -0.000121892743\n", - " values: 0.180585355\n", - " values: 2.79924843e-05\n", - " values: 0.180529684\n", - " values: 0.180502385\n", - " values: 0.360968471\n", - " values: 9.5160317e-07\n", - " values: 2.07705089e-05\n", - " values: 0.541499794\n", - " values: 0.180510744\n", - " values: 3.17802869e-06\n", - " values: 0.541474462\n", - " values: 8.61464214e-05\n", - " values: 0.180452779\n", - " values: 0.360933602\n", - " values: 0.180488572\n", - " values: 0.18048881\n", - " values: -2.77618365e-05\n", - " values: 0.36098966\n", - " values: -0.000100682053\n", - " values: 0.180616692\n", - " values: 0.54154253\n", - " values: -4.45125916e-05\n", - " values: 0.180510551\n", - " values: 0.361002862\n", - " values: 0.180459201\n", - " values: 1.96660858e-05\n", - " values: 0.541504443\n", - " values: 0.180473059\n", - " values: 0.360932827\n", - " values: 0.360937506\n", - " values: -1.70527153e-06\n", - " values: 0.541591585\n", - " values: 0.541560948\n", - " values: 5.38147942e-05\n", - " values: 0.541621745\n", - " values: 0.360923469\n", - " values: 0.180553615\n", - " values: 0.361063689\n", - " values: 0.54145807\n", - " values: 0.180471554\n", - " values: -0.000130070563\n", - " values: 6.13400189e-05\n", - " values: 0.361090571\n", - " values: 0.180384412\n", - " values: 0.180465981\n", - " values: 0.361024141\n", - " values: 0.180568308\n", - " values: 6.71299858e-05\n", - " values: 0.541510165\n", - " values: -9.05262568e-05\n", - " values: 0.180540755\n", - " values: 0.541512489\n", - " values: 0.361037076\n", - " values: -0.000111934241\n", - " values: 0.361083776\n", - " values: 0.541487396\n", - " values: 0.180450678\n", - " values: 0.360990524\n", - " values: 0.541398406\n", - " values: -3.65134474e-05\n", - " values: 0.541491389\n", - " values: 0.361062944\n", - " values: 0.180633172\n", - " values: 0.541459858\n", - " values: 3.68724932e-06\n", - " values: 0.361044049\n", - " values: 0.361014456\n", - " values: 0.180656612\n", - " values: 0.541588902\n", - " values: 0.36102587\n", - " values: 0.18043974\n", - " values: 0.360911578\n", - " values: 0.541519\n", - " values: 7.53806526e-05\n", - " values: 0.541534\n", - " values: 0.541450381\n", - " values: 0.360926658\n", - " values: 0.361004591\n", - " values: 0.361001849\n", - " values: 0.541527331\n", - " values: 0.541467249\n", - " values: 0.360999465\n", - " values: 0.541394055\n", - " values: 0.361007959\n", - " values: 0.541488886\n", - " values: 0.361046\n", - " values: 0.541450739\n", - " values: 0.541552186\n", + " values: -2.57891206e-005\n", + " values: -2.0524134e-005\n", + " values: 8.89585863e-005\n", + " values: 0.180520535\n", + " values: 0.180497617\n", + " values: 4.96765351e-005\n", + " values: 0.180475205\n", + " values: 6.78303841e-005\n", + " values: 0.180522472\n", + " values: -2.4701294e-005\n", + " values: 0.180553824\n", + " values: 0.180488899\n", + " values: 0.361087948\n", + " values: -2.28799872e-005\n", + " values: -0.000158874725\n", + " values: 0.541501164\n", + " values: 0.180490583\n", + " values: 9.44005587e-005\n", + " values: 0.541436672\n", + " values: -8.53484235e-005\n", + " values: 0.180487275\n", + " values: 0.360923886\n", + " values: 0.180420578\n", + " values: 0.180435285\n", + " values: 1.48455629e-005\n", + " values: 0.360919446\n", + " values: 5.25337236e-005\n", + " values: 0.180496529\n", + " values: 0.541544259\n", + " values: 7.89733385e-005\n", + " values: 0.180510089\n", + " values: 0.3609716\n", + " values: 0.180563897\n", + " values: -7.14274393e-006\n", + " values: 0.541649461\n", + " values: 0.180537418\n", + " values: 0.360967368\n", + " values: 0.361063093\n", + " values: 3.95568441e-006\n", + " values: 0.541555643\n", + " values: 0.541472316\n", + " values: -6.97793439e-005\n", + " values: 0.541533411\n", + " values: 0.361041844\n", + " values: 0.180529654\n", + " values: 0.360885143\n", + " values: 0.541497111\n", + " values: 0.180487618\n", + " values: 1.28358652e-005\n", + " values: -5.65789305e-005\n", + " values: 0.360953867\n", + " values: 0.180560574\n", + " values: 0.180615798\n", + " values: 0.361081362\n", + " values: 0.18040663\n", + " values: -2.62168014e-005\n", + " values: 0.541526735\n", + " values: -5.80319902e-005\n", + " values: 0.180435121\n", + " values: 0.541554093\n", + " values: 0.360913038\n", + " values: 5.63940157e-005\n", + " values: 0.360977978\n", + " values: 0.54145503\n", + " values: 0.180398583\n", + " values: 0.360798508\n", + " values: 0.541579366\n", + " values: -1.15873063e-005\n", + " values: 0.541453958\n", + " values: 0.360971063\n", + " values: 0.180490524\n", + " values: 0.541446686\n", + " values: 1.85172412e-005\n", + " values: 0.360958368\n", + " values: 0.360977501\n", + " values: 0.180577591\n", + " values: 0.541521072\n", + " values: 0.361136883\n", + " values: 0.180443242\n", + " values: 0.360989183\n", + " values: 0.541458547\n", + " values: 0.000127856576\n", + " values: 0.54152447\n", + " values: 0.541487\n", + " values: 0.361068428\n", + " values: 0.361038029\n", + " values: 0.360974282\n", + " values: 0.541438937\n", + " values: 0.541541874\n", + " values: 0.361018956\n", + " values: 0.54158926\n", + " values: 0.36091733\n", + " values: 0.541396856\n", + " values: 0.361016721\n", + " values: 0.541506529\n", + " values: 0.541540623\n", " }\n", " }\n", "}\n", @@ -784,7 +767,7 @@ "}" ] }, - "execution_count": 18, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -803,7 +786,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 24, "metadata": { "pycharm": { "is_executing": false @@ -824,7 +807,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 25, "metadata": { "pycharm": { "is_executing": false @@ -846,7 +829,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 26, "metadata": { "pycharm": { "is_executing": false @@ -856,10 +839,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 21, + "execution_count": 26, "metadata": {}, "output_type": "execute_result" } @@ -878,7 +861,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 27, "metadata": { "pycharm": { "is_executing": false @@ -889,677 +872,328 @@ "data": { "text/html": [ "\n", - "\n", - " \n", - "\n", - " ASE atomic visualization\n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", - " \n", - "\n", + " \n", + " ASE atomic visualization\n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + " \n", + "\n", + "\n", + "\n", + " \n", + " \n", "\n", "\n" ], @@ -1567,7 +1201,7 @@ "" ] }, - "execution_count": 22, + "execution_count": 27, "metadata": {}, "output_type": "execute_result" } @@ -1592,7 +1226,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 28, "metadata": { "pycharm": { "is_executing": false @@ -1600,8 +1234,7 @@ }, "outputs": [], "source": [ - "nanover_imd.close()\n", - "app_server.close()" + "runner.close()" ] }, { @@ -1617,7 +1250,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 30, "metadata": { "pycharm": { "is_executing": false @@ -1625,8 +1258,8 @@ }, "outputs": [], "source": [ - "with NanoverASEDynamics.basic_imd(dyn) as app:\n", - " app.run(20)" + "with OmniRunner.with_basic_server(ASESimulation.from_dynamics(dyn), port=0) as runner:\n", + " runner.next()" ] }, { @@ -1644,20 +1277,13 @@ "* Run bigger molecular mechanics simulations with OpenMM. The [nanotube](./openmm_nanotube.ipynb) and [neuraminidase](./openmm_neuraminidase.ipynb) examples show how to set up simulations with OpenMM.\n", "* To understand what's going on under the hood, consider starting with the [NanoVer frame explained](../fundamentals/frame.ipynb) example. " ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [] } ], "metadata": { "kernelspec": { - "display_name": "Python (nanover)", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "nanover" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -1669,7 +1295,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.12.0" }, "pycharm": { "stem_cell": { @@ -1682,5 +1308,5 @@ } }, "nbformat": 4, - "nbformat_minor": 2 + "nbformat_minor": 4 } diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index ace67f6d..5190daa4 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -76,6 +76,7 @@ def __init__(self, name: Optional[str] = None): self.dynamics: Optional[MolecularDynamics] = None self.checkpoint: Optional[InitialState] = None + self.frame_method = send_ase_frame self._frame_adapter: Optional[Callable] = None def load(self): @@ -117,7 +118,7 @@ def reset(self, app_server: NanoverImdApplication): if self._frame_adapter is not None: remove_observer(self.dynamics, self._frame_adapter) - self._frame_adapter = openmm_ase_frame_adaptor( + self._frame_adapter = self.frame_method( self.atoms, self.app_server.frame_publisher, include_velocities=self.include_velocities, From 75626b02ab2f3741cca52baaf67ec985d17da54f Mon Sep 17 00:00:00 2001 From: candle Date: Thu, 26 Sep 2024 12:57:25 +0200 Subject: [PATCH 04/36] lint --- python-libraries/nanover-omni/src/nanover/omni/ase.py | 1 - 1 file changed, 1 deletion(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 5190daa4..073ca20c 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -9,7 +9,6 @@ from nanover.ase import send_ase_frame from nanover.ase.converter import EV_TO_KJMOL from nanover.ase.imd_calculator import ImdCalculator -from nanover.ase.openmm.runner import openmm_ase_frame_adaptor from nanover.ase.wall_constraint import VelocityWallConstraint from nanover.utilities.event import Event From 174b590d5608316c9c0d35349d7df20b099572b1 Mon Sep 17 00:00:00 2001 From: candle Date: Thu, 26 Sep 2024 13:02:36 +0200 Subject: [PATCH 05/36] typing --- python-libraries/nanover-omni/src/nanover/omni/ase.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 073ca20c..f4adeea4 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -51,10 +51,10 @@ def from_dynamics( @property def atoms(self): - try: - return self.dynamics.atoms - except AttributeError: + if self.dynamics is None: return None + else: + return self.dynamics.atoms def __init__(self, name: Optional[str] = None): self.name = name or "Unnamed ASE OpenMM Simulation" From f9c2385c5397f1ded56f50d4877f3c4bac42844f Mon Sep 17 00:00:00 2001 From: candle Date: Thu, 26 Sep 2024 13:36:23 +0200 Subject: [PATCH 06/36] test right thing + do reset dynamics each loop for ase_omm for now --- .../nanover-omni/src/nanover/omni/ase_omm.py | 24 ++++++++----------- .../nanover-omni/tests/test_ase_omm.py | 2 +- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index 438ee008..1203841c 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -128,17 +128,16 @@ def reset(self, app_server: NanoverImdApplication): if self.simulation.system.getNumConstraints() > 0: warnings.warn(CONSTRAINTS_UNSUPPORTED_MESSAGE) - if self.dynamics is None: - # We do not remove the center of mass (fixcm=False). If the center of - # mass translations should be removed, then the removal should be added - # to the OpenMM system. - self.dynamics = Langevin( - atoms=self.atoms, - timestep=self.time_step * units.fs, - temperature_K=300, - friction=1e-2, - fixcm=False, - ) + # We do not remove the center of mass (fixcm=False). If the center of + # mass translations should be removed, then the removal should be added + # to the OpenMM system. + self.dynamics = Langevin( + atoms=self.atoms, + timestep=self.time_step * units.fs, + temperature_K=300, + friction=1e-2, + fixcm=False, + ) self.atoms.calc = ImdCalculator( self.app_server.imd, @@ -146,9 +145,6 @@ def reset(self, app_server: NanoverImdApplication): dynamics=self.dynamics, ) - if self._frame_adapter is not None: - remove_observer(self.dynamics, self._frame_adapter) - self._frame_adapter = openmm_ase_frame_adaptor( self.atoms, self.app_server.frame_publisher, diff --git a/python-libraries/nanover-omni/tests/test_ase_omm.py b/python-libraries/nanover-omni/tests/test_ase_omm.py index 0d35afb7..0d20dbff 100644 --- a/python-libraries/nanover-omni/tests/test_ase_omm.py +++ b/python-libraries/nanover-omni/tests/test_ase_omm.py @@ -35,7 +35,7 @@ def test_time_step(example_ase_omm, time_step, app_server): example_ase_omm.frame_interval = 1 example_ase_omm.reset(app_server) for i in range(5): - assert example_ase_omm.dynamics.dt == pytest.approx(time_step * units.fs) + assert example_ase_omm.dynamics.get_time() == pytest.approx(time_step * units.fs * i) example_ase_omm.advance_by_one_step() From 8fccddd54a776fb4a66684fed1ec6ffdf8648acd Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 12:08:31 +0200 Subject: [PATCH 07/36] fix test, fix style, don't use observer in ase --- .../nanover-omni/src/nanover/omni/ase.py | 21 ++++++++++++------- .../nanover-omni/src/nanover/omni/ase_omm.py | 2 +- .../nanover-omni/tests/test_ase_omm.py | 4 +++- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index f4adeea4..37d59ea7 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -113,17 +113,12 @@ def reset(self, app_server: NanoverImdApplication): dynamics=self.dynamics, ) - # remove previous frame adaptor and attach new one - if self._frame_adapter is not None: - remove_observer(self.dynamics, self._frame_adapter) - self._frame_adapter = self.frame_method( self.atoms, self.app_server.frame_publisher, include_velocities=self.include_velocities, include_forces=self.include_forces, ) - self.dynamics.attach(self._frame_adapter, interval=self.frame_interval) if self.verbose: self.dynamics.attach( @@ -158,11 +153,23 @@ def advance_by_seconds(self, dt: float): def advance_to_next_report(self): """ - Step the simulation to the next point a frame should be reported. + Step the simulation to the next point a frame should be reported, and send that frame. """ assert self.dynamics is not None - self.dynamics.run(self.frame_interval) + # determine step count for next frame + steps_to_next_frame = ( + self.frame_interval + - self.dynamics.get_number_of_steps() % self.frame_interval + ) + + # advance the simulation + self.dynamics.run(steps_to_next_frame) + + # call frame adapter to send frame + self._frame_adapter() + + # check if excessive energy requires sim reset if self.reset_energy is not None and self.app_server is not None: energy = self.atoms.get_total_energy() * EV_TO_KJMOL if not np.isfinite(energy) or energy > self.reset_energy: diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index 1203841c..04403c11 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -16,7 +16,7 @@ from nanover.ase.openmm import OpenMMCalculator from nanover.ase.openmm.runner import openmm_ase_frame_adaptor from nanover.ase.wall_constraint import VelocityWallConstraint -from nanover.omni.ase import InitialState, remove_observer +from nanover.omni.ase import InitialState from nanover.openmm import serializer from nanover.utilities.event import Event diff --git a/python-libraries/nanover-omni/tests/test_ase_omm.py b/python-libraries/nanover-omni/tests/test_ase_omm.py index 0d20dbff..f2ad8060 100644 --- a/python-libraries/nanover-omni/tests/test_ase_omm.py +++ b/python-libraries/nanover-omni/tests/test_ase_omm.py @@ -35,7 +35,9 @@ def test_time_step(example_ase_omm, time_step, app_server): example_ase_omm.frame_interval = 1 example_ase_omm.reset(app_server) for i in range(5): - assert example_ase_omm.dynamics.get_time() == pytest.approx(time_step * units.fs * i) + assert example_ase_omm.dynamics.get_time() == pytest.approx( + time_step * units.fs * i + ) example_ase_omm.advance_by_one_step() From dbb3210523889ea74975cbe4110266f036e763c6 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 12:31:40 +0200 Subject: [PATCH 08/36] change ase_omm to work like omm (don't use observers/reporters --- .../nanover-omni/src/nanover/omni/ase_omm.py | 80 +++++++++++++++---- 1 file changed, 63 insertions(+), 17 deletions(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index 04403c11..d430b953 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -11,13 +11,16 @@ from openmm.app import Simulation from nanover.app import NanoverImdApplication -from nanover.ase.converter import EV_TO_KJMOL +from nanover.ase.converter import ( + EV_TO_KJMOL, + add_ase_positions_to_frame_data, + ase_to_frame_data, +) from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.openmm import OpenMMCalculator -from nanover.ase.openmm.runner import openmm_ase_frame_adaptor from nanover.ase.wall_constraint import VelocityWallConstraint from nanover.omni.ase import InitialState -from nanover.openmm import serializer +from nanover.openmm import serializer, openmm_to_frame_data from nanover.utilities.event import Event @@ -81,6 +84,7 @@ def __init__(self, name: Optional[str] = None): self.openmm_calculator: Optional[OpenMMCalculator] = None self.checkpoint: Optional[InitialState] = None + self.frame_index = 0 self._frame_adapter: Optional[Callable] = None def load(self): @@ -125,9 +129,14 @@ def reset(self, app_server: NanoverImdApplication): self.app_server = app_server + self.atoms.set_positions(self.checkpoint.positions) + self.atoms.set_velocities(self.checkpoint.velocities) + self.atoms.set_cell(self.checkpoint.cell) + if self.simulation.system.getNumConstraints() > 0: warnings.warn(CONSTRAINTS_UNSUPPORTED_MESSAGE) + # TODO: do we really need to reconstruct the dynamics? (maybe for step count?) # We do not remove the center of mass (fixcm=False). If the center of # mass translations should be removed, then the removal should be added # to the OpenMM system. @@ -145,13 +154,10 @@ def reset(self, app_server: NanoverImdApplication): dynamics=self.dynamics, ) - self._frame_adapter = openmm_ase_frame_adaptor( - self.atoms, - self.app_server.frame_publisher, - include_velocities=self.include_velocities, - include_forces=self.include_forces, - ) - self.dynamics.attach(self._frame_adapter, interval=self.frame_interval) + # send the initial topology frame + frame_data = self.make_topology_frame() + self.app_server.frame_publisher.send_frame(0, frame_data) + self.frame_index = 1 if self.verbose: self.dynamics.attach( @@ -166,10 +172,6 @@ def reset(self, app_server: NanoverImdApplication): interval=100, ) - self.atoms.set_positions(self.checkpoint.positions) - self.atoms.set_velocities(self.checkpoint.velocities) - self.atoms.set_cell(self.checkpoint.cell) - def advance_by_one_step(self): """ Advance the simulation to the next point a frame should be reported, and send that frame. @@ -185,13 +187,57 @@ def advance_by_seconds(self, dt: float): def advance_to_next_report(self): """ - Step the simulation to the next point a frame should be reported. + Step the simulation to the next point a frame should be reported, and send that frame. """ - assert self.dynamics is not None - self.dynamics.run(self.frame_interval) + assert self.dynamics is not None and self.app_server is not None + + # determine step count for next frame + steps_to_next_frame = ( + self.frame_interval + - self.dynamics.get_number_of_steps() % self.frame_interval + ) + + # advance the simulation + self.dynamics.run(steps_to_next_frame) + # generate the next frame + frame_data = self.make_regular_frame() + + # send the next frame + self.app_server.frame_publisher.send_frame(self.frame_index, frame_data) + self.frame_index += 1 + + # check if excessive energy necessitates reset if self.reset_energy is not None and self.app_server is not None: energy = self.dynamics.atoms.get_total_energy() * EV_TO_KJMOL if not np.isfinite(energy) or energy > self.reset_energy: self.on_reset_energy_exceeded.invoke() self.reset(self.app_server) + + def make_topology_frame(self): + """ + Make a NanoVer FrameData corresponding to the current particle positions and topology of the simulation. + """ + assert self.atoms is not None + + imd_calculator = self.atoms.calc + topology = imd_calculator.calculator.topology + frame_data = openmm_to_frame_data( + state=None, + topology=topology, + include_velocities=self.include_velocities, + include_forces=self.include_forces, + ) + add_ase_positions_to_frame_data(frame_data, self.atoms.get_positions()) + + return frame_data + + def make_regular_frame(self): + """ + Make a NanoVer FrameData corresponding to the current state of the simulation. + """ + assert self.atoms is not None + + frame_data = ase_to_frame_data(self.atoms, topology=False) + + return frame_data From 5be80cef052d8c79d5ee6d06d92df77962e24adc Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 12:42:30 +0200 Subject: [PATCH 09/36] change ase to avoid observers --- .../nanover-omni/src/nanover/omni/ase.py | 70 +++++++++++++------ .../nanover-omni/src/nanover/omni/ase_omm.py | 11 +-- 2 files changed, 54 insertions(+), 27 deletions(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 37d59ea7..3d21bac5 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -1,5 +1,5 @@ from dataclasses import dataclass -from typing import Optional, Any, Callable +from typing import Optional, Any import numpy as np from ase.md import MDLogger @@ -7,7 +7,7 @@ from nanover.app import NanoverImdApplication from nanover.ase import send_ase_frame -from nanover.ase.converter import EV_TO_KJMOL +from nanover.ase.converter import EV_TO_KJMOL, ase_to_frame_data from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.wall_constraint import VelocityWallConstraint from nanover.utilities.event import Event @@ -76,7 +76,7 @@ def __init__(self, name: Optional[str] = None): self.checkpoint: Optional[InitialState] = None self.frame_method = send_ase_frame - self._frame_adapter: Optional[Callable] = None + self.frame_index = 0 def load(self): """ @@ -107,18 +107,21 @@ def reset(self, app_server: NanoverImdApplication): self.app_server = app_server + # reset atoms to initial state + self.atoms.set_positions(self.checkpoint.positions) + self.atoms.set_velocities(self.checkpoint.velocities) + self.atoms.set_cell(self.checkpoint.cell) + self.atoms.calc = ImdCalculator( self.app_server.imd, self.atoms.calc, dynamics=self.dynamics, ) - self._frame_adapter = self.frame_method( - self.atoms, - self.app_server.frame_publisher, - include_velocities=self.include_velocities, - include_forces=self.include_forces, - ) + # send the initial topology frame + frame_data = self.make_topology_frame() + self.app_server.frame_publisher.send_frame(0, frame_data) + self.frame_index = 1 if self.verbose: self.dynamics.attach( @@ -133,11 +136,6 @@ def reset(self, app_server: NanoverImdApplication): interval=100, ) - # reset atoms to initial state - self.atoms.set_positions(self.checkpoint.positions) - self.atoms.set_velocities(self.checkpoint.velocities) - self.atoms.set_cell(self.checkpoint.cell) - def advance_by_one_step(self): """ Advance the simulation to the next point a frame should be reported, and send that frame. @@ -155,7 +153,7 @@ def advance_to_next_report(self): """ Step the simulation to the next point a frame should be reported, and send that frame. """ - assert self.dynamics is not None + assert self.dynamics is not None and self.app_server is not None # determine step count for next frame steps_to_next_frame = ( @@ -166,8 +164,12 @@ def advance_to_next_report(self): # advance the simulation self.dynamics.run(steps_to_next_frame) - # call frame adapter to send frame - self._frame_adapter() + # generate the next frame + frame_data = self.make_regular_frame() + + # send the next frame + self.app_server.frame_publisher.send_frame(self.frame_index, frame_data) + self.frame_index += 1 # check if excessive energy requires sim reset if self.reset_energy is not None and self.app_server is not None: @@ -176,10 +178,32 @@ def advance_to_next_report(self): self.on_reset_energy_exceeded.invoke() self.reset(self.app_server) + def make_topology_frame(self): + """ + Make a NanoVer FrameData corresponding to the current particle positions and topology of the simulation. + """ + assert self.atoms is not None + + frame_data = ase_to_frame_data( + self.atoms, + topology=True, + include_velocities=self.include_velocities, + include_forces=self.include_forces, + ) + + return frame_data + + def make_regular_frame(self): + """ + Make a NanoVer FrameData corresponding to the current state of the simulation. + """ + assert self.atoms is not None + + frame_data = ase_to_frame_data( + self.atoms, + topology=False, + include_velocities=self.include_velocities, + include_forces=self.include_forces, + ) -def remove_observer(dynamics: MolecularDynamics, func: Callable): - entry = next(entry for entry in dynamics.observers if entry[0] == func) - try: - dynamics.observers.remove(entry) - except StopIteration: - pass + return frame_data diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index d430b953..ee79d7b2 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -1,7 +1,7 @@ import warnings from os import PathLike from pathlib import Path -from typing import Optional, Callable +from typing import Optional import numpy as np from ase import units, Atoms @@ -85,7 +85,6 @@ def __init__(self, name: Optional[str] = None): self.checkpoint: Optional[InitialState] = None self.frame_index = 0 - self._frame_adapter: Optional[Callable] = None def load(self): """ @@ -223,7 +222,6 @@ def make_topology_frame(self): imd_calculator = self.atoms.calc topology = imd_calculator.calculator.topology frame_data = openmm_to_frame_data( - state=None, topology=topology, include_velocities=self.include_velocities, include_forces=self.include_forces, @@ -238,6 +236,11 @@ def make_regular_frame(self): """ assert self.atoms is not None - frame_data = ase_to_frame_data(self.atoms, topology=False) + frame_data = ase_to_frame_data( + self.atoms, + topology=False, + include_velocities=self.include_velocities, + include_forces=self.include_forces, + ) return frame_data From 7769bb9bc6ac0fdaefa43a330195ba44ef4f52ce Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 13:21:43 +0200 Subject: [PATCH 10/36] some basic ase tests --- .../nanover-omni/src/nanover/omni/ase.py | 7 +--- .../nanover-omni/tests/test_all.py | 3 ++ .../nanover-omni/tests/test_ase.py | 38 +++++++++++++++++++ 3 files changed, 42 insertions(+), 6 deletions(-) create mode 100644 python-libraries/nanover-omni/tests/test_ase.py diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 3d21bac5..57333517 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -13,11 +13,6 @@ from nanover.utilities.event import Event -CONSTRAINTS_UNSUPPORTED_MESSAGE = ( - "The simulation contains constraints which will be ignored by this runner!" -) - - @dataclass class InitialState: positions: Any @@ -66,7 +61,6 @@ def __init__(self, name: Optional[str] = None): self.verbose = False self.use_walls = False self.reset_energy: Optional[float] = None - self.time_step = 1 self.frame_interval = 5 self.include_velocities = False self.include_forces = False @@ -123,6 +117,7 @@ def reset(self, app_server: NanoverImdApplication): self.app_server.frame_publisher.send_frame(0, frame_data) self.frame_index = 1 + # TODO: deal with this when its clear if dynamics should be reconstructed or not.. if self.verbose: self.dynamics.attach( MDLogger( diff --git a/python-libraries/nanover-omni/tests/test_all.py b/python-libraries/nanover-omni/tests/test_all.py index 217cd731..a6fc17d2 100644 --- a/python-libraries/nanover-omni/tests/test_all.py +++ b/python-libraries/nanover-omni/tests/test_all.py @@ -9,6 +9,7 @@ from nanover.testing import assert_equal_soon from test_openmm import example_openmm from test_ase_omm import example_ase_omm +from test_ase import example_ase, example_dynamics from test_playback import example_playback from common import app_server @@ -16,11 +17,13 @@ "example_openmm", "example_playback", "example_ase_omm", + "example_ase", ) SIMULATION_FIXTURES_WITHOUT_PLAYBACK = [ "example_openmm", "example_ase_omm", + "example_ase", ] diff --git a/python-libraries/nanover-omni/tests/test_ase.py b/python-libraries/nanover-omni/tests/test_ase.py new file mode 100644 index 00000000..4158807c --- /dev/null +++ b/python-libraries/nanover-omni/tests/test_ase.py @@ -0,0 +1,38 @@ +import pytest +from ase import units, Atoms +from ase.calculators.lj import LennardJones +from ase.md import VelocityVerlet + +from nanover.omni.ase import ASESimulation + +from common import app_server + + +@pytest.fixture +def example_ase(app_server, example_dynamics): + sim = ASESimulation.from_dynamics(example_dynamics) + sim.load() + sim.reset(app_server) + yield sim + + +@pytest.fixture +def example_dynamics(): + d = 1.1 + atoms = Atoms("CO", positions=[(0, 0, 0), (0, 0, d)], cell=[2, 2, 2], pbc=[1, 1, 1]) + calculator = LennardJones() + atoms.calc = calculator + dynamics = VelocityVerlet(atoms, timestep=0.5) + yield dynamics + + +def test_step_interval(example_ase): + """ + Test that advancing by one step increments the dynamics steps by frame_interval. + """ + for i in range(5): + assert ( + example_ase.dynamics.get_number_of_steps() + == i * example_ase.frame_interval + ) + example_ase.advance_by_one_step() From 9788781d99ed6f9e161bc1e07ad36063bcbd2883 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 13:26:39 +0200 Subject: [PATCH 11/36] style --- python-libraries/nanover-omni/tests/test_ase.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/python-libraries/nanover-omni/tests/test_ase.py b/python-libraries/nanover-omni/tests/test_ase.py index 4158807c..2f8e125f 100644 --- a/python-libraries/nanover-omni/tests/test_ase.py +++ b/python-libraries/nanover-omni/tests/test_ase.py @@ -32,7 +32,6 @@ def test_step_interval(example_ase): """ for i in range(5): assert ( - example_ase.dynamics.get_number_of_steps() - == i * example_ase.frame_interval + example_ase.dynamics.get_number_of_steps() == i * example_ase.frame_interval ) example_ase.advance_by_one_step() From 0278d3a06c35ea9de4b308750b807bf75c8668bd Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 13:51:06 +0200 Subject: [PATCH 12/36] remove unused --- .../nanover-omni/src/nanover/omni/ase.py | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 57333517..a66279c3 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -6,7 +6,6 @@ from ase.md.md import MolecularDynamics from nanover.app import NanoverImdApplication -from nanover.ase import send_ase_frame from nanover.ase.converter import EV_TO_KJMOL, ase_to_frame_data from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.wall_constraint import VelocityWallConstraint @@ -26,22 +25,14 @@ class ASESimulation: """ @classmethod - def from_dynamics( - cls, - dynamics: MolecularDynamics, - *, - name: Optional[str] = None, - frame_method=send_ase_frame, - ): + def from_dynamics(cls, dynamics: MolecularDynamics, *, name: Optional[str] = None): """ Construct this from an existing ASE dynamics. :param dynamics: An existing ASE Dynamics :param name: An optional name for the simulation instead of default - :param frame_method: A """ sim = cls(name) sim.dynamics = dynamics - sim.frame_method = frame_method return sim @property @@ -69,7 +60,6 @@ def __init__(self, name: Optional[str] = None): self.dynamics: Optional[MolecularDynamics] = None self.checkpoint: Optional[InitialState] = None - self.frame_method = send_ase_frame self.frame_index = 0 def load(self): From 8234f21629c9f84cce361e127dafea980586bb71 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 16:01:07 +0200 Subject: [PATCH 13/36] removing unsuitable options, decompose frame conversion --- .../nanover-ase/src/nanover/ase/converter.py | 24 +++++++++ .../src/nanover/ase/frame_adaptor.py | 19 +++++-- .../src/nanover/ase/openmm/runner.py | 45 +++++++++++----- .../nanover-omni/src/nanover/omni/ase.py | 10 ++-- .../nanover-omni/src/nanover/omni/ase_omm.py | 54 +++++++++---------- .../nanover-omni/tests/test_ase.py | 2 +- .../nanover-omni/tests/test_ase_omm.py | 12 ----- 7 files changed, 98 insertions(+), 68 deletions(-) diff --git a/python-libraries/nanover-ase/src/nanover/ase/converter.py b/python-libraries/nanover-ase/src/nanover/ase/converter.py index d06d0879..a5135fee 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/converter.py +++ b/python-libraries/nanover-ase/src/nanover/ase/converter.py @@ -50,6 +50,30 @@ } +def ase_atoms_to_regular_frame( + ase_atoms: Atoms, + **kwargs, +): + frame = ase_to_frame_data( + ase_atoms, + topology=False, + **kwargs, + ) + return frame + + +def ase_atoms_to_topology_frame( + ase_atoms: Atoms, + **kwargs, +): + frame = ase_to_frame_data( + ase_atoms, + topology=False, + **kwargs, + ) + return frame + + def ase_to_frame_data( ase_atoms: Atoms, positions=True, diff --git a/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py b/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py index babd1457..dbe6f7f5 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py +++ b/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py @@ -4,6 +4,8 @@ from typing import Callable from ase import Atoms # type: ignore + +from nanover.ase.converter import ase_atoms_to_topology_frame, ase_atoms_to_regular_frame from nanover.trajectory import FramePublisher from nanover.ase import ase_to_frame_data @@ -39,11 +41,18 @@ def send_ase_frame( def send(): nonlocal frame_index - frame = ase_to_frame_data( - ase_atoms, - include_velocities=include_velocities, - include_forces=include_forces, - ) + if frame_index == 0: + frame = ase_atoms_to_topology_frame( + ase_atoms, + include_velocities=include_velocities, + include_forces=include_forces, + ) + else: + frame = ase_atoms_to_regular_frame( + ase_atoms, + include_velocities=include_velocities, + include_forces=include_forces, + ) frame_publisher.send_frame(frame_index, frame) frame_index += 1 diff --git a/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py b/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py index 0476b3d2..1d9276e1 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py +++ b/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py @@ -38,38 +38,55 @@ def openmm_ase_frame_adaptor( ase_atoms: Atoms, frame_publisher: FramePublisher, - include_velocities=False, - include_forces=False, + **kwargs, ): """ Generates and sends frames for a simulation using an :class: OpenMMCalculator. """ frame_index = 0 - topology: Optional[Topology] = None def send(): - nonlocal frame_index, topology + nonlocal frame_index # generate topology frame using OpenMM converter. if frame_index == 0: - imd_calculator = ase_atoms.calc - topology = imd_calculator.calculator.topology - frame = openmm_to_frame_data( - state=None, - topology=topology, - include_velocities=include_velocities, - include_forces=include_forces, - ) - add_ase_positions_to_frame_data(frame, ase_atoms.get_positions()) + frame = openmm_ase_atoms_to_topology_frame(ase_atoms, **kwargs) # from then on, just send positions and state. else: - frame = ase_to_frame_data(ase_atoms, topology=False) + frame = openmm_ase_atoms_to_regular_frame(ase_atoms, **kwargs) frame_publisher.send_frame(frame_index, frame) frame_index += 1 return send +def openmm_ase_atoms_to_regular_frame( + ase_atoms: Atoms, + **kwargs, +): + frame = ase_to_frame_data( + ase_atoms, + topology=False, + **kwargs, + ) + return frame + + +def openmm_ase_atoms_to_topology_frame( + ase_atoms: Atoms, + **kwargs, +): + imd_calculator = ase_atoms.calc + topology = imd_calculator.calculator.topology + frame = openmm_to_frame_data( + state=None, + topology=topology, + **kwargs, + ) + add_ase_positions_to_frame_data(frame, ase_atoms.get_positions()) + return frame + + @dataclass class ImdParams: """ diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index a66279c3..882514aa 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -25,7 +25,7 @@ class ASESimulation: """ @classmethod - def from_dynamics(cls, dynamics: MolecularDynamics, *, name: Optional[str] = None): + def from_ase_dynamics(cls, dynamics: MolecularDynamics, *, name: Optional[str] = None): """ Construct this from an existing ASE dynamics. :param dynamics: An existing ASE Dynamics @@ -169,26 +169,22 @@ def make_topology_frame(self): """ assert self.atoms is not None - frame_data = ase_to_frame_data( + return ase_to_frame_data( self.atoms, topology=True, include_velocities=self.include_velocities, include_forces=self.include_forces, ) - return frame_data - def make_regular_frame(self): """ Make a NanoVer FrameData corresponding to the current state of the simulation. """ assert self.atoms is not None - frame_data = ase_to_frame_data( + return ase_to_frame_data( self.atoms, topology=False, include_velocities=self.include_velocities, include_forces=self.include_forces, ) - - return frame_data diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index ee79d7b2..e966d2c0 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -11,16 +11,13 @@ from openmm.app import Simulation from nanover.app import NanoverImdApplication -from nanover.ase.converter import ( - EV_TO_KJMOL, - add_ase_positions_to_frame_data, - ase_to_frame_data, -) +from nanover.ase.converter import EV_TO_KJMOL from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.openmm import OpenMMCalculator +from nanover.ase.openmm.runner import openmm_ase_atoms_to_regular_frame, openmm_ase_atoms_to_topology_frame from nanover.ase.wall_constraint import VelocityWallConstraint from nanover.omni.ase import InitialState -from nanover.openmm import serializer, openmm_to_frame_data +from nanover.openmm import serializer from nanover.utilities.event import Event @@ -72,7 +69,6 @@ def __init__(self, name: Optional[str] = None): self.verbose = False self.use_walls = False self.reset_energy: Optional[float] = None - self.time_step = 1 self.frame_interval = 5 self.include_velocities = False self.include_forces = False @@ -107,6 +103,9 @@ def load(self): # Set the momenta corresponding to T=300K MaxwellBoltzmannDistribution(self.atoms, temperature_K=300) + # we don't read this from the openmm xml + self.dynamics = make_default_ase_omm_dynamics(self.atoms) + self.checkpoint = InitialState( positions=self.atoms.get_positions(), velocities=self.atoms.get_velocities(), @@ -135,18 +134,6 @@ def reset(self, app_server: NanoverImdApplication): if self.simulation.system.getNumConstraints() > 0: warnings.warn(CONSTRAINTS_UNSUPPORTED_MESSAGE) - # TODO: do we really need to reconstruct the dynamics? (maybe for step count?) - # We do not remove the center of mass (fixcm=False). If the center of - # mass translations should be removed, then the removal should be added - # to the OpenMM system. - self.dynamics = Langevin( - atoms=self.atoms, - timestep=self.time_step * units.fs, - temperature_K=300, - friction=1e-2, - fixcm=False, - ) - self.atoms.calc = ImdCalculator( self.app_server.imd, self.openmm_calculator, @@ -158,6 +145,7 @@ def reset(self, app_server: NanoverImdApplication): self.app_server.frame_publisher.send_frame(0, frame_data) self.frame_index = 1 + # TODO: deal with this when its clear if dynamics should be reconstructed or not.. if self.verbose: self.dynamics.attach( MDLogger( @@ -219,16 +207,11 @@ def make_topology_frame(self): """ assert self.atoms is not None - imd_calculator = self.atoms.calc - topology = imd_calculator.calculator.topology - frame_data = openmm_to_frame_data( - topology=topology, + return openmm_ase_atoms_to_topology_frame( + self.atoms, include_velocities=self.include_velocities, include_forces=self.include_forces, ) - add_ase_positions_to_frame_data(frame_data, self.atoms.get_positions()) - - return frame_data def make_regular_frame(self): """ @@ -236,11 +219,24 @@ def make_regular_frame(self): """ assert self.atoms is not None - frame_data = ase_to_frame_data( + return openmm_ase_atoms_to_regular_frame( self.atoms, - topology=False, include_velocities=self.include_velocities, include_forces=self.include_forces, ) - return frame_data + +def make_default_ase_omm_dynamics(atoms: Atoms): + # We do not remove the center of mass (fixcm=False). If the center of + # mass translations should be removed, then the removal should be added + # to the OpenMM system. + dynamics = Langevin( + atoms=atoms, + timestep=1 * units.fs, + temperature_K=300, + friction=1e-2, + fixcm=False, + ) + + return dynamics + diff --git a/python-libraries/nanover-omni/tests/test_ase.py b/python-libraries/nanover-omni/tests/test_ase.py index 2f8e125f..49dced22 100644 --- a/python-libraries/nanover-omni/tests/test_ase.py +++ b/python-libraries/nanover-omni/tests/test_ase.py @@ -10,7 +10,7 @@ @pytest.fixture def example_ase(app_server, example_dynamics): - sim = ASESimulation.from_dynamics(example_dynamics) + sim = ASESimulation.from_ase_dynamics(example_dynamics) sim.load() sim.reset(app_server) yield sim diff --git a/python-libraries/nanover-omni/tests/test_ase_omm.py b/python-libraries/nanover-omni/tests/test_ase_omm.py index f2ad8060..49492b25 100644 --- a/python-libraries/nanover-omni/tests/test_ase_omm.py +++ b/python-libraries/nanover-omni/tests/test_ase_omm.py @@ -29,18 +29,6 @@ def test_step_interval(example_ase_omm): example_ase_omm.advance_by_one_step() -@pytest.mark.parametrize("time_step", (0.5, 1.0, 1.5)) -def test_time_step(example_ase_omm, time_step, app_server): - example_ase_omm.time_step = time_step - example_ase_omm.frame_interval = 1 - example_ase_omm.reset(app_server) - for i in range(5): - assert example_ase_omm.dynamics.get_time() == pytest.approx( - time_step * units.fs * i - ) - example_ase_omm.advance_by_one_step() - - # TODO: test it actually outputs def test_verbose(example_ase_omm, app_server): """ From 1d268c48c8a2ac4cf99c4986f48160f9a3b24916 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 16:01:07 +0200 Subject: [PATCH 14/36] removing unsuitable options, decompose frame conversion --- .../nanover-ase/src/nanover/ase/converter.py | 24 +++++++++ .../src/nanover/ase/frame_adaptor.py | 19 +++++-- .../src/nanover/ase/openmm/runner.py | 45 +++++++++++----- .../nanover-omni/src/nanover/omni/ase.py | 10 ++-- .../nanover-omni/src/nanover/omni/ase_omm.py | 54 +++++++++---------- .../nanover-omni/tests/test_ase.py | 2 +- .../nanover-omni/tests/test_ase_omm.py | 12 ----- 7 files changed, 98 insertions(+), 68 deletions(-) diff --git a/python-libraries/nanover-ase/src/nanover/ase/converter.py b/python-libraries/nanover-ase/src/nanover/ase/converter.py index d06d0879..a5135fee 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/converter.py +++ b/python-libraries/nanover-ase/src/nanover/ase/converter.py @@ -50,6 +50,30 @@ } +def ase_atoms_to_regular_frame( + ase_atoms: Atoms, + **kwargs, +): + frame = ase_to_frame_data( + ase_atoms, + topology=False, + **kwargs, + ) + return frame + + +def ase_atoms_to_topology_frame( + ase_atoms: Atoms, + **kwargs, +): + frame = ase_to_frame_data( + ase_atoms, + topology=False, + **kwargs, + ) + return frame + + def ase_to_frame_data( ase_atoms: Atoms, positions=True, diff --git a/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py b/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py index babd1457..dbe6f7f5 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py +++ b/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py @@ -4,6 +4,8 @@ from typing import Callable from ase import Atoms # type: ignore + +from nanover.ase.converter import ase_atoms_to_topology_frame, ase_atoms_to_regular_frame from nanover.trajectory import FramePublisher from nanover.ase import ase_to_frame_data @@ -39,11 +41,18 @@ def send_ase_frame( def send(): nonlocal frame_index - frame = ase_to_frame_data( - ase_atoms, - include_velocities=include_velocities, - include_forces=include_forces, - ) + if frame_index == 0: + frame = ase_atoms_to_topology_frame( + ase_atoms, + include_velocities=include_velocities, + include_forces=include_forces, + ) + else: + frame = ase_atoms_to_regular_frame( + ase_atoms, + include_velocities=include_velocities, + include_forces=include_forces, + ) frame_publisher.send_frame(frame_index, frame) frame_index += 1 diff --git a/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py b/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py index 0476b3d2..1d9276e1 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py +++ b/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py @@ -38,38 +38,55 @@ def openmm_ase_frame_adaptor( ase_atoms: Atoms, frame_publisher: FramePublisher, - include_velocities=False, - include_forces=False, + **kwargs, ): """ Generates and sends frames for a simulation using an :class: OpenMMCalculator. """ frame_index = 0 - topology: Optional[Topology] = None def send(): - nonlocal frame_index, topology + nonlocal frame_index # generate topology frame using OpenMM converter. if frame_index == 0: - imd_calculator = ase_atoms.calc - topology = imd_calculator.calculator.topology - frame = openmm_to_frame_data( - state=None, - topology=topology, - include_velocities=include_velocities, - include_forces=include_forces, - ) - add_ase_positions_to_frame_data(frame, ase_atoms.get_positions()) + frame = openmm_ase_atoms_to_topology_frame(ase_atoms, **kwargs) # from then on, just send positions and state. else: - frame = ase_to_frame_data(ase_atoms, topology=False) + frame = openmm_ase_atoms_to_regular_frame(ase_atoms, **kwargs) frame_publisher.send_frame(frame_index, frame) frame_index += 1 return send +def openmm_ase_atoms_to_regular_frame( + ase_atoms: Atoms, + **kwargs, +): + frame = ase_to_frame_data( + ase_atoms, + topology=False, + **kwargs, + ) + return frame + + +def openmm_ase_atoms_to_topology_frame( + ase_atoms: Atoms, + **kwargs, +): + imd_calculator = ase_atoms.calc + topology = imd_calculator.calculator.topology + frame = openmm_to_frame_data( + state=None, + topology=topology, + **kwargs, + ) + add_ase_positions_to_frame_data(frame, ase_atoms.get_positions()) + return frame + + @dataclass class ImdParams: """ diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index a66279c3..882514aa 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -25,7 +25,7 @@ class ASESimulation: """ @classmethod - def from_dynamics(cls, dynamics: MolecularDynamics, *, name: Optional[str] = None): + def from_ase_dynamics(cls, dynamics: MolecularDynamics, *, name: Optional[str] = None): """ Construct this from an existing ASE dynamics. :param dynamics: An existing ASE Dynamics @@ -169,26 +169,22 @@ def make_topology_frame(self): """ assert self.atoms is not None - frame_data = ase_to_frame_data( + return ase_to_frame_data( self.atoms, topology=True, include_velocities=self.include_velocities, include_forces=self.include_forces, ) - return frame_data - def make_regular_frame(self): """ Make a NanoVer FrameData corresponding to the current state of the simulation. """ assert self.atoms is not None - frame_data = ase_to_frame_data( + return ase_to_frame_data( self.atoms, topology=False, include_velocities=self.include_velocities, include_forces=self.include_forces, ) - - return frame_data diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index ee79d7b2..e966d2c0 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -11,16 +11,13 @@ from openmm.app import Simulation from nanover.app import NanoverImdApplication -from nanover.ase.converter import ( - EV_TO_KJMOL, - add_ase_positions_to_frame_data, - ase_to_frame_data, -) +from nanover.ase.converter import EV_TO_KJMOL from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.openmm import OpenMMCalculator +from nanover.ase.openmm.runner import openmm_ase_atoms_to_regular_frame, openmm_ase_atoms_to_topology_frame from nanover.ase.wall_constraint import VelocityWallConstraint from nanover.omni.ase import InitialState -from nanover.openmm import serializer, openmm_to_frame_data +from nanover.openmm import serializer from nanover.utilities.event import Event @@ -72,7 +69,6 @@ def __init__(self, name: Optional[str] = None): self.verbose = False self.use_walls = False self.reset_energy: Optional[float] = None - self.time_step = 1 self.frame_interval = 5 self.include_velocities = False self.include_forces = False @@ -107,6 +103,9 @@ def load(self): # Set the momenta corresponding to T=300K MaxwellBoltzmannDistribution(self.atoms, temperature_K=300) + # we don't read this from the openmm xml + self.dynamics = make_default_ase_omm_dynamics(self.atoms) + self.checkpoint = InitialState( positions=self.atoms.get_positions(), velocities=self.atoms.get_velocities(), @@ -135,18 +134,6 @@ def reset(self, app_server: NanoverImdApplication): if self.simulation.system.getNumConstraints() > 0: warnings.warn(CONSTRAINTS_UNSUPPORTED_MESSAGE) - # TODO: do we really need to reconstruct the dynamics? (maybe for step count?) - # We do not remove the center of mass (fixcm=False). If the center of - # mass translations should be removed, then the removal should be added - # to the OpenMM system. - self.dynamics = Langevin( - atoms=self.atoms, - timestep=self.time_step * units.fs, - temperature_K=300, - friction=1e-2, - fixcm=False, - ) - self.atoms.calc = ImdCalculator( self.app_server.imd, self.openmm_calculator, @@ -158,6 +145,7 @@ def reset(self, app_server: NanoverImdApplication): self.app_server.frame_publisher.send_frame(0, frame_data) self.frame_index = 1 + # TODO: deal with this when its clear if dynamics should be reconstructed or not.. if self.verbose: self.dynamics.attach( MDLogger( @@ -219,16 +207,11 @@ def make_topology_frame(self): """ assert self.atoms is not None - imd_calculator = self.atoms.calc - topology = imd_calculator.calculator.topology - frame_data = openmm_to_frame_data( - topology=topology, + return openmm_ase_atoms_to_topology_frame( + self.atoms, include_velocities=self.include_velocities, include_forces=self.include_forces, ) - add_ase_positions_to_frame_data(frame_data, self.atoms.get_positions()) - - return frame_data def make_regular_frame(self): """ @@ -236,11 +219,24 @@ def make_regular_frame(self): """ assert self.atoms is not None - frame_data = ase_to_frame_data( + return openmm_ase_atoms_to_regular_frame( self.atoms, - topology=False, include_velocities=self.include_velocities, include_forces=self.include_forces, ) - return frame_data + +def make_default_ase_omm_dynamics(atoms: Atoms): + # We do not remove the center of mass (fixcm=False). If the center of + # mass translations should be removed, then the removal should be added + # to the OpenMM system. + dynamics = Langevin( + atoms=atoms, + timestep=1 * units.fs, + temperature_K=300, + friction=1e-2, + fixcm=False, + ) + + return dynamics + diff --git a/python-libraries/nanover-omni/tests/test_ase.py b/python-libraries/nanover-omni/tests/test_ase.py index 2f8e125f..49dced22 100644 --- a/python-libraries/nanover-omni/tests/test_ase.py +++ b/python-libraries/nanover-omni/tests/test_ase.py @@ -10,7 +10,7 @@ @pytest.fixture def example_ase(app_server, example_dynamics): - sim = ASESimulation.from_dynamics(example_dynamics) + sim = ASESimulation.from_ase_dynamics(example_dynamics) sim.load() sim.reset(app_server) yield sim diff --git a/python-libraries/nanover-omni/tests/test_ase_omm.py b/python-libraries/nanover-omni/tests/test_ase_omm.py index f2ad8060..49492b25 100644 --- a/python-libraries/nanover-omni/tests/test_ase_omm.py +++ b/python-libraries/nanover-omni/tests/test_ase_omm.py @@ -29,18 +29,6 @@ def test_step_interval(example_ase_omm): example_ase_omm.advance_by_one_step() -@pytest.mark.parametrize("time_step", (0.5, 1.0, 1.5)) -def test_time_step(example_ase_omm, time_step, app_server): - example_ase_omm.time_step = time_step - example_ase_omm.frame_interval = 1 - example_ase_omm.reset(app_server) - for i in range(5): - assert example_ase_omm.dynamics.get_time() == pytest.approx( - time_step * units.fs * i - ) - example_ase_omm.advance_by_one_step() - - # TODO: test it actually outputs def test_verbose(example_ase_omm, app_server): """ From fe8c322f4c8557799288cca2edd8a2880159c0b7 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 16:03:43 +0200 Subject: [PATCH 15/36] removing unsuitable options, decompose frame conversion --- .../nanover-ase/src/nanover/ase/frame_adaptor.py | 6 ++++-- .../nanover-ase/src/nanover/ase/openmm/runner.py | 2 +- python-libraries/nanover-omni/src/nanover/omni/ase.py | 4 +++- python-libraries/nanover-omni/src/nanover/omni/ase_omm.py | 6 ++++-- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py b/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py index dbe6f7f5..1d7c5d1d 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py +++ b/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py @@ -5,9 +5,11 @@ from typing import Callable from ase import Atoms # type: ignore -from nanover.ase.converter import ase_atoms_to_topology_frame, ase_atoms_to_regular_frame +from nanover.ase.converter import ( + ase_atoms_to_topology_frame, + ase_atoms_to_regular_frame, +) from nanover.trajectory import FramePublisher -from nanover.ase import ase_to_frame_data def send_ase_frame( diff --git a/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py b/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py index 1d9276e1..ab71ac32 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py +++ b/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py @@ -17,7 +17,7 @@ from nanover.essd import DiscoveryServer from nanover.openmm import openmm_to_frame_data, serializer from nanover.trajectory.frame_publisher import FramePublisher -from openmm.app import Simulation, Topology +from openmm.app import Simulation from nanover.ase import ase_to_frame_data from nanover.ase.converter import add_ase_positions_to_frame_data diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 882514aa..67c7800f 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -25,7 +25,9 @@ class ASESimulation: """ @classmethod - def from_ase_dynamics(cls, dynamics: MolecularDynamics, *, name: Optional[str] = None): + def from_ase_dynamics( + cls, dynamics: MolecularDynamics, *, name: Optional[str] = None + ): """ Construct this from an existing ASE dynamics. :param dynamics: An existing ASE Dynamics diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index e966d2c0..93f2cd55 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -14,7 +14,10 @@ from nanover.ase.converter import EV_TO_KJMOL from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.openmm import OpenMMCalculator -from nanover.ase.openmm.runner import openmm_ase_atoms_to_regular_frame, openmm_ase_atoms_to_topology_frame +from nanover.ase.openmm.runner import ( + openmm_ase_atoms_to_regular_frame, + openmm_ase_atoms_to_topology_frame, +) from nanover.ase.wall_constraint import VelocityWallConstraint from nanover.omni.ase import InitialState from nanover.openmm import serializer @@ -239,4 +242,3 @@ def make_default_ase_omm_dynamics(atoms: Atoms): ) return dynamics - From d710956f62779a57d25bff75182be435f367f9e3 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 16:07:55 +0200 Subject: [PATCH 16/36] missing None check --- python-libraries/nanover-omni/src/nanover/omni/ase_omm.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index 93f2cd55..62096bca 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -123,6 +123,7 @@ def reset(self, app_server: NanoverImdApplication): """ assert ( self.simulation is not None + and self.dynamics is not None and self.atoms is not None and self.checkpoint is not None and self.openmm_calculator is not None From 65aa507ec1740514aaaf47b0899b19eec604b392 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 16:12:02 +0200 Subject: [PATCH 17/36] cleanup --- .../nanover-ase/src/nanover/ase/openmm/runner.py | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py b/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py index ab71ac32..7e7f1523 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py +++ b/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py @@ -15,12 +15,12 @@ from nanover.core import NanoverServer, DEFAULT_SERVE_ADDRESS from nanover.ase import TrajectoryLogger from nanover.essd import DiscoveryServer -from nanover.openmm import openmm_to_frame_data, serializer +from nanover.openmm import serializer +from nanover.openmm.converter import add_openmm_topology_to_frame_data from nanover.trajectory.frame_publisher import FramePublisher from openmm.app import Simulation from nanover.ase import ase_to_frame_data -from nanover.ase.converter import add_ase_positions_to_frame_data from nanover.ase.imd import NanoverASEDynamics from nanover.ase.openmm.calculator import OpenMMCalculator from nanover.ase.wall_constraint import VelocityWallConstraint @@ -78,12 +78,8 @@ def openmm_ase_atoms_to_topology_frame( ): imd_calculator = ase_atoms.calc topology = imd_calculator.calculator.topology - frame = openmm_to_frame_data( - state=None, - topology=topology, - **kwargs, - ) - add_ase_positions_to_frame_data(frame, ase_atoms.get_positions()) + frame = openmm_ase_atoms_to_regular_frame(ase_atoms, **kwargs) + add_openmm_topology_to_frame_data(frame, topology) return frame From fedd3dff3f193a05b2f81191e27df304e2bc7637 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 16:18:05 +0200 Subject: [PATCH 18/36] cleanup --- .../src/nanover/ase/openmm/frame_adaptor.py | 53 ++++++++++++++++++ .../src/nanover/ase/openmm/runner.py | 54 +------------------ .../nanover-omni/src/nanover/omni/ase_omm.py | 5 +- 3 files changed, 56 insertions(+), 56 deletions(-) create mode 100644 python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py diff --git a/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py b/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py new file mode 100644 index 00000000..654a2593 --- /dev/null +++ b/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py @@ -0,0 +1,53 @@ +from ase import Atoms + +from nanover.ase import ase_to_frame_data +from nanover.openmm.converter import add_openmm_topology_to_frame_data +from nanover.trajectory import FramePublisher + + +def openmm_ase_frame_adaptor( + ase_atoms: Atoms, + frame_publisher: FramePublisher, + **kwargs, +): + """ + Generates and sends frames for a simulation using an :class: OpenMMCalculator. + """ + + frame_index = 0 + + def send(): + nonlocal frame_index + # generate topology frame using OpenMM converter. + if frame_index == 0: + frame = openmm_ase_atoms_to_topology_frame(ase_atoms, **kwargs) + # from then on, just send positions and state. + else: + frame = openmm_ase_atoms_to_regular_frame(ase_atoms, **kwargs) + frame_publisher.send_frame(frame_index, frame) + frame_index += 1 + + return send + + +def openmm_ase_atoms_to_regular_frame( + ase_atoms: Atoms, + **kwargs, +): + frame = ase_to_frame_data( + ase_atoms, + topology=False, + **kwargs, + ) + return frame + + +def openmm_ase_atoms_to_topology_frame( + ase_atoms: Atoms, + **kwargs, +): + imd_calculator = ase_atoms.calc + topology = imd_calculator.calculator.topology + frame = openmm_ase_atoms_to_regular_frame(ase_atoms, **kwargs) + add_openmm_topology_to_frame_data(frame, topology) + return frame diff --git a/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py b/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py index 7e7f1523..871dd0cf 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py +++ b/python-libraries/nanover-ase/src/nanover/ase/openmm/runner.py @@ -6,21 +6,19 @@ from pathlib import Path from typing import Optional, List -from ase import units, Atoms # type: ignore +from ase import units # type: ignore from ase.md import MDLogger, Langevin from ase.md.velocitydistribution import MaxwellBoltzmannDistribution from attr import dataclass from nanover.app import NanoverImdApplication, NanoverRunner from nanover.app.app_server import DEFAULT_NANOVER_PORT +from nanover.ase.openmm.frame_adaptor import openmm_ase_frame_adaptor from nanover.core import NanoverServer, DEFAULT_SERVE_ADDRESS from nanover.ase import TrajectoryLogger from nanover.essd import DiscoveryServer from nanover.openmm import serializer -from nanover.openmm.converter import add_openmm_topology_to_frame_data -from nanover.trajectory.frame_publisher import FramePublisher from openmm.app import Simulation -from nanover.ase import ase_to_frame_data from nanover.ase.imd import NanoverASEDynamics from nanover.ase.openmm.calculator import OpenMMCalculator from nanover.ase.wall_constraint import VelocityWallConstraint @@ -35,54 +33,6 @@ ) -def openmm_ase_frame_adaptor( - ase_atoms: Atoms, - frame_publisher: FramePublisher, - **kwargs, -): - """ - Generates and sends frames for a simulation using an :class: OpenMMCalculator. - """ - - frame_index = 0 - - def send(): - nonlocal frame_index - # generate topology frame using OpenMM converter. - if frame_index == 0: - frame = openmm_ase_atoms_to_topology_frame(ase_atoms, **kwargs) - # from then on, just send positions and state. - else: - frame = openmm_ase_atoms_to_regular_frame(ase_atoms, **kwargs) - frame_publisher.send_frame(frame_index, frame) - frame_index += 1 - - return send - - -def openmm_ase_atoms_to_regular_frame( - ase_atoms: Atoms, - **kwargs, -): - frame = ase_to_frame_data( - ase_atoms, - topology=False, - **kwargs, - ) - return frame - - -def openmm_ase_atoms_to_topology_frame( - ase_atoms: Atoms, - **kwargs, -): - imd_calculator = ase_atoms.calc - topology = imd_calculator.calculator.topology - frame = openmm_ase_atoms_to_regular_frame(ase_atoms, **kwargs) - add_openmm_topology_to_frame_data(frame, topology) - return frame - - @dataclass class ImdParams: """ diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index 62096bca..41976242 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -14,10 +14,7 @@ from nanover.ase.converter import EV_TO_KJMOL from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.openmm import OpenMMCalculator -from nanover.ase.openmm.runner import ( - openmm_ase_atoms_to_regular_frame, - openmm_ase_atoms_to_topology_frame, -) +from nanover.ase.openmm.frame_adaptor import openmm_ase_atoms_to_topology_frame, openmm_ase_atoms_to_regular_frame from nanover.ase.wall_constraint import VelocityWallConstraint from nanover.omni.ase import InitialState from nanover.openmm import serializer From 6d4aa2f50cdad48d94775d5f08fce51e92529d13 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 16:20:39 +0200 Subject: [PATCH 19/36] cleanup --- python-libraries/nanover-omni/src/nanover/omni/ase.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 67c7800f..cd3aa92f 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -6,7 +6,8 @@ from ase.md.md import MolecularDynamics from nanover.app import NanoverImdApplication -from nanover.ase.converter import EV_TO_KJMOL, ase_to_frame_data +from nanover.ase.converter import EV_TO_KJMOL, ase_to_frame_data, ase_atoms_to_topology_frame, \ + ase_atoms_to_regular_frame from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.wall_constraint import VelocityWallConstraint from nanover.utilities.event import Event @@ -171,9 +172,8 @@ def make_topology_frame(self): """ assert self.atoms is not None - return ase_to_frame_data( + return ase_atoms_to_topology_frame( self.atoms, - topology=True, include_velocities=self.include_velocities, include_forces=self.include_forces, ) @@ -184,9 +184,8 @@ def make_regular_frame(self): """ assert self.atoms is not None - return ase_to_frame_data( + return ase_atoms_to_regular_frame( self.atoms, - topology=False, include_velocities=self.include_velocities, include_forces=self.include_forces, ) From 5cd703b22168fd9afe00028977c2467c423785d5 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 16:30:01 +0200 Subject: [PATCH 20/36] cleanup --- .../nanover-ase/src/nanover/ase/converter.py | 24 +++----------- .../src/nanover/ase/frame_adaptor.py | 24 +++++--------- .../src/nanover/ase/openmm/frame_adaptor.py | 33 +++++++++++-------- .../nanover-omni/src/nanover/omni/ase.py | 9 ++--- .../nanover-omni/src/nanover/omni/ase_omm.py | 10 ++++-- 5 files changed, 44 insertions(+), 56 deletions(-) diff --git a/python-libraries/nanover-ase/src/nanover/ase/converter.py b/python-libraries/nanover-ase/src/nanover/ase/converter.py index a5135fee..39dab3e1 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/converter.py +++ b/python-libraries/nanover-ase/src/nanover/ase/converter.py @@ -50,28 +50,12 @@ } -def ase_atoms_to_regular_frame( - ase_atoms: Atoms, - **kwargs, -): - frame = ase_to_frame_data( - ase_atoms, - topology=False, - **kwargs, - ) - return frame - - -def ase_atoms_to_topology_frame( - ase_atoms: Atoms, +def ase_atoms_to_frame_data( + atoms: Atoms, + topology=False, **kwargs, ): - frame = ase_to_frame_data( - ase_atoms, - topology=False, - **kwargs, - ) - return frame + return ase_to_frame_data(atoms, topology=topology, **kwargs) def ase_to_frame_data( diff --git a/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py b/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py index 1d7c5d1d..a1b6c681 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py +++ b/python-libraries/nanover-ase/src/nanover/ase/frame_adaptor.py @@ -5,10 +5,7 @@ from typing import Callable from ase import Atoms # type: ignore -from nanover.ase.converter import ( - ase_atoms_to_topology_frame, - ase_atoms_to_regular_frame, -) +from nanover.ase.converter import ase_atoms_to_frame_data from nanover.trajectory import FramePublisher @@ -43,18 +40,13 @@ def send_ase_frame( def send(): nonlocal frame_index - if frame_index == 0: - frame = ase_atoms_to_topology_frame( - ase_atoms, - include_velocities=include_velocities, - include_forces=include_forces, - ) - else: - frame = ase_atoms_to_regular_frame( - ase_atoms, - include_velocities=include_velocities, - include_forces=include_forces, - ) + include_topology = frame_index == 0 + frame = ase_atoms_to_frame_data( + ase_atoms, + topology=include_topology, + include_velocities=include_velocities, + include_forces=include_forces, + ) frame_publisher.send_frame(frame_index, frame) frame_index += 1 diff --git a/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py b/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py index 654a2593..98dd06d6 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py +++ b/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py @@ -18,13 +18,11 @@ def openmm_ase_frame_adaptor( def send(): nonlocal frame_index - # generate topology frame using OpenMM converter. - if frame_index == 0: - frame = openmm_ase_atoms_to_topology_frame(ase_atoms, **kwargs) - # from then on, just send positions and state. - else: - frame = openmm_ase_atoms_to_regular_frame(ase_atoms, **kwargs) - frame_publisher.send_frame(frame_index, frame) + include_topology = frame_index == 0 + frame_data = openmm_ase_atoms_to_frame_data( + ase_atoms, topology=include_topology, **kwargs + ) + frame_publisher.send_frame(frame_index, frame_data) frame_index += 1 return send @@ -42,12 +40,21 @@ def openmm_ase_atoms_to_regular_frame( return frame -def openmm_ase_atoms_to_topology_frame( +def openmm_ase_atoms_to_frame_data( ase_atoms: Atoms, + *, + topology=False, **kwargs, ): - imd_calculator = ase_atoms.calc - topology = imd_calculator.calculator.topology - frame = openmm_ase_atoms_to_regular_frame(ase_atoms, **kwargs) - add_openmm_topology_to_frame_data(frame, topology) - return frame + frame_data = ase_to_frame_data( + ase_atoms, + topology=False, + **kwargs, + ) + + if topology: + imd_calculator = ase_atoms.calc + topology = imd_calculator.calculator.topology + add_openmm_topology_to_frame_data(frame_data, topology) + + return frame_data diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index cd3aa92f..a23abaa2 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -6,8 +6,7 @@ from ase.md.md import MolecularDynamics from nanover.app import NanoverImdApplication -from nanover.ase.converter import EV_TO_KJMOL, ase_to_frame_data, ase_atoms_to_topology_frame, \ - ase_atoms_to_regular_frame +from nanover.ase.converter import EV_TO_KJMOL, ase_atoms_to_frame_data from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.wall_constraint import VelocityWallConstraint from nanover.utilities.event import Event @@ -172,8 +171,9 @@ def make_topology_frame(self): """ assert self.atoms is not None - return ase_atoms_to_topology_frame( + return ase_atoms_to_frame_data( self.atoms, + topology=True, include_velocities=self.include_velocities, include_forces=self.include_forces, ) @@ -184,8 +184,9 @@ def make_regular_frame(self): """ assert self.atoms is not None - return ase_atoms_to_regular_frame( + return ase_atoms_to_frame_data( self.atoms, + topology=False, include_velocities=self.include_velocities, include_forces=self.include_forces, ) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index 41976242..1c4ba9da 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -14,7 +14,9 @@ from nanover.ase.converter import EV_TO_KJMOL from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.openmm import OpenMMCalculator -from nanover.ase.openmm.frame_adaptor import openmm_ase_atoms_to_topology_frame, openmm_ase_atoms_to_regular_frame +from nanover.ase.openmm.frame_adaptor import ( + openmm_ase_atoms_to_frame_data, +) from nanover.ase.wall_constraint import VelocityWallConstraint from nanover.omni.ase import InitialState from nanover.openmm import serializer @@ -208,8 +210,9 @@ def make_topology_frame(self): """ assert self.atoms is not None - return openmm_ase_atoms_to_topology_frame( + return openmm_ase_atoms_to_frame_data( self.atoms, + topology=True, include_velocities=self.include_velocities, include_forces=self.include_forces, ) @@ -220,8 +223,9 @@ def make_regular_frame(self): """ assert self.atoms is not None - return openmm_ase_atoms_to_regular_frame( + return openmm_ase_atoms_to_frame_data( self.atoms, + topology=False, include_velocities=self.include_velocities, include_forces=self.include_forces, ) From 28cbea504d63994ce2c68bfe410dc991e4d0f24b Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 16:55:48 +0200 Subject: [PATCH 21/36] fixes + update notebook --- examples/ase/openmm_neuraminidase.ipynb | 153 +++++++++--------- .../src/nanover/ase/openmm/frame_adaptor.py | 12 -- .../nanover-omni/src/nanover/omni/ase.py | 21 ++- .../nanover-omni/src/nanover/omni/ase_omm.py | 115 ++----------- 4 files changed, 101 insertions(+), 200 deletions(-) diff --git a/examples/ase/openmm_neuraminidase.ipynb b/examples/ase/openmm_neuraminidase.ipynb index 326f580a..87c79104 100644 --- a/examples/ase/openmm_neuraminidase.ipynb +++ b/examples/ase/openmm_neuraminidase.ipynb @@ -50,7 +50,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 10, "metadata": {}, "outputs": [], "source": [ @@ -61,7 +61,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -99,14 +99,14 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 12, "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "/home/jon/.mambaforge/envs/nanover/lib/python3.10/site-packages/openmm/app/internal/amber_file_parser.py:1165: UserWarning: Non-optimal GB parameters detected for GB model OBC2\n", + "C:\\Users\\ragzo\\anaconda3\\envs\\nanover-dev\\Lib\\site-packages\\openmm\\app\\internal\\amber_file_parser.py:1168: UserWarning: Non-optimal GB parameters detected for GB model OBC2\n", " warnings.warn(\n" ] } @@ -120,7 +120,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 13, "metadata": { "pycharm": { "is_executing": true @@ -140,7 +140,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 14, "metadata": {}, "outputs": [], "source": [ @@ -149,7 +149,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -167,7 +167,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 16, "metadata": {}, "outputs": [], "source": [ @@ -183,7 +183,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 17, "metadata": {}, "outputs": [], "source": [ @@ -192,7 +192,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 18, "metadata": {}, "outputs": [], "source": [ @@ -201,7 +201,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": 19, "metadata": {}, "outputs": [ { @@ -209,16 +209,16 @@ "output_type": "stream", "text": [ "#\"Step\",\"Potential Energy (kJ/mole)\",\"Temperature (K)\"\n", - "100,-39540.22208032991,172.0368640414814\n", - "200,-38037.813714933814,176.83360536377518\n", - "300,-36957.922669540145,186.50658465938525\n", - "400,-36537.67326410094,202.19986509983823\n", - "500,-35849.644951178234,213.220791136058\n", - "600,-35094.31895770768,219.77104104177\n", - "700,-34314.613707171666,224.59222300857243\n", - "800,-33729.39031191092,229.9811264977871\n", - "900,-33440.23194823894,239.22371410931424\n", - "1000,-32960.056166880924,244.41153511927288\n" + "100,-39322.728645545474,172.8978401967851\n", + "200,-37794.347786170474,178.36680131402554\n", + "300,-36947.80033133649,191.42981846756774\n", + "400,-36300.61284659528,202.61229973698843\n", + "500,-35362.4622881236,209.92177439617308\n", + "600,-34806.25983451032,219.47886351217505\n", + "700,-34212.024864417544,226.02847374554963\n", + "800,-33687.36612723493,235.26808978386075\n", + "900,-33257.65744803571,242.45830788867468\n", + "1000,-32679.138481360904,246.52136866948084\n" ] } ], @@ -248,17 +248,9 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 20, "metadata": {}, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Warning: importing 'simtk.openmm' is deprecated. Import 'openmm' instead.\n" - ] - } - ], + "outputs": [], "source": [ "from nanover.openmm.serializer import serialize_simulation\n", "\n", @@ -310,7 +302,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 21, "metadata": {}, "outputs": [], "source": [ @@ -319,7 +311,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 22, "metadata": {}, "outputs": [], "source": [ @@ -328,16 +320,24 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 23, "metadata": {}, "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "C:\\Users\\ragzo\\AppData\\Local\\Temp\\ipykernel_21988\\3079109835.py:2: DeprecationWarning: Please use atoms.calc = calc\n", + " atoms.set_calculator(calculator)\n" + ] + }, { "data": { "text/plain": [ "5880" ] }, - "execution_count": 14, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -358,7 +358,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 24, "metadata": {}, "outputs": [], "source": [ @@ -369,43 +369,27 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": 27, "metadata": {}, "outputs": [], "source": [ - "from nanover.ase import NanoverASEDynamics\n", "from nanover.app import NanoverImdApplication\n", - "from nanover.ase.openmm.runner import openmm_ase_frame_adaptor" + "from nanover.ase.openmm.frame_adaptor import openmm_ase_atoms_to_frame_data\n", + "from nanover.omni import OmniRunner\n", + "from nanover.omni.ase import ASESimulation" ] }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 28, "metadata": {}, "outputs": [], "source": [ - "nanover_server = NanoverImdApplication.basic_server(port=0)\n", - "imd = NanoverASEDynamics(nanover_server,dynamics, frame_method=openmm_ase_frame_adaptor)" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "imd.atoms.get_calculator()" + "omni_sim = ASESimulation.from_ase_dynamics(\n", + " dynamics, \n", + " ase_atoms_to_frame_data=openmm_ase_atoms_to_frame_data,\n", + ")\n", + "omni = OmniRunner.with_basic_server(omni_sim)" ] }, { @@ -417,31 +401,23 @@ }, { "cell_type": "code", - "execution_count": 19, - "metadata": {}, - "outputs": [], - "source": [ - "imd.run(10)" - ] - }, - { - "cell_type": "code", - "execution_count": 20, + "execution_count": 38, "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "-416.8531416057526" + "-431.67088595016065" ] }, - "execution_count": 20, + "execution_count": 38, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "imd.atoms.get_potential_energy()" + "omni_sim.dynamics.run(100)\n", + "omni_sim.atoms.get_potential_energy()" ] }, { @@ -453,11 +429,11 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 39, "metadata": {}, "outputs": [], "source": [ - "imd.run()" + "omni.next()" ] }, { @@ -492,9 +468,24 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 41, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "Exception", + "evalue": "Timed out waiting for first frame.", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mException\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[41], line 4\u001b[0m\n\u001b[0;32m 2\u001b[0m client \u001b[38;5;241m=\u001b[39m NanoverImdClient\u001b[38;5;241m.\u001b[39mconnect_to_single_server(port\u001b[38;5;241m=\u001b[39mnanover_server\u001b[38;5;241m.\u001b[39mport)\n\u001b[0;32m 3\u001b[0m client\u001b[38;5;241m.\u001b[39msubscribe_to_frames()\n\u001b[1;32m----> 4\u001b[0m client\u001b[38;5;241m.\u001b[39mwait_until_first_frame()\n", + "File \u001b[1;32mc:\\users\\ragzo\\documents\\work\\nanover-protocol\\python-libraries\\nanover-core\\src\\nanover\\app\\client.py:64\u001b[0m, in \u001b[0;36m_need_attribute..wrapper\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 62\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mgetattr\u001b[39m(\u001b[38;5;28mself\u001b[39m, attr) \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m 63\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mNot connected to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mname\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m service\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m---> 64\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m func(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", + "File \u001b[1;32mc:\\users\\ragzo\\documents\\work\\nanover-protocol\\python-libraries\\nanover-core\\src\\nanover\\app\\client.py:77\u001b[0m, in \u001b[0;36mneed_trajectory_joined..wrapper\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 72\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_are_framed_subscribed:\n\u001b[0;32m 73\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mRuntimeError\u001b[39;00m(\n\u001b[0;32m 74\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mYou need to first subscribe to the frame using the \u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 75\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124msubscribe_to_frames or the subscribe_to_all_frames methods.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 76\u001b[0m )\n\u001b[1;32m---> 77\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m func(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", + "File \u001b[1;32mc:\\users\\ragzo\\documents\\work\\nanover-protocol\\python-libraries\\nanover-core\\src\\nanover\\app\\client.py:387\u001b[0m, in \u001b[0;36mNanoverImdClient.wait_until_first_frame\u001b[1;34m(self, check_interval, timeout)\u001b[0m\n\u001b[0;32m 385\u001b[0m \u001b[38;5;28;01mwhile\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfirst_frame \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m 386\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;241m0\u001b[39m \u001b[38;5;241m<\u001b[39m endtime \u001b[38;5;241m<\u001b[39m time\u001b[38;5;241m.\u001b[39mmonotonic():\n\u001b[1;32m--> 387\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mException\u001b[39;00m(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mTimed out waiting for first frame.\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[0;32m 388\u001b[0m time\u001b[38;5;241m.\u001b[39msleep(check_interval)\n\u001b[0;32m 390\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfirst_frame\n", + "\u001b[1;31mException\u001b[0m: Timed out waiting for first frame." + ] + } + ], "source": [ "from nanover.app import NanoverImdClient\n", "client = NanoverImdClient.connect_to_single_server(port=nanover_server.port)\n", @@ -511,7 +502,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -738,7 +729,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.10.12" + "version": "3.12.0" }, "pycharm": { "stem_cell": { diff --git a/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py b/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py index 98dd06d6..04b116c4 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py +++ b/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py @@ -28,18 +28,6 @@ def send(): return send -def openmm_ase_atoms_to_regular_frame( - ase_atoms: Atoms, - **kwargs, -): - frame = ase_to_frame_data( - ase_atoms, - topology=False, - **kwargs, - ) - return frame - - def openmm_ase_atoms_to_frame_data( ase_atoms: Atoms, *, diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index a23abaa2..29ed8e1e 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -1,7 +1,8 @@ from dataclasses import dataclass -from typing import Optional, Any +from typing import Optional, Any, Protocol import numpy as np +from ase import Atoms from ase.md import MDLogger from ase.md.md import MolecularDynamics @@ -19,6 +20,10 @@ class InitialState: cell: Any +class ASEAtomsToFrameData(Protocol): + def __call__(self, ase_atoms: Atoms, *, topology: bool, **kwargs) -> float: ... + + class ASESimulation: """ A wrapper for ASE simulations so they can be run inside the OmniRunner. @@ -26,15 +31,21 @@ class ASESimulation: @classmethod def from_ase_dynamics( - cls, dynamics: MolecularDynamics, *, name: Optional[str] = None + cls, + dynamics: MolecularDynamics, + *, + name: Optional[str] = None, + ase_atoms_to_frame_data: ASEAtomsToFrameData = ase_atoms_to_frame_data ): """ Construct this from an existing ASE dynamics. :param dynamics: An existing ASE Dynamics :param name: An optional name for the simulation instead of default + :param ase_atoms_to_frame_data: An optional callback to extra frames from the system """ sim = cls(name) sim.dynamics = dynamics + sim.ase_atoms_to_frame_data = ase_atoms_to_frame_data return sim @property @@ -57,12 +68,12 @@ def __init__(self, name: Optional[str] = None): self.frame_interval = 5 self.include_velocities = False self.include_forces = False - self.platform: Optional[str] = None self.dynamics: Optional[MolecularDynamics] = None self.checkpoint: Optional[InitialState] = None self.frame_index = 0 + self.ase_atoms_to_frame_data = ase_atoms_to_frame_data def load(self): """ @@ -171,7 +182,7 @@ def make_topology_frame(self): """ assert self.atoms is not None - return ase_atoms_to_frame_data( + return self.ase_atoms_to_frame_data( self.atoms, topology=True, include_velocities=self.include_velocities, @@ -184,7 +195,7 @@ def make_regular_frame(self): """ assert self.atoms is not None - return ase_atoms_to_frame_data( + return self.ase_atoms_to_frame_data( self.atoms, topology=False, include_velocities=self.include_velocities, diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py index 1c4ba9da..8aabd784 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase_omm.py @@ -3,24 +3,19 @@ from pathlib import Path from typing import Optional -import numpy as np from ase import units, Atoms from ase.md import Langevin, MDLogger -from ase.md.md import MolecularDynamics from ase.md.velocitydistribution import MaxwellBoltzmannDistribution from openmm.app import Simulation from nanover.app import NanoverImdApplication -from nanover.ase.converter import EV_TO_KJMOL from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.openmm import OpenMMCalculator from nanover.ase.openmm.frame_adaptor import ( openmm_ase_atoms_to_frame_data, ) -from nanover.ase.wall_constraint import VelocityWallConstraint -from nanover.omni.ase import InitialState +from nanover.omni.ase import ASESimulation from nanover.openmm import serializer -from nanover.utilities.event import Event CONSTRAINTS_UNSUPPORTED_MESSAGE = ( @@ -28,7 +23,7 @@ ) -class ASEOpenMMSimulation: +class ASEOpenMMSimulation(ASESimulation): """ A wrapper for ASE OpenMM simulations so they can be run inside the OmniRunner. """ @@ -61,28 +56,17 @@ def from_xml_path(cls, path: PathLike[str], *, name: Optional[str] = None): return sim def __init__(self, name: Optional[str] = None): - self.name = name or "Unnamed ASE OpenMM Simulation" + name = name or "Unnamed ASE OpenMM Simulation" - self.xml_path: Optional[PathLike[str]] = None - self.app_server: Optional[NanoverImdApplication] = None + super().__init__(name or "Unnamed ASE OpenMM Simulation") - self.on_reset_energy_exceeded = Event() + self.ase_atoms_to_frame_data = openmm_ase_atoms_to_frame_data - self.verbose = False - self.use_walls = False - self.reset_energy: Optional[float] = None - self.frame_interval = 5 - self.include_velocities = False - self.include_forces = False - self.platform: Optional[str] = None + self.xml_path: Optional[PathLike[str]] = None - self.atoms: Optional[Atoms] = None - self.dynamics: Optional[MolecularDynamics] = None + self.platform: Optional[str] = None self.simulation: Optional[Simulation] = None self.openmm_calculator: Optional[OpenMMCalculator] = None - self.checkpoint: Optional[InitialState] = None - - self.frame_index = 0 def load(self): """ @@ -97,22 +81,17 @@ def load(self): assert self.simulation is not None self.openmm_calculator = OpenMMCalculator(self.simulation) - self.atoms = self.openmm_calculator.generate_atoms() - if self.use_walls: - self.atoms.constraints.append(VelocityWallConstraint()) + atoms = self.openmm_calculator.generate_atoms() + + # we don't read this from the openmm xml + self.dynamics = make_default_ase_omm_dynamics(atoms) + self.atoms.calc = self.openmm_calculator # Set the momenta corresponding to T=300K MaxwellBoltzmannDistribution(self.atoms, temperature_K=300) - # we don't read this from the openmm xml - self.dynamics = make_default_ase_omm_dynamics(self.atoms) - - self.checkpoint = InitialState( - positions=self.atoms.get_positions(), - velocities=self.atoms.get_velocities(), - cell=self.atoms.get_cell(), - ) + super().load() def reset(self, app_server: NanoverImdApplication): """ @@ -162,74 +141,6 @@ def reset(self, app_server: NanoverImdApplication): interval=100, ) - def advance_by_one_step(self): - """ - Advance the simulation to the next point a frame should be reported, and send that frame. - """ - self.advance_to_next_report() - - def advance_by_seconds(self, dt: float): - """ - Advance playback time by some seconds, and advance the simulation to the next frame output. - :param dt: Time to advance playback by in seconds (ignored) - """ - self.advance_to_next_report() - - def advance_to_next_report(self): - """ - Step the simulation to the next point a frame should be reported, and send that frame. - """ - assert self.dynamics is not None and self.app_server is not None - - # determine step count for next frame - steps_to_next_frame = ( - self.frame_interval - - self.dynamics.get_number_of_steps() % self.frame_interval - ) - - # advance the simulation - self.dynamics.run(steps_to_next_frame) - - # generate the next frame - frame_data = self.make_regular_frame() - - # send the next frame - self.app_server.frame_publisher.send_frame(self.frame_index, frame_data) - self.frame_index += 1 - - # check if excessive energy necessitates reset - if self.reset_energy is not None and self.app_server is not None: - energy = self.dynamics.atoms.get_total_energy() * EV_TO_KJMOL - if not np.isfinite(energy) or energy > self.reset_energy: - self.on_reset_energy_exceeded.invoke() - self.reset(self.app_server) - - def make_topology_frame(self): - """ - Make a NanoVer FrameData corresponding to the current particle positions and topology of the simulation. - """ - assert self.atoms is not None - - return openmm_ase_atoms_to_frame_data( - self.atoms, - topology=True, - include_velocities=self.include_velocities, - include_forces=self.include_forces, - ) - - def make_regular_frame(self): - """ - Make a NanoVer FrameData corresponding to the current state of the simulation. - """ - assert self.atoms is not None - - return openmm_ase_atoms_to_frame_data( - self.atoms, - topology=False, - include_velocities=self.include_velocities, - include_forces=self.include_forces, - ) - def make_default_ase_omm_dynamics(atoms: Atoms): # We do not remove the center of mass (fixcm=False). If the center of From 39877664775c0ae6d726797943057f4f31e91b3e Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 17:02:28 +0200 Subject: [PATCH 22/36] typign attempt --- python-libraries/nanover-ase/src/nanover/ase/converter.py | 1 + 1 file changed, 1 insertion(+) diff --git a/python-libraries/nanover-ase/src/nanover/ase/converter.py b/python-libraries/nanover-ase/src/nanover/ase/converter.py index 39dab3e1..e746cd69 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/converter.py +++ b/python-libraries/nanover-ase/src/nanover/ase/converter.py @@ -52,6 +52,7 @@ def ase_atoms_to_frame_data( atoms: Atoms, + *, topology=False, **kwargs, ): From 178ade3ce2c7c05584b684deac46db2cd0f8f88a Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 17:05:57 +0200 Subject: [PATCH 23/36] typign attempt --- python-libraries/nanover-omni/src/nanover/omni/ase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 29ed8e1e..1ace8948 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -21,7 +21,7 @@ class InitialState: class ASEAtomsToFrameData(Protocol): - def __call__(self, ase_atoms: Atoms, *, topology: bool, **kwargs) -> float: ... + def __call__(self, ase_atoms: Atoms, *, topology: bool = False, **kwargs) -> float: ... class ASESimulation: From c54584451df0d45033acce7eeb734254f5791c12 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 17:08:35 +0200 Subject: [PATCH 24/36] whoops --- python-libraries/nanover-omni/src/nanover/omni/ase.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 1ace8948..1e26fcbd 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -10,6 +10,7 @@ from nanover.ase.converter import EV_TO_KJMOL, ase_atoms_to_frame_data from nanover.ase.imd_calculator import ImdCalculator from nanover.ase.wall_constraint import VelocityWallConstraint +from nanover.trajectory import FrameData from nanover.utilities.event import Event @@ -21,7 +22,9 @@ class InitialState: class ASEAtomsToFrameData(Protocol): - def __call__(self, ase_atoms: Atoms, *, topology: bool = False, **kwargs) -> float: ... + def __call__( + self, ase_atoms: Atoms, *, topology: bool = False, **kwargs + ) -> FrameData: ... class ASESimulation: From 7126583954e20f4930e6e168b1342eccb8c0e162 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 17:14:10 +0200 Subject: [PATCH 25/36] another try --- python-libraries/nanover-ase/src/nanover/ase/converter.py | 4 ++-- python-libraries/nanover-omni/src/nanover/omni/ase.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/python-libraries/nanover-ase/src/nanover/ase/converter.py b/python-libraries/nanover-ase/src/nanover/ase/converter.py index e746cd69..d7a01524 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/converter.py +++ b/python-libraries/nanover-ase/src/nanover/ase/converter.py @@ -53,9 +53,9 @@ def ase_atoms_to_frame_data( atoms: Atoms, *, - topology=False, + topology, **kwargs, -): +) -> FrameData: return ase_to_frame_data(atoms, topology=topology, **kwargs) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 1e26fcbd..e0a6e805 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -23,7 +23,7 @@ class InitialState: class ASEAtomsToFrameData(Protocol): def __call__( - self, ase_atoms: Atoms, *, topology: bool = False, **kwargs + self, ase_atoms: Atoms, *, topology: bool, **kwargs ) -> FrameData: ... From 350a5c7e73cc42eaf4fd4ad7db3c3e8d8d584c8e Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 17:16:48 +0200 Subject: [PATCH 26/36] again --- python-libraries/nanover-ase/src/nanover/ase/converter.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/python-libraries/nanover-ase/src/nanover/ase/converter.py b/python-libraries/nanover-ase/src/nanover/ase/converter.py index d7a01524..b3b40b4a 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/converter.py +++ b/python-libraries/nanover-ase/src/nanover/ase/converter.py @@ -53,7 +53,7 @@ def ase_atoms_to_frame_data( atoms: Atoms, *, - topology, + topology: bool, **kwargs, ) -> FrameData: return ase_to_frame_data(atoms, topology=topology, **kwargs) From 392d1005907898ef0e43116fc973d0b91459034d Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 17:20:58 +0200 Subject: [PATCH 27/36] ffs --- .../nanover-ase/src/nanover/ase/openmm/frame_adaptor.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py b/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py index 04b116c4..bd211b83 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py +++ b/python-libraries/nanover-ase/src/nanover/ase/openmm/frame_adaptor.py @@ -2,7 +2,7 @@ from nanover.ase import ase_to_frame_data from nanover.openmm.converter import add_openmm_topology_to_frame_data -from nanover.trajectory import FramePublisher +from nanover.trajectory import FramePublisher, FrameData def openmm_ase_frame_adaptor( @@ -31,9 +31,9 @@ def send(): def openmm_ase_atoms_to_frame_data( ase_atoms: Atoms, *, - topology=False, + topology: bool, **kwargs, -): +) -> FrameData: frame_data = ase_to_frame_data( ase_atoms, topology=False, From 72b45164c89a9899f21dbdf9d5faad55019c179d Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 17:26:29 +0200 Subject: [PATCH 28/36] bla --- python-libraries/nanover-ase/src/nanover/ase/converter.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/python-libraries/nanover-ase/src/nanover/ase/converter.py b/python-libraries/nanover-ase/src/nanover/ase/converter.py index b3b40b4a..6548dd7b 100644 --- a/python-libraries/nanover-ase/src/nanover/ase/converter.py +++ b/python-libraries/nanover-ase/src/nanover/ase/converter.py @@ -51,12 +51,12 @@ def ase_atoms_to_frame_data( - atoms: Atoms, + ase_atoms: Atoms, *, topology: bool, **kwargs, ) -> FrameData: - return ase_to_frame_data(atoms, topology=topology, **kwargs) + return ase_to_frame_data(ase_atoms, topology=topology, **kwargs) def ase_to_frame_data( From d056781a10ab3bba758c42b1a0aed679637cf026 Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 30 Sep 2024 17:34:43 +0200 Subject: [PATCH 29/36] style --- python-libraries/nanover-omni/src/nanover/omni/ase.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index e0a6e805..06cd96c0 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -22,9 +22,7 @@ class InitialState: class ASEAtomsToFrameData(Protocol): - def __call__( - self, ase_atoms: Atoms, *, topology: bool, **kwargs - ) -> FrameData: ... + def __call__(self, ase_atoms: Atoms, *, topology: bool, **kwargs) -> FrameData: ... class ASESimulation: @@ -49,6 +47,7 @@ def from_ase_dynamics( sim = cls(name) sim.dynamics = dynamics sim.ase_atoms_to_frame_data = ase_atoms_to_frame_data + return sim @property @@ -112,6 +111,7 @@ def reset(self, app_server: NanoverImdApplication): self.atoms.set_velocities(self.checkpoint.velocities) self.atoms.set_cell(self.checkpoint.cell) + # TODO: this can't be right... nesting the calculator every reset self.atoms.calc = ImdCalculator( self.app_server.imd, self.atoms.calc, From af35db1c3e5f98c75e1ba1749d6a1814ac72353c Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 7 Oct 2024 17:49:41 +0200 Subject: [PATCH 30/36] fix calculator nesting and check dynamics actually responds to interactions --- .../nanover-omni/src/nanover/omni/ase.py | 8 +++-- .../nanover-omni/tests/test_ase.py | 33 ++++++++++++++++--- 2 files changed, 35 insertions(+), 6 deletions(-) diff --git a/python-libraries/nanover-omni/src/nanover/omni/ase.py b/python-libraries/nanover-omni/src/nanover/omni/ase.py index 06cd96c0..030b033d 100644 --- a/python-libraries/nanover-omni/src/nanover/omni/ase.py +++ b/python-libraries/nanover-omni/src/nanover/omni/ase.py @@ -3,6 +3,7 @@ import numpy as np from ase import Atoms +from ase.calculators.calculator import Calculator from ase.md import MDLogger from ase.md.md import MolecularDynamics @@ -47,6 +48,7 @@ def from_ase_dynamics( sim = cls(name) sim.dynamics = dynamics sim.ase_atoms_to_frame_data = ase_atoms_to_frame_data + sim.initial_calc = dynamics.atoms.calc return sim @@ -73,6 +75,7 @@ def __init__(self, name: Optional[str] = None): self.dynamics: Optional[MolecularDynamics] = None self.checkpoint: Optional[InitialState] = None + self.initial_calc: Optional[Calculator] = None self.frame_index = 0 self.ase_atoms_to_frame_data = ase_atoms_to_frame_data @@ -102,6 +105,7 @@ def reset(self, app_server: NanoverImdApplication): self.dynamics is not None and self.atoms is not None and self.checkpoint is not None + and self.initial_calc is not None ) self.app_server = app_server @@ -111,10 +115,10 @@ def reset(self, app_server: NanoverImdApplication): self.atoms.set_velocities(self.checkpoint.velocities) self.atoms.set_cell(self.checkpoint.cell) - # TODO: this can't be right... nesting the calculator every reset + # setup calculator self.atoms.calc = ImdCalculator( self.app_server.imd, - self.atoms.calc, + self.initial_calc, dynamics=self.dynamics, ) diff --git a/python-libraries/nanover-omni/tests/test_ase.py b/python-libraries/nanover-omni/tests/test_ase.py index 49dced22..9a49bfae 100644 --- a/python-libraries/nanover-omni/tests/test_ase.py +++ b/python-libraries/nanover-omni/tests/test_ase.py @@ -3,6 +3,8 @@ from ase.calculators.lj import LennardJones from ase.md import VelocityVerlet +from nanover.imd import ParticleInteraction +from nanover.omni import OmniRunner from nanover.omni.ase import ASESimulation from common import app_server @@ -18,10 +20,8 @@ def example_ase(app_server, example_dynamics): @pytest.fixture def example_dynamics(): - d = 1.1 - atoms = Atoms("CO", positions=[(0, 0, 0), (0, 0, d)], cell=[2, 2, 2], pbc=[1, 1, 1]) - calculator = LennardJones() - atoms.calc = calculator + atoms = Atoms("C", positions=[(0, 0, 0)], cell=[2, 2, 2]) + atoms.calc = LennardJones() dynamics = VelocityVerlet(atoms, timestep=0.5) yield dynamics @@ -35,3 +35,28 @@ def test_step_interval(example_ase): example_ase.dynamics.get_number_of_steps() == i * example_ase.frame_interval ) example_ase.advance_by_one_step() + + +def test_dynamics_interaction(example_ase): + """ + Test that example dynamics responds to interactions. + """ + + with OmniRunner.with_basic_server(example_ase, port=0) as runner: + runner.app_server.imd.insert_interaction( + "interaction.0", + ParticleInteraction( + position=(0.0, 0.0, 10.0), + particles=[0], + interaction_type="constant", + ), + ) + runner.next() + runner.pause() + for _ in range(30): + example_ase.advance_by_one_step() + + positions = example_ase.atoms.get_positions() + (x, y, z) = positions[0] + + assert z > 2.5 From 6177db3e9b34795af68e8744dc1b5e886f75775b Mon Sep 17 00:00:00 2001 From: candle Date: Mon, 7 Oct 2024 17:59:01 +0200 Subject: [PATCH 31/36] fix test setup --- .../nanover-omni/tests/test_ase.py | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/python-libraries/nanover-omni/tests/test_ase.py b/python-libraries/nanover-omni/tests/test_ase.py index 9a49bfae..d7a35f5b 100644 --- a/python-libraries/nanover-omni/tests/test_ase.py +++ b/python-libraries/nanover-omni/tests/test_ase.py @@ -41,20 +41,16 @@ def test_dynamics_interaction(example_ase): """ Test that example dynamics responds to interactions. """ - - with OmniRunner.with_basic_server(example_ase, port=0) as runner: - runner.app_server.imd.insert_interaction( - "interaction.0", - ParticleInteraction( - position=(0.0, 0.0, 10.0), - particles=[0], - interaction_type="constant", - ), - ) - runner.next() - runner.pause() - for _ in range(30): - example_ase.advance_by_one_step() + example_ase.app_server.imd.insert_interaction( + "interaction.0", + ParticleInteraction( + position=(0.0, 0.0, 10.0), + particles=[0], + interaction_type="constant", + ), + ) + for _ in range(30): + example_ase.advance_by_one_step() positions = example_ase.atoms.get_positions() (x, y, z) = positions[0] From 631d3d859c18059cde1b0896fd6afe8dc592e55b Mon Sep 17 00:00:00 2001 From: candle Date: Fri, 11 Oct 2024 13:04:35 +0200 Subject: [PATCH 32/36] fixes --- examples/ase/ase_openmm_neuraminidase.ipynb | 457 ++++++++++++-------- 1 file changed, 287 insertions(+), 170 deletions(-) diff --git a/examples/ase/ase_openmm_neuraminidase.ipynb b/examples/ase/ase_openmm_neuraminidase.ipynb index 62810d2b..2d42d32f 100644 --- a/examples/ase/ase_openmm_neuraminidase.ipynb +++ b/examples/ase/ase_openmm_neuraminidase.ipynb @@ -50,24 +50,34 @@ }, { "cell_type": "code", - "execution_count": 10, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:02:37.212605Z", + "start_time": "2024-10-11T11:02:36.898363Z" + } + }, "source": [ "import openmm as mm\n", "import openmm.unit as unit \n", "import openmm.app as app" - ] + ], + "outputs": [], + "execution_count": 1 }, { "cell_type": "code", - "execution_count": 11, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:02:37.999054Z", + "start_time": "2024-10-11T11:02:37.749626Z" + } + }, "source": [ "prmtop = app.AmberPrmtopFile(\"openmm_files/3TI6_ose_wt.top\")\n", "amber_coords = app.AmberInpcrdFile(\"openmm_files/3TI6_ose_wt.rst\")" - ] + ], + "outputs": [], + "execution_count": 2 }, { "cell_type": "markdown", @@ -99,8 +109,18 @@ }, { "cell_type": "code", - "execution_count": 12, - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:02:39.650723Z", + "start_time": "2024-10-11T11:02:39.461710Z" + } + }, + "source": [ + "system = prmtop.createSystem(nonbondedMethod=app.CutoffPeriodic, \n", + " nonbondedCutoff=2*unit.nanometer, \n", + " implicitSolvent=app.OBC2,\n", + " constraints=None)" + ], "outputs": [ { "name": "stderr", @@ -111,25 +131,24 @@ ] } ], - "source": [ - "system = prmtop.createSystem(nonbondedMethod=app.CutoffPeriodic, \n", - " nonbondedCutoff=2*unit.nanometer, \n", - " implicitSolvent=app.OBC2,\n", - " constraints=None)" - ] + "execution_count": 3 }, { "cell_type": "code", - "execution_count": 13, "metadata": { "pycharm": { "is_executing": true + }, + "ExecuteTime": { + "end_time": "2024-10-11T11:02:42.514705Z", + "start_time": "2024-10-11T11:02:42.510481Z" } }, - "outputs": [], "source": [ "integrator = mm.LangevinIntegrator(300*unit.kelvin, 1/unit.picosecond, 0.001*unit.picoseconds)" - ] + ], + "outputs": [], + "execution_count": 4 }, { "cell_type": "markdown", @@ -140,23 +159,33 @@ }, { "cell_type": "code", - "execution_count": 14, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:02:44.327171Z", + "start_time": "2024-10-11T11:02:44.225632Z" + } + }, "source": [ "simulation = app.Simulation(prmtop.topology, system, integrator)" - ] + ], + "outputs": [], + "execution_count": 5 }, { "cell_type": "code", - "execution_count": 15, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:02:45.946111Z", + "start_time": "2024-10-11T11:02:45.929227Z" + } + }, "source": [ "simulation.context.setPositions(amber_coords.positions)\n", "if amber_coords.boxVectors is not None:\n", " simulation.context.setPeriodicBoxVectors(*amber_coords.boxVectors)" - ] + ], + "outputs": [], + "execution_count": 6 }, { "cell_type": "markdown", @@ -167,12 +196,17 @@ }, { "cell_type": "code", - "execution_count": 16, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:02:48.726771Z", + "start_time": "2024-10-11T11:02:47.571332Z" + } + }, "source": [ "simulation.minimizeEnergy()" - ] + ], + "outputs": [], + "execution_count": 7 }, { "cell_type": "markdown", @@ -183,50 +217,65 @@ }, { "cell_type": "code", - "execution_count": 17, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:02:49.802180Z", + "start_time": "2024-10-11T11:02:49.779330Z" + } + }, "source": [ "simulation.context.setVelocitiesToTemperature(300 * unit.kelvin)" - ] + ], + "outputs": [], + "execution_count": 8 }, { "cell_type": "code", - "execution_count": 18, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:02:51.579581Z", + "start_time": "2024-10-11T11:02:51.576491Z" + } + }, "source": [ "import sys" - ] + ], + "outputs": [], + "execution_count": 9 }, { "cell_type": "code", - "execution_count": 19, - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:02:58.583405Z", + "start_time": "2024-10-11T11:02:52.972305Z" + } + }, + "source": [ + "simulation.reporters.append(app.StateDataReporter(sys.stdout, 100, step=True,\n", + " potentialEnergy=True, temperature=True))\n", + "simulation.step(1000)" + ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#\"Step\",\"Potential Energy (kJ/mole)\",\"Temperature (K)\"\n", - "100,-39322.728645545474,172.8978401967851\n", - "200,-37794.347786170474,178.36680131402554\n", - "300,-36947.80033133649,191.42981846756774\n", - "400,-36300.61284659528,202.61229973698843\n", - "500,-35362.4622881236,209.92177439617308\n", - "600,-34806.25983451032,219.47886351217505\n", - "700,-34212.024864417544,226.02847374554963\n", - "800,-33687.36612723493,235.26808978386075\n", - "900,-33257.65744803571,242.45830788867468\n", - "1000,-32679.138481360904,246.52136866948084\n" + "100,-39543.773704749576,171.94629506417792\n", + "200,-37456.68643973493,172.30788716141828\n", + "300,-36960.350029212466,185.9325771671761\n", + "400,-36279.01056693219,197.09489585675647\n", + "500,-35987.88951895856,211.20127489471548\n", + "600,-35227.428032142154,219.9709517508048\n", + "700,-34626.85153983258,225.99942530207284\n", + "800,-34018.469032508365,231.04540015999513\n", + "900,-33447.22238944196,238.21879439965178\n", + "1000,-33096.13106558942,244.96548097108987\n" ] } ], - "source": [ - "simulation.reporters.append(app.StateDataReporter(sys.stdout, 100, step=True,\n", - " potentialEnergy=True, temperature=True))\n", - "simulation.step(1000)" - ] + "execution_count": 10 }, { "cell_type": "markdown", @@ -248,15 +297,20 @@ }, { "cell_type": "code", - "execution_count": 20, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:04.176799Z", + "start_time": "2024-10-11T11:03:01.073873Z" + } + }, "source": [ "from nanover.openmm.serializer import serialize_simulation\n", "\n", "with open('neuraminidase_nanover.xml','w') as f:\n", " f.write(serialize_simulation(simulation))" - ] + ], + "outputs": [], + "execution_count": 11 }, { "cell_type": "markdown", @@ -302,32 +356,51 @@ }, { "cell_type": "code", - "execution_count": 21, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:08.198123Z", + "start_time": "2024-10-11T11:03:07.931047Z" + } + }, "source": [ "from nanover.ase.openmm import OpenMMCalculator" - ] + ], + "outputs": [], + "execution_count": 12 }, { "cell_type": "code", - "execution_count": 22, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:10.021005Z", + "start_time": "2024-10-11T11:03:10.017521Z" + } + }, "source": [ "calculator = OpenMMCalculator(simulation)" - ] + ], + "outputs": [], + "execution_count": 13 }, { "cell_type": "code", - "execution_count": 23, - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:11.841719Z", + "start_time": "2024-10-11T11:03:11.574654Z" + } + }, + "source": [ + "atoms = calculator.generate_atoms()\n", + "atoms.set_calculator(calculator)\n", + "len(atoms)" + ], "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "C:\\Users\\ragzo\\AppData\\Local\\Temp\\ipykernel_21988\\3079109835.py:2: DeprecationWarning: Please use atoms.calc = calc\n", + "C:\\Users\\ragzo\\AppData\\Local\\Temp\\ipykernel_10760\\2943926735.py:2: DeprecationWarning: Please use atoms.calc = calc\n", " atoms.set_calculator(calculator)\n" ] }, @@ -337,16 +410,12 @@ "5880" ] }, - "execution_count": 23, + "execution_count": 14, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "atoms = calculator.generate_atoms()\n", - "atoms.set_calculator(calculator)\n", - "len(atoms)" - ] + "execution_count": 14 }, { "cell_type": "markdown", @@ -358,39 +427,53 @@ }, { "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:13.895040Z", + "start_time": "2024-10-11T11:03:13.889625Z" + } + }, "source": [ "from ase.md import Langevin\n", "import ase.units as ase_units\n", "dynamics = Langevin(atoms, timestep=1.0 * ase_units.fs, temperature_K=300 * ase_units.kB, friction=1.0e-03)" - ] + ], + "outputs": [], + "execution_count": 15 }, { "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:19.899207Z", + "start_time": "2024-10-11T11:03:19.894562Z" + } + }, "source": [ - "from nanover.app import NanoverImdApplication\n", "from nanover.ase.openmm.frame_adaptor import openmm_ase_atoms_to_frame_data\n", "from nanover.omni import OmniRunner\n", "from nanover.omni.ase import ASESimulation" - ] + ], + "outputs": [], + "execution_count": 17 }, { "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:21.800989Z", + "start_time": "2024-10-11T11:03:21.762441Z" + } + }, "source": [ "omni_sim = ASESimulation.from_ase_dynamics(\n", " dynamics, \n", " ase_atoms_to_frame_data=openmm_ase_atoms_to_frame_data,\n", ")\n", "omni = OmniRunner.with_basic_server(omni_sim)" - ] + ], + "outputs": [], + "execution_count": 18 }, { "cell_type": "markdown", @@ -401,24 +484,29 @@ }, { "cell_type": "code", - "execution_count": 38, - "metadata": {}, + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:25.543985Z", + "start_time": "2024-10-11T11:03:24.067230Z" + } + }, + "source": [ + "omni_sim.dynamics.run(100)\n", + "omni_sim.atoms.get_potential_energy()" + ], "outputs": [ { "data": { "text/plain": [ - "-431.67088595016065" + "-432.65624999030933" ] }, - "execution_count": 38, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } ], - "source": [ - "omni_sim.dynamics.run(100)\n", - "omni_sim.atoms.get_potential_energy()" - ] + "execution_count": 19 }, { "cell_type": "markdown", @@ -429,12 +517,17 @@ }, { "cell_type": "code", - "execution_count": 39, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:27.561636Z", + "start_time": "2024-10-11T11:03:27.550961Z" + } + }, "source": [ "omni.next()" - ] + ], + "outputs": [], + "execution_count": 20 }, { "cell_type": "markdown", @@ -468,30 +561,20 @@ }, { "cell_type": "code", - "execution_count": 41, - "metadata": {}, - "outputs": [ - { - "ename": "Exception", - "evalue": "Timed out waiting for first frame.", - "output_type": "error", - "traceback": [ - "\u001B[1;31m---------------------------------------------------------------------------\u001B[0m", - "\u001B[1;31mException\u001B[0m Traceback (most recent call last)", - "Cell \u001B[1;32mIn[41], line 4\u001B[0m\n\u001B[0;32m 2\u001B[0m client \u001B[38;5;241m=\u001B[39m NanoverImdClient\u001B[38;5;241m.\u001B[39mconnect_to_single_server(port\u001B[38;5;241m=\u001B[39mnanover_server\u001B[38;5;241m.\u001B[39mport)\n\u001B[0;32m 3\u001B[0m client\u001B[38;5;241m.\u001B[39msubscribe_to_frames()\n\u001B[1;32m----> 4\u001B[0m client\u001B[38;5;241m.\u001B[39mwait_until_first_frame()\n", - "File \u001B[1;32mc:\\users\\ragzo\\documents\\work\\nanover-protocol\\python-libraries\\nanover-core\\src\\nanover\\app\\client.py:64\u001B[0m, in \u001B[0;36m_need_attribute..wrapper\u001B[1;34m(self, *args, **kwargs)\u001B[0m\n\u001B[0;32m 62\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;28mgetattr\u001B[39m(\u001B[38;5;28mself\u001B[39m, attr) \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[0;32m 63\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mRuntimeError\u001B[39;00m(\u001B[38;5;124mf\u001B[39m\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mNot connected to \u001B[39m\u001B[38;5;132;01m{\u001B[39;00mname\u001B[38;5;132;01m}\u001B[39;00m\u001B[38;5;124m service\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[1;32m---> 64\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m func(\u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n", - "File \u001B[1;32mc:\\users\\ragzo\\documents\\work\\nanover-protocol\\python-libraries\\nanover-core\\src\\nanover\\app\\client.py:77\u001B[0m, in \u001B[0;36mneed_trajectory_joined..wrapper\u001B[1;34m(self, *args, **kwargs)\u001B[0m\n\u001B[0;32m 72\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;129;01mnot\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39m_are_framed_subscribed:\n\u001B[0;32m 73\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mRuntimeError\u001B[39;00m(\n\u001B[0;32m 74\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mYou need to first subscribe to the frame using the \u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m 75\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124msubscribe_to_frames or the subscribe_to_all_frames methods.\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[0;32m 76\u001B[0m )\n\u001B[1;32m---> 77\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m func(\u001B[38;5;28mself\u001B[39m, \u001B[38;5;241m*\u001B[39margs, \u001B[38;5;241m*\u001B[39m\u001B[38;5;241m*\u001B[39mkwargs)\n", - "File \u001B[1;32mc:\\users\\ragzo\\documents\\work\\nanover-protocol\\python-libraries\\nanover-core\\src\\nanover\\app\\client.py:387\u001B[0m, in \u001B[0;36mNanoverImdClient.wait_until_first_frame\u001B[1;34m(self, check_interval, timeout)\u001B[0m\n\u001B[0;32m 385\u001B[0m \u001B[38;5;28;01mwhile\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mfirst_frame \u001B[38;5;129;01mis\u001B[39;00m \u001B[38;5;28;01mNone\u001B[39;00m:\n\u001B[0;32m 386\u001B[0m \u001B[38;5;28;01mif\u001B[39;00m \u001B[38;5;241m0\u001B[39m \u001B[38;5;241m<\u001B[39m endtime \u001B[38;5;241m<\u001B[39m time\u001B[38;5;241m.\u001B[39mmonotonic():\n\u001B[1;32m--> 387\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mException\u001B[39;00m(\u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mTimed out waiting for first frame.\u001B[39m\u001B[38;5;124m\"\u001B[39m)\n\u001B[0;32m 388\u001B[0m time\u001B[38;5;241m.\u001B[39msleep(check_interval)\n\u001B[0;32m 390\u001B[0m \u001B[38;5;28;01mreturn\u001B[39;00m \u001B[38;5;28mself\u001B[39m\u001B[38;5;241m.\u001B[39mfirst_frame\n", - "\u001B[1;31mException\u001B[0m: Timed out waiting for first frame." - ] + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:44.647191Z", + "start_time": "2024-10-11T11:03:44.611045Z" } - ], + }, "source": [ "from nanover.app import NanoverImdClient\n", - "client = NanoverImdClient.connect_to_single_server(port=nanover_server.port)\n", + "client = NanoverImdClient.connect_to_single_server(port=omni.app_server.port)\n", "client.subscribe_to_frames()\n", "client.wait_until_first_frame();" - ] + ], + "outputs": [], + "execution_count": 22 }, { "cell_type": "markdown", @@ -502,29 +585,39 @@ }, { "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:46.675877Z", + "start_time": "2024-10-11T11:03:46.488107Z" + } + }, "source": [ "import matplotlib.cm\n", "\n", "def get_matplotlib_gradient(name: str):\n", " cmap = matplotlib.colormaps[name]\n", " return list(list(cmap(x/7)) for x in range(0, 8, 1))" - ] + ], + "outputs": [], + "execution_count": 23 }, { "cell_type": "code", - "execution_count": 24, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:48.580877Z", + "start_time": "2024-10-11T11:03:48.086332Z" + } + }, "source": [ "from nanover.mdanalysis import frame_data_to_mdanalysis\n", "def generate_mdanalysis_selection(selection: str):\n", " universe = frame_data_to_mdanalysis(client.first_frame)\n", " idx_array = universe.select_atoms(selection).indices\n", " return map(int, idx_array)" - ] + ], + "outputs": [], + "execution_count": 24 }, { "cell_type": "markdown", @@ -535,15 +628,20 @@ }, { "cell_type": "code", - "execution_count": 25, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:50.261018Z", + "start_time": "2024-10-11T11:03:50.253941Z" + } + }, "source": [ "root_selection = client.root_selection\n", "with root_selection.modify():\n", " root_selection.hide = True\n", " root_selection.interaction_method = 'none'" - ] + ], + "outputs": [], + "execution_count": 25 }, { "cell_type": "markdown", @@ -554,22 +652,32 @@ }, { "cell_type": "code", - "execution_count": 26, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:53.226476Z", + "start_time": "2024-10-11T11:03:53.219531Z" + } + }, "source": [ "protein = client.create_selection(\"Protein\", [])" - ] + ], + "outputs": [], + "execution_count": 26 }, { "cell_type": "code", - "execution_count": 27, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:54.671539Z", + "start_time": "2024-10-11T11:03:54.630624Z" + } + }, "source": [ "with protein.modify():\n", " protein.set_particles(generate_mdanalysis_selection(\"protein and not type H\"))" - ] + ], + "outputs": [], + "execution_count": 27 }, { "cell_type": "markdown", @@ -584,9 +692,12 @@ }, { "cell_type": "code", - "execution_count": 28, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:56.755224Z", + "start_time": "2024-10-11T11:03:56.733137Z" + } + }, "source": [ "with protein.modify():\n", " protein.renderer = {\n", @@ -599,7 +710,9 @@ " 'scale': 0.2\n", " }\n", " protein.interaction_method = 'single'" - ] + ], + "outputs": [], + "execution_count": 28 }, { "cell_type": "markdown", @@ -610,21 +723,29 @@ }, { "cell_type": "code", - "execution_count": 29, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:58.254043Z", + "start_time": "2024-10-11T11:03:58.230434Z" + } + }, "source": [ "# Select ligand\n", "ligand = client.create_selection(\"Ligand\", [])\n", "with ligand.modify():\n", " ligand.set_particles(generate_mdanalysis_selection(\"resname OSE\"))" - ] + ], + "outputs": [], + "execution_count": 29 }, { "cell_type": "code", - "execution_count": 30, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:03:59.744295Z", + "start_time": "2024-10-11T11:03:59.735321Z" + } + }, "source": [ "with ligand.modify():\n", " ligand.renderer = {\n", @@ -634,7 +755,9 @@ " }\n", " ligand.velocity_reset = True\n", " ligand.interaction_method = 'group'" - ] + ], + "outputs": [], + "execution_count": 30 }, { "cell_type": "markdown", @@ -654,29 +777,23 @@ }, { "cell_type": "code", - "execution_count": 31, - "metadata": {}, - "outputs": [], + "metadata": { + "ExecuteTime": { + "end_time": "2024-10-11T11:04:14.060954Z", + "start_time": "2024-10-11T11:04:14.056779Z" + } + }, "source": [ - "client.close()" - ] - }, - { - "cell_type": "code", - "execution_count": 32, - "metadata": {}, + "client.close()\n", + "omni.close()" + ], "outputs": [], - "source": [ - "imd.close()\n", - "nanover_server.close()" - ] + "execution_count": 33 }, { "cell_type": "markdown", "metadata": {}, - "source": [ - "# Next Steps" - ] + "source": "# Next Steps" }, { "cell_type": "markdown", From d9da88d328eefc110d1147d359baf5b244bef5ca Mon Sep 17 00:00:00 2001 From: Harry Stroud Date: Fri, 11 Oct 2024 15:47:30 +0200 Subject: [PATCH 33/36] Change notebook to use correct functions, and add minor changes to notebook --- examples/ase/ase_basic_example.ipynb | 1478 +++++++++++++++----------- 1 file changed, 851 insertions(+), 627 deletions(-) diff --git a/examples/ase/ase_basic_example.ipynb b/examples/ase/ase_basic_example.ipynb index f5e3d552..9170dfbe 100644 --- a/examples/ase/ase_basic_example.ipynb +++ b/examples/ase/ase_basic_example.ipynb @@ -132,7 +132,7 @@ { "data": { "text/plain": [ - "-0.18180819310664376" + "-0.18180821639163902" ] }, "execution_count": 5, @@ -146,13 +146,13 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 6, "metadata": {}, "outputs": [], "source": [ "from nanover.omni.ase import ASESimulation\n", "\n", - "nanover_imd = ASESimulation.from_dynamics(dyn)" + "nanover_imd = ASESimulation.from_ase_dynamics(dyn)" ] }, { @@ -164,7 +164,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": 7, "metadata": { "pycharm": { "is_executing": false @@ -177,16 +177,37 @@ "11" ] }, - "execution_count": 11, + "execution_count": 7, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "nanover_imd.advance_to_next_report()\n", + "nanover_imd.dynamics.run(10)\n", "nanover_imd.dynamics.nsteps" ] }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "-0.18179475821364477" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Note that this is the energy in eV, not kJ mol-1 (the standard units of ASE are different to those of OpenMM and NanoVer)\n", + "nanover_imd.dynamics.atoms.get_potential_energy()" + ] + }, { "cell_type": "markdown", "metadata": {}, @@ -203,7 +224,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": 9, "metadata": { "pycharm": { "is_executing": false @@ -223,7 +244,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": 10, "metadata": { "pycharm": { "is_executing": false @@ -258,7 +279,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": 11, "metadata": { "pycharm": { "is_executing": false @@ -269,7 +290,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "ragzo: NanoVer iMD Server: Running at [::]:55943\n" + "harrystroud: NanoVer iMD Server: Running at [::]:59522\n" ] } ], @@ -293,7 +314,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": 12, "metadata": {}, "outputs": [], "source": [ @@ -302,7 +323,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": 13, "metadata": { "pycharm": { "is_executing": false @@ -313,7 +334,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Simulation time: 18.859573993851, (192 steps)\n" + "Simulation time: 1.2769503225003282, (13 steps)\n" ] } ], @@ -361,7 +382,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": 14, "metadata": { "pycharm": { "is_executing": false @@ -382,7 +403,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": 15, "metadata": {}, "outputs": [], "source": [ @@ -398,7 +419,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": 16, "metadata": { "pycharm": { "is_executing": false @@ -412,7 +433,34 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": 17, + "metadata": {}, + "outputs": [ + { + "ename": "MissingDataError", + "evalue": "'\\'No value with the key \"particle.count\".\\''", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", + "File \u001b[0;32m~/IRL/nanover-protocol/python-libraries/nanover-core/src/nanover/trajectory/frame_data.py:88\u001b[0m, in \u001b[0;36m_make_getter..wrapped\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 87\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 88\u001b[0m value \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mgetattr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshortcut\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrecord_type\u001b[49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[43mshortcut\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkey\u001b[49m\u001b[43m]\u001b[49m\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m error:\n", + "File \u001b[0;32m~/IRL/nanover-protocol/python-libraries/nanover-core/src/nanover/trajectory/frame_data.py:467\u001b[0m, in \u001b[0;36mRecordView.__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 466\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_convert_to_python(field)\n\u001b[0;32m--> 467\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mNo \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msingular\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m with the key \u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkey\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", + "\u001b[0;31mKeyError\u001b[0m: 'No value with the key \"particle.count\".'", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001b[0;31mMissingDataError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[17], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mframe\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparticle_count\u001b[49m\n", + "File \u001b[0;32m~/IRL/nanover-protocol/python-libraries/nanover-core/src/nanover/trajectory/frame_data.py:90\u001b[0m, in \u001b[0;36m_make_getter..wrapped\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 88\u001b[0m value \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mgetattr\u001b[39m(\u001b[38;5;28mself\u001b[39m, shortcut\u001b[38;5;241m.\u001b[39mrecord_type)[shortcut\u001b[38;5;241m.\u001b[39mkey]\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m error:\n\u001b[0;32m---> 90\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m MissingDataError(\u001b[38;5;28mstr\u001b[39m(error))\n\u001b[1;32m 91\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m shortcut\u001b[38;5;241m.\u001b[39mto_python(value)\n", + "\u001b[0;31mMissingDataError\u001b[0m: '\\'No value with the key \"particle.count\".\\''" + ] + } + ], + "source": [ + "frame.particle_count" + ] + }, + { + "cell_type": "code", + "execution_count": 18, "metadata": { "pycharm": { "is_executing": false @@ -422,16 +470,17 @@ { "data": { "text/plain": [ - "32" + "-17.533535971835082" ] }, - "execution_count": 22, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], "source": [ - "frame.particle_count # use TAB to see what's available!" + "# Print the potential energy, here in kJ mol-1 as we are accessing it via NanoVer\n", + "frame.potential_energy # use TAB to see what's available!" ] }, { @@ -443,7 +492,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": 19, "metadata": { "pycharm": { "is_executing": false @@ -457,37 +506,19 @@ "values {\n", " key: \"server.timestamp\"\n", " value {\n", - " number_value: 91197.171\n", - " }\n", - "}\n", - "values {\n", - " key: \"residue.count\"\n", - " value {\n", - " number_value: 1\n", - " }\n", - "}\n", - "values {\n", - " key: \"particle.count\"\n", - " value {\n", - " number_value: 32\n", + " number_value: 65362.763076708\n", " }\n", "}\n", "values {\n", " key: \"energy.potential\"\n", " value {\n", - " number_value: -17.531048553386476\n", + " number_value: -17.53193626520158\n", " }\n", "}\n", "values {\n", " key: \"energy.kinetic\"\n", " value {\n", - " number_value: 0.0095670517563931166\n", - " }\n", - "}\n", - "values {\n", - " key: \"chain.count\"\n", - " value {\n", - " number_value: 1\n", + " number_value: 0.010637719027177908\n", " }\n", "}\n", "arrays {\n", @@ -507,267 +538,111 @@ " }\n", "}\n", "arrays {\n", - " key: \"residue.names\"\n", - " value {\n", - " string_values {\n", - " values: \"ASE\"\n", - " }\n", - " }\n", - "}\n", - "arrays {\n", - " key: \"residue.ids\"\n", - " value {\n", - " string_values {\n", - " values: \"1\"\n", - " }\n", - " }\n", - "}\n", - "arrays {\n", - " key: \"residue.chains\"\n", - " value {\n", - " index_values {\n", - " values: 0\n", - " }\n", - " }\n", - "}\n", - "arrays {\n", - " key: \"particle.residues\"\n", - " value {\n", - " index_values {\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " values: 0\n", - " }\n", - " }\n", - "}\n", - "arrays {\n", " key: \"particle.positions\"\n", " value {\n", " float_values {\n", - " values: -2.57891206e-005\n", - " values: -2.0524134e-005\n", - " values: 8.89585863e-005\n", - " values: 0.180520535\n", - " values: 0.180497617\n", - " values: 4.96765351e-005\n", - " values: 0.180475205\n", - " values: 6.78303841e-005\n", - " values: 0.180522472\n", - " values: -2.4701294e-005\n", - " values: 0.180553824\n", - " values: 0.180488899\n", - " values: 0.361087948\n", - " values: -2.28799872e-005\n", - " values: -0.000158874725\n", - " values: 0.541501164\n", - " values: 0.180490583\n", - " values: 9.44005587e-005\n", - " values: 0.541436672\n", - " values: -8.53484235e-005\n", - " values: 0.180487275\n", - " values: 0.360923886\n", - " values: 0.180420578\n", - " values: 0.180435285\n", - " values: 1.48455629e-005\n", - " values: 0.360919446\n", - " values: 5.25337236e-005\n", - " values: 0.180496529\n", - " values: 0.541544259\n", - " values: 7.89733385e-005\n", - " values: 0.180510089\n", - " values: 0.3609716\n", - " values: 0.180563897\n", - " values: -7.14274393e-006\n", - " values: 0.541649461\n", - " values: 0.180537418\n", - " values: 0.360967368\n", - " values: 0.361063093\n", - " values: 3.95568441e-006\n", - " values: 0.541555643\n", - " values: 0.541472316\n", - " values: -6.97793439e-005\n", - " values: 0.541533411\n", - " values: 0.361041844\n", - " values: 0.180529654\n", - " values: 0.360885143\n", - " values: 0.541497111\n", - " values: 0.180487618\n", - " values: 1.28358652e-005\n", - " values: -5.65789305e-005\n", - " values: 0.360953867\n", - " values: 0.180560574\n", - " values: 0.180615798\n", - " values: 0.361081362\n", - " values: 0.18040663\n", - " values: -2.62168014e-005\n", - " values: 0.541526735\n", - " values: -5.80319902e-005\n", - " values: 0.180435121\n", - " values: 0.541554093\n", - " values: 0.360913038\n", - " values: 5.63940157e-005\n", - " values: 0.360977978\n", - " values: 0.54145503\n", - " values: 0.180398583\n", - " values: 0.360798508\n", - " values: 0.541579366\n", - " values: -1.15873063e-005\n", - " values: 0.541453958\n", - " values: 0.360971063\n", - " values: 0.180490524\n", - " values: 0.541446686\n", - " values: 1.85172412e-005\n", - " values: 0.360958368\n", - " values: 0.360977501\n", - " values: 0.180577591\n", - " values: 0.541521072\n", - " values: 0.361136883\n", - " values: 0.180443242\n", - " values: 0.360989183\n", - " values: 0.541458547\n", - " values: 0.000127856576\n", - " values: 0.54152447\n", - " values: 0.541487\n", - " values: 0.361068428\n", - " values: 0.361038029\n", - " values: 0.360974282\n", - " values: 0.541438937\n", - " values: 0.541541874\n", - " values: 0.361018956\n", - " values: 0.54158926\n", - " values: 0.36091733\n", - " values: 0.541396856\n", - " values: 0.361016721\n", - " values: 0.541506529\n", - " values: 0.541540623\n", - " }\n", - " }\n", - "}\n", - "arrays {\n", - " key: \"particle.names\"\n", - " value {\n", - " string_values {\n", - " values: \"0\"\n", - " values: \"1\"\n", - " values: \"2\"\n", - " values: \"3\"\n", - " values: \"4\"\n", - " values: \"5\"\n", - " values: \"6\"\n", - " values: \"7\"\n", - " values: \"8\"\n", - " values: \"9\"\n", - " values: \"10\"\n", - " values: \"11\"\n", - " values: \"12\"\n", - " values: \"13\"\n", - " values: \"14\"\n", - " values: \"15\"\n", - " values: \"16\"\n", - " values: \"17\"\n", - " values: \"18\"\n", - " values: \"19\"\n", - " values: \"20\"\n", - " values: \"21\"\n", - " values: \"22\"\n", - " values: \"23\"\n", - " values: \"24\"\n", - " values: \"25\"\n", - " values: \"26\"\n", - " values: \"27\"\n", - " values: \"28\"\n", - " values: \"29\"\n", - " values: \"30\"\n", - " values: \"31\"\n", - " }\n", - " }\n", - "}\n", - "arrays {\n", - " key: \"particle.elements\"\n", - " value {\n", - " index_values {\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " values: 29\n", - " }\n", - " }\n", - "}\n", - "arrays {\n", - " key: \"chain.names\"\n", - " value {\n", - " string_values {\n", - " values: \"A\"\n", - " }\n", - " }\n", - "}\n", - "arrays {\n", - " key: \"bond.pairs\"\n", - " value {\n", - " index_values {\n", + " values: 4.66322599e-05\n", + " values: -1.54206082e-05\n", + " values: -4.11602268e-05\n", + " values: 0.180452704\n", + " values: 0.180625215\n", + " values: -7.51803509e-06\n", + " values: 0.180429354\n", + " values: 1.40723705e-05\n", + " values: 0.180513784\n", + " values: 1.56591759e-05\n", + " values: 0.180587754\n", + " values: 0.18056719\n", + " values: 0.360936195\n", + " values: 5.33200873e-05\n", + " values: 7.40820469e-05\n", + " values: 0.541458189\n", + " values: 0.180477798\n", + " values: 8.6451706e-05\n", + " values: 0.541640222\n", + " values: -1.10521751e-05\n", + " values: 0.180465683\n", + " values: 0.361125082\n", + " values: 0.180563465\n", + " values: 0.180500045\n", + " values: -7.13305781e-05\n", + " values: 0.361000061\n", + " values: 6.72447932e-05\n", + " values: 0.180520281\n", + " values: 0.541463733\n", + " values: 3.83991537e-05\n", + " values: 0.180571958\n", + " values: 0.360893935\n", + " values: 0.180417344\n", + " values: 1.52346856e-05\n", + " values: 0.541406631\n", + " values: 0.180498779\n", + " values: 0.361025244\n", + " values: 0.361103505\n", + " values: 1.31766524e-06\n", + " values: 0.541434288\n", + " values: 0.541539133\n", + " values: 4.06882718e-05\n", + " values: 0.54154861\n", + " values: 0.360994518\n", + " values: 0.180495068\n", + " values: 0.360880345\n", + " values: 0.541523\n", + " values: 0.180486187\n", + " values: 5.72355239e-05\n", + " values: -6.74093535e-05\n", + " values: 0.3609896\n", + " values: 0.180595845\n", + " values: 0.180479705\n", + " values: 0.360977054\n", + " values: 0.180555701\n", + " values: -8.23238515e-05\n", + " values: 0.541480422\n", + " values: -1.11158352e-05\n", + " values: 0.18041645\n", + " values: 0.541434586\n", + " values: 0.360896975\n", + " values: 4.793568e-07\n", + " values: 0.360957742\n", + " values: 0.541380763\n", + " values: 0.180369288\n", + " values: 0.361004353\n", + " values: 0.541503668\n", + " values: -1.23347381e-05\n", + " values: 0.5415712\n", + " values: 0.360947132\n", + " values: 0.180602387\n", + " values: 0.541529059\n", + " values: -3.41255072e-05\n", + " values: 0.3609972\n", + " values: 0.360951662\n", + " values: 0.180520937\n", + " values: 0.541406\n", + " values: 0.360887378\n", + " values: 0.180498406\n", + " values: 0.36106509\n", + " values: 0.541447401\n", + " values: -7.27466831e-05\n", + " values: 0.541444659\n", + " values: 0.54149729\n", + " values: 0.360979736\n", + " values: 0.361053228\n", + " values: 0.361077905\n", + " values: 0.541441202\n", + " values: 0.541528761\n", + " values: 0.360949188\n", + " values: 0.541601717\n", + " values: 0.361002713\n", + " values: 0.541436553\n", + " values: 0.361086965\n", + " values: 0.54153043\n", + " values: 0.541564047\n", " }\n", " }\n", "}" ] }, - "execution_count": 23, + "execution_count": 19, "metadata": {}, "output_type": "execute_result" } @@ -786,7 +661,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": 20, "metadata": { "pycharm": { "is_executing": false @@ -807,7 +682,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": 21, "metadata": { "pycharm": { "is_executing": false @@ -829,7 +704,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": 22, "metadata": { "pycharm": { "is_executing": false @@ -839,10 +714,10 @@ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 26, + "execution_count": 22, "metadata": {}, "output_type": "execute_result" } @@ -861,7 +736,7 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": 23, "metadata": { "pycharm": { "is_executing": false @@ -872,328 +747,677 @@ "data": { "text/html": [ "\n", - " \n", - " ASE atomic visualization\n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - " \n", - "\n", - "\n", - "\n", - " \n", - " \n", + "\n", + " \n", + "\n", + " ASE atomic visualization\n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", + " \n", + "\n", "\n", "\n" ], @@ -1201,7 +1425,7 @@ "" ] }, - "execution_count": 27, + "execution_count": 23, "metadata": {}, "output_type": "execute_result" } @@ -1226,7 +1450,7 @@ }, { "cell_type": "code", - "execution_count": 28, + "execution_count": 24, "metadata": { "pycharm": { "is_executing": false @@ -1250,7 +1474,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": 25, "metadata": { "pycharm": { "is_executing": false @@ -1258,7 +1482,7 @@ }, "outputs": [], "source": [ - "with OmniRunner.with_basic_server(ASESimulation.from_dynamics(dyn), port=0) as runner:\n", + "with OmniRunner.with_basic_server(ASESimulation.from_ase_dynamics(dyn), port=0) as runner:\n", " runner.next()" ] }, From 8c2e157c7f2a744753270a1f7b80867d58a35636 Mon Sep 17 00:00:00 2001 From: Harry Stroud Date: Fri, 11 Oct 2024 15:49:50 +0200 Subject: [PATCH 34/36] Change position of comment --- examples/ase/ase_basic_example.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/ase/ase_basic_example.ipynb b/examples/ase/ase_basic_example.ipynb index 9170dfbe..0dbb9aea 100644 --- a/examples/ase/ase_basic_example.ipynb +++ b/examples/ase/ase_basic_example.ipynb @@ -141,6 +141,7 @@ } ], "source": [ + "# Note that this is the energy in eV, not kJ mol-1 (the standard units of ASE are different to those of OpenMM and NanoVer)\n", "dyn.atoms.get_potential_energy()" ] }, @@ -204,7 +205,6 @@ } ], "source": [ - "# Note that this is the energy in eV, not kJ mol-1 (the standard units of ASE are different to those of OpenMM and NanoVer)\n", "nanover_imd.dynamics.atoms.get_potential_energy()" ] }, From b0b793d07296931d6056241abb235dd3ff94c241 Mon Sep 17 00:00:00 2001 From: Harry Stroud Date: Fri, 11 Oct 2024 15:54:56 +0200 Subject: [PATCH 35/36] Change units of temp from kT to Kelvin --- examples/ase/ase_openmm_neuraminidase.ipynb | 248 ++++++++++---------- 1 file changed, 122 insertions(+), 126 deletions(-) diff --git a/examples/ase/ase_openmm_neuraminidase.ipynb b/examples/ase/ase_openmm_neuraminidase.ipynb index 2d42d32f..f26ad9b7 100644 --- a/examples/ase/ase_openmm_neuraminidase.ipynb +++ b/examples/ase/ase_openmm_neuraminidase.ipynb @@ -50,34 +50,34 @@ }, { "cell_type": "code", + "execution_count": 1, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:02:37.212605Z", "start_time": "2024-10-11T11:02:36.898363Z" } }, + "outputs": [], "source": [ "import openmm as mm\n", "import openmm.unit as unit \n", "import openmm.app as app" - ], - "outputs": [], - "execution_count": 1 + ] }, { "cell_type": "code", + "execution_count": 2, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:02:37.999054Z", "start_time": "2024-10-11T11:02:37.749626Z" } }, + "outputs": [], "source": [ "prmtop = app.AmberPrmtopFile(\"openmm_files/3TI6_ose_wt.top\")\n", "amber_coords = app.AmberInpcrdFile(\"openmm_files/3TI6_ose_wt.rst\")" - ], - "outputs": [], - "execution_count": 2 + ] }, { "cell_type": "markdown", @@ -109,46 +109,46 @@ }, { "cell_type": "code", + "execution_count": 3, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:02:39.650723Z", "start_time": "2024-10-11T11:02:39.461710Z" } }, - "source": [ - "system = prmtop.createSystem(nonbondedMethod=app.CutoffPeriodic, \n", - " nonbondedCutoff=2*unit.nanometer, \n", - " implicitSolvent=app.OBC2,\n", - " constraints=None)" - ], "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ - "C:\\Users\\ragzo\\anaconda3\\envs\\nanover-dev\\Lib\\site-packages\\openmm\\app\\internal\\amber_file_parser.py:1168: UserWarning: Non-optimal GB parameters detected for GB model OBC2\n", + "/opt/homebrew/Caskroom/miniforge/base/envs/nanover-dev/lib/python3.12/site-packages/openmm/app/internal/amber_file_parser.py:1168: UserWarning: Non-optimal GB parameters detected for GB model OBC2\n", " warnings.warn(\n" ] } ], - "execution_count": 3 + "source": [ + "system = prmtop.createSystem(nonbondedMethod=app.CutoffPeriodic, \n", + " nonbondedCutoff=2*unit.nanometer, \n", + " implicitSolvent=app.OBC2,\n", + " constraints=None)" + ] }, { "cell_type": "code", + "execution_count": 4, "metadata": { - "pycharm": { - "is_executing": true - }, "ExecuteTime": { "end_time": "2024-10-11T11:02:42.514705Z", "start_time": "2024-10-11T11:02:42.510481Z" + }, + "pycharm": { + "is_executing": true } }, + "outputs": [], "source": [ "integrator = mm.LangevinIntegrator(300*unit.kelvin, 1/unit.picosecond, 0.001*unit.picoseconds)" - ], - "outputs": [], - "execution_count": 4 + ] }, { "cell_type": "markdown", @@ -159,33 +159,33 @@ }, { "cell_type": "code", + "execution_count": 5, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:02:44.327171Z", "start_time": "2024-10-11T11:02:44.225632Z" } }, + "outputs": [], "source": [ "simulation = app.Simulation(prmtop.topology, system, integrator)" - ], - "outputs": [], - "execution_count": 5 + ] }, { "cell_type": "code", + "execution_count": 6, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:02:45.946111Z", "start_time": "2024-10-11T11:02:45.929227Z" } }, + "outputs": [], "source": [ "simulation.context.setPositions(amber_coords.positions)\n", "if amber_coords.boxVectors is not None:\n", " simulation.context.setPeriodicBoxVectors(*amber_coords.boxVectors)" - ], - "outputs": [], - "execution_count": 6 + ] }, { "cell_type": "markdown", @@ -196,17 +196,17 @@ }, { "cell_type": "code", + "execution_count": 7, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:02:48.726771Z", "start_time": "2024-10-11T11:02:47.571332Z" } }, + "outputs": [], "source": [ "simulation.minimizeEnergy()" - ], - "outputs": [], - "execution_count": 7 + ] }, { "cell_type": "markdown", @@ -217,65 +217,65 @@ }, { "cell_type": "code", + "execution_count": 8, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:02:49.802180Z", "start_time": "2024-10-11T11:02:49.779330Z" } }, + "outputs": [], "source": [ "simulation.context.setVelocitiesToTemperature(300 * unit.kelvin)" - ], - "outputs": [], - "execution_count": 8 + ] }, { "cell_type": "code", + "execution_count": 9, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:02:51.579581Z", "start_time": "2024-10-11T11:02:51.576491Z" } }, + "outputs": [], "source": [ "import sys" - ], - "outputs": [], - "execution_count": 9 + ] }, { "cell_type": "code", + "execution_count": 10, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:02:58.583405Z", "start_time": "2024-10-11T11:02:52.972305Z" } }, - "source": [ - "simulation.reporters.append(app.StateDataReporter(sys.stdout, 100, step=True,\n", - " potentialEnergy=True, temperature=True))\n", - "simulation.step(1000)" - ], "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "#\"Step\",\"Potential Energy (kJ/mole)\",\"Temperature (K)\"\n", - "100,-39543.773704749576,171.94629506417792\n", - "200,-37456.68643973493,172.30788716141828\n", - "300,-36960.350029212466,185.9325771671761\n", - "400,-36279.01056693219,197.09489585675647\n", - "500,-35987.88951895856,211.20127489471548\n", - "600,-35227.428032142154,219.9709517508048\n", - "700,-34626.85153983258,225.99942530207284\n", - "800,-34018.469032508365,231.04540015999513\n", - "900,-33447.22238944196,238.21879439965178\n", - "1000,-33096.13106558942,244.96548097108987\n" + "100,-39686.99454520368,171.15355646771883\n", + "200,-37969.39191458844,174.47405302152586\n", + "300,-36926.46134207868,185.81969663776286\n", + "400,-36312.37470267438,197.06870343518318\n", + "500,-35988.50852225446,211.3250616837355\n", + "600,-35148.14240286969,216.96937436728012\n", + "700,-34459.43003104352,223.55437355836068\n", + "800,-34169.05051444196,232.81622289859095\n", + "900,-33392.66649649762,234.1818586856779\n", + "1000,-33060.31974051618,244.3846325582557\n" ] } ], - "execution_count": 10 + "source": [ + "simulation.reporters.append(app.StateDataReporter(sys.stdout, 100, step=True,\n", + " potentialEnergy=True, temperature=True))\n", + "simulation.step(1000)" + ] }, { "cell_type": "markdown", @@ -297,20 +297,20 @@ }, { "cell_type": "code", + "execution_count": 11, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:04.176799Z", "start_time": "2024-10-11T11:03:01.073873Z" } }, + "outputs": [], "source": [ "from nanover.openmm.serializer import serialize_simulation\n", "\n", "with open('neuraminidase_nanover.xml','w') as f:\n", " f.write(serialize_simulation(simulation))" - ], - "outputs": [], - "execution_count": 11 + ] }, { "cell_type": "markdown", @@ -356,54 +356,42 @@ }, { "cell_type": "code", + "execution_count": 12, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:08.198123Z", "start_time": "2024-10-11T11:03:07.931047Z" } }, + "outputs": [], "source": [ "from nanover.ase.openmm import OpenMMCalculator" - ], - "outputs": [], - "execution_count": 12 + ] }, { "cell_type": "code", + "execution_count": 13, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:10.021005Z", "start_time": "2024-10-11T11:03:10.017521Z" } }, + "outputs": [], "source": [ "calculator = OpenMMCalculator(simulation)" - ], - "outputs": [], - "execution_count": 13 + ] }, { "cell_type": "code", + "execution_count": 14, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:11.841719Z", "start_time": "2024-10-11T11:03:11.574654Z" } }, - "source": [ - "atoms = calculator.generate_atoms()\n", - "atoms.set_calculator(calculator)\n", - "len(atoms)" - ], "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - "C:\\Users\\ragzo\\AppData\\Local\\Temp\\ipykernel_10760\\2943926735.py:2: DeprecationWarning: Please use atoms.calc = calc\n", - " atoms.set_calculator(calculator)\n" - ] - }, { "data": { "text/plain": [ @@ -415,7 +403,11 @@ "output_type": "execute_result" } ], - "execution_count": 14 + "source": [ + "atoms = calculator.generate_atoms()\n", + "atoms.set_calculator(calculator)\n", + "len(atoms)" + ] }, { "cell_type": "markdown", @@ -427,53 +419,53 @@ }, { "cell_type": "code", + "execution_count": 15, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:13.895040Z", "start_time": "2024-10-11T11:03:13.889625Z" } }, + "outputs": [], "source": [ "from ase.md import Langevin\n", "import ase.units as ase_units\n", - "dynamics = Langevin(atoms, timestep=1.0 * ase_units.fs, temperature_K=300 * ase_units.kB, friction=1.0e-03)" - ], - "outputs": [], - "execution_count": 15 + "dynamics = Langevin(atoms, timestep=1.0 * ase_units.fs, temperature_K=300, friction=1.0e-03)" + ] }, { "cell_type": "code", + "execution_count": 16, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:19.899207Z", "start_time": "2024-10-11T11:03:19.894562Z" } }, + "outputs": [], "source": [ "from nanover.ase.openmm.frame_adaptor import openmm_ase_atoms_to_frame_data\n", "from nanover.omni import OmniRunner\n", "from nanover.omni.ase import ASESimulation" - ], - "outputs": [], - "execution_count": 17 + ] }, { "cell_type": "code", + "execution_count": 17, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:21.800989Z", "start_time": "2024-10-11T11:03:21.762441Z" } }, + "outputs": [], "source": [ "omni_sim = ASESimulation.from_ase_dynamics(\n", " dynamics, \n", " ase_atoms_to_frame_data=openmm_ase_atoms_to_frame_data,\n", ")\n", "omni = OmniRunner.with_basic_server(omni_sim)" - ], - "outputs": [], - "execution_count": 18 + ] }, { "cell_type": "markdown", @@ -484,29 +476,29 @@ }, { "cell_type": "code", + "execution_count": 18, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:25.543985Z", "start_time": "2024-10-11T11:03:24.067230Z" } }, - "source": [ - "omni_sim.dynamics.run(100)\n", - "omni_sim.atoms.get_potential_energy()" - ], "outputs": [ { "data": { "text/plain": [ - "-432.65624999030933" + "-431.0731347117381" ] }, - "execution_count": 19, + "execution_count": 18, "metadata": {}, "output_type": "execute_result" } ], - "execution_count": 19 + "source": [ + "omni_sim.dynamics.run(100)\n", + "omni_sim.atoms.get_potential_energy()" + ] }, { "cell_type": "markdown", @@ -517,17 +509,17 @@ }, { "cell_type": "code", + "execution_count": 19, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:27.561636Z", "start_time": "2024-10-11T11:03:27.550961Z" } }, + "outputs": [], "source": [ "omni.next()" - ], - "outputs": [], - "execution_count": 20 + ] }, { "cell_type": "markdown", @@ -561,20 +553,20 @@ }, { "cell_type": "code", + "execution_count": 20, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:44.647191Z", "start_time": "2024-10-11T11:03:44.611045Z" } }, + "outputs": [], "source": [ "from nanover.app import NanoverImdClient\n", "client = NanoverImdClient.connect_to_single_server(port=omni.app_server.port)\n", "client.subscribe_to_frames()\n", "client.wait_until_first_frame();" - ], - "outputs": [], - "execution_count": 22 + ] }, { "cell_type": "markdown", @@ -585,39 +577,39 @@ }, { "cell_type": "code", + "execution_count": 21, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:46.675877Z", "start_time": "2024-10-11T11:03:46.488107Z" } }, + "outputs": [], "source": [ "import matplotlib.cm\n", "\n", "def get_matplotlib_gradient(name: str):\n", " cmap = matplotlib.colormaps[name]\n", " return list(list(cmap(x/7)) for x in range(0, 8, 1))" - ], - "outputs": [], - "execution_count": 23 + ] }, { "cell_type": "code", + "execution_count": 22, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:48.580877Z", "start_time": "2024-10-11T11:03:48.086332Z" } }, + "outputs": [], "source": [ "from nanover.mdanalysis import frame_data_to_mdanalysis\n", "def generate_mdanalysis_selection(selection: str):\n", " universe = frame_data_to_mdanalysis(client.first_frame)\n", " idx_array = universe.select_atoms(selection).indices\n", " return map(int, idx_array)" - ], - "outputs": [], - "execution_count": 24 + ] }, { "cell_type": "markdown", @@ -628,20 +620,20 @@ }, { "cell_type": "code", + "execution_count": 23, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:50.261018Z", "start_time": "2024-10-11T11:03:50.253941Z" } }, + "outputs": [], "source": [ "root_selection = client.root_selection\n", "with root_selection.modify():\n", " root_selection.hide = True\n", " root_selection.interaction_method = 'none'" - ], - "outputs": [], - "execution_count": 25 + ] }, { "cell_type": "markdown", @@ -652,32 +644,32 @@ }, { "cell_type": "code", + "execution_count": 24, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:53.226476Z", "start_time": "2024-10-11T11:03:53.219531Z" } }, + "outputs": [], "source": [ "protein = client.create_selection(\"Protein\", [])" - ], - "outputs": [], - "execution_count": 26 + ] }, { "cell_type": "code", + "execution_count": 25, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:54.671539Z", "start_time": "2024-10-11T11:03:54.630624Z" } }, + "outputs": [], "source": [ "with protein.modify():\n", " protein.set_particles(generate_mdanalysis_selection(\"protein and not type H\"))" - ], - "outputs": [], - "execution_count": 27 + ] }, { "cell_type": "markdown", @@ -692,12 +684,14 @@ }, { "cell_type": "code", + "execution_count": 26, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:56.755224Z", "start_time": "2024-10-11T11:03:56.733137Z" } }, + "outputs": [], "source": [ "with protein.modify():\n", " protein.renderer = {\n", @@ -710,9 +704,7 @@ " 'scale': 0.2\n", " }\n", " protein.interaction_method = 'single'" - ], - "outputs": [], - "execution_count": 28 + ] }, { "cell_type": "markdown", @@ -723,29 +715,31 @@ }, { "cell_type": "code", + "execution_count": 27, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:58.254043Z", "start_time": "2024-10-11T11:03:58.230434Z" } }, + "outputs": [], "source": [ "# Select ligand\n", "ligand = client.create_selection(\"Ligand\", [])\n", "with ligand.modify():\n", " ligand.set_particles(generate_mdanalysis_selection(\"resname OSE\"))" - ], - "outputs": [], - "execution_count": 29 + ] }, { "cell_type": "code", + "execution_count": 28, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:03:59.744295Z", "start_time": "2024-10-11T11:03:59.735321Z" } }, + "outputs": [], "source": [ "with ligand.modify():\n", " ligand.renderer = {\n", @@ -755,9 +749,7 @@ " }\n", " ligand.velocity_reset = True\n", " ligand.interaction_method = 'group'" - ], - "outputs": [], - "execution_count": 30 + ] }, { "cell_type": "markdown", @@ -777,28 +769,32 @@ }, { "cell_type": "code", + "execution_count": 29, "metadata": { "ExecuteTime": { "end_time": "2024-10-11T11:04:14.060954Z", "start_time": "2024-10-11T11:04:14.056779Z" } }, + "outputs": [], "source": [ "client.close()\n", "omni.close()" - ], - "outputs": [], - "execution_count": 33 + ] }, { "cell_type": "markdown", "metadata": {}, - "source": "# Next Steps" + "source": [ + "# Next Steps" + ] }, { "cell_type": "markdown", "metadata": {}, - "source": "* Set up an OpenMM simulation of [graphene](./ase_openmm_graphene.ipynb) with restraints and add UI and custom commands in the notebook " + "source": [ + "* Set up an OpenMM simulation of [graphene](./ase_openmm_graphene.ipynb) with restraints and add UI and custom commands in the notebook " + ] }, { "cell_type": "code", From d9b88545448847fe5121a683d2ce8c13e95c5604 Mon Sep 17 00:00:00 2001 From: Harry Stroud Date: Fri, 11 Oct 2024 17:55:39 +0200 Subject: [PATCH 36/36] Change `latest_frame` to `current_frame` --- examples/ase/ase_basic_example.ipynb | 461 ++++++++++++++++++--------- 1 file changed, 317 insertions(+), 144 deletions(-) diff --git a/examples/ase/ase_basic_example.ipynb b/examples/ase/ase_basic_example.ipynb index 0dbb9aea..25d7f94f 100644 --- a/examples/ase/ase_basic_example.ipynb +++ b/examples/ase/ase_basic_example.ipynb @@ -132,7 +132,7 @@ { "data": { "text/plain": [ - "-0.18180821639163902" + "-0.18180823716253158" ] }, "execution_count": 5, @@ -196,7 +196,7 @@ { "data": { "text/plain": [ - "-0.18179475821364477" + "-0.18179726385287687" ] }, "execution_count": 8, @@ -290,7 +290,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "harrystroud: NanoVer iMD Server: Running at [::]:59522\n" + "harrystroud: NanoVer iMD Server: Running at [::]:63903\n" ] } ], @@ -334,7 +334,7 @@ "name": "stdout", "output_type": "stream", "text": [ - "Simulation time: 1.2769503225003282, (13 steps)\n" + "Simulation time: 1.7680850619235313, (18 steps)\n" ] } ], @@ -428,7 +428,7 @@ "outputs": [], "source": [ "client.wait_until_first_frame()\n", - "frame = client.latest_frame" + "frame = client.current_frame" ] }, { @@ -437,21 +437,14 @@ "metadata": {}, "outputs": [ { - "ename": "MissingDataError", - "evalue": "'\\'No value with the key \"particle.count\".\\''", - "output_type": "error", - "traceback": [ - "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", - "\u001b[0;31mKeyError\u001b[0m Traceback (most recent call last)", - "File \u001b[0;32m~/IRL/nanover-protocol/python-libraries/nanover-core/src/nanover/trajectory/frame_data.py:88\u001b[0m, in \u001b[0;36m_make_getter..wrapped\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 87\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m---> 88\u001b[0m value \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mgetattr\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mshortcut\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrecord_type\u001b[49m\u001b[43m)\u001b[49m\u001b[43m[\u001b[49m\u001b[43mshortcut\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mkey\u001b[49m\u001b[43m]\u001b[49m\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m error:\n", - "File \u001b[0;32m~/IRL/nanover-protocol/python-libraries/nanover-core/src/nanover/trajectory/frame_data.py:467\u001b[0m, in \u001b[0;36mRecordView.__getitem__\u001b[0;34m(self, key)\u001b[0m\n\u001b[1;32m 466\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_convert_to_python(field)\n\u001b[0;32m--> 467\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m'\u001b[39m\u001b[38;5;124mNo \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39msingular\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m with the key \u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;132;01m{\u001b[39;00mkey\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124m.\u001b[39m\u001b[38;5;124m'\u001b[39m)\n", - "\u001b[0;31mKeyError\u001b[0m: 'No value with the key \"particle.count\".'", - "\nDuring handling of the above exception, another exception occurred:\n", - "\u001b[0;31mMissingDataError\u001b[0m Traceback (most recent call last)", - "Cell \u001b[0;32mIn[17], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m \u001b[43mframe\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mparticle_count\u001b[49m\n", - "File \u001b[0;32m~/IRL/nanover-protocol/python-libraries/nanover-core/src/nanover/trajectory/frame_data.py:90\u001b[0m, in \u001b[0;36m_make_getter..wrapped\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 88\u001b[0m value \u001b[38;5;241m=\u001b[39m \u001b[38;5;28mgetattr\u001b[39m(\u001b[38;5;28mself\u001b[39m, shortcut\u001b[38;5;241m.\u001b[39mrecord_type)[shortcut\u001b[38;5;241m.\u001b[39mkey]\n\u001b[1;32m 89\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mKeyError\u001b[39;00m \u001b[38;5;28;01mas\u001b[39;00m error:\n\u001b[0;32m---> 90\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m MissingDataError(\u001b[38;5;28mstr\u001b[39m(error))\n\u001b[1;32m 91\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m shortcut\u001b[38;5;241m.\u001b[39mto_python(value)\n", - "\u001b[0;31mMissingDataError\u001b[0m: '\\'No value with the key \"particle.count\".\\''" - ] + "data": { + "text/plain": [ + "32" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" } ], "source": [ @@ -470,7 +463,7 @@ { "data": { "text/plain": [ - "-17.533535971835082" + "-17.533980241570806" ] }, "execution_count": 18, @@ -503,22 +496,46 @@ { "data": { "text/plain": [ + "values {\n", + " key: \"system.simulation.counter\"\n", + " value {\n", + " number_value: 0\n", + " }\n", + "}\n", "values {\n", " key: \"server.timestamp\"\n", " value {\n", - " number_value: 65362.763076708\n", + " number_value: 71745.708391166\n", + " }\n", + "}\n", + "values {\n", + " key: \"residue.count\"\n", + " value {\n", + " number_value: 1\n", + " }\n", + "}\n", + "values {\n", + " key: \"particle.count\"\n", + " value {\n", + " number_value: 32\n", " }\n", "}\n", "values {\n", " key: \"energy.potential\"\n", " value {\n", - " number_value: -17.53193626520158\n", + " number_value: -17.532057455938844\n", " }\n", "}\n", "values {\n", " key: \"energy.kinetic\"\n", " value {\n", - " number_value: 0.010637719027177908\n", + " number_value: 0.010858480390873912\n", + " }\n", + "}\n", + "values {\n", + " key: \"chain.count\"\n", + " value {\n", + " number_value: 1\n", " }\n", "}\n", "arrays {\n", @@ -538,105 +555,261 @@ " }\n", "}\n", "arrays {\n", + " key: \"residue.names\"\n", + " value {\n", + " string_values {\n", + " values: \"ASE\"\n", + " }\n", + " }\n", + "}\n", + "arrays {\n", + " key: \"residue.ids\"\n", + " value {\n", + " string_values {\n", + " values: \"1\"\n", + " }\n", + " }\n", + "}\n", + "arrays {\n", + " key: \"residue.chains\"\n", + " value {\n", + " index_values {\n", + " values: 0\n", + " }\n", + " }\n", + "}\n", + "arrays {\n", + " key: \"particle.residues\"\n", + " value {\n", + " index_values {\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " values: 0\n", + " }\n", + " }\n", + "}\n", + "arrays {\n", " key: \"particle.positions\"\n", " value {\n", " float_values {\n", - " values: 4.66322599e-05\n", - " values: -1.54206082e-05\n", - " values: -4.11602268e-05\n", - " values: 0.180452704\n", - " values: 0.180625215\n", - " values: -7.51803509e-06\n", - " values: 0.180429354\n", - " values: 1.40723705e-05\n", - " values: 0.180513784\n", - " values: 1.56591759e-05\n", - " values: 0.180587754\n", - " values: 0.18056719\n", - " values: 0.360936195\n", - " values: 5.33200873e-05\n", - " values: 7.40820469e-05\n", - " values: 0.541458189\n", - " values: 0.180477798\n", - " values: 8.6451706e-05\n", - " values: 0.541640222\n", - " values: -1.10521751e-05\n", - " values: 0.180465683\n", - " values: 0.361125082\n", - " values: 0.180563465\n", - " values: 0.180500045\n", - " values: -7.13305781e-05\n", - " values: 0.361000061\n", - " values: 6.72447932e-05\n", - " values: 0.180520281\n", - " values: 0.541463733\n", - " values: 3.83991537e-05\n", - " values: 0.180571958\n", - " values: 0.360893935\n", - " values: 0.180417344\n", - " values: 1.52346856e-05\n", - " values: 0.541406631\n", - " values: 0.180498779\n", - " values: 0.361025244\n", - " values: 0.361103505\n", - " values: 1.31766524e-06\n", - " values: 0.541434288\n", - " values: 0.541539133\n", - " values: 4.06882718e-05\n", - " values: 0.54154861\n", - " values: 0.360994518\n", - " values: 0.180495068\n", - " values: 0.360880345\n", - " values: 0.541523\n", - " values: 0.180486187\n", - " values: 5.72355239e-05\n", - " values: -6.74093535e-05\n", - " values: 0.3609896\n", - " values: 0.180595845\n", - " values: 0.180479705\n", - " values: 0.360977054\n", - " values: 0.180555701\n", - " values: -8.23238515e-05\n", - " values: 0.541480422\n", - " values: -1.11158352e-05\n", - " values: 0.18041645\n", - " values: 0.541434586\n", - " values: 0.360896975\n", - " values: 4.793568e-07\n", - " values: 0.360957742\n", - " values: 0.541380763\n", - " values: 0.180369288\n", - " values: 0.361004353\n", - " values: 0.541503668\n", - " values: -1.23347381e-05\n", - " values: 0.5415712\n", - " values: 0.360947132\n", - " values: 0.180602387\n", - " values: 0.541529059\n", - " values: -3.41255072e-05\n", - " values: 0.3609972\n", - " values: 0.360951662\n", - " values: 0.180520937\n", - " values: 0.541406\n", - " values: 0.360887378\n", - " values: 0.180498406\n", - " values: 0.36106509\n", - " values: 0.541447401\n", - " values: -7.27466831e-05\n", - " values: 0.541444659\n", - " values: 0.54149729\n", - " values: 0.360979736\n", - " values: 0.361053228\n", - " values: 0.361077905\n", - " values: 0.541441202\n", - " values: 0.541528761\n", - " values: 0.360949188\n", - " values: 0.541601717\n", - " values: 0.361002713\n", - " values: 0.541436553\n", - " values: 0.361086965\n", - " values: 0.54153043\n", - " values: 0.541564047\n", + " values: -8.08861296e-05\n", + " values: -7.04341028e-06\n", + " values: 3.44130422e-05\n", + " values: 0.18042554\n", + " values: 0.180388376\n", + " values: -5.42464331e-05\n", + " values: 0.180535182\n", + " values: 4.58165741e-05\n", + " values: 0.180564299\n", + " values: 6.37728881e-05\n", + " values: 0.180476949\n", + " values: 0.180508599\n", + " values: 0.361018121\n", + " values: 2.66284333e-05\n", + " values: -6.3303989e-05\n", + " values: 0.541461766\n", + " values: 0.180484831\n", + " values: 4.9048318e-05\n", + " values: 0.541466117\n", + " values: -3.439801e-05\n", + " values: 0.180518121\n", + " values: 0.360976517\n", + " values: 0.180539131\n", + " values: 0.180530474\n", + " values: 4.32907509e-05\n", + " values: 0.360934794\n", + " values: -9.07003196e-05\n", + " values: 0.180561259\n", + " values: 0.541539\n", + " values: 1.6454569e-05\n", + " values: 0.180554852\n", + " values: 0.361037016\n", + " values: 0.180560142\n", + " values: -5.34986866e-05\n", + " values: 0.541486084\n", + " values: 0.180490911\n", + " values: 0.36085\n", + " values: 0.361027539\n", + " values: 2.54441748e-05\n", + " values: 0.541395843\n", + " values: 0.541514218\n", + " values: 8.32559e-05\n", + " values: 0.541443229\n", + " values: 0.360983938\n", + " values: 0.180545077\n", + " values: 0.361049861\n", + " values: 0.541501701\n", + " values: 0.180474699\n", + " values: 0.000100237128\n", + " values: 6.13787488e-05\n", + " values: 0.360888392\n", + " values: 0.180479616\n", + " values: 0.180498898\n", + " values: 0.360999823\n", + " values: 0.180450305\n", + " values: 6.63495885e-05\n", + " values: 0.541473031\n", + " values: -7.80999617e-05\n", + " values: 0.180430397\n", + " values: 0.54154557\n", + " values: 0.361086\n", + " values: 2.14801639e-05\n", + " values: 0.3610605\n", + " values: 0.541564286\n", + " values: 0.180553809\n", + " values: 0.361035645\n", + " values: 0.54155618\n", + " values: -4.97167057e-05\n", + " values: 0.541514456\n", + " values: 0.361072928\n", + " values: 0.180593193\n", + " values: 0.541416705\n", + " values: -9.44544536e-06\n", + " values: 0.360899121\n", + " values: 0.361074507\n", + " values: 0.180493355\n", + " values: 0.541564882\n", + " values: 0.360985\n", + " values: 0.180486605\n", + " values: 0.360950112\n", + " values: 0.541464865\n", + " values: -2.54885272e-05\n", + " values: 0.541466534\n", + " values: 0.541552067\n", + " values: 0.361087292\n", + " values: 0.36101082\n", + " values: 0.360883027\n", + " values: 0.541595399\n", + " values: 0.541372716\n", + " values: 0.36103496\n", + " values: 0.541488826\n", + " values: 0.361009538\n", + " values: 0.54156816\n", + " values: 0.361011147\n", + " values: 0.541493833\n", + " values: 0.541347742\n", + " }\n", + " }\n", + "}\n", + "arrays {\n", + " key: \"particle.names\"\n", + " value {\n", + " string_values {\n", + " values: \"0\"\n", + " values: \"1\"\n", + " values: \"2\"\n", + " values: \"3\"\n", + " values: \"4\"\n", + " values: \"5\"\n", + " values: \"6\"\n", + " values: \"7\"\n", + " values: \"8\"\n", + " values: \"9\"\n", + " values: \"10\"\n", + " values: \"11\"\n", + " values: \"12\"\n", + " values: \"13\"\n", + " values: \"14\"\n", + " values: \"15\"\n", + " values: \"16\"\n", + " values: \"17\"\n", + " values: \"18\"\n", + " values: \"19\"\n", + " values: \"20\"\n", + " values: \"21\"\n", + " values: \"22\"\n", + " values: \"23\"\n", + " values: \"24\"\n", + " values: \"25\"\n", + " values: \"26\"\n", + " values: \"27\"\n", + " values: \"28\"\n", + " values: \"29\"\n", + " values: \"30\"\n", + " values: \"31\"\n", + " }\n", + " }\n", + "}\n", + "arrays {\n", + " key: \"particle.elements\"\n", + " value {\n", + " index_values {\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " values: 29\n", + " }\n", + " }\n", + "}\n", + "arrays {\n", + " key: \"chain.names\"\n", + " value {\n", + " string_values {\n", + " values: \"A\"\n", + " }\n", + " }\n", + "}\n", + "arrays {\n", + " key: \"bond.pairs\"\n", + " value {\n", + " index_values {\n", " }\n", " }\n", "}" @@ -649,7 +822,7 @@ ], "source": [ "# view the latest frame\n", - "client.latest_frame.raw" + "client.current_frame.raw" ] }, { @@ -772,7 +945,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -792,7 +965,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -832,7 +1005,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -872,7 +1045,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -892,7 +1065,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -912,7 +1085,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -932,7 +1105,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -952,7 +1125,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -972,7 +1145,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -992,7 +1165,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1012,7 +1185,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1052,7 +1225,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1072,7 +1245,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1092,7 +1265,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1112,7 +1285,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1132,7 +1305,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1152,7 +1325,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1192,7 +1365,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1212,7 +1385,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1232,7 +1405,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1292,7 +1465,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1352,7 +1525,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n", @@ -1392,7 +1565,7 @@ "\n", " \n", "\n", - " \n", + " \n", "\n", " \n", "\n",