"""submodule containing the command line interfaces of SOAPify"""
from argparse import ArgumentParser
[docs]def getDictFromList(nameAndValues: list) -> dict:
"""generates a dictionary from a list of couples [name, value]
Args:
nameAndValues (list):
the list of couples [name, value]
Returns:
dict:
the dictionary, for example {name0:value0, name1:value1}
"""
myDict = {}
for attr in nameAndValues:
myDict[attr[0]] = attr[1]
return myDict
[docs]def createTrajectory():
"""Creates or overide an hdf5 file containing a given trajectory
if you are creating ahdf5 file from a data+dump from a soap simulation
remember to add `-u atom_style "id type x y z"` to the arguments
defaults trajChunkSize=1000"""
from MDAnalysis import Universe as mdaUniverse
from SOAPify.HDF5er import MDA2HDF5
from os import path
parser = ArgumentParser(description=createTrajectory.__doc__)
parser.add_argument("topology", help="the topology file")
parser.add_argument("hdf5File", help="the file where to putput the trajectory")
parser.add_argument(
"-t",
"--trajectory",
help="the trajectory file(s)",
metavar="trajectory",
action="append",
default=[],
)
parser.add_argument(
"-n",
"--name",
metavar="name",
help="the name of the trajectory to save",
)
parser.add_argument(
"--types",
metavar="atomNames",
help="list of the atoms names",
nargs="+",
dest="atomTypes",
)
parser.add_argument(
"-a",
"--attribute",
nargs=2,
action="append",
dest="extraAttributes",
metavar=("name", "value"),
help="extra attributes to store in the trajectory, saved as strings",
)
parser.add_argument(
"-u",
"--universe-options",
nargs=2,
action="append",
dest="universeOPTs",
metavar=("name", "value"),
help="extra option to pass to the MDA universe, compatible only with string"
" values, use the python script if you need to pass more other settings",
)
parser.add_argument(
"-d",
"--dry-run",
action="store_true",
help="just print the output without making any action",
)
args = parser.parse_args()
# print(args)
# arguments
trajectoryFiles = args.trajectory
filename = args.hdf5File
topo = args.topology
name = args.name
if name is None:
name = path.basename(topo)
name = name.split(".")[0]
print(
f'from topology "{topo}"',
f'and trajectory "{trajectoryFiles}":',
"and creating a new trajectory in",
)
print(f'"{filename}/Trajectories/{name}"')
extraAttrs = None
if args.extraAttributes:
extraAttrs = getDictFromList(args.extraAttributes)
print("extra attributes:", extraAttrs)
universeOptions = {}
if args.universeOPTs:
universeOptions = getDictFromList(args.universeOPTs)
if args.dry_run:
exit()
u = mdaUniverse(topo, *trajectoryFiles, **universeOptions)
if args.atomTypes:
ntypes = len(args.atomTypes)
if len(u.atoms) % ntypes != 0:
raise ValueError(
f"The number of atom types is not compatible with the number"
f" of atoms:{len(u.atoms)} % {ntypes} = {len(u.atoms) % ntypes}"
)
u.atoms.types = args.atomTypes * (len(u.atoms) // ntypes)
MDA2HDF5(u, filename, name, trajChunkSize=1000, attrs=extraAttrs)
# TODO: implement this:
# from MDAnalysis import transformations
# ref = mdaUniverse(topo, atom_style="id type x y z")
# u.trajectory.add_transformations(transformations.fit_rot_trans(u, ref))
# MDA2HDF5(u, name + "_fitted.hdf5", f"{name}_fitted", trajChunkSize=1000))
[docs]def traj2SOAP():
"""Given an hdf5 file containing trajectories calculates SOAP of the contained trajectories
default SOAP engine is dscribe"""
from SOAPify import saponifyTrajectory
from SOAPify.HDF5er import isTrajectoryGroup
import h5py
parser = ArgumentParser(description=traj2SOAP.__doc__)
parser.add_argument(
"trajFile",
help="the file containing the trajectories",
)
parser.add_argument(
"-s",
"--SOAPFile",
help="The file were to save the SOAP fingerprints, if not specified"
' creates a "SOAP" group in within the trajFile',
)
parser.add_argument(
"-g",
"--group",
default="SOAP",
help="the name of the group where to store the SOAP fingerprints,"
' if not specified is "SOAP"',
dest="SOAPgroup",
)
parser.add_argument(
"-t",
"--trajectory",
default="Trajectories",
help="Specify the group containing the trajectories groups or the"
" trajectory group tha you want to calculate the SOAP fingerprints",
)
parser.add_argument(
"-e",
"--engine",
choices=["dscribe", "quippy"],
default="dscribe",
help="the engine used to calculate SOAP",
)
parser.add_argument(
"-l",
"--lMax",
type=int,
default=8,
help="the lmax parameter, defaults to 8",
)
parser.add_argument(
"-n",
"--nMax",
type=int,
default=8,
help="the nmax parameter, defaults to 8",
)
parser.add_argument(
"-r",
"--rCut",
type=float,
default=10.0,
help="the rcut parameter, defaults to 10.0 Å",
)
parser.add_argument(
"-j",
"--jobs",
type=int,
default=1,
help="the number of jobs to use, defaults to 1",
)
parser.add_argument(
"-d",
"--dry-run",
action="store_true",
help="just print the output without making any action",
)
args = parser.parse_args()
# print(args)
trajGroupLocation = args.trajectory
def worker(
group: "h5py.Group|h5py.Dataset", soapFile: h5py.File, SOAPgroup: str = "SOAP"
):
print(
f"\"{group.name}\" is {'' if isTrajectoryGroup(group) else 'not '}a trajectory group"
)
if isTrajectoryGroup(group):
if args.dry_run:
return
saponifyTrajectory(
trajContainer=group,
SOAPoutContainer=soapFile.require_group(SOAPgroup),
SOAPOutputChunkDim=1000,
SOAPnJobs=args.jobs,
SOAPrcut=args.rCut,
SOAPnmax=args.nMax,
SOAPlmax=args.lMax,
useSoapFrom=args.engine,
)
SOAPFile = args.SOAPFile
SOAPgroup = args.SOAPgroup
if args.SOAPFile is None:
SOAPFile = args.trajFile
with h5py.File(
args.trajFile, "r" if SOAPFile != args.trajFile else "a"
) as workFile, h5py.File(SOAPFile, "a") as SOAPFile:
trajGroup = workFile[trajGroupLocation]
if isTrajectoryGroup(trajGroup):
worker(trajGroup, SOAPFile, SOAPgroup)
else:
for _, group in trajGroup.items():
worker(group, SOAPFile, SOAPgroup)