Skip to content

Commit

Permalink
Optimized the logging behavior of autosolvate.
Browse files Browse the repository at this point in the history
  • Loading branch information
fangning-ren committed Jul 14, 2024
1 parent 6a0ffdf commit 9c864de
Show file tree
Hide file tree
Showing 24 changed files with 27,572 additions and 12,774 deletions.
1 change: 1 addition & 0 deletions autosolvate/autosolvate.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class AmberParamsBuilder(object):
1. Generate standard pdb
2. AnteChamber or Gaussian charge fitting
3. Tleap create Lib
Others work with similar function: acpype
"""
def __init__(self, xyzfile:str, name = "", resname = "", charge = 0, spinmult = 1,
charge_method="resp", folder = WORKING_DIR, **kwargs):
Expand Down
2 changes: 1 addition & 1 deletion autosolvate/dockers/_antechamber_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def __init__(self,
charge_method: str = 'bcc',
out_format: str = 'mol2',
workfolder: str = WORKING_DIR,
exeoutfile: str = None,
exeoutfile: str = "antechamber.log",
eq: int = 2,
pl: int = -1,

Expand Down
2 changes: 1 addition & 1 deletion autosolvate/dockers/_general_docker.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ def execute(self, cmd):
self.logger.info("CMD: {}".format(cmd))
subprocess.run(cmd, shell = True, stdout=exeout, stderr=sys.stdout)
else:
exeout = open(self.exeoutfile, "w")
exeout = open(self.exeoutfile, "a")
self.logger.info("CMD: {}".format(cmd))
subprocess.run(cmd, shell = True, stdout=exeout, stderr=sys.stdout)
exeout.close()
Expand Down
21 changes: 16 additions & 5 deletions autosolvate/molecule/molecule.py
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ def __setattr__(self, __name: str, __value: Any) -> None:
else:
if __name in self._FILEATTR_FILEPATH_DICT:
self._FILEATTR_FILEPATH_DICT[__name] = __value
self.logger.warning("The '{:s}' file of system '{:s}' is set to a non-existent path '{:s}'".format(__name, self.name, __value))
if not (hasattr(self, "amber_solvent") and self.amber_solvent):
self.logger.warning("The '{:s}' file of system '{:s}' is set to a non-existent path '{:s}'".format(__name, self.name, __value))
else:
self.logger.debug("set the '{:s}' attribute of system '{:s}' as {:s}".format(__name, self.name, __value))
else:
Expand Down Expand Up @@ -120,7 +121,7 @@ def check_exist(self, extensions:List[str]) -> bool:
self.logger.debug("The '{:s}' file of system '{:s}' is not defined".format(ext, self.name))
elif not isinstance(self.__getattribute__(ext), str):
flag *= False
self.logger.debug("The '{:s}' attribute of system '{:s}' does noe exist".format(ext, self.name))
self.logger.debug("The '{:s}' attribute of system '{:s}' does not exist".format(ext, self.name))
elif not os.path.isfile(self.__getattribute__(ext)):
flag *= False
self.logger.debug("The '{:s}' file of system '{:s}' does not exist".format(ext, self.name))
Expand Down Expand Up @@ -296,6 +297,13 @@ def generate_pdb(self):
shutil.move(self.pdb, self.reference_name + "-bak.pdb")
self.logger.info(f"Converted the prep file {self.prep} to pdb file {self.pdb}")
prep2pdb(self)
elif self.check_exist("lib") or self.check_exist("off"):
newpath = self.reference_name + ".pdb"
if self.check_exist("pdb"):
self.logger.warning(f"The existing pdb file {self.pdb} will be ignored as amber lib/off file is provided.")
shutil.move(self.pdb, self.reference_name + "-bak.pdb")
self.logger.info(f"Converted the lib file {self.lib} to pdb file {self.pdb}")
lib2pdb(self)
elif self.check_exist("mol2"):
newpath = self.reference_name + ".pdb"
if self.check_exist("pdb"):
Expand All @@ -318,9 +326,12 @@ def get_residue_name(self):
Note if the mol2, or prep file is provided, the 'residue_name' attribute will be updated according to these files instead of the argument 'residue_name'.
"""
new_residue_name = ""
if self.check_exist("prep"): # 这里必须要改。都已经知道residue name了就没有必要从prep文件里获取了。必须找到从prep文件中直接读取residue name的方法,或者找到把prep文件转换成pdb文件并且不借助residue name的方法。
prep2pdb_withexactpath(self.prep, self.reference_name + "-fromprep.pdb", self.residue_name)
new_residue_name = get_residue_name_from_pdb(self.reference_name + "-fromprep.pdb")
if self.check_exist("prep"):
new_residue_name = extract_residue_name_from_prep(self.prep)
elif self.check_exist("lib"):
new_residue_name = extract_residue_name_from_lib(self.lib)
elif self.check_exist("off"):
new_residue_name = extract_residue_name_from_lib(self.off)
elif self.check_exist("mol2"):
newpath = self.reference_name + "-frommol2.pdb"
subprocess.run(f"obabel -i mol2 {self.mol2} -o pdb -O {newpath} ---errorlevel 0", shell = True)
Expand Down
5 changes: 3 additions & 2 deletions autosolvate/molecule/molecule_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,8 +65,6 @@ def __init__(self,
self.residue_name = "SYS" if not residue_name else residue_name
self.number = 0
self.read_coordinate(xyzfile)
super(MoleculeComplex, self).__init__(name = self.name)
self.logger.name = self.__class__.__name__

self.mol_obmol = pybel.readfile("pdb", self.pdb).__next__().OBMol
self.fragresiduenames = [] # name of each fragment
Expand All @@ -82,6 +80,9 @@ def __init__(self,

self.aminoacidresidues = AMINO_ACID_RESIDUES

super(MoleculeComplex, self).__init__(name = self.name)
self.logger.name = self.__class__.__name__

if reorder_pdb:
reorderPDB(self.pdb, self.pdb)
self.build_molecules()
Expand Down
2 changes: 1 addition & 1 deletion autosolvate/molecule/transition_metal_complex.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ def __init__(
name : str, optional
The name of the transition metal complex, by default "", which means the name will be generated from the pdb file.
residue_name : str, optional
The residue name of the transition metal complex, by default "MOL".
The residue name of the transition metal complex. Not required as the metal and each legand has its unique name. by default "MOL".
folder : str, optional
The folder to store the files generated by this class, by default WORKING_DIR.
"""
Expand Down
80 changes: 39 additions & 41 deletions autosolvate/multicomponent.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@
# author: Fangning Ren (2022-02-04)
# path: autosolvate/multicomponent.py
#--------------------------------------------------------------------------------------------------#
# Update 2024-07-12:
# 1. Add a MixtureBuilder class to generate mixed solventbox for both single solute and molecular pairs
# 2. Now accept pre-generated prep, lib, and off files if the frcmod file is provided.
# 3. Mixed solvent with amber defined solvent such as TIP3P water, methanol are enabled.
#--------------------------------------------------------------------------------------------------#
import getopt, sys, os
import subprocess
from typing import List, Tuple, Iterable
Expand All @@ -27,7 +32,9 @@

class MulticomponentParamsBuilder():
"""
Create amber parameter files for a single xyz or pdb file with multiple separate fragments
Create amber parameter files for a single xyz or pdb file with multiple separate fragments.
Warning: If you want to create the forcefield for transition metal complexes please use the ```boxgen_metal``` module instead of ```boxgen_multicomponent```.
Parameters
----------
Expand Down Expand Up @@ -186,6 +193,8 @@ class MixtureBuilder():
Solute-solvent closeness setting, corresponding to the tolerance parameter in packmol in Å,
charge_method : str, Optional, default: "bcc"
name of charge fitting method (bcc, resp)
prefix : str, Optional, default: None
prefix of the output file names. Default will be <solute_name>_<solvent_name_1>_...-<solvent_name_n>
"""
def __init__(self, folder = WORKING_DIR, cube_size = 54, closeness = 2.0, charge_method = "bcc", prefix = None):
self.solutes = []
Expand Down Expand Up @@ -218,7 +227,7 @@ def add_complex_solute(self, xyzfile:str, fragment_charge = 0, fragment_spinmult
Parameters
----------
xyzfile : str
structure file name, can be any type within ["xyz", "pdb", "mol2"]. frcmod are not supported for molecular complex.
structure file name, can be any type within ["xyz", "pdb", "mol2"]. "prep", "lib", "off" are not supported for molecular complex.
fragment_charge : dict | array_like, Optional, default: 0
Charge for each fragment. A dictionary with the three-letter name of the residue as the key and the corresponding charge as the value. If not given, all fragment will be considered as neutral.
fragment_spinmult : dict | array_like, Optional, default: 1
Expand Down Expand Up @@ -255,12 +264,13 @@ def add_solute(self, xyzfile:str, name="", residue_name="SLU", charge=0, spinmul
number : int, Optional, default: 1
number of the solute in the system.
**kwargs : dict
additional files needed for the solute, including "mol2", "frcmod", "lib", "prep".
additional files needed for the solute, including "mol2", "frcmod", "lib", "prep", and "off". Will support "itp", "top" in the future.
If the user want to skip the antechamber and leap steps, the user need to provide the "mol2" and "frcmod" files by adding the following arguments:
mol2 : str
the path of the mol2 file of the solute
frcmod : str
the path of the frcmod file of the solute
mol2 : str
the path of the mol2 file of the solute
frcmod : str
the path of the frcmod file of the solute
"""

if ("mol2" in kwargs and os.path.isfile(kwargs["mol2"])) and \
Expand Down Expand Up @@ -380,9 +390,9 @@ def build(self):
system_name = "-".join([m.name for m in self.solutes] + [m.name for m in self.solvents])
else:
system_name = self.systemprefix
self.solutes:List[Molecule]
self.solutes :List[Molecule]
self.solvents:List[Molecule]
solute_numbers = [m.number for m in self.solutes]
solute_numbers = [m.number for m in self.solutes ]
solvent_numbers = [m.number for m in self.solvents]
system = SolvatedSystem(system_name, solute = self.solutes, solvent = self.solvents,
cubesize=self.boxsize, closeness=self.closeness,
Expand Down Expand Up @@ -428,15 +438,7 @@ def startmulticomponent_fromfile(file:str):
def create_parser_multicomponent():
parser = argparse.ArgumentParser(
description='Add solvent box to a given solute and generate related force field parameters.',
epilog='''
suggest usage: autosolvate multicomponent -f input.json \n
if an input file is provided, all command line options will be ignored. \n
If using command line as the traditional way, it will only generate a single solute with single solvent. \n
This is a legacy feature, designed solely for the compatibility with the older version. It is not recommended for further use.
''',
epilog="suggest usage: autosolvate multicomponent -f input.json \nif an input file is provided, all command line options will be ignored. \nIf using command line as the traditional way, it will only generate a single solute with single solvent. \nThis is a legacy feature, designed solely for the compatibility with the older version. It is not recommended for further use."
)

parser.add_argument('-f', '--file', type=str, help='json file containing the input parameters. Will ignore all other options if provided. Required when using multiple solvents')
Expand All @@ -459,43 +461,39 @@ def startmulticomponent(args):
Wrap function that parses command line options for autosolvate multicomponent module,
generate solvent box and related force field parameters.
Parameters
Command Line Options
----------
None
Command line option definitions
-f, --file
json file containing the input parameters, Required when using multiple solvents
-m, --main
solute xyz file, not suggested to use when using multiple solvents
-o, --output
-f, --file
json file containing the input parameters, Required when using multiple solvents. Will ignore all other options if provided.
-m, --main
solute xyz file, An Legacy feature, designed for the compatibility with the older version. It is not recommended for further use.
-o, --output
prefix of the output file names
-c, --charge
-c, --charge
formal charge of solute
-u, --spinmultiplicity
-u, --spinmultiplicity
spin multiplicity of solute
-s, --solvent
solvent xyz files, Will use single solvent if provided. Not suggested to use when using multiple solvents
-g, --chargemethod
-s, --solvent
solvent xyz files, Will use single solvent if provided. Not available for using multiple solvents
-g, --chargemethod
name of charge fitting method (bcc, resp)
-b, --cubesize
-b, --cubesize
size of solvent cube in angstroms
-t, --closeness
Solute-solvent closeness setting, for acetonitrile tolerance parameter in packmol in Å, for water, methanol, nma, chloroform the scaling factor in tleap, setting to 'automated' will automatically set this parameter based on solvent.
-r, --srunuse
-t, --closeness
Solute-solvent closeness setting. Default 2.0 Å for mixed solvent. For acetonitrile tolerance parameter in packmol in Å, for water, methanol, nma, chloroform the scaling factor in tleap, setting to 'automated' will automatically set this parameter based on solvent.
-r, --srunuse
option to run inside a slurm job
-e, --gaussianexe
-e, --gaussianexe
name of the Gaussian quantum chemistry package executable used to generate electrostatic potential needed for RESP charge fitting
-d, --gaussiandir
-d, --gaussiandir
path to the Gaussian package
-a, --amberhome
-a, --amberhome
path to the AMBER molecular dynamics package root directory. Definition of the environment variable $AMBERHOME
-h, --help
-h, --help
short usage description
Returns
-------
None
Generates the structure files and save as ```.pdb```. Generates the MD parameter-topology and coordinates files and saves as ```.prmtop``` and ```.inpcrd```
"""
#print(argumentList)
Expand Down
Loading

0 comments on commit 9c864de

Please sign in to comment.