Note that currently we are working on a simpler installation procedure, and some names may change. The actual version cannot be called from within the plumed python interface
For compiling the plugin you just need pybind11 and numpy. I always recommend creating and ad-hoc environment for your projects:
python3 -m venv pycvenv
source ./pycvenv/bin/activate
pip install -U pip
pip install -r requirements.txt
The requirements.txt file is in the home of the plug in (plumeddir/plugins/pycv
)
If you have a plumed that supports plumed mklib with multiple files you can simply
./standaloneCompile.sh
This usually goes smooth, especially if plumed has already found the necessary python configuration and plumed --no-mpi config makefile_conf | grep canPyCV
returns canPyCV=yes
.
After running ./standaloneCompile.sh
you should have a PythonCVInterface.so
file into the pycv directory
When using PyCV the user will need to create a module1 that must at least contain an initialization dictionary and a calculate function
cvPY: PYCVINTERFACE ATOMS=1,4 IMPORT=pydistancePBCs CALCULATE=pydist
IMPORT
this is the only mandatory keyword, this indicates the python module to loadINIT
indicates the function to call at initialization. Defaults toplumedInit
COMPONENTS
can be specified either in python or in the plumed.datNOPBC
can be specified either in python or in the plumed.datATOMS
,GROUPA
,GROUPB
, usingGROUP*
will make plumed set up a neighbor list between the groups, or group A, whereas with ATOMS all the atom will be passedPAIR
,NLIST
,NL_CUTOFF
,NL_STRIDE
can only be specified in the plumed.datto be verifiedCALCULATE
indicates the function to call at calculate time. Defaults toplumedCalculate
PREPARE
indicates the function to call at prepare time. Ignored if not specifiedUPDATE
indicates the function to call at update time. Ignored if not specified
d1: DISTANCE ATOMS=1,2
d2: DISTANCE ATOMS=1,3
fPY: PYFUNCTION IMPORT=pycvfunc CALCULATE=plumedCalculate ARG=d1,d2
IMPORT
this is the only mandatory keyword, this indicates the python module to loadINIT
indicates the function to call at initialization. Defaults toplumedInit
COMPONENTS
can be specified either in python or in the plumed.dat
CALCULATE
indicates the function to call at calculate time. Defaults toplumedCalculate
ARG
the list of arguments, to be specified in the plumed.dat
PYFUNCTION is simpler: but needs to get the arguments from the plumed object
import plumedCommunications as PLMD
import numpy
plumedInit={"Value": PLMD.defaults.COMPONENT_NODEV}
def plumedCalculate(action: PLMD.PythonFunction):
arg = [action.argument(0),action.argument(1)]
return arg[0]*arg[0]*arg[1]
For both PYFUNCTION and PYCVINTERFACE the function called by plumed must accept a specific object.
- PYCVINTERFACE functions will expect a plumedCommunications.PythonCVInterface
object
- PYFUNCTION functions will expect a plumedCommunications.PythonFunction
object
These objects are used to retrieve data and settings from plumed. Plumed will get data back with the data
attribute (see below) but mainly with the use of returned dictionaries.
In the examples I show how to retrieve the manual for those objects
If in the plumed.dat INIT
is not specified, plumed will search for an object "plumedInit",
that can be either a function that returns a dict or a dict
This dict MUST contain at least the information about the presence of the
derivatives and on the periodicity of the variable.
We will refer to this dict as "the init dict" from now.
The init dict will tell plumed how many components the calculate function will return and how they shall behave. Along this the dict can contain all the keyword that are compatible with PYCVINTERFACE. Mind that if the same keyword is specified both in the init dict and in the plumed file the calculation will be aborted to avoid unwanted settings conflicts. In case of flags the dict entry must be a boolean, differently from the standard plumed input.
The only keyword that can only be specified in python is COMPONENTS
.
The COMPONENTS
key must point to a dict that has as keys the names of the
components.
Each component dictionary must have two keys:
"period"
:None
of a list of two values, min and max (like[0,1]
or also strings like["0.5*pi","2*pi"]
)"derivative"
:True
orFalse
If you want to use a single component you can create the"COMPONENTS"
dict with as single key, the name will be ignored. In the previous example the key"Value"
is used instead of"COMPONENTS"
: it is a shorter form for"COMPONENTS":{"any":{...}}
. To avoid confusion you cannot specify both"COMPONENTS"
and"Value"
in the same dict.
To speed up the declarations of the components the plumedCommunications
module
contains a submodule defaults
with the default dictionaries already set up:
plumedCommunications.defaults.COMPONENT={"period":None, "derivative":True}
plumedCommunications.defaults.COMPONENT_NODEV={"period":None, "derivative":False}
If CALCULATE
is not specified, plumed will search for a function named
"plumedCalculate" plumed will read the variable returned accordingly to what it
was specified in the initialization dict.
The calculate function must, as all the other functions accept a
plumedCommunications.PythonCVInterface
(or a plumedCommunications.PythonFunction
in case of a pyfunction) object as only input.
The calculate function must either return a float or a tuple or, in the case of multiple components, a dict whose keys are the name of the components, whose elements are either float or tuple.
Plumed will assign automatically the result to the CV (to the key named element), if the name of the component is missing the calculation will be interrupted with an error message. If derivatives are disabled it will expect a float(or a double). In case of activated derivatives it will interrupt the calculation if the return value would not be a tuple. The tuple should be (float, ndArray(nat,3),ndArray(3,3)) with the first elements the value, the second the atomic derivatives and the third the box derivative (that can also have shape(9), with format (x_x, x_y, x_z, y_x, y_y, y_z, z_x, z_y, z_z)), if the box derivative are not present a WARNING will be raised, but the calculation won't be interrupted.
If the PREPARE
keyword is used, the defined function will be called at
prepare time, before calculate.
The returned "prepare" dictionary can contain a "setAtomRequest"
key with a parseable
ATOM string, like in the standard plumed input (or a list of indexes, 0 based).
#this , with "PREPARE=changeAtom" in the plumed file will select a new atom at each new step
def changeAtom(plmdAction: plumedCommunications.PythonCVInterface):
toret = {"setAtomRequest": f"1, {int(plmdAction.getStep()) + 2}"}
if plmdAction.getStep() == 3:
toret["setAtomRequest"] = "1,2"
return toret
If the UPDATE
keyword is used, the defined function will be called at update
time, after calculate. As now plumed will ignore the return of this function
(but it stills need to return a dict) and it is intended to accumulate things
or post process data afer calculate
In the example plmdAction.data["pycv"]=0
is initialized in pyinit
and its
value is updated in calculate.
The plumedCommunications.PythonCVInterface has a data
attribute that is a
dictionary and can be used to store data during the calculations
cv1: PYCVINTERFACE ...
ATOMS=@mdatoms
IMPORT=pycvPersistentData
CALCULATE=pydist
INIT=pyinit
...
PRINT FILE=colvar.out ARG=*
import plumedCommunications as PLMD
from plumedCommunications.defaults import COMPONENT_NODEV
def pyinit(plmdAction: PLMD.PythonCVInterface):
plmdAction.data["pycv"]=0
print(f"{plmdAction.data=}", file=log)
return {"Value":COMPONENT_NODEV}
def pydist(plmdAction: PLMD.PythonCVInterface):
plmdAction.data["pycv"]+=plmdAction.getStep()
d=plmdAction.data["pycv"]
return d
Footnotes
-
a module is a
.py
file or a directory that contains a__init__.py
, here we will only showpy
files ↩