From 8a4d1f9c2f5fcbde5c1e7cd416fdee45c92f74b2 Mon Sep 17 00:00:00 2001 From: Daniele Rapetti <5535617+Iximiel@users.noreply.github.com> Date: Thu, 30 Nov 2023 12:01:46 +0100 Subject: [PATCH] moved the interface documentation --- plugins/pycv/PythonInterface.md | 83 +++++++++++++++ plugins/pycv/README.md | 175 +++++--------------------------- 2 files changed, 109 insertions(+), 149 deletions(-) create mode 100644 plugins/pycv/PythonInterface.md diff --git a/plugins/pycv/PythonInterface.md b/plugins/pycv/PythonInterface.md new file mode 100644 index 0000000000..db646aedfb --- /dev/null +++ b/plugins/pycv/PythonInterface.md @@ -0,0 +1,83 @@ +# The Python interface + +## Getting the manual +To obtain a **VERY BASIC** reference/manual with all the function and method definitions, run the test rt-doc or call `PYFUNCTION` in with: + +**plumed.dat** +``` +LOAD GLOBAL FILE=path/to/PythonCVInterface.so +PYFUNCTION IMPORT=pycv +``` + +**pycv.py** +```python +import plumedCommunications +import pydoc + +def plumedInit(_): + pydoc.writedoc(plumedCommunications) + pydoc.writedoc(plumedCommunications.defaults) + return {"Value":plumedCommunications.defaults.COMPONENT_NODEV} + +def plumedCalculate(_): + return 0.0 +``` + +## Specifics +In the following section +### Common interface +Both `PYFUNCTION` and `PYCVINTERFACE` have the following attribute: + - `label` (readonly) returns the label + +And the following functions: + - `log(s:object)` puts a string in the PLUMED output + - `lognl(s:object)` puts a string in the PLUMED output (and appends a newline) + - `getStep()` Returns the current step + - `getTime()` Return the present time + - `getTimeStep()` Return the timestep + - `isExchangeStep()` Check if we are on an exchange step + - `isRestart()` Return true if we are doing a restart + +### PYFUNCTION: arguments + +`PYFUNCTION` accepts arguments in the plumed file with the `ARG` keyword, the arguments are then accessible in python with the functions: + - `PythonFunction.argument(argID:int)` Get value of the of argID-th argument (as `float`) + - `PythonFunction.arguments()` Retuns a ndarray with the values of the arguments (as `numpy.ndarray[numpy.float64]`) + +and the argument: +- `PythonFunction.nargs` (readonly) Get the number of arguments + +`PYFUNCTION` also has a few functions that can be used to interact with the periodicity of the arguments: + - `PythonFunction.bringBackInPbc(argID:int,x:float)` Takes one value and brings it back into the pbc of argument argID + - `PythonFunction.difference(argID:int,x:float,y:float)` Takes the difference taking into account pbc for argument argID + +### PYCVINTERFACE: atoms, pbc, neigbourlist, makeWhole +`PYCVINTERFACE` works with atoms: + +Has the following attributes: + - `PythonCVInterface.nat` (readonly) Return the number of atoms + +For getting the atomic data you can call the following functions: + - `PythonCVInterface.getPosition(atomID:int)` Returns an ndarray with the position of the atomID-th atom + - `PythonCVInterface.getPositions()` Returns a numpy.array that contains the atomic positions of the atoms + - `PythonCVInterface.mass(atomID:int)` Get mass of atomID-th atom + - `PythonCVInterface.masses()` Returns and ndarray with the masses + - `PythonCVInterface.charge(atomID:int)` Get charge of atomID-th atom + - `PythonCVInterface.charges()` Returns and ndarray with the charges + - `PythonCVInterface.absoluteIndexes()` Get the npArray of the absolute indexes (like in AtomNumber::index()). + + And in general you can use some support-function from plumed: + - `PythonCVInterface.getNeighbourList()` returns an interface to the current Neighborlist + - `PythonCVInterface.getPbc()` returns an interface to the current pbcs + - `PythonCVInterface.makeWhole()` Make atoms whole, assuming they are in the proper order + +`plumedCommunications.Pbc` and `plumedCommunications.NeighborList` are simple methods container to help with the calculations: + +`plumedCommunications.Pbc` has the following functions: + - `Pbc.apply(d:ndarray)` pply PBC to a set of positions or distance vectors (`d.shape==(n,3)`) + - `Pbc.getBox()` Get a numpy array of shape (3,3) with the box vectors + - `Pbc.getInvBox()` Get a numpy array of shape (3,3) with the inverted box vectors + +`plumedCommunications.NeighborList` has the following functions and attributes: +- `NeigbourList.getClosePairs()` get the (nl.size,2) nd array with the list of couple indexes +- `NeigbourList.size` and `len(nl:NeigbourList.size)` give the number of couples \ No newline at end of file diff --git a/plugins/pycv/README.md b/plugins/pycv/README.md index 2e5fb817e9..7b540e03cb 100644 --- a/plugins/pycv/README.md +++ b/plugins/pycv/README.md @@ -103,30 +103,8 @@ If you are using an older plumed version you must know that: - On linux the plug-in can be loaded only if `LOAD` supports the `GLOBAL` keyword - mklib won't work (supports only single file compilations), so you'll need to use `./prepareMakeForDevelop.sh` -## Some Examples - -### Bare minimum -The minimum invocation can be the following: - -**plumed.dat** -``` -LOAD GLOBAL FILE=path/to/PythonCVInterface.so -cvPY: PYFUNCTION IMPORT=pycv -PRINT FILE=colvar.out ARG=* -``` +## Getting started -**pycv.py** -```python -import plumedCommunications as PLMD -plumedInit={"Value":PLMD.defaults.COMPONENT_NODEV} - -def plumedCalculate(action: PLMD.PythonFunction): - action.lognl("Hello, world!") - return 0.0 -``` -This simply prints an "Hello, world!" at each step of the simulation/trajectory. - -I am using `PYFUNCTION` because needs less options to be initializated. ### Initialization: the INIT keyword Both `PYFUNCTION` and `PYCVINTERFACE` use the keyword INIT to finalize the set up for the action. @@ -219,110 +197,50 @@ As now nothing will be done after the python UPDATE call. You can however act on the `.data` dict or access to all the parameters accessible from python, and for example update a plot or accumulate an histogram or any other thing that may be useful for your analysis/simulation. -### Getting the manual -To obtain a **VERY BASIC** reference/manual with all the function and method definitions, run the test rt-doc or call `PYFUNCTION` in with: +## Some Examples + +In the following paragraphs I am showing a few examples, for a short description of the python interface look [here](PythonInterface.md) + +### Bare minimum +The minimum invocation can be the following: **plumed.dat** ``` LOAD GLOBAL FILE=path/to/PythonCVInterface.so -PYFUNCTION IMPORT=pycv +cvPY: PYFUNCTION IMPORT=pycv +PRINT FILE=colvar.out ARG=* ``` **pycv.py** ```python -import plumedCommunications -import pydoc - -def plumedInit(_): - pydoc.writedoc(plumedCommunications) - pydoc.writedoc(plumedCommunications.defaults) - return {"Value":plumedCommunications.defaults.COMPONENT_NODEV} +import plumedCommunications as PLMD +plumedInit={"Value":PLMD.defaults.COMPONENT_NODEV} -def plumedCalculate(_): +def plumedCalculate(action: PLMD.PythonFunction): + action.lognl("Hello, world!") return 0.0 ``` -With this you'll obtain two basic html files with the documentation (these documentation will show also the pybind11 helper methods) - -## Specifics -In the following section -### Common interface -Both `PYFUNCTION` and `PYCVINTERFACE` have the following attribute: - - `label` (readonly) returns the label - -And the following functions: - - `log(s:object)` puts a string in the PLUMED output - - `lognl(s:object)` puts a string in the PLUMED output (and appends a newline) - - `getStep()` Returns the current step - - `getTime()` Return the present time - - `getTimeStep()` Return the timestep - - `isExchangeStep()` Check if we are on an exchange step - - `isRestart()` Return true if we are doing a restart - -### PYFUNCTION: arguments - -`PYFUNCTION` accepts arguments in the plumed file with the `ARG` keyword, the arguments are then accessible in python with the functions: - - `PythonFunction.argument(argID:int)` Get value of the of argID-th argument (as `float`) - - `PythonFunction.arguments()` Retuns a ndarray with the values of the arguments (as `numpy.ndarray[numpy.float64]`) - -and the argument: -- `PythonFunction.nargs` (readonly) Get the number of arguments - -`PYFUNCTION` also has a few functions that can be used to interact with the periodicity of the arguments: - - `PythonFunction.bringBackInPbc(argID:int,x:float)` Takes one value and brings it back into the pbc of argument argID - - `PythonFunction.difference(argID:int,x:float,y:float)` Takes the difference taking into account pbc for argument argID - -### PYCVINTERFACE: atoms, pbc, neigbourlist, makeWhole -`PYCVINTERFACE` works with atoms: - -Has the following attributes: - - `PythonCVInterface.nat` (readonly) Return the number of atoms - -For getting the atomic data you can call the following functions: - - `PythonCVInterface.getPosition(atomID:int)` Returns an ndarray with the position of the atomID-th atom - - `PythonCVInterface.getPositions()` Returns a numpy.array that contains the atomic positions of the atoms - - `PythonCVInterface.mass(atomID:int)` Get mass of atomID-th atom - - `PythonCVInterface.masses()` Returns and ndarray with the masses - - `PythonCVInterface.charge(atomID:int)` Get charge of atomID-th atom - - `PythonCVInterface.charges()` Returns and ndarray with the charges - - `PythonCVInterface.absoluteIndexes()` Get the npArray of the absolute indexes (like in AtomNumber::index()). - - And in general you can use some support-function from plumed: - - `PythonCVInterface.getNeighbourList()` returns an interface to the current Neighborlist - - `PythonCVInterface.getPbc()` returns an interface to the current pbcs - - `PythonCVInterface.makeWhole()` Make atoms whole, assuming they are in the proper order - -`plumedCommunications.Pbc` and `plumedCommunications.NeighborList` are simple methods container to help with the calculations: - -`plumedCommunications.Pbc` has the following functions: - - `Pbc.apply(d:ndarray)` pply PBC to a set of positions or distance vectors (`d.shape==(n,3)`) - - `Pbc.getBox()` Get a numpy array of shape (3,3) with the box vectors - - `Pbc.getInvBox()` Get a numpy array of shape (3,3) with the inverted box vectors - -`plumedCommunications.NeighborList` has the following functions and attributes: -- `NeigbourList.getClosePairs()` get the (nl.size,2) nd array with the list of couple indexes -- `NeigbourList.size` and `len(nl:NeigbourList.size)` give the number of couples ---- - -Here's a quick example to whet your appetite, following the regression test `rt-jax2`. +This simply prints an "Hello, world!" at each step of the simulation/trajectory. - export PLUMED_PROGRAM_NAME=$PWD/src/lib/plumed-static - make -C regtest/pycv/rt-jax2 +### An example, calculation the gradient with jax -The files in `regtest/pycv/rt-jax2` are reproduced here: +Here's a quick example with calculation of an angle between three atoms -**File plumed.dat** +**plumed.dat** ``` -cv1: PYTHONCV ATOMS=1,4,3 IMPORT=jaxcv FUNCTION=cv1 +cv1: PYTHONCV ATOMS=1,4,3 IMPORT=jaxcv CALCULATE=cv1 ``` -**File jaxcv.py** +**jaxcv.py** ```py # Import the JAX library import jax.numpy as np from jax import grad, jit, vmap +import plumedCommunications +plumedInit={"Value": plumedCommunications.defaults.COMPONENT} # Implementation of the angle function. @jit really improves speed @jit def angle(x): @@ -338,11 +256,11 @@ def angle(x): grad_angle = grad(angle) # The CV function actually called -def cv1(x): +def cv1(action): + x=action.getPositions() return angle(x), grad_angle(x) ``` - ## EXTRA: JAX Transparent auto-differentiation, JIT compilation, and vectorization @@ -361,58 +279,17 @@ The command for installing should be similar to: - example if you have a cuda12 compatible device, and **cuda already installed on your system**: `pip install "jax[cuda12_local]" -f https://storage.googleapis.com/jax-releases/jax_cuda_releases.html` -## Demos and regression tests - -A number of PLUMED-style regression tests are provided to test and -demonstrate the package features. - - -Name | Feature --------|------------ -`rt-1` | Basic test (distance of two atoms), pure Python, no gradient -`rt-2` | CV and gradient explicitly coded, pure Python -`rt-3` | Multiple PYTHON actions in the same file -`rt-f1`| Function, pure Python -`rt-f2`| Function, with JIT and auto-gradient, with MATHEVAL equivalent -`rt-jax1` | Distance CV with JAX reverse-mode differentiation -`rt-jax2` | Angle CV with JAX reverse-mode differentiation and JIT decorator -`rt-jax3` | Radius of curvature, as in [doi:10.1016/j.cpc.2018.02.017](http://doi.org/10.1016/j.cpc.2018.02.017) -`rt-multi1` | Multi-component CV, pure Python -`rt-multi2` | Multi-component CV, with JAX reverse-mode differentiation - - -To run: - -```bash -cd [path_to_repository] -export PLUMED_PROGRAM_NAME=$PWD/src/lib/plumed -cd regtest/pycv -make -``` - -## Common errors - -* Missing modules at run time: you may need to set the `PYTHONHOME` - environment variable. - -* `uncaught exception [...] The interpreter is already running` This - occurs if the module is loaded twice. The most common cause is when - it is both built-in in the current kernel, and loaded as a module. - - ## Limitations - No test have been done with MPI -- JAX's GPU/TPU offloading are unde. - - +- JAX's GPU/TPU offloading are not 100% testes. ## Authors -Toni Giorgino - +Original author: Toni Giorgino +Daniele Rapetti ## Contributing Please report bugs and ideas via this repository's *Issues*.