Skip to content

Commit

Permalink
added a test for str atomrequests
Browse files Browse the repository at this point in the history
  • Loading branch information
Iximiel committed Nov 23, 2023
1 parent 78b7679 commit e2f5301
Show file tree
Hide file tree
Showing 8 changed files with 99 additions and 44 deletions.
2 changes: 1 addition & 1 deletion pycv/PlumedPythonEmbeddedModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ PYBIND11_EMBEDDED_MODULE(plumedCommunications, m) {
);
return atomList;
},
"Returns a numpy.array that contaisn the atomic positions of the atoms requested by the action")
"Returns a numpy.array that contains the atomic positions of the atoms requested by the action")
.def("log",[](PLMD::pycv::PythonCVInterface* self, py::object data) {
self->log << py::str(data).cast<std::string>();
},
Expand Down
71 changes: 28 additions & 43 deletions pycv/PythonCVInterface.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ Each element or function can be selected with its dedicated keyword:
update() invocation
- `PREPARE` will select the function to be called at each step, during the
prepare() invocation
All the function called will need a single argument of type
All the function called will need a single argument of type
`plumedCommunications.PythonCVInterface`
Expand All @@ -78,15 +78,15 @@ def plumedCompute(action: PLMD.PythonCVInterface):
If `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 informations about the presence of the
This dict MUST contain at least the informations 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.
If `CALCULATE` is not specified, plumed will search for a function named
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 init dict will tell plumed how many components the calculate function will
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.
Expand Down Expand Up @@ -115,7 +115,7 @@ contains a submodule `defaults` with the default dictionaries already set up:
\par The calculate function
The calculate funtion must, as all the other functions accept a
The calculate funtion must, as all the other functions accept a
PLMD.PythonCVInterface 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.
Expand All @@ -125,7 +125,12 @@ 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.
\par The prepare and update functions
\par The prepare and update functions and the "data" attribute
If the `PREPARE` keyword is used, the defined function will be called at prepare time, before calculate.
If the `UPDATE` keyword is used, the defined function will be called at update time, after calculate
\par Getting the manual
Expand Down Expand Up @@ -157,34 +162,8 @@ def plumedCalculate(_):
return 0
@endcode
@code{.py}
#this make python aware of plumed
import plumedCommunications as PLMD
def plumedInit(action: PLMD.PythonCVInterface):
action.log("Hello, world, from init!")
#this tells plumed that there is only a component and that componed has the default settings
return {"Value":PLMD.defaults.COMPONENT_NODEV}
#note that if you do not to calculate anything you can simply write the dict that will be returned:
#plumedInit={"Value":PLMD.defaults.COMPONENT_NODEV}
def plumedCompute(action: PLMD.PythonCVInterface):
action.log("Hello, world, from calculate!")
#since we do not have derivatives we can simply return a number
return 0.0
@endcode
In the scalar case (`COMPONENTS` keyword not given), the function
sho return two values: a scalar (the CV value), and its gradient
with respect to each coordinate (an array of the same shape as the
input). Not returning the gradient will prevent biasing from working
(with warnings).
If a list of `COMPONENTS` is given, multiple components can be
computed at once, as described in the section *Multiple components*.
/par Tips and tricks
Automatic differentiation and transparent compilation (including to
GPU) can be performed via Google's [JAX
Expand Down Expand Up @@ -609,16 +588,21 @@ void PythonCVInterface::prepare() try {
py::dict prepareDict = pyPrepare(this);
if (prepareDict.contains("setAtomRequest")) {
//should I use "interpretAtomList"?
py::tuple t = prepareDict["setAtomRequest"];
std::vector<PLMD::AtomNumber> myatoms;
for (const auto &i : t) {
auto at = PLMD::AtomNumber::index(i.cast<unsigned>());
myatoms.push_back(at);
}
for (const auto &i : myatoms) {
std::cout << i.index() << " ";
if(py::isinstance<py::tuple>(prepareDict["setAtomRequest"])||
py::isinstance<py::list>(prepareDict["setAtomRequest"])) {
py::tuple t = prepareDict["setAtomRequest"];

for (const auto &i : t) {
auto at = PLMD::AtomNumber::index(i.cast<unsigned>());
myatoms.push_back(at);
}
} else {
auto atomlist=PLMD::Tools::getWords(
py::str(prepareDict["setAtomRequest"]).cast<std::string>(),
"\t\n ,");
interpretAtomList( atomlist, myatoms );
}
std::cout << "\n";
requestAtoms(myatoms);
}
}
Expand Down Expand Up @@ -750,9 +734,10 @@ void PythonCVInterface::calculateMultiComponent(py::object &r) {

void PythonCVInterface::pyParseAtomList(const char* key, const ::pybind11::dict &initDict, std::vector<AtomNumber> &myatoms) {
parseAtomList(key,myatoms);
if (myatoms.size()>0 && initDict.contains(key))
error(std::string("you specified the same keyword ").append(key)+ " both in python and in the settings file");

if(initDict.contains(key)) {
if (myatoms.size()>0)
error(std::string("you specified the same keyword ").append(key)+ " both in python and in the settings file");
auto atomlist=PLMD::Tools::getWords(
py::str(initDict[key]).cast<std::string>(),
"\t\n ,");
Expand Down
1 change: 1 addition & 0 deletions pycv/regtest/pycvcomm/rt-newFrameNewAtomSTR/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
include ../../scripts/test.make
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#! FIELDS time cv1
0.000000 1.000000
1.000000 2.000000
2.000000 3.000000
3.000000 4.000000
3 changes: 3 additions & 0 deletions pycv/regtest/pycvcomm/rt-newFrameNewAtomSTR/config
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@

type=driver
arg="--plumed plumed.dat --ixyz traj.xyz"
5 changes: 5 additions & 0 deletions pycv/regtest/pycvcomm/rt-newFrameNewAtomSTR/plumed.dat
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
LOAD GLOBAL FILE=../../../../PythonCVInterface.so

cv1: PYCVINTERFACE ATOMS=@mdatoms IMPORT=pycvPerFrame CALCULATE=pydist PREPARE=changeAtom

PRINT FILE=colvar.out ARG=*
32 changes: 32 additions & 0 deletions pycv/regtest/pycvcomm/rt-newFrameNewAtomSTR/pycvPerFrame.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# This is only a partial example. This function does not compute the
# gradient, so it is useless for biasing. See the other regression
# tests for how to auto-grad.

# And, of course, one should not call slow functions (such as print)
# in the CV calculation.

import numpy as np
import plumedCommunications

log = open("pycv.log", "w")

print("Imported.", file=log)
plumedInit={"Value": plumedCommunications.defaults.COMPONENT,}

def changeAtom(plmdAction: plumedCommunications.PythonCVInterface):
print(f"pyCVCALLED")
toret = {"setAtomRequest": f"1, {int(plmdAction.getStep()) + 2}"}
# this is just for "fun"
if plmdAction.getStep() == 3:
toret["setAtomRequest"] = "1,2"
print(toret)
return toret


def pydist(action: plumedCommunications.PythonCVInterface):
at: np.ndarray = action.getPositions()
d = at[0] - at[1]
d = np.linalg.norm(d)
print(f"{at[0]},{at[1]},{d}", file=log)

return d
24 changes: 24 additions & 0 deletions pycv/regtest/pycvcomm/rt-newFrameNewAtomSTR/traj.xyz
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
4
100 100 100
X 0 0 0
X 0 0 1
X 0 0 0
X 0 0 0
4
100 100 100
X 0 0 0
X 0 0 0
X 0 0 2
X 0 0 0
4
100 100 100
X 0 0 0
X 0 0 0
X 0 0 0
X 0 0 3
4
100 100 100
X 0 0 0
X 0 0 4
X 0 0 0
X 0 0 0

0 comments on commit e2f5301

Please sign in to comment.