# @file generator.py
# Main script that coordinates all parts of the program.
#
# Written by Kulik Group
#
# Department of Chemical Engineering, MIT
import os
import sys
import glob
import argparse
import copy
from molSimplify.Classes.globalvars import (globalvars)
from molSimplify.Scripts.addtodb import addtoldb
from molSimplify.Scripts.io import loadcdxml
from molSimplify.Scripts.cellbuilder import (slab_module_supervisor)
from molSimplify.Scripts.chains import (chain_builder_supervisor)
from molSimplify.Scripts.dbinteract import (dbsearch)
from molSimplify.Scripts.findcorrelations import (analysis_supervisor)
from molSimplify.Scripts.inparse import (checkinput,
cleaninput,
parseall,
parseinputfile)
from molSimplify.Scripts.postproc import (postproc)
from molSimplify.Scripts.rungen import (constrgen,
multigenruns,
draw_supervisor)
[docs]def startgen_pythonic(input_dict={'-core': 'fe', '-lig': 'cl,cl,cl,cl,cl,cl'},
argv=['main.py', '-i', 'asdfasdfasdfasdf'],
flag=True,
gui=False,
write=False):
"""This is the main way to generate structures completely within Python.
Parameters
----------
input_dict : dict
Argument list in the form of a dictionary.
argv : list
Default argument list used to "fool" startgen into accepting input_dict.
flag : bool, optional
Flag for printing information. Default is True.
gui : bool, optional
Flag for GUI. Default is False.
write : bool, optional
Flag to generate outputfile from python
Returns
-------
strfiles : str
Folder containing the runs.
emsg : bool
Flag for error. If error, returns a string with error.
this_diag : rundiag
Rundiag class instance that contains ANN attributes (this_diag.ANN_attributes)
and a mol3D class instance (this_diag.mol).
"""
# from molSimplify.Scripts.generator import startgen_pythonic
inputfile_str = '\n'.join([k + ' ' + v for k, v in list(input_dict.items())])
if write:
startgen(argv, flag, gui, inputfile_str, write_files=write)
else:
strfiles, emsg, this_diag = startgen(argv, flag, gui, inputfile_str, write_files=write)
return (strfiles, emsg, this_diag)
# Coordinates subroutines
# @param argv Argument list
# @param flag Flag for printing information
# @param gui Flag for GUI
# @return Error messages
[docs]def startgen(argv, flag, gui, inputfile_str=None, write_files=True):
"""Coordinates subroutines.
Parameters
----------
argv : list
Argument list.
flag : bool
Flag for printing information.
gui : bool
Flag for GUI.
inputfile_str : str, optional
Optional input passed in as a string. Default is None.
write_files : bool, optional
Flag for whether or not files should be written. Should set to false for pythonic generation.
Returns
-------
emsg : bool
Flag for error. If error, returns a string with error.
"""
emsg = False
# check for configuration file
# homedir = os.path.expanduser("~")
# configfile = False if not glob.glob(homedir+'/.molSimplify') else True
# if not configfile:
# print("It looks like the configuration file '~/.molSimplify' does not exist!"
# "Please follow the next steps to configure the file.")
# instdir = raw_input("Please select the full path of the top installation directory for the program: ")
# cdbdir = raw_input("Please specify the full path of the directory containing chemical databases:")
# mwfn = raw_input("Specify the full path to the Multiwfn executable (for post-processing):")
# with open(homedir+'/.molSimplify','w') as f:
# if len(instdir) > 1:
# f.write("INSTALLDIR="+instdir+'\n')
# if len(cdbdir) > 1:
# f.write("CHEMDBDIR="+cdbdir+'\n')
# if len(mwfn) > 1 :
# f.write("MULTIWFN="+mwfn[0]+'\n')
# ## end set-up configuration file ###
# ########### GLOBALS DEFINITION ############
globs = globalvars()
# installdir = globs.installdir
rundir = globs.rundir
PROGRAM = globs.PROGRAM
# ##### END GLOBALS DEFINITION ##############
# correct installdir
# if installdir[-1]!='/':
# installdir+='/'
# print welcome message
ss = "\n************************************************************"
ss += "\n******** Welcome to "+PROGRAM+"! Let's get started. ********\n"
ss += "************************************************************\n\n"
if not flag:
print(ss)
sys.argv = argv
parser = argparse.ArgumentParser()
args = parseall(parser)
# check if input file exists
if not glob.glob(args.i) and not inputfile_str:
emsg = 'Input file '+args.i+' does not exist. Please specify a valid input file.\n'
print(emsg)
return emsg
args.gui = gui # add gui flag
# parse input file
if args.i or inputfile_str:
parseinputfile(args, inputfile_str=inputfile_str)
if args.cdxml:
print('converting cdxml file into xyz')
cdxml = args.cdxml[0]
fname, msg = loadcdxml(cdxml)
print(msg)
if 'two' in msg:
core = fname + '_cat.xyz'
sub = fname + '_sub.xyz'
args.core = [core]
args.substrate = [sub]
args.tsgen = True
if args.custom_data_dir is not None:
globs.custom_path = args.custom_data_dir
# if not args.postp and not args.dbsearch and not args.dbfinger and not args.drawmode
# and not (args.slab_gen or args.place_on_slab) and not (args.chain) and not (args.correlate):
# check input arguments
if (not args.postp and not args.dbsearch and not args.dbfinger
and not (args.slab_gen or args.place_on_slab)
and not (args.chain) and not (args.correlate)):
# check input arguments
print('Checking input...')
if args.tsgen:
emsg = checkinput(args, calctype="tsgen")
elif args.ligadd:
emsg = checkinput(args, calctype="dbadd")
else:
emsg = checkinput(args)
# check before cleaning input arguments and clean only if checked
cleaninput(args)
args.gui = False # deepcopy will give error
if emsg:
del args
return emsg
# check for jobs directory
rundir = args.rundir+'/' if (args.rundir) else rundir
if not os.path.isdir(rundir):
if write_files:
os.mkdir(rundir)
# ################## START MAIN ####################
args0 = copy.deepcopy(args) # save initial arguments
# add gui flag
args.gui = gui
# postprocessing run?
if (args.postp):
postproc(rundir, args, globs)
# database search?
elif (args.dbsearch or args.dbfinger):
emsg = dbsearch(rundir, args, globs)
if emsg:
del args
return emsg
else:
print('Successful database search!\n')
# random generation?
elif (args.rgen): # check if random generation was requested
if args.charge:
args.charge = args.charge[0]
if args.spin:
args.spin = args.spin[0]
corests = args.core
for cc in corests:
args = copy.deepcopy(args0)
# add gui flag
args.gui = gui
args.core = cc
if (args.lig or args.coord or args.lignum or args.ligocc): # constraints given?
args, emsg = constrgen(rundir, args)
if emsg:
del args
return emsg
else:
emsg = 'For random generation specify at least a ligand, coordination or ligand types.\n'
print(emsg)
del args
return emsg
elif args.drawmode:
draw_supervisor(args, rundir)
# slab/place on slab?
elif (args.slab_gen or args.place_on_slab):
emsg = slab_module_supervisor(args, rundir)
# chain builder
elif (args.chain):
print('chain on')
emsg = chain_builder_supervisor(args, rundir)
# correlation analysis
elif (args.correlate):
print('analysis is looking for correlations')
analysis_supervisor(args, rundir)
# add ligand to list
elif (args.ligadd):
print(('adding ' + str(args.ligadd) + ' to ligand database with name ' +
args.ligname + ' and connection atom(s) ' + str(args.ligcon)))
addtoldb(smimol=args.ligadd, sminame=args.ligname, smident=len(args.ligcon),
smicat=str(args.ligcon).strip('[]'), smigrps="custom", smictg="custom", ffopt=args.ligffopt)
# normal structure generation or transition state building
else:
args = copy.deepcopy(args0)
# add gui flag
args.gui = gui
corests = args.core
# if args.tsgen: # goes through multigenruns for maximum interoperability
# print('building a transition state')
if args.tsgen: # goes through multigenruns for maximum interoperability
print('building a transition state')
else:
print('building an equilibrium complex')
for cc in corests:
args.core = cc
emsg = multigenruns(rundir, args, write_files=write_files)
if emsg:
print(emsg)
del args
return emsg
ss = "\n**************************************************************"
ss += "\n***** Thank you for using "+PROGRAM+". Have a nice day! ******\n"
ss += "**************************************************************"
ss += globs.about
if not flag:
print(ss)
del args
return emsg