MayaChemTools

    1 #!/bin/env python
    2 #
    3 # File: OpenFECalculateAbsoluteBindingFreeEnergy.py
    4 # Author: Manish Sud <msud@san.rr.com>
    5 #
    6 # Copyright (C) 2026 Manish Sud. All rights reserved.
    7 #
    8 # The functionality available in this script is implemented using OpenFE, an
    9 # open source package for alchemical free energy calculations.
   10 #
   11 # This file is part of MayaChemTools.
   12 #
   13 # MayaChemTools is free software; you can redistribute it and/or modify it under
   14 # the terms of the GNU Lesser General Public License as published by the Free
   15 # Software Foundation; either version 3 of the License, or (at your option) any
   16 # later version.
   17 #
   18 # MayaChemTools is distributed in the hope that it will be useful, but without
   19 # any warranty; without even the implied warranty of merchantability of fitness
   20 # for a particular purpose.  See the GNU Lesser General Public License for more
   21 # details.
   22 #
   23 # You should have received a copy of the GNU Lesser General Public License
   24 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or
   25 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330,
   26 # Boston, MA, 02111-1307, USA.
   27 #
   28 
   29 from __future__ import print_function
   30 
   31 import os
   32 import sys
   33 import time
   34 import re
   35 import logging
   36 import pathlib
   37 import pandas as pd
   38 
   39 # OpenFE imports...
   40 try:
   41     import openfe
   42     from openfe.protocols.openmm_afe import AbsoluteBindingProtocol
   43 except ImportError as ErrMsg:
   44     sys.stderr.write("\nFailed to import OpenFE related module/package: %s\n" % ErrMsg)
   45     sys.stderr.write("Check/update your OpenFE environment and try again.\n\n")
   46     sys.exit(1)
   47 
   48 # RDKit imports...
   49 try:
   50     from rdkit import rdBase
   51 except ImportError as ErrMsg:
   52     sys.stderr.write("\nFailed to import RDKit module/package: %s\n" % ErrMsg)
   53     sys.stderr.write("Check/update your RDKit environment and try again.\n\n")
   54     sys.exit(1)
   55 
   56 # MayaChemTools imports...
   57 sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "..", "lib", "Python"))
   58 try:
   59     from docopt import docopt
   60     import MiscUtil
   61     import OpenFEUtil
   62 except ImportError as ErrMsg:
   63     sys.stderr.write("\nFailed to import MayaChemTools module/package: %s\n" % ErrMsg)
   64     sys.stderr.write("Check/update your MayaChemTools environment and try again.\n\n")
   65     sys.exit(1)
   66 
   67 ScriptName = os.path.basename(sys.argv[0])
   68 Options = {}
   69 OptionsInfo = {}
   70 
   71 
   72 def main():
   73     """Start execution of the script."""
   74 
   75     MiscUtil.PrintInfo(
   76         "\n%s (OpenFE v%s; OpenMM v%s; RDKit v%s; MayaChemTools v%s; %s): Starting...\n"
   77         % (
   78             ScriptName,
   79             openfe.version("openfe"),
   80             openfe.version("openmm"),
   81             rdBase.rdkitVersion,
   82             MiscUtil.GetMayaChemToolsVersion(),
   83             time.asctime(),
   84         )
   85     )
   86 
   87     (WallClockTime, ProcessorTime) = MiscUtil.GetWallClockAndProcessorTime()
   88 
   89     # Retrieve command line arguments and options...
   90     RetrieveOptions()
   91 
   92     if Options["--list"]:
   93         ProcessListOption()
   94     else:
   95         # Process and validate command line arguments and options...
   96         ProcessOptions()
   97 
   98         # Perform actions required by the script...
   99         CalculateAbsoluteBindingFreeEnergy()
  100 
  101     MiscUtil.PrintInfo("\n%s: Done...\n" % ScriptName)
  102     MiscUtil.PrintInfo("Total time: %s" % MiscUtil.GetFormattedElapsedTime(WallClockTime, ProcessorTime))
  103 
  104 
  105 def CalculateAbsoluteBindingFreeEnergy():
  106     """Calculate absolute binding free energy."""
  107 
  108     # Process input files...
  109     MacroMol, InMols = ProcessInputFiles()
  110 
  111     # Process molecule names...
  112     Mols = ProcessMoleculeNames(InMols)
  113 
  114     # Check for missing partial charges...
  115     CheckMissingPartialCharges(Mols)
  116 
  117     # Initialize ABFE protocols...
  118     ABFEProtocol = InitializeAbsoluteBindingProtocol()
  119 
  120     # Initialize solvent...
  121     Solvent = InitializeSolventComponent()
  122 
  123     # Setup transformations...
  124     MolTransformations = SetupTransformations(MacroMol, Mols, Solvent, ABFEProtocol)
  125 
  126     # Setup protocol DAGs...
  127     MolProtocolDAGs = SetupProtocolDAGs(MolTransformations)
  128 
  129     # Execute protocol DAGs and gather results...
  130     MolProtocolResults = ExecuteProtocolDAGsAndGatherResults(MolTransformations, MolProtocolDAGs)
  131 
  132     # Process protocol results...
  133     ProcessProtocolResults(MolTransformations, MolProtocolResults)
  134 
  135 
  136 def InitializeAbsoluteBindingProtocol():
  137     """Initialize absolute solvation protocol."""
  138 
  139     MiscUtil.PrintInfo("\nInitializing absolute solvation protocol...")
  140 
  141     ABFESettings = OpenFEUtil.SetupAbsoluteBindingFreeEnergySettings("-a, --abfeParams", OptionsInfo["ABFEParams"])
  142     ABFEProtocol = OpenFEUtil.InitializeAbsoluteBindingFreeEngeryProtocol(ABFESettings)
  143 
  144     return ABFEProtocol
  145 
  146 
  147 def InitializeSolventComponent():
  148     """Initialize solvent component."""
  149 
  150     SolventParams = OptionsInfo["SolventParams"]
  151     MiscUtil.PrintInfo(
  152         "\nInitializing solvent component (PositiveIon: %s; NegativeIon: %s; Neutralize: %s; IonConcentration: %s)..."
  153         % (
  154             SolventParams["PositiveIon"],
  155             SolventParams["NegativeIon"],
  156             SolventParams["Neutralize"],
  157             SolventParams["IonConcentration"],
  158         )
  159     )
  160 
  161     Solvent = OpenFEUtil.InitializeSolventComponent(SolventParams)
  162 
  163     return Solvent
  164 
  165 
  166 def SetupTransformations(MacroMol, Mols, Solvent, ABFEProtocol):
  167     """Set up transformations for molecules."""
  168 
  169     MiscUtil.PrintInfo("\nSetting up transformations (Count: %s)..." % (len(Mols)))
  170 
  171     MolTransformations = []
  172 
  173     for Mol in Mols:
  174         # Setup a chemical system for a molecule fully interacting with protein in the solvent...
  175         ComplexSolventSystem = OpenFEUtil.InitializeChemicalSystem(
  176             SmallMol=Mol, MacroMol=MacroMol, Solvent=Solvent, Name="%s_Complex_Solvent" % Mol.name
  177         )
  178 
  179         # Setup a system for a molecule fully decoupled in the solvent: Only need to use the protein and solvent....
  180         ProteinSolventSystem = OpenFEUtil.InitializeChemicalSystem(
  181             SmallMol=None, MacroMol=MacroMol, Solvent=Solvent, Name="Protein_Solvent"
  182         )
  183 
  184         # Setup a transformation for absolute binding protocol from ComplexSolventSystem to ProteinSolventSystem.
  185         # The AbsoluteBindingProtocol automatically creates the separate solvents state based on the complex states.
  186         TransformationName = "%s_AbsoluteBinding" % (Mol.name)
  187         MolTransformation = OpenFEUtil.InitializeTransformation(
  188             StateA=ComplexSolventSystem,
  189             StateB=ProteinSolventSystem,
  190             Mapping=None,
  191             Protocol=ABFEProtocol,
  192             Name=TransformationName,
  193             Validate=False,
  194         )
  195 
  196         MolTransformations.append(MolTransformation)
  197 
  198     # Write out transformations...
  199     WriteTransformations(MolTransformations)
  200 
  201     return MolTransformations
  202 
  203 
  204 def WriteTransformations(MolTransformations):
  205     """Write out transformations."""
  206 
  207     TransformationsOutDirPath = pathlib.Path(OptionsInfo["TransformationsOutDirPath"])
  208 
  209     MiscUtil.PrintInfo(
  210         "Writing transformations files (Files: *.json; Count: %s; Subdirectory: %s)..."
  211         % (len(MolTransformations), OptionsInfo["TransformationsOutDir"])
  212     )
  213 
  214     for Transformation in MolTransformations:
  215         TransformationFilePath = TransformationsOutDirPath.joinpath("%s.json" % Transformation.name)
  216         Transformation.dump(TransformationFilePath)
  217 
  218 
  219 def SetupProtocolDAGs(MolTransformations):
  220     """Setup protocol Directed Acyclic Graphs (DAGs) for each transformation to
  221     to perform calculations.
  222     """
  223 
  224     MiscUtil.PrintInfo("\nSetting up protocol DAGs (Count: %s)..." % len(MolTransformations))
  225 
  226     MolProtocolDAGs = []
  227     for Transformation in MolTransformations:
  228         ProtocolDAG = OpenFEUtil.InitializeProtocolDAG(Transformation, Name=Transformation.name)
  229         MolProtocolDAGs.append(ProtocolDAG)
  230 
  231     return MolProtocolDAGs
  232 
  233 
  234 def ExecuteProtocolDAGsAndGatherResults(MolTransformations, MolProtocolDAGs):
  235     """Execute protocol DAGs and gather results."""
  236 
  237     ResultsSharedOutDirPath = OptionsInfo["ResultsOutDirPath"]
  238     ResultsScratchOutDirPath = OptionsInfo["ResultsScratchOutDirPath"]
  239     ExecuteDAGParams = OptionsInfo["ExecuteDAGParams"]
  240 
  241     MolProtocolResults = OpenFEUtil.ExecuteProtocolDAGsAndGatherResults(
  242         MolTransformations,
  243         MolProtocolDAGs,
  244         ResultsSharedOutDirPath,
  245         ResultsScratchOutDirPath,
  246         KeepShared=ExecuteDAGParams["KeepShared"],
  247         KeepScratch=ExecuteDAGParams["KeepScratch"],
  248         NRetries=ExecuteDAGParams["NRetries"],
  249         WriteResults=True,
  250     )
  251 
  252     return MolProtocolResults
  253 
  254 
  255 def ProcessProtocolResults(MolTransformations, MolProtocolResults):
  256     """Process protocol results."""
  257 
  258     ResultFileParams = OptionsInfo["ResultFileParams"]
  259 
  260     ResultFile = "%s_ABFE_Results.%s" % (OptionsInfo["OutfilePrefix"], ResultFileParams["Ext"])
  261     ResultFilePath = os.path.join(OptionsInfo["OutfileDirPath"], ResultFile)
  262     MiscUtil.PrintInfo("\nWriting %s..." % ResultFile)
  263 
  264     Precision = ResultFileParams["Precision"]
  265 
  266     ResultData = []
  267     for Index in range(0, len(MolProtocolResults), 1):
  268         MolProtocolResult = MolProtocolResults[Index]
  269 
  270         # Setup mol name using transformation...
  271         MolTransformation = MolTransformations[Index]
  272         Mol = MolTransformation.stateA.components["ligand"]
  273         MolName = Mol.name
  274 
  275         if MolProtocolResult is None:
  276             DeltaGBinding = "NA"
  277             DeltaGBindingUncertainty = "NA"
  278         else:
  279             # Setup binding value without the units...
  280             DeltaGBinding = MolProtocolResult.get_estimate()
  281             DeltaGBinding = "%.*f" % (Precision, DeltaGBinding.m)
  282 
  283             # Setup uncertainty value without the units...
  284             DeltaGBindingUncertainty = MolProtocolResult.get_uncertainty()
  285             DeltaGBindingUncertainty = "%.*f" % (Precision, DeltaGBindingUncertainty.m)
  286 
  287         ResultData.append([MolName, DeltaGBinding, DeltaGBindingUncertainty])
  288 
  289     ResultDF = pd.DataFrame(ResultData, columns=["MolName", "ABFE DeltaG (kcal/mol)", "Uncertainty (kcal/mol)"])
  290     ResultDF.to_csv(ResultFilePath, sep=ResultFileParams["Delim"], lineterminator="\n", index=False)
  291 
  292 
  293 def ProcessInputFiles():
  294     """Process input files."""
  295 
  296     # Read PDB file...
  297     MiscUtil.PrintInfo("\nReading PDB file %s..." % OptionsInfo["Infile"])
  298     MacroMol = OpenFEUtil.ReadPDBFile(OptionsInfo["InfilePath"], Name=OptionsInfo["InfileRoot"])
  299 
  300     # Read small molecule input file...
  301     MiscUtil.PrintInfo("\nReading small molecule file %s..." % OptionsInfo["SmallMolFile"])
  302     Mols, MolCount, ValidMolCount = OpenFEUtil.ReadAndValidateMolecules(
  303         OptionsInfo["SmallMolFilePath"], **OptionsInfo["SmallMolFileParams"]
  304     )
  305 
  306     MiscUtil.PrintInfo("\nTotal number of molecules: %d" % MolCount)
  307     MiscUtil.PrintInfo("Number of valid molecules: %d" % ValidMolCount)
  308     MiscUtil.PrintInfo("Number of ignored molecules: %d" % (MolCount - ValidMolCount))
  309 
  310     if ValidMolCount == 0:
  311         MiscUtil.PrintInfo("")
  312         MiscUtil.PrintError("No valid molecules found in small molecule input file.\n")
  313 
  314     return (MacroMol, Mols)
  315 
  316 
  317 def ProcessMoleculeNames(Mols):
  318     """Process molecule names."""
  319 
  320     SpecifiedMols = []
  321     if OptionsInfo["FirstMoleculeMode"]:
  322         SpecifiedMols.append(Mols[0])
  323     elif OptionsInfo["AllMoleculesMode"]:
  324         SpecifiedMols = Mols
  325     elif OptionsInfo["MoleculesNamesMode"]:
  326         SpecifiedMols = OpenFEUtil.ProcessMoleculeNames(Mols, OptionsInfo["MoleculeNamesList"])
  327 
  328     return SpecifiedMols
  329 
  330 
  331 def CheckMissingPartialCharges(Mols):
  332     """Check missing partial charges for small molecules."""
  333 
  334     MiscUtil.PrintInfo("\nChecking missing partial charges for small molecules...")
  335 
  336     MissingChargesMolCount = OpenFEUtil.GetMissingPartialChargesMolCount(Mols)
  337     MiscUtil.PrintInfo("Number of molecules with missing partial charges: %s" % MissingChargesMolCount)
  338 
  339     if MissingChargesMolCount == 0:
  340         return
  341 
  342     if re.match("^Stop$", OptionsInfo["MissingChargeMode"], re.I):
  343         MiscUtil.PrintInfo("")
  344         MiscUtil.PrintError(
  345             'The small molecule input file contains molecules with missing partial charges. The execution of the script has been terminated for "Stop" value of "--missingChargedMode" option. You may continue the execution of the script by specifying "Calculate" value for "--missingChargedMode" option.\n\nThe missing charges will be automatically calculated by OpenFE AbsoluteBindingProtocol module during the calculation of ABFE. You may control the calculation of partial charges by specifying values for partialCharge* parameters using "--abfe" option.  Alternatively, you may employ the OpenFECalculatePartialCharges.py script to calculate partial charges and use the small molecule input file containing charges to calculate ABFE.\n'
  346         )
  347     else:
  348         MiscUtil.PrintInfo("")
  349         MiscUtil.PrintWarning(
  350             'The small molecule input file contains molecules with missing partial charges. The missing charges will be automatically calculated by OpenFE AbsoluteBindingProtocol module during the calculation of ABFE. You may control the calculation of partial charges by specifying values for partialCharge* parameters using "--abfeParams" option. Alternatively, you may employ the OpenFECalculatePartialCharges.py script to calculate partial charges and use the small molecule input file containing charges to calculate ABFE.\n'
  351         )
  352 
  353 
  354 def ProcessMoleculeNamesOption():
  355     """Process molecule names Option."""
  356 
  357     OptionsInfo["MoleculeNames"] = Options["--moleculeNames"]
  358     OptionsInfo["MoleculeNamesList"] = None
  359 
  360     if OptionsInfo["MoleculeNames"] is None:
  361         return
  362 
  363     MoleculeNamesList = []
  364     for MoleculeName in OptionsInfo["MoleculeNames"].split(","):
  365         MoleculeNamesList.append(MoleculeName.strip())
  366 
  367     OptionsInfo["MoleculeNamesList"] = MoleculeNamesList
  368 
  369 
  370 def ProcessOutfilePrefixOption():
  371     """Process outfile prefix option."""
  372 
  373     OutfilePrefix = Options["--outfilePrefix"]
  374 
  375     if re.match("^auto$", OutfilePrefix, re.I):
  376         OutfilePrefix = OptionsInfo["SmallMolFileRoot"]
  377 
  378     OptionsInfo["OutfilePrefix"] = OutfilePrefix
  379 
  380 
  381 def ProcessOutfileDirOption():
  382     """Process outfile directory Option."""
  383 
  384     # Setup output directory...
  385     OutfileDir = Options["--outfileDir"]
  386     OutfileDirPath = os.path.abspath(OutfileDir)
  387     if not os.path.exists(OutfileDir):
  388         MiscUtil.PrintInfo("\nCreating output directory %s..." % (OutfileDir))
  389         os.mkdir(OutfileDirPath)
  390     OptionsInfo["OutfileDir"] = OutfileDir
  391     OptionsInfo["OutfileDirPath"] = OutfileDirPath
  392 
  393     # Setup a transformations subdirectory...
  394     TransformationsOutDir = "Transformations"
  395     TransformationsOutDirPath = os.path.join(OptionsInfo["OutfileDirPath"], TransformationsOutDir)
  396     if not os.path.exists(TransformationsOutDirPath):
  397         os.mkdir(TransformationsOutDirPath)
  398     OptionsInfo["TransformationsOutDir"] = TransformationsOutDir
  399     OptionsInfo["TransformationsOutDirPath"] = TransformationsOutDirPath
  400 
  401     # Setup a results subdirectory...
  402     ResultsOutDir = "Results"
  403     ResultsOutDirPath = os.path.join(OptionsInfo["OutfileDirPath"], ResultsOutDir)
  404     if not os.path.exists(ResultsOutDirPath):
  405         os.mkdir(ResultsOutDirPath)
  406     OptionsInfo["ResultsOutDir"] = ResultsOutDir
  407     OptionsInfo["ResultsOutDirPath"] = ResultsOutDirPath
  408 
  409     # Use results subdirectory for scratch results...
  410     OptionsInfo["ResultsScratchOutDir"] = ResultsOutDir
  411     OptionsInfo["ResultsScratchOutDirPath"] = ResultsOutDirPath
  412 
  413 
  414 def ProcessListOption():
  415     """Process list protocol settings option."""
  416 
  417     ABFESettings = AbsoluteBindingProtocol.default_settings()
  418 
  419     MiscUtil.PrintInfo("\nListing ABFE settings...")
  420     OpenFEUtil.ListOpenFESettings(ABFESettings)
  421 
  422 
  423 def ConfigureLogging():
  424     """Configure logging."""
  425 
  426     OptionsInfo["LoggingLevel"] = Options["--loggingLevel"]
  427 
  428     if re.match("^Error$", OptionsInfo["LoggingLevel"], re.I):
  429         LoggingLevel = logging.ERROR
  430     elif re.match("^Warning$", OptionsInfo["LoggingLevel"], re.I):
  431         LoggingLevel = logging.WARNING
  432     else:
  433         LoggingLevel = logging.INFO
  434 
  435     logging.basicConfig(format="%(levelname)s: %(message)s", level=LoggingLevel)
  436 
  437     # Turn warnings issued by warnings.warn() into log message to avoid display
  438     # of a stack trace...
  439     logging.captureWarnings(True)
  440 
  441 
  442 def ProcessOptions():
  443     """Process and validate command line arguments and options."""
  444 
  445     MiscUtil.PrintInfo("Processing options...")
  446 
  447     # Validate options...
  448     ValidateOptions()
  449 
  450     # Configure logging...
  451     ConfigureLogging()
  452 
  453     OptionsInfo["Infile"] = Options["--infile"]
  454     OptionsInfo["InfilePath"] = os.path.abspath(OptionsInfo["Infile"])
  455     FileDir, FileName, FileExt = MiscUtil.ParseFileName(OptionsInfo["Infile"])
  456     OptionsInfo["InfileRoot"] = FileName
  457 
  458     OptionsInfo["SmallMolFile"] = Options["--smallMolFile"]
  459     OptionsInfo["SmallMolFilePath"] = os.path.abspath(OptionsInfo["SmallMolFile"])
  460     FileDir, FileName, FileExt = MiscUtil.ParseFileName(OptionsInfo["SmallMolFile"])
  461     OptionsInfo["SmallMolFileRoot"] = FileName
  462 
  463     ParamsDefaultInfoOverride = {"RemoveHydrogens": False}
  464     OptionsInfo["SmallMolFileParams"] = MiscUtil.ProcessOptionInfileParameters(
  465         "--smallMolFileParams",
  466         Options["--smallMolFileParams"],
  467         InfileName=Options["--smallMolFile"],
  468         ParamsDefaultInfo=ParamsDefaultInfoOverride,
  469     )
  470 
  471     ParamsDefaultInfoOverride = {"EngineComputePlatform": "CPU"}
  472     OptionsInfo["ABFEParams"] = OpenFEUtil.ProcessOptionOpenFEAbsoluteBindingFreeEnergyParameters(
  473         "-a, --abfeParams", Options["--abfeParams"], ParamsDefaultInfo=ParamsDefaultInfoOverride
  474     )
  475 
  476     OptionsInfo["ExecuteDAGParams"] = OpenFEUtil.ProcessOptionOpenFEExecuteDAGParameters(
  477         "--executeDAGParams", Options["--executeDAGParams"]
  478     )
  479     OptionsInfo["LoggingLevel"] = Options["--loggingLevel"]
  480 
  481     OptionsInfo["Mode"] = OpenFEUtil.ProcessOptionOpenFEAbsoluteFreeEnergyMode("-m, --mode", Options["--mode"])
  482     OptionsInfo["FirstMoleculeMode"] = True if re.match("^FirstMolecule$", OptionsInfo["Mode"], re.I) else False
  483     OptionsInfo["AllMoleculesMode"] = True if re.match("^AllMolecules$", OptionsInfo["Mode"], re.I) else False
  484     OptionsInfo["MoleculesNamesMode"] = True if re.match("^MoleculeNames$", OptionsInfo["Mode"], re.I) else False
  485 
  486     OptionsInfo["MissingChargeMode"] = OpenFEUtil.ProcessOptionOpenFEMissingChargeMode(
  487         "--missingChargeMode", Options["--missingChargeMode"]
  488     )
  489 
  490     ProcessMoleculeNamesOption()
  491 
  492     OptionsInfo["ResultFileParams"] = OpenFEUtil.ProcessOptionOpenFEResultFileParameters(
  493         "--resultFileParams", Options["--resultFileParams"]
  494     )
  495     OptionsInfo["SolventParams"] = OpenFEUtil.ProcessOptionOpenFESolventParameters(
  496         "--solventParams", Options["--solventParams"]
  497     )
  498 
  499     ProcessOutfilePrefixOption()
  500     ProcessOutfileDirOption()
  501 
  502     OptionsInfo["Overwrite"] = Options["--overwrite"]
  503 
  504     # Track top level working directory...
  505     OptionsInfo["TopWorkingDir"] = os.getcwd()
  506 
  507 
  508 def RetrieveOptions():
  509     """Retrieve command line arguments and options."""
  510 
  511     # Get options...
  512     global Options
  513     Options = docopt(_docoptUsage_)
  514 
  515     # Set current working directory to the specified directory...
  516     WorkingDir = Options["--workingdir"]
  517     if WorkingDir:
  518         os.chdir(WorkingDir)
  519 
  520     # Handle examples option...
  521     if "--examples" in Options and Options["--examples"]:
  522         MiscUtil.PrintInfo(MiscUtil.GetExamplesTextFromDocOptText(_docoptUsage_))
  523         sys.exit(0)
  524 
  525 
  526 def ValidateOptions():
  527     """Validate option values."""
  528 
  529     MiscUtil.ValidateOptionFilePath("-i, --infile", Options["--infile"])
  530     MiscUtil.ValidateOptionFileExt("-i, --infile", Options["--infile"], "pdb cif")
  531 
  532     MiscUtil.ValidateOptionFilePath("-s, --smallMolFile", Options["--smallMolFile"])
  533     MiscUtil.ValidateOptionFileExt("-s, --smallMolFile", Options["--smallMolFile"], "sdf sd")
  534 
  535     MiscUtil.ValidateOptionDirPath("-o, --outfileDir", Options["--outfileDir"])
  536     MiscUtil.ValidateOptionsOutputDirOverwrite(
  537         "-o, --outfileDir", Options["--outfileDir"], "--overwrite", Options["--overwrite"]
  538     )
  539 
  540     MiscUtil.ValidateOptionTextValue("--loggingLevel", Options["--loggingLevel"], "Info Warning Error")
  541 
  542     MiscUtil.ValidateOptionTextValue("-m, --mode", Options["--mode"], "FirstMolecule AllMolecules MoleculeNames")
  543     MiscUtil.ValidateOptionTextValue("--missingChargeMode", Options["--missingChargeMode"], "Calculate Stop")
  544 
  545     if re.match("^MoleculeNames$", Options["--mode"], re.I):
  546         if MiscUtil.IsEmpty(Options["--moleculeNames"]):
  547             MiscUtil.PrintError(
  548                 'You must specify a value for "--moleculeNames" option during, MoleculeNames, value for "-m, --mode" option.'
  549             )
  550 
  551 
  552 # Setup a usage string for docopt...
  553 _docoptUsage_ = """
  554 OpenFECalculateAbsoluteBindingFreeEnergy.py - Calculate absolute binding free energy
  555 
  556 Usage:
  557     OpenFECalculateAbsoluteBindingFreeEnergy.py [--abfeParams <Name,Value,...>] [--executeDAGParams <Name,Value,..>]
  558                                                   [--loggingLevel <Info, Warning or Error>] [--mode <FirstMolecule, AllMolecules, or ...>]
  559                                                   [--missingChargeMode <Calculate or Stop>] [--moleculeNames <MolName1,MolName2,..>]
  560                                                   [--outfilePrefix <text>] [--overwrite] [--resultFileParams <Name,Value,..>] [--solventParams <Name,Value,...>]
  561                                                   [--smallMolFileParams <Name,Value,...> ] [-w <dir>] -i <infile>   -s <smallmolfile> -o <outifiledir>
  562     OpenFECalculateAbsoluteBindingFreeEnergy.py -l | --list
  563     OpenFECalculateAbsoluteBindingFreeEnergy.py -h | --help | -e | --examples
  564 
  565 Description:
  566     Calculate Absolute Binding Free Energy (ABFE) for molecules in a small
  567     molecule input file. You may calculate ABFEs for specific molecules or all
  568     molecules in the input file.
  569 
  570     The input file must contain a macromolecule already prepared for simulation.
  571     The preparation of the macromolecule for a simulation generally involves the
  572     following tasks: identification and replacement of non-standard residues;
  573     addition of missing residues; addition of missing heavy atoms; addition of
  574     missing hydrogens.
  575 
  576     In addition, the small molecule input file must contain molecules already
  577     prepared for simulation. It must contain appropriate 3D coordinates relative
  578     to the macromolecule along with no missing hydrogens.
  579 
  580     The MD simulation workflow, employed for the calculation of ABFEs, involves
  581     the following steps:
  582         
  583         Protocol repeats, 3
  584         
  585         Time step size: 4.0 femtosecond
  586 
  587         Complex equilibration phase:
  588         
  589         Max minimization steps: 5,000
  590         NVT equilibration length: 0.25 nanosecond
  591         NPT equilibration length: 0.5 nanosecond
  592         NPT length: 5.0 nanosecond
  593         
  594         Complex production phase:
  595         
  596         Max minimization steps: 5,000
  597         NPT equilibration length: 1.0 nanosecond
  598         NPT length: 10.0 nanosecond
  599 
  600         Solvent equilibration phase:
  601         
  602         Max minimization steps: 5,000
  603         NVT equilibration length: 0.1 nanosecond
  604         NPT equilibration length: 0.2 nanosecond
  605         NPT length: 0.5 nanosecond
  606         
  607         Solvent production phase:
  608         
  609         Max minimization steps: 5,000
  610         NPT equilibration length: 1.0 nanosecond
  611         NPT length: 10.0 nanosecond
  612 
  613     Each complex and solvent simulation, by default, may run for 16.75 and 11.8
  614     nanosecond respectively, for a total of 28.55 nanoseconds. The total MD
  615     simulation time for correspond to 85.66 nanosecond to repeat the protocol
  616     3 times for the complex and solvent simulations.
  617 
  618     Possible outfile prefix:
  619         
  620         <OutfilePrefix> or <SmallMolFileRoot>
  621         
  622     Possible output directories:
  623         
  624         <OutfileDir>
  625         
  626         <OutfileDir>/Transformations
  627         <OutfileDir>/Results
  628         
  629     Possible output files and directories under <OutfileDir>:
  630         
  631         <OutfilePrefix>_ABFE_Results.<csv or tsv>
  632         
  633         Transformations/<MolName>_AbsoluteBinding.json
  634         ... ... ...
  635         
  636         Results/<MolName>_AbsoluteBinding_Results.json
  637         
  638         Results/shared_AbsoluteBindingComplexUnit-*/
  639         Results/shared_AbsoluteBindingSolventUnit-*/
  640         ... ... ...
  641 
  642 Options:
  643     -a, --abfeParams <Name,Value,...>  [default: auto]
  644         A comma delimited list of parameter name and value pairs for ABFE protocol
  645         settings employed during the calculation of ABFEs.
  646         
  647         The default values are automatically updated to match settings provided by
  648         OpenFE module AbsoluteBindingProtocol.
  649         
  650         You must specify valid OpenFE values for these parameters. An extensive
  651         validation is not performed.
  652         
  653         The supported parameter names along with their default values are
  654         are shown below: explain and doc...
  655             
  656             protocolRepeats, 3
  657             
  658             Complex equil output settings:
  659             
  660             complexEquilOutputCheckpointInterval, 1  [ Units: nanosecond ]
  661             complexEquilOutputCheckpointStorageFilename, checkpoint.chk
  662             complexEquilOutputEquilNPTStructure, equil_npt_structure.pdb
  663             complexEquilOutputEquilNVTstructure, equil_nvt_structure.pdb
  664             complexEquilOutputForcefieldCache, db.json
  665             complexEquilOutputLogOutput, production_equil_simulation.log
  666             complexEquilOutputMinimizedStructure, minimized.pdb
  667             complexEquilOutputIndices, all  [ Possible value: Any valid
  668                 selection. ]
  669             complexEquilOutputPremnimizedStructure, system.pdb
  670             complexEquilOutputProductionTrajectoryFilename, production_equil.xtc
  671             complexEquilOutputTrajectoryWriteInterval,  20.0  [ Units:
  672                 picosecond ]
  673             
  674             Complex equil simulation settings:
  675             
  676             complexEquilSimulationEquilibrationLength, 0.5 [ Units: nanosecond ]
  677             complexEquilSimulationEquilibrationLengthNVT, 0.25   [ Units:
  678                 nanosecond ]
  679             complexEquilSimulationMinimizationSteps, 5000
  680             complexEquilSimulationProductionLength, 5.0  [ Units: nanosecond ]
  681             
  682             Complex lambda settings:
  683             
  684             complexLambdaElec, 0.0 0.0 0.0 0.0 0.0 0.0 0.1 0.2 0.3 0.4 0.5 0.6
  685                 0.7 0.8 0.9 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
  686                 1.0 1.0  [ Possible values: A space delimited list of values
  687                 between 0.0 and 1.0 ]
  688             complexLambdaRestraints, 0.0 0.2 0.4 0.6 0.8 1.0 1.0 1.0 1.0 1.0
  689                 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
  690                 1.0 1.0 1.0 1.0  [ Possible values: A space delimited list of
  691                 values between 0.0 and 1.0 ]
  692             complexLambdaVdw, 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
  693                 0.0 0.0 0.0 0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.65 0.7 0.75 0.8 0.85
  694                 0.9 0.95 1.0  [ Possible values: A space delimited list of values
  695                 between 0.0 and 1.0 ]
  696             
  697             Complex output settings:
  698             
  699             complexOutputCheckpointInterval, 1.0  [ Units: nanosecond ]
  700             complexOutputCheckpointStorageFilename, complex_checkpoint.nc
  701             complexOutputForcefieldCache, db.json
  702             complexOutputFilename, complex.nc
  703             complexOutputIndices, not water   [ Possible value: Any valid
  704                 selection. ]
  705             complexOutputStructure, alchemical_system.pdb
  706             complexOutputPositionsWriteFrequency, 100.0  [ Units: picosecond ]
  707             complexOutputVelocitiesWriteFrequency, None  [ Possible
  708                 values: > 0; Units: picosecond ]
  709             
  710             Complex simulation settings:
  711             
  712             complexSimulationEarlyTerminationTargetError, 0.0  [ Units:
  713                 kilocalorie_per_mole ]
  714             complexSimulationEquilibrationLength,  1.0  [ Units: nanosecond ]
  715             complexSimulationMinimizationSteps, 5000
  716             complexSimulationNReplicas, 30
  717             complexSimulationProductionLength, 10.0  [ Units: nanosecond ]
  718             complexSimulationRealTimeAnalysisInterval, 250.0  [ Units:
  719                 picosecond ]
  720             complexSimulationRealTimeAnalysisMinimumTime, 500.0  [ Units:
  721                 picosecond ]
  722             complexSimulationSamplerMethod, repex  [ Possible values: repex,
  723                 sams, or independent ]
  724             complexSimulationSamsFlatnessCriteria, logZ-flatness  [ Possible
  725                 values: logZ-flatness, minimum-visits or histogram-flatness ]
  726             complexSimulationSamsGamma0, 1.0
  727             complexSimulationTimePerIteration, 2.5   [ Units: picosecond ]
  728             
  729             Complex solvation settings:
  730             
  731             complexSolvationBoxShape, dodecahedron  [  Possible values: cube,
  732                 dodecahedron, or octahedron ]
  733             complexSolvationBoxSize, None  [ Possible value: A triplet of space
  734                 X Y Z values; Units: nanometer ]
  735             complexSolvationSolventModel, tip3p  [ Possible values: tip3p, spce,
  736                 tip4pew, or tip5p ]
  737             complexSolvationSolventPadding, 1.0  [ Units: nanometer ]
  738             
  739             Engine settings:
  740             
  741             engineComputePlatform, CPU  [ Possible values: CPU, CUDA,
  742                 OpenCL, or Reference ]
  743             engineGpuDeviceIndex, None [ Possible values: 0, 0 1, etc. ]
  744              
  745             Forcefield settings:
  746             
  747             forcefieldConstraints, HBonds  [ Possible values: HBonds,
  748                 AllBonds, or HAngles ]
  749             forcefields, amber/ff14SB.xml amber/tip3p_standard.xml
  750                 amber/tip3p_HFE_multivalent.xml amber/phosaa10.xml
  751                 [ Possible values: A space delimited list of valid names. ]
  752             forcefieldHydrogenMass, 3.0  [ Units: amu ]
  753             forcefieldNonbondedCutoff, 0.9   [ Units: nanometer ]
  754             forcefieldNonbondedMethod, PME  [ Possible values: PME or
  755                 NoCutoff ]
  756             forcefieldRigidWater, yes,  [ Possible values: yes or no ]
  757             forcefieldSmallMoleculeForcefield, openff-2.1.1  [ Possible
  758                 value: A valid forcefield name. ]
  759             
  760             Integrator settings:
  761             
  762             integratorBarostatFrequency, 25.0 * timestep  [ The specified value
  763                 is a multiple of integratorTimestep. ]
  764             integratorConstraintTolerance, 1e-06
  765             integratorLangevinCollisionRate, 1.0  [ Units: 1 / picosecond ]
  766             integratorNRestartAttempts, 20
  767             integratorReassignVelocities, no  [ Possible values: yes or no ]
  768             integratorRemoveCom, no  [ Possible values: yes or no ]
  769             integratorTimestep, 4.0 [ Units: femtosecond ] 
  770             
  771             Partial charge settings:
  772             
  773             partialChargeNaglModel, None  [ Default: Production AM1BCC model for
  774                 NAGL; Possible value: Any valid name. ]
  775             partialChargeNumberOfConformers, None  [ Possible value: > 0 ]
  776             partialChargeOffToolkitBackend, AmberTools  [ Possible values:
  777                 AmberTools or RDKit ]
  778             partialChargeMethod, AM1BCC  [ Possble values: AM1BCC, Espaloma,
  779                 or NAGL ]
  780             
  781             Restraint settings:
  782             
  783             restraintKPhiA, 334.72  [ Units: kilojoule_per_mole / radian**2
  784                 The default value is equivalent to 80 kcal/mol/radian**2 ]
  785             restraintKPhiB, 334.72  [ Units: kilojoule_per_mole / radian**2
  786                 The default value is equivalent to 80 kcal/mol/radian**2 ]
  787             restraintKPhiC, 334.72  [ Units: kilojoule_per_mole / radian**2
  788                 The default value is equivalent to 80 kcal/mol/radian**2 ]
  789             restraintKR, 4184.0  [ Units: kilojoule_per_mole / nanometer**2
  790                  The default value is equivalent to 10 kcal/mol/angstrom**2
  791             restraintKThetaA, 334.72  [ Units: kilojoule_per_mole / radian**2
  792                 The default value is equivalent to 80 kcal/mol/radian**2 ]
  793             restraintKThetaB, 334.72  [ Units: kilojoule_per_mole / radian**2
  794                 The default value is equivalent to 80 kcal/mol/radian**2 ]
  795             restraintAnchorFindingStrategy, bonded  [ Possible values:
  796                 multi-residue or bonded ] 
  797             restraintDsspFilter, yes   [ Possible values: yes or no ]
  798             restraintHostMaxDistance, 1.5  [ Units: nanometer ]
  799             restraintHostMinDistance, 0.5  [ Units: nanometer ]
  800             restraintHostSelection, backbone   [ Possible value: Any valid
  801                 selection. ]
  802             restraintRmsfCutoff, 0.1  [ Units: nanometer ]
  803             
  804             Solvent equil output settings:
  805             
  806             solventEquilOutputCheckpointInterval, 1.0  [ Units: nanosecond ]
  807             solventEquilOutputCheckpointStorageFilename, checkpoint.chk
  808             solventEquilEquilOutputNPTStructure, equil_npt_structure.pdb
  809             solventEquilEquilNVTOutputStructure, equil_nvt_structure.pdb
  810             solventEquilOutputForcefieldCache, db.json
  811             solventEquilOutputLogOutput, production_equil_simulation.log
  812             solventEquilOutputMinimizedStructure, minimized.pdb
  813             solventEquilOutputIndices, all  [  Possible value: Any valid
  814                 selection. ]
  815             solventEquilOutputPreminimizedStructure, system.pdb
  816             solventEquilOutputProductionTrajectoryFilename, production_equil.xtc
  817             solventEquilOutputTrajectoryWriteInterval, 20.0  [ Units:
  818                 picosecond ]
  819             
  820             Solvent_equil_simulation_settings:
  821             
  822             solventEquilSimulationEquilibrationLength, 0.2 [ Units: nanosecond ]
  823             solventEquilSimulationEquilibrationLengthNVT, 0.1  [ Units:
  824                 nanosecond ]
  825             solventEquilSimulationMinimizationSteps, 5000
  826             solventEquilSimulationProductionLength, 0.5  [ Units: nanosecond ]
  827             
  828             Solvent lambda settings:
  829             
  830             solventLambdaElec, 0.0 0.25 0.5 0.75 1.0 1.0 1.0 1.0 1.0 1.0 1.0 1.0
  831                 1.0 1.0  [ Possible values: A space delimited list of values
  832                 between 0.0 and 1.0 ]
  833             solventLambdaRestraints, 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0 0.0
  834                 0.0 0.0 0.0  [ Possible values: A space delimited list of values
  835                 between 0.0 and 1.0 ]
  836             solventLambdaVdw, 0.0 0.0 0.0 0.0 0.0 0.12 0.24 0.36 0.48 0.6 0.7
  837                 0.77 0.85 1.0  [ Possible values: A space delimited list of values
  838                 between 0.0 and 1.0 ]
  839             
  840             Solvent output settings:
  841             
  842             solventOutputCheckpointInterval, 1.0  [ Units: nanosecond ]
  843             solventOutputCheckpointStorageFilename, solvent_checkpoint.nc
  844             solventOutputForcefieldCache, db.json
  845             solventOutputFilename, solvent.nc
  846             solventOutputIndices, not water  [ Possible value: Any valid
  847                 selection. ]
  848             solventOutputStructure, alchemical_system.pdb
  849             solventOutputPositionsWriteFrequency, 100.0  [ Units: picosecond ]
  850             solventOutputVelocitiesWriteFrequency, None  [ Possible
  851                 values: > 0; Units: picosecond ]
  852             
  853             Solvent simulation settings:
  854             
  855             solventSimulationEarlyTerminationTargetError, 0.0  [ Units:
  856                 kilocalorie_per_mole ]
  857             solventSimulationEquilibrationLength, 1.0  [ Units: nanosecond ]
  858             solventSimulationMinimizationSteps, 5000
  859             solventSimulationNReplicas, 14
  860             solventSimulationProductionLength, 10.0  [ Units: nanosecond ]
  861             solventSimulationRealTimeAnalysisInterval, 250.0  [ Unit: picosecond ]
  862             solventSimulationRealTimeAnalysisMinimumTime, 500.0  [ Units:
  863                 picosecond ]
  864             solventSimulationSamplerMethod, repex  [ Possible values: repex,
  865                 sams, or independent ]
  866             solventSimulationSamsFlatnessCriteria, logZ-flatness  [ Possible
  867                 values: logZ-flatness, minimum-visits or histogram-flatness ]
  868             solventSimulationSamsGamma0, 1.0
  869             solventSimulationTimePerIteration, 2.5  [ Units: picosecond ]
  870             
  871             Solvent solvation settings:
  872             
  873             solventSolvationBoxShape, dodecahedron  [  Possible values: cube,
  874                 dodecahedron, or octahedron ]
  875             solventSolvationBoxSize, None  [ Possible value: A triplet of space
  876                 X Y Z values; Units: nanometer ]
  877             solventSolvationSolventModel, tip3p  [ Possible values: tip3p, spce,
  878                 tip4pew, or tip5p ]
  879             solventSolvationSolventPadding, 1.5  [ Units: nanometer ]
  880             
  881             Thermo settings:
  882             
  883             thermoPh, None  [ Possible values: > 0 ]
  884             thermoPressure, 1.0  [ Units: bar ]
  885             thermoRedoxPotential, None  [ Possible values: A valid float.
  886                 Units: millivolts (mV) ]
  887             thermoTemperature, 298.15  [ Units: kelvin ]
  888             
  889         A brief description of parameters, taken from OpenFE documentation, is
  890         provided below:
  891             
  892             protocolRepeats: Number of completely independent repeats of the
  893                 entire sampling process.
  894             
  895             Complex settings:
  896             
  897             Complex parameters for the system, including the solvent model and
  898             the solvent padding.
  899             
  900             Complex equil output settings:
  901             
  902             Parameters controlling simulation output during equilibration
  903             phase of complex transformation.
  904             
  905             complexEquilOutputCheckpointInterval: Frequency to write the
  906                 checkpoint file.
  907             complexEquilOutputCheckpointStorageFilename: Checkpoint filename.
  908             complexEquilOutputEquilNPTStructure: NPT structure filename.
  909             complexEquilOutputEquilNVTstructure: NVT strucure filename.
  910             complexEquilOutputForcefieldCache:  Filename for caching small
  911                 molecule residue templates.
  912             complexEquilOutputLogOutput: Simulation log filename.
  913             complexEquilOutputMinimizedStructure: Minimized structire filename.
  914             complexEquilOutputIndices: Selection string for selecting
  915                 coordinates to write.
  916             complexEquilOutputPremnimizedStructure: Initial structure filename.
  917             complexEquilOutputProductionTrajectoryFilename: Trajectory filename.
  918             complexEquilOutputTrajectoryWriteInterval: Frequency for writing
  919                 velocities to trajectory file.
  920             
  921             Complex equil simulation settings:
  922             
  923             Parameters controlling simulation during equilibration phase of
  924             complex transformation.
  925             
  926             complexEquilSimulationEquilibrationLength:  Length of the NPT
  927                 equilibration phase.
  928             complexEquilSimulationEquilibrationLengthNVT: Length of the NVT
  929                 equilibration phase.
  930             complexEquilSimulationMinimizationSteps: Maximum number of
  931                 minimization steps to perform.
  932             complexEquilSimulationProductionLength:  Length of the NPT
  933                 production phase.
  934             
  935             Complex lambda settings:
  936             
  937             Lambda protocol parameters for complex transformation.
  938             
  939             complexLambdaElec: List of lambda values for electrostatics. The
  940                 values of 0 and 1 imply state A and state B respectively.
  941             complexLambdaRestraints: List of lambda values for restraints. The
  942                 values of 0 and 1 imply state A and state B respectively.
  943             complexLambdaVdw: List of lamda values for van der Waals. The
  944                 values of of 0 and 1 imply state A and state B respectively.
  945             
  946             Complex output settings:
  947             
  948             Parameters controlling simulation output during final phase of
  949             complex transformation.
  950             
  951             complexOutputCheckpointInterval:  Frequency to write the checkpoint
  952                 file.
  953             complexOutputCheckpointStorageFilename: Checkpoint filename.
  954             complexOutputForcefieldCache: Filename for caching small molecule
  955                 residue templates.
  956             complexOutputFilename: Trajectory filename.
  957             complexOutputIndices: Selection string for selecting coordinates to
  958                 write.
  959             complexOutputStructure: Topology structure filename.
  960             complexOutputPositionsWriteFrequency: Frequency for writing
  961                 positions to trajectory file.
  962             complexOutputVelocitiesWriteFrequency: Frequency for writing
  963                 velocities to trajectory file.
  964             
  965             Complex simulation settings:
  966             
  967             Parameters controlling simulation during final phase of complex
  968             transformation.
  969             
  970             complexSimulationEarlyTerminationTargetError: Target error for the
  971                 real time analysis measured in kcal/mol. Once the MBAR error of
  972                 the free energy is at or below this value, the simulation will
  973                 be considered complete. The suggested value of 0.12 has shown to
  974                 be effective in both hydration and binding free energy
  975                 benchmarks.
  976             complexSimulationEquilibrationLength: Length of the equilibration
  977                 phase. The specified value must be divisible by
  978                 'integratorTimestep'.
  979             complexSimulationMinimizationSteps: Maximum number of minimization
  980                 steps to perform.
  981             complexSimulationNReplicas: Number of replicas to use.
  982             complexSimulationProductionLength: Length of the production phase.
  983                 The specified value must be divisible by 'integratorTimestep'.
  984             complexSimulationRealTimeAnalysisMinimumTime: Time interval for
  985                 performing analysis of the free energies. At each interval, real
  986                 time analysis data will be written to a yaml file named
  987                 <outputFileName>_real_time_analysis.yaml. The current error
  988                 in the estimate will also be assessed and the simulation will
  989                 be terminated when it drops below
  990                 'complexSimulationEarlyTerminationTargetError'.
  991             complexSimulationSamplerMethod: Alchemical sampling method to use:
  992                 REPEX (Hamiltonian REPlica EXchange), SAMS (Self-Adjusted
  993                 Mixture Sampling), or Independent (Independently sampled lambda
  994                 windows).
  995             complexSimulationSamsFlatnessCriteria:Method for assessing when to
  996                 switch to asymptomatically optimal scheme for SAMS.
  997             complexSimulationsamsGamma0: Initial weight adaptation rate for
  998                 SAMS.
  999             complexSimulationTimePerIteration: Simulation time between each
 1000                MCMC move attempt 
 1001             
 1002             Complex solvation settings:
 1003             
 1004             Solvation parameters for the system, including the solvent model and
 1005             the solvent padding.
 1006             
 1007             complexSolvationBoxShape: Shape of the periodic solvent box.
 1008             complexSolvationBoxSize:  Lengths of the unit cell for a solvent box.
 1009             complexSolvationSolventModel: Forcefield water model to use during
 1010                 solvation and defining the model properties.
 1011             complexSolvationSolventPadding: Minimum distance from any solute
 1012                 bounding sphere to the edge of the box.
 1013             
 1014             Engine settings:
 1015             
 1016             Parameters configuring the compute platform used by the OpenMM to
 1017             perform the simulation.
 1018             
 1019             engineComputePlatform: Platform to use for running OpenMM MD
 1020                 calculations.
 1021             engineGpuDeviceIndex: Space delimited list of device indices
 1022                 to use for running OpenMM MD calculations.
 1023             
 1024             Forcefield settings:
 1025             
 1026             forcefieldConstraints:Constraints  to use.
 1027             forcefields: List of valid forcefield paths for all components
 1028                 except small molecules.
 1029             forcefieldHydrogenMass: Mass to be repartitioned to hydrogens
 1030                 from neighboring heavy atoms.
 1031             forcefieldNonbondedCutoff: Cutoff for short range nonbonded
 1032                 interactions.
 1033             forcefieldNonbondedMethod: Method for treating nonbonded
 1034                 interactions.
 1035             forcefieldRigidWater: Use a rigid water model.
 1036             forcefieldSmallMoleculeForcefield: A valid forcefield name to use
 1037                 for small molecules.
 1038             
 1039             Integrator settings:
 1040             
 1041             Parameters controlling the LangevinSplittingDynamicsMove integrator
 1042             used for simulation.
 1043             
 1044             integratorBarostatFrequency: Frequency at which volume scaling
 1045                 changes should be attempted.
 1046             integratorConstraintTolerance: Tolerance for constraint solver.
 1047             integratorLangevinCollisionRate: Collision frequency.
 1048             integratorNRestartAttempts: Number of attempts to restart from
 1049                 Context in case there are NaNs in the energies after
 1050                 integration.
 1051             integratorReassignVelocities: Reassign velocities  from the
 1052                 Maxwell-Boltzmann distribution at the beginning of each
 1053                 Monte Carlo move.
 1054             integratorRemoveCom: Remove the center of mass motion.
 1055             integratorTimestep: Size of the simulation timestep.
 1056             
 1057             Partial charge settings:
 1058             
 1059             Parameters for automatically assigning missing partial charges to
 1060             small molecules, including the partial charge method.
 1061             
 1062             partialChargeNaglModel: Model to use for partial charge assignment.
 1063                 A value of None implies the use of the latest available
 1064                 production AM1BCC model.
 1065             partialChargeNumberOfConformers: Number of conformers to generate
 1066                 as part of the partial charge assignment. A value of None
 1067                 implies the use of the existing conformer.
 1068             partialChargeOffToolkitBackend: OpenFF toolkit registry backend to
 1069                 use for calculating partial charges.
 1070             partialChargeMethod: Method to use for calculating partial charges.
 1071             
 1072             Restraint settings:
 1073             
 1074             Parameters to configure Boresch-style restraint between two groups
 1075             of atoms named host  (Hx) and guest (Gx).
 1076             
 1077             restraintKPhiA: Equilibrium force constant for the dihedral formed
 1078                 by H2-H1-H0-G0.
 1079             restraintKPhiB: Equilibrium force constant for the dihedral formed
 1080                 by H1-H0-G0-G1.
 1081             restraintKPhiC: Equilibrium force constant for the dihedral formed
 1082                 by H0-G0-G1-G2.
 1083             restraintKR: Bond spring constant between H0 and G0.
 1084             restraintKThetaA: Spring constant for the angle formed by H1-H0-G0.
 1085             restraintKThetaB: Spring constant for the angle formed by H0-G0-G1
 1086             restraintAnchorFindingStrategy: Boresch atom picking strategy to
 1087                 use. bonded: pick host atoms that are bonded to each other.
 1088                 multi-residue: pick host atoms which can span multiple residues.
 1089             restraintDsspFilter: Apply DSSP filter to the host atoms.
 1090             restraintHostMaxDistance: Minimum distance between any host atom
 1091                 and the guest G0 atom.
 1092             restraintHostMinDistance: Xaximum distance between any host atom
 1093                 and the guest G0 atom
 1094             restraintHostSelection: A valid selection string to sub-select the
 1095                 host atoms which will be involved in the restraint.
 1096             restraintRmsfCutoff: Cutoff value for filtering atoms by their root
 1097                 mean square fluctuation. Atoms with values above this cutoff
 1098                 are ignored.
 1099             
 1100             Solvent equil output settings:
 1101             Solvent equil simulation settings:
 1102             Solvent lambda settings:
 1103             Solvent output settings:
 1104             Solvent simulation settings:
 1105             Solvent solvation settings:
 1106             
 1107             The solvent settings are similar to the complex settings already
 1108             described under various sections for complex. The prefix 'solvent'
 1109             is used for the names of the pramaters instead of the prefix
 1110             'complex.'
 1111             
 1112             Thermo settings:
 1113             
 1114             Thermodynamic parameters, including the temperature and the pressure
 1115             of the system.
 1116             
 1117             thermoPh: Simulation pH
 1118             thermoPressure: Simulation pressure.
 1119             thermoRedoxPotential:Simulation redox potential.
 1120             thermoTemperature: Simulation temperature. 
 1121             
 1122     -e, --examples
 1123         Print examples.
 1124     --executeDAGParams <Name,Value,..>  [default: auto]
 1125         A comma delimited list of parameter name and value pairs for executing
 1126         protocol DAGs (Directed Acyclic Graph) to run ABFE calculations.
 1127         
 1128         The supported parameter names along with their default values are
 1129         are shown below:
 1130             
 1131             keepShared, yes  [ Possible values: yes or no ]
 1132             keepScratch, no  [ Possible values: yes or no ]
 1133             nRetries, 2  [ Possible values: >= 0. A value of 0 implies only
 1134                 1 try. ]
 1135             
 1136         A brief description of parameters is provided below:
 1137             
 1138             keepShared: Keep shared directories after the execution of DAG.
 1139             keepScratch: Keep scratch directories after the execution of DAG.
 1140             nRetries: Number of times to attempt the execution.
 1141             
 1142     -h, --help
 1143         Print this help message.
 1144     -i, --infile <infile>
 1145         Input file name containing a macromolecule.
 1146     -l, --list
 1147         List default ABFE protocol settings provided by OpenFE module
 1148         AbsoluteBindingProtocol.
 1149     --loggingLevel <Info, Warning or Error>  [default: Error]
 1150         Logging level to configure the 'root logger' via logging.basicConfig()
 1151         function. The default logging level is changed from 'logging.INFO' to
 1152         'logging.ERROR'. Otherwise, OpenFE and its associated modules
 1153         may generate a lot of informational messages.
 1154     -m, --mode <FirstMolecule, AllMolecules, or ...>  [default: FirstMolecule]
 1155         Calculate ABFE for the first molecule, the specified molecule names,
 1156         or all molecules in an input file. Possible values:  FirstMolecule,
 1157         AllMolecules, or MoleculeNames. You must specify a comma delimited list
 1158         of molecule names using '--moleculeNames'option during 'MoleculeNames'
 1159         value for '--mode' option. 
 1160     --missingChargeMode <Calculate or Stop>  [default: Stop]
 1161         Calculate missing partial charges for molecules before running ABFE
 1162         calculations or terminate the execution of the script. The missing
 1163         partial charges will be automatically calculated by OpenFE module
 1164         AbsoluteBindingProtocol during the calculation of ABFE. You
 1165         may control the calculation of partial charges by specifying values for
 1166         partialCharge* parameters using '--abfe' option.
 1167     --moleculeNames <MolName1,MolName2,..>
 1168         A comma delimited list of molecule names for calculating ABFEs.
 1169         This option is only used during 'MoleculeNames' value for
 1170         '--mode' option. 
 1171     -o, --outfileDir <outfiledir>
 1172         Output directory.
 1173     --outfilePrefix <text>  [default: auto]
 1174         Prefix for generating output files under output directory.
 1175     --overwrite
 1176         Overwrite existing files.
 1177     --resultFileParams <Name,Value,..>  [default: auto]
 1178         A comma delimited list of parameter name and value pairs for writing
 1179         calculated RHFEs values to a results file.
 1180         
 1181         The supported parameter names along with their default values are
 1182         are shown below:
 1183             
 1184             precision, 4  [ Possible values: > 0 ]
 1185             delimiter, comma  [ Possible values: comma or tab ]
 1186             
 1187     --solventParams <Name,Value,...>  [default: auto]
 1188         A comma delimited list of parameter name and value pairs for solvent
 1189         component. You must specify valid OpenFE values. No extensive validation
 1190         is performed. These parameters are used in conjunction with solvation*
 1191         parameters available through '--abfeParams' to perform solvation.
 1192         
 1193         The supported parameter names along with their default values are
 1194         are shown below:
 1195             
 1196             positiveIon, Na+ [ Possible value: Li+, Na+, K+, Rb+, or Cs+ ]
 1197             negativeIon, Cl- [ Possible values: Cl-, Br-, F-, or I- ]
 1198             neutralize, yes  [ Possible values: yes or no ]
 1199             ionConcentration, 0.15  [ Units: molar ]
 1200             
 1201         A brief description of parameters is provided below:
 1202             
 1203             positiveIon, negativeion: Pair of ions used to neutralize and bring
 1204                 the solvent to required ionic concentration.
 1205             neutralize: Neutralize the net charge on the chemical state by the
 1206                 ions in the solvent component.
 1207             ionConcentration: Ionic concentration.
 1208             
 1209     -s, --smallMolFile <SmallMolFile>
 1210         Input file containing small molecules.
 1211     --smallMolFileParams <Name,Value,...>  [default: auto]
 1212         A comma delimited list of parameter name and value pairs for reading
 1213         molecules from files. The supported parameter names for different file
 1214         formats, along with their default values, are shown below:
 1215             
 1216             SD: removeHydrogens,no,sanitize,yes,strictParsing,yes
 1217             
 1218     -w, --workingdir <dir>
 1219         Location of working directory which defaults to the current directory.
 1220 
 1221 Examples:
 1222     The sample protein and ligand files for tyrosine kinase 2 (Tyk2) are
 1223     distributed with MayaChemTools and are available in data directory. These
 1224     files have been taken from OpenFE distribution for example notebooks. The
 1225     AM1BCC partial charges have been calculated for the ligands in SD file to
 1226     facilitate calculations. You may review OpenFE tutorial notebooks for the
 1227     expected results.
 1228 
 1229     To calcuate ABFE for the first molecule in a SD file, performing 3 independent
 1230     repeats of the entire MD sampling process to estimate ABFE for the molecule,
 1231     each solvent and vacuum MD repeat consisting of equilibration phase ( Complex:
 1232     Minimization - 5,000; NVT - 0.25 ns; NPT - 0.5; NPT prod - 5.0 ns; Solvent:
 1233     Minimization  - 5,000; NVT - 0.1; NPT - 0.2 ns; NPT prod - 0.5 ns) and
 1234     production phase ( Complex: Minimization - 5,000; NPT equil - 1.0 ns; NPT prod:
 1235     10.0 ns; Solvent: Minimization - 5,000; NPT equil - 1.0 ns; NPT prod - 10 ns)
 1236     using a step size of of 4 fs, writing out appropriate trajectory and PDB files for
 1237     each MD repeat in Results subdirectory under output directory, type:
 1238 
 1239         % OpenFECalculateAbsoluteBindingFreeEnergy.py -i SampleTyk2.pdb
 1240           -s SampleTyk2Ligands.sdf -o SampleTyk2LigandsAHFE
 1241 
 1242     To run the first example for calculating ABFE for specific molecules using CUDA
 1243     platform on your machine to perform solvent and vacuum MD simulations and
 1244     generate various output files, type:
 1245 
 1246         % OpenFECalculateAbsoluteBindingFreeEnergy.py -i SampleTyk2.pdb
 1247           -s SampleTyk2Ligands.sdf -o SampleTyk2LigandsAHFE -m MoleculeNames
 1248           --moleculeNames "lig_ejm_31, lig_ejm_47"
 1249           --abfeParams "engineComputePlatform,CUDA"
 1250 
 1251     To run the second example to see all warning messages produced by OpenFE
 1252     modules and write various output files, type;
 1253 
 1254         % OpenFECalculateAbsoluteBindingFreeEnergy.py -i SampleTyk2.pdb
 1255           -s SampleTyk2Ligands.sdf -o SampleTyk2LigandsAHFE -m MoleculeNames
 1256           --moleculeNames "lig_ejm_31, lig_ejm_47"
 1257           --abfeParams "engineComputePlatform,CUDA"
 1258           --loggingLevel Warning
 1259 
 1260     To run the first example for calculating ABFE for all molecules using CUDA
 1261     platform on your machine to perform solvent and vacuum MD simulations,
 1262     automatically calculate missing partial charges for molecules, and generate
 1263     various output files, type:
 1264 
 1265         % OpenFECalculateAbsoluteBindingFreeEnergy.py -i SampleTyk2.pdb
 1266           -s SampleTyk2LigandsNoCharges.sdf -o SampleTyk2LigandsAHFE
 1267           -m AllMolecules --abfeParams "engineComputePlatform,CUDA"
 1268           --missingChargeMode Calculate
 1269 
 1270     To run the second example by specifying explict values for various parametres
 1271     and generate various output files, type:
 1272 
 1273         % OpenFECalculateAbsoluteBindingFreeEnergy.py -i SampleTyk2.pdb
 1274           -s SampleTyk2Ligands.sdf -o SampleTyk2LigandsAHFE -m MoleculeNames
 1275           --moleculeNames "lig_ejm_31, lig_ejm_47"
 1276           --loggingLevel Error
 1277           --executeDAGParams "keepShared, yes, nRetries, 2"
 1278           --missingChargeMode Stop --abfeParams "protocolRepeats,3,
 1279           engineComputePlatform,CUDA,integratorTimestep, 4.0,
 1280           complexEquilSimulationEquilibrationLengthNVT, 0.25,
 1281           complexEquilSimulationEquilibrationLength, 0.5,
 1282           complexEquilSimulationProductionLength,5.0,
 1283           complexSimulationEquilibrationLength, 1.0,
 1284           complexSimulationProductionLength, 10.0,
 1285           solventEquilSimulationEquilibrationLengthNVT, 0.1,
 1286           solventEquilSimulationEquilibrationLength, 0.2,
 1287           solventEquilSimulationProductionLength, 0.5,
 1288           solventSimulationEquilibrationLength, 1.0,
 1289           solventSimulationProductionLength, 10.0,
 1290           thermoPressure, 1.0, thermoTemperature, 298.15"
 1291 
 1292 Author:
 1293     Manish Sud(msud@san.rr.com)
 1294 
 1295 See also:
 1296     OpenFECalculateAbsoluteHydrationFreeEnergy.py,
 1297     OpenFECalculatePartialCharges.py, OpenFECalculateRelativeBindingFreeEnergy.py,
 1298     OpenFECalculateRelativeHydrationFreeEnergy.py, OpenFEGenerateLigandNetwork.py
 1299 
 1300 Copyright:
 1301     Copyright (C) 2026 Manish Sud. All rights reserved.
 1302 
 1303     The functionality available in this script is implemented using OpenFE, an
 1304     open source molecuar for alchemical free energy calculations.
 1305 
 1306     This file is part of MayaChemTools.
 1307 
 1308     MayaChemTools is free software; you can redistribute it and/or modify it under
 1309     the terms of the GNU Lesser General Public License as published by the Free
 1310     Software Foundation; either version 3 of the License, or (at your option) any
 1311     later version.
 1312 
 1313 """
 1314 
 1315 if __name__ == "__main__":
 1316     main()