1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106
|
#!/usr/bin/python3
# This source file is part of the Avogadro project.
# This source code is released under the 3-Clause BSD License, (see "LICENSE").
import argparse
import json
import sys
import os
from shutil import which
import tempfile
import subprocess
def getMetaData():
# before we return metadata, make sure xtb is in the path
if which("xtb") is None:
return {} # Avogadro will ignore us now
metaData = {}
metaData["inputFormat"] = "mol" # could be other formats, but this is fine
metaData["identifier"] = "GFN2"
metaData["name"] = "GFN2"
metaData["description"] = "Calculate atomic partial charges using GFN2 and xtb"
metaData["charges"] = True
metaData["potential"] = False
metaData["elements"] = "1-86" # up to Radon
return metaData
def charges():
# Avogadro will send us the mol file as stdin
# we need to write it to a temporary file
# get the whole file
mol = sys.stdin.read()
fd, name = tempfile.mkstemp(".mol")
os.write(fd, mol.encode())
os.close(fd)
# run xtb
xtb = which("xtb")
if xtb is None: # we check again
return ""
# for now, ignore the output itself
tempdir = tempfile.mkdtemp()
output = subprocess.run(
[xtb, name], stdout=subprocess.PIPE, cwd=tempdir, check=True
)
# instead we read the "charges" file
result = ""
with open(tempdir + "/" + "charges", "r", encoding="utf-8") as f:
result = f.read()
# try to cleanup the temporary files
os.remove(name)
for filename in os.listdir(tempdir):
try:
os.remove(tempdir + "/" + filename)
except:
continue
# and try to cleanup the directory
try:
os.rmdir(tempdir)
except:
pass
# write the charges to stdout
return result
def potential():
# at the moment, xtb doesn't have a good way to do this
# and the method shouldn't be called anyway
# if your plugin has a potential, you can return it here
# .. you'll get JSON with the file and the set of points
# e.g. { "xyz" : "xyz file contents", "points" : [ x,y,z, x,y,z, ... ] }
# or { "sdf" : "sdf file contents", "points" : [ x,y,z, x,y,z, ... ] }
# .. and you print the list of potentials to stdout
return ""
if __name__ == "__main__":
parser = argparse.ArgumentParser("GFN2 partial charges")
parser.add_argument("--display-name", action="store_true")
parser.add_argument("--metadata", action="store_true")
parser.add_argument("--charges", action="store_true")
parser.add_argument("--potential", action="store_true")
parser.add_argument("--lang", nargs="?", default="en")
args = vars(parser.parse_args())
if args["metadata"]:
print(json.dumps(getMetaData()))
elif args["display_name"]:
name = getMetaData().get("name")
if name:
print(name)
else:
raise RuntimeError("xtb is unavailable")
elif args["charges"]:
print(charges())
elif args["potential"]:
print(potential())
|