1 #!/bin/env python 2 # 3 # File: Psi4CalculateEnergy.py 4 # Author: Manish Sud <msud@san.rr.com> 5 # 6 # Copyright (C) 2024 Manish Sud. All rights reserved. 7 # 8 # The functionality available in this script is implemented using Psi4, an 9 # open source quantum chemistry software package, and RDKit, an open 10 # source toolkit for cheminformatics developed by Greg Landrum. 11 # 12 # This file is part of MayaChemTools. 13 # 14 # MayaChemTools is free software; you can redistribute it and/or modify it under 15 # the terms of the GNU Lesser General Public License as published by the Free 16 # Software Foundation; either version 3 of the License, or (at your option) any 17 # later version. 18 # 19 # MayaChemTools is distributed in the hope that it will be useful, but without 20 # any warranty; without even the implied warranty of merchantability of fitness 21 # for a particular purpose. See the GNU Lesser General Public License for more 22 # details. 23 # 24 # You should have received a copy of the GNU Lesser General Public License 25 # along with MayaChemTools; if not, see <http://www.gnu.org/licenses/> or 26 # write to the Free Software Foundation Inc., 59 Temple Place, Suite 330, 27 # Boston, MA, 02111-1307, USA. 28 # 29 30 from __future__ import print_function 31 32 # Add local python path to the global path and import standard library modules... 33 import os 34 import sys; sys.path.insert(0, os.path.join(os.path.dirname(sys.argv[0]), "..", "lib", "Python")) 35 import time 36 import re 37 import shutil 38 import multiprocessing as mp 39 40 # Psi4 imports... 41 if (hasattr(shutil, 'which') and shutil.which("psi4") is None): 42 sys.stderr.write("\nWarning: Failed to find 'psi4' in your PATH indicating potential issues with your\n") 43 sys.stderr.write("Psi4 environment. The 'import psi4' directive in the global scope of the script\n") 44 sys.stderr.write("interferes with the multiprocessing functionality. It is imported later in the\n") 45 sys.stderr.write("local scope during the execution of the script and may fail. Check/update your\n") 46 sys.stderr.write("Psi4 environment and try again.\n\n") 47 48 # RDKit imports... 49 try: 50 from rdkit import rdBase 51 from rdkit import Chem 52 from rdkit.Chem import AllChem 53 except ImportError as ErrMsg: 54 sys.stderr.write("\nFailed to import RDKit module/package: %s\n" % ErrMsg) 55 sys.stderr.write("Check/update your RDKit environment and try again.\n\n") 56 sys.exit(1) 57 58 # MayaChemTools imports... 59 try: 60 from docopt import docopt 61 import MiscUtil 62 import Psi4Util 63 import RDKitUtil 64 except ImportError as ErrMsg: 65 sys.stderr.write("\nFailed to import MayaChemTools module/package: %s\n" % ErrMsg) 66 sys.stderr.write("Check/update your MayaChemTools environment and try again.\n\n") 67 sys.exit(1) 68 69 ScriptName = os.path.basename(sys.argv[0]) 70 Options = {} 71 OptionsInfo = {} 72 73 def main(): 74 """Start execution of the script.""" 75 76 MiscUtil.PrintInfo("\n%s (Psi4: Imported later; RDKit v%s; MayaChemTools v%s; %s): Starting...\n" % (ScriptName, rdBase.rdkitVersion, MiscUtil.GetMayaChemToolsVersion(), time.asctime())) 77 78 (WallClockTime, ProcessorTime) = MiscUtil.GetWallClockAndProcessorTime() 79 80 # Retrieve command line arguments and options... 81 RetrieveOptions() 82 83 # Process and validate command line arguments and options... 84 ProcessOptions() 85 86 # Perform actions required by the script... 87 CalculateInteractionEnergy() 88 89 MiscUtil.PrintInfo("\n%s: Done...\n" % ScriptName) 90 MiscUtil.PrintInfo("Total time: %s" % MiscUtil.GetFormattedElapsedTime(WallClockTime, ProcessorTime)) 91 92 def CalculateInteractionEnergy(): 93 """Calculate interaction energy.""" 94 95 # Setup a molecule reader... 96 MiscUtil.PrintInfo("\nProcessing file %s..." % OptionsInfo["Infile"]) 97 Mols = RDKitUtil.ReadMolecules(OptionsInfo["Infile"], **OptionsInfo["InfileParams"]) 98 99 # Set up a molecule writer... 100 Writer = RDKitUtil.MoleculesWriter(OptionsInfo["Outfile"], **OptionsInfo["OutfileParams"]) 101 if Writer is None: 102 MiscUtil.PrintError("Failed to setup a writer for output fie %s " % OptionsInfo["Outfile"]) 103 MiscUtil.PrintInfo("Generating file %s..." % OptionsInfo["Outfile"]) 104 105 MolCount, ValidMolCount, EnergyFailedCount = ProcessMolecules(Mols, Writer) 106 107 if Writer is not None: 108 Writer.close() 109 110 MiscUtil.PrintInfo("\nTotal number of molecules: %d" % MolCount) 111 MiscUtil.PrintInfo("Number of valid molecules: %d" % ValidMolCount) 112 MiscUtil.PrintInfo("Number of molecules failed during energy calculation: %d" % EnergyFailedCount) 113 MiscUtil.PrintInfo("Number of ignored molecules: %d" % (MolCount - ValidMolCount + EnergyFailedCount)) 114 115 def ProcessMolecules(Mols, Writer): 116 """Process and calculate energy of molecules.""" 117 118 if OptionsInfo["MPMode"]: 119 return ProcessMoleculesUsingMultipleProcesses(Mols, Writer) 120 else: 121 return ProcessMoleculesUsingSingleProcess(Mols, Writer) 122 123 def ProcessMoleculesUsingSingleProcess(Mols, Writer): 124 """Process and calculate energy of molecules using a single process.""" 125 126 # Intialize Psi4... 127 MiscUtil.PrintInfo("\nInitializing Psi4...") 128 Psi4Handle = Psi4Util.InitializePsi4(Psi4RunParams = OptionsInfo["Psi4RunParams"], Psi4OptionsParams = OptionsInfo["Psi4OptionsParams"], PrintVersion = True, PrintHeader = True) 129 OptionsInfo["psi4"] = Psi4Handle 130 131 # Setup conversion factor for energy units... 132 SetupEnergyConversionFactor(Psi4Handle) 133 134 MiscUtil.PrintInfo("\nCalculating interaction energy...") 135 136 (MolCount, ValidMolCount, EnergyFailedCount) = [0] * 3 137 for Mol in Mols: 138 MolCount += 1 139 140 if not CheckAndValidateMolecule(Mol, MolCount): 141 continue 142 143 # Setup a Psi4 molecule... 144 Psi4Mol = SetupPsi4Mol(Psi4Handle, Mol, MolCount) 145 if Psi4Mol is None: 146 continue 147 148 ValidMolCount += 1 149 150 CalcStatus, Energy, EnergyDetails = CalculateMoleculeInteractionEnergy(Psi4Handle, Psi4Mol, Mol, MolCount) 151 152 if not CalcStatus: 153 if not OptionsInfo["QuietMode"]: 154 MiscUtil.PrintWarning("Failed to calculate interaction energy for molecule %s" % RDKitUtil.GetMolName(Mol, MolCount)) 155 156 EnergyFailedCount += 1 157 continue 158 159 WriteMolecule(Writer, Mol, Energy, EnergyDetails) 160 161 return (MolCount, ValidMolCount, EnergyFailedCount) 162 163 def ProcessMoleculesUsingMultipleProcesses(Mols, Writer): 164 """Process and calculate energy of molecules using process.""" 165 166 MPParams = OptionsInfo["MPParams"] 167 168 # Setup data for initializing a worker process... 169 InitializeWorkerProcessArgs = (MiscUtil.ObjectToBase64EncodedString(Options), MiscUtil.ObjectToBase64EncodedString(OptionsInfo)) 170 171 # Setup a encoded mols data iterable for a worker process... 172 WorkerProcessDataIterable = RDKitUtil.GenerateBase64EncodedMolStrings(Mols) 173 174 # Setup process pool along with data initialization for each process... 175 if not OptionsInfo["QuietMode"]: 176 MiscUtil.PrintInfo("\nConfiguring multiprocessing using %s method..." % ("mp.Pool.imap()" if re.match("^Lazy$", MPParams["InputDataMode"], re.I) else "mp.Pool.map()")) 177 MiscUtil.PrintInfo("NumProcesses: %s; InputDataMode: %s; ChunkSize: %s\n" % (MPParams["NumProcesses"], MPParams["InputDataMode"], ("automatic" if MPParams["ChunkSize"] is None else MPParams["ChunkSize"]))) 178 179 ProcessPool = mp.Pool(MPParams["NumProcesses"], InitializeWorkerProcess, InitializeWorkerProcessArgs) 180 181 # Start processing... 182 if re.match("^Lazy$", MPParams["InputDataMode"], re.I): 183 Results = ProcessPool.imap(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"]) 184 elif re.match("^InMemory$", MPParams["InputDataMode"], re.I): 185 Results = ProcessPool.map(WorkerProcess, WorkerProcessDataIterable, MPParams["ChunkSize"]) 186 else: 187 MiscUtil.PrintError("The value, %s, specified for \"--inputDataMode\" is not supported." % (MPParams["InputDataMode"])) 188 189 # Print out Psi4 version in the main process... 190 MiscUtil.PrintInfo("\nInitializing Psi4...\n") 191 Psi4Handle = Psi4Util.InitializePsi4(PrintVersion = True, PrintHeader = False) 192 OptionsInfo["psi4"] = Psi4Handle 193 194 (MolCount, ValidMolCount, EnergyFailedCount) = [0] * 3 195 for Result in Results: 196 MolCount += 1 197 MolIndex, EncodedMol, CalcStatus, Energy, EnergyDetails = Result 198 199 if EncodedMol is None: 200 continue 201 202 ValidMolCount += 1 203 204 Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol) 205 206 if not CalcStatus: 207 if not OptionsInfo["QuietMode"]: 208 MolName = RDKitUtil.GetMolName(Mol, MolCount) 209 MiscUtil.PrintWarning("Failed to calculate energy for molecule %s" % MolName) 210 211 EnergyFailedCount += 1 212 continue 213 214 WriteMolecule(Writer, Mol, Energy, EnergyDetails) 215 216 return (MolCount, ValidMolCount, EnergyFailedCount) 217 218 def InitializeWorkerProcess(*EncodedArgs): 219 """Initialize data for a worker process.""" 220 221 global Options, OptionsInfo 222 223 if not OptionsInfo["QuietMode"]: 224 MiscUtil.PrintInfo("Starting process (PID: %s)..." % os.getpid()) 225 226 # Decode Options and OptionInfo... 227 Options = MiscUtil.ObjectFromBase64EncodedString(EncodedArgs[0]) 228 OptionsInfo = MiscUtil.ObjectFromBase64EncodedString(EncodedArgs[1]) 229 230 # Psi4 is initialized in the worker process to avoid creation of redundant Psi4 231 # output files for each process... 232 OptionsInfo["Psi4Initialized"] = False 233 234 def InitializePsi4ForWorkerProcess(): 235 """Initialize Psi4 for a worker process.""" 236 237 if OptionsInfo["Psi4Initialized"]: 238 return 239 240 OptionsInfo["Psi4Initialized"] = True 241 242 # Update output file... 243 OptionsInfo["Psi4RunParams"]["OutputFile"] = Psi4Util.UpdatePsi4OutputFileUsingPID(OptionsInfo["Psi4RunParams"]["OutputFile"], os.getpid()) 244 245 # Intialize Psi4... 246 OptionsInfo["psi4"] = Psi4Util.InitializePsi4(Psi4RunParams = OptionsInfo["Psi4RunParams"], Psi4OptionsParams = OptionsInfo["Psi4OptionsParams"], PrintVersion = False, PrintHeader = True) 247 248 # Setup conversion factor for energy units... 249 SetupEnergyConversionFactor(OptionsInfo["psi4"]) 250 251 def WorkerProcess(EncodedMolInfo): 252 """Process data for a worker process.""" 253 254 if not OptionsInfo["Psi4Initialized"]: 255 InitializePsi4ForWorkerProcess() 256 257 MolIndex, EncodedMol = EncodedMolInfo 258 259 CalcStatus = False 260 Energy = None 261 EnergyDetails = None 262 263 if EncodedMol is None: 264 return [MolIndex, None, CalcStatus, Energy, EnergyDetails] 265 266 Mol = RDKitUtil.MolFromBase64EncodedMolString(EncodedMol) 267 MolCount = MolIndex + 1 268 269 if not CheckAndValidateMolecule(Mol, MolCount): 270 return [MolIndex, None, CalcStatus, Energy, EnergyDetails] 271 272 # Setup a Psi4 molecule... 273 Psi4Mol = SetupPsi4Mol(OptionsInfo["psi4"], Mol, MolCount) 274 if Psi4Mol is None: 275 return [MolIndex, None, CalcStatus, Energy, EnergyDetails] 276 277 CalcStatus, Energy, EnergyDetails = CalculateMoleculeInteractionEnergy(OptionsInfo["psi4"], Psi4Mol, Mol, MolCount) 278 279 return [MolIndex, RDKitUtil.MolToBase64EncodedMolString(Mol, PropertyPickleFlags = Chem.PropertyPickleOptions.MolProps | Chem.PropertyPickleOptions.PrivateProps), CalcStatus, Energy, EnergyDetails] 280 281 def CalculateMoleculeInteractionEnergy(Psi4Handle, Psi4Mol, Mol, MolNum = None): 282 """Calculate interaction energy for a molecule containing two components.""" 283 284 # Setup reference wave function... 285 Reference = SetupReferenceWavefunction(Mol) 286 Psi4Handle.set_options({'Reference': Reference}) 287 288 # Setup method name and basis set... 289 MethodName, BasisSet = SetupMethodNameAndBasisSet(Mol) 290 MethodAndBasisSet = Psi4Util.JoinMethodNameAndBasisSet(MethodName, BasisSet) 291 292 Status, Energy, EnergyDetails = [False, None, None] 293 try: 294 if OptionsInfo["BSSEType"] is None: 295 Energy = Psi4Handle.energy(MethodAndBasisSet, molecule = Psi4Mol, return_wfn = False) 296 else: 297 Energy = Psi4Handle.energy(MethodAndBasisSet, bsse_type = OptionsInfo["BSSEType"], molecule = Psi4Mol, return_wfn = False) 298 Status = True 299 except Exception as ErrMsg: 300 if not OptionsInfo["QuietMode"]: 301 MiscUtil.PrintWarning("Failed to calculate interaction energy:\n%s\n" % ErrMsg) 302 303 # Retrieve SAPT energy details... 304 if Status and OptionsInfo["SAPTMode"]: 305 EnergyTypeMap = OptionsInfo["SAPTEnergyIDsToTypes"] 306 EnergyDetails = {} 307 for EnergyType in EnergyTypeMap: 308 try: 309 EnergyDetails[EnergyType] = Psi4Handle.variable(EnergyTypeMap[EnergyType]) 310 except Exception as ErrMsg: 311 EnergyDetails[EnergyType] = None 312 if not OptionsInfo["QuietMode"]: 313 MiscUtil.PrintWarning("Failed to retrieve value for interaction energy components %s:\n%s\n" % (EnergyType, ErrMsg)) 314 315 # Convert energy units... 316 if Status and OptionsInfo["ApplyEnergyConversionFactor"]: 317 if Energy is not None: 318 Energy = Energy * OptionsInfo["EnergyConversionFactor"] 319 if EnergyDetails is not None: 320 for EnergyType in EnergyDetails: 321 if EnergyDetails[EnergyType] is not None: 322 EnergyDetails[EnergyType] = EnergyDetails[EnergyType] * OptionsInfo["EnergyConversionFactor"] 323 324 # Clean up 325 PerformPsi4Cleanup(Psi4Handle) 326 327 return (Status, Energy, EnergyDetails) 328 329 def SetupPsi4Mol(Psi4Handle, Mol, MolCount = None): 330 """Setup a Psi4 molecule object.""" 331 332 MolGeometry = RDKitUtil.GetPsi4XYZFormatString(Mol, NoCom = True, NoReorient = True, CheckFragments = True) 333 334 try: 335 Psi4Mol = Psi4Handle.geometry(MolGeometry) 336 except Exception as ErrMsg: 337 Psi4Mol = None 338 if not OptionsInfo["QuietMode"]: 339 MiscUtil.PrintWarning("Failed to create Psi4 molecule from geometry string: %s\n" % ErrMsg) 340 MolName = RDKitUtil.GetMolName(Mol, MolCount) 341 MiscUtil.PrintWarning("Ignoring molecule: %s" % MolName) 342 343 return Psi4Mol 344 345 def PerformPsi4Cleanup(Psi4Handle): 346 """Perform clean up.""" 347 348 # Clean up after Psi4 run ... 349 Psi4Handle.core.clean() 350 351 # Clean up any leftover scratch files... 352 if OptionsInfo["MPMode"]: 353 Psi4Util.RemoveScratchFiles(Psi4Handle, OptionsInfo["Psi4RunParams"]["OutputFile"]) 354 355 def CheckAndValidateMolecule(Mol, MolCount = None): 356 """Validate molecule for Psi4 calculations.""" 357 358 if Mol is None: 359 if not OptionsInfo["QuietMode"]: 360 MiscUtil.PrintInfo("\nProcessing molecule number %s..." % MolCount) 361 return False 362 363 MolName = RDKitUtil.GetMolName(Mol, MolCount) 364 if not OptionsInfo["QuietMode"]: 365 MiscUtil.PrintInfo("\nProcessing molecule %s..." % MolName) 366 367 if RDKitUtil.IsMolEmpty(Mol): 368 if not OptionsInfo["QuietMode"]: 369 MiscUtil.PrintWarning("Ignoring empty molecule: %s\n" % MolName) 370 return False 371 372 if not RDKitUtil.ValidateElementSymbols(RDKitUtil.GetAtomSymbols(Mol)): 373 if not OptionsInfo["QuietMode"]: 374 MiscUtil.PrintWarning("Ignoring molecule containing invalid element symbols: %s\n" % MolName) 375 return False 376 377 # Check for number of fragments... 378 NumFragments = RDKitUtil.GetNumFragments(Mol) 379 if OptionsInfo["SAPTMode"] or OptionsInfo["SNSMP2Mode"]: 380 if NumFragments != 2 : 381 if not OptionsInfo["QuietMode"]: 382 MiscUtil.PrintWarning("Ignoring molecule containing invalid number of fragments: %s. It must contain exaclty 2 fragments for calculation of interaction energy using SAPT or SNS-MP2 methodology.\n" % NumFragments) 383 return False 384 else: 385 if NumFragments == 1: 386 if not OptionsInfo["QuietMode"]: 387 MiscUtil.PrintWarning("Ignoring molecule containing invalid number of fragments: %s. It must contain more than 1 fragment for calculation of interaction energy using counterpoise correctio methodology.\n" % NumFragments) 388 return False 389 390 # Check for 3D flag... 391 if not Mol.GetConformer().Is3D(): 392 if not OptionsInfo["QuietMode"]: 393 MiscUtil.PrintWarning("3D tag is not set for molecule: %s\n" % MolName) 394 395 # Check for missing hydrogens... 396 if RDKitUtil.AreHydrogensMissingInMolecule(Mol): 397 if not OptionsInfo["QuietMode"]: 398 MiscUtil.PrintWarning("Missing hydrogens in molecule: %s\n" % MolName) 399 400 return True 401 402 def SetupMethodNameAndBasisSet(Mol): 403 """Setup method name and basis set.""" 404 405 return (OptionsInfo["MethodName"], OptionsInfo["BasisSet"]) 406 407 def SetupReferenceWavefunction(Mol): 408 """Setup reference wave function.""" 409 410 Reference = OptionsInfo["Reference"] 411 if OptionsInfo["ReferenceAuto"]: 412 Reference = 'UHF' if (RDKitUtil.GetSpinMultiplicity(Mol) > 1) else 'RHF' 413 414 return Reference 415 416 def SetupEnergyConversionFactor(Psi4Handle): 417 """Setup converstion factor for energt units. The Psi4 energy units are Hartrees.""" 418 419 EnergyUnits = OptionsInfo["EnergyUnits"] 420 421 ApplyConversionFactor = True 422 if re.match("^kcal\/mol$", EnergyUnits, re.I): 423 ConversionFactor = Psi4Handle.constants.hartree2kcalmol 424 elif re.match("^kJ\/mol$", EnergyUnits, re.I): 425 ConversionFactor = Psi4Handle.constants.hartree2kJmol 426 elif re.match("^eV$", EnergyUnits, re.I): 427 ConversionFactor = Psi4Handle.constants.hartree2ev 428 else: 429 ApplyConversionFactor = False 430 ConversionFactor = 1.0 431 432 OptionsInfo["ApplyEnergyConversionFactor"] = ApplyConversionFactor 433 OptionsInfo["EnergyConversionFactor"] = ConversionFactor 434 435 def WriteMolecule(Writer, Mol, Energy, EnergyDetails): 436 """Write molecule.""" 437 438 # Setup energy... 439 EnergyValue = "%.*f" % (OptionsInfo["Precision"], Energy) if Energy is not None else "" 440 Mol.SetProp(OptionsInfo["EnergyDataFieldLabel"], EnergyValue) 441 442 # Setup SAPT energy details... 443 if EnergyDetails is not None and OptionsInfo["SAPTMode"]: 444 for EnergyID in OptionsInfo["SAPTEnergyIDs"]: 445 Energy = EnergyDetails[EnergyID] if EnergyID in EnergyDetails else None 446 EnergyValue = "%.*f" % (OptionsInfo["Precision"], Energy) if Energy is not None else "" 447 448 Mol.SetProp(OptionsInfo["SAPTEnergyIDsToLabels"][EnergyID], EnergyValue) 449 450 Writer.write(Mol) 451 452 def ProcessMethodNameAndBasisSetOptions(): 453 """Process method name and basis set options.""" 454 455 MethodName = Options["--methodName"] 456 MethodNameAuto = True if re.match("^auto$", MethodName, re.I) else False 457 if MethodNameAuto: 458 MethodName = "SAPT0" 459 SAPTMode = True if re.match("^SAPT", MethodName, re.I) else False 460 461 SNSMP2Mode = True if re.match("^SNS-MP2$", MethodName, re.I) else False 462 463 BasisSet = Options["--basisSet"] 464 BasisSetAuto = True if re.match("^auto$", BasisSet, re.I) else False 465 if BasisSetAuto: 466 if SAPTMode: 467 BasisSet = "jun-cc-pVDZ" 468 elif SNSMP2Mode: 469 BasisSet = "" 470 else: 471 MiscUtil.PrintError("A basis set must be explicitly specified using \"-b, --basisSet\" option for, \"%s\", value of \"-m, --methodName\". " % (MethodName)) 472 473 if SNSMP2Mode and not MiscUtil.IsEmpty(BasisSet): 474 MiscUtil.PrintError("The basis set value, \"%s\", specified using \"-b, --basisSet\" option is not valid. It must be an empty string SNS-MP2 calculations." % (Options["--basisSet"])) 475 476 OptionsInfo["MethodName"] = MethodName 477 OptionsInfo["MethodNameAuto"] = MethodNameAuto 478 OptionsInfo["SAPTMode"] = SAPTMode 479 OptionsInfo["SNSMP2Mode"] = SNSMP2Mode 480 481 OptionsInfo["BasisSet"] = BasisSet 482 OptionsInfo["BasisSetAuto"] = BasisSetAuto 483 484 def ProcessBSSETypeOption(): 485 """Process basis set superposition energy correction option.""" 486 487 BSSEType = None if re.match("^None$", Options["--bsseType"], re.I) or MiscUtil.IsEmpty(Options["--bsseType"]) else Options["--bsseType"] 488 BSSETypeAuto = True if re.match("^auto$", Options["--bsseType"], re.I) else False 489 490 if BSSETypeAuto: 491 if OptionsInfo["SAPTMode"] or OptionsInfo["SNSMP2Mode"]: 492 BSSEType = None 493 elif re.match("^HF3c$", OptionsInfo["MethodName"], re.I): 494 BSSEType = "noCP" 495 else: 496 BSSEType = "CP" 497 else: 498 if OptionsInfo["SAPTMode"] or OptionsInfo["SNSMP2Mode"]: 499 if BSSEType is not None: 500 MiscUtil.PrintError("The BSSE type value, \"%s\", specified using \"--bsseType\" option is not valid for SAPT or SNS-MP2 calculations. It must be set to None." % (Options["--bsseType"])) 501 else: 502 if BSSEType is None: 503 MiscUtil.PrintWarning("The BSSE type value, \"%s\", specified using \"--bsseType\" option is not valid for \"%s\" calculations. Possible values: CP, noCP or VMFC" % (Options["--bsseType"], OptionsInfo["MethodName"])) 504 505 OptionsInfo["BSSEType"] = BSSEType 506 OptionsInfo["BSSETypeAuto"] = BSSETypeAuto 507 508 def ProcessSAPTEnergyDataFieldLabelsOption(): 509 """Process data field labels for SAPT interaction energy components.""" 510 511 ParamsOptionName = "--energySAPTDataFieldLabels" 512 ParamsOptionValue = Options["--energySAPTDataFieldLabels"] 513 514 ParamsIDs = ["ElectrostaticEnergy", "ExchangeEnergy", "InductionEnergy", "DispersionEnergy"] 515 ParamsIDsToTypes = {"ElectrostaticEnergy": "SAPT ELST ENERGY", "ExchangeEnergy": "SAPT EXCH ENERGY", "InductionEnergy": "SAPT IND ENERGY", "DispersionEnergy": "SAPT DISP ENERGY"} 516 517 UnitsLabel = "(%s)" % Options["--energyUnits"] 518 ParamsIDsToLabels = {"ElectrostaticEnergy": "Psi4_SAPT_Electrostatic_Energy %s" % UnitsLabel, "ExchangeEnergy": "Psi4_SAPT_Exchange_Energy %s" % UnitsLabel, "InductionEnergy": "Psi4_SAPT_Induction_Energy %s" % UnitsLabel, "DispersionEnergy": "Psi4_SAPT_Dispersion_Energy %s" % UnitsLabel} 519 520 if re.match("^auto$", ParamsOptionValue, re.I): 521 OptionsInfo["SAPTEnergyIDs"] = ParamsIDs 522 OptionsInfo["SAPTEnergyIDsToTypes"] = ParamsIDsToTypes 523 OptionsInfo["SAPTEnergyIDsToLabels"] = ParamsIDsToLabels 524 return 525 526 # Setup a canonical paramater names... 527 ValidParamNames = [] 528 CanonicalParamNamesMap = {} 529 for ParamName in sorted(ParamsIDsToLabels): 530 ValidParamNames.append(ParamName) 531 CanonicalParamNamesMap[ParamName.lower()] = ParamName 532 533 ParamsOptionValue = ParamsOptionValue.strip() 534 if not ParamsOptionValue: 535 PrintError("No valid parameter name and value pairs specified using \"%s\" option" % ParamsOptionName) 536 537 ParamsOptionValueWords = ParamsOptionValue.split(",") 538 if len(ParamsOptionValueWords) % 2: 539 MiscUtil.PrintError("The number of comma delimited paramater names and values, %d, specified using \"%s\" option must be an even number." % (len(ParamsOptionValueWords), ParamsOptionName)) 540 541 # Validate paramater name and value pairs... 542 for Index in range(0, len(ParamsOptionValueWords), 2): 543 Name = ParamsOptionValueWords[Index].strip() 544 Value = ParamsOptionValueWords[Index + 1].strip() 545 546 CanonicalName = Name.lower() 547 if not CanonicalName in CanonicalParamNamesMap: 548 MiscUtil.PrintError("The parameter name, %s, specified using \"%s\" is not a valid name. Supported parameter names: %s" % (Name, ParamsOptionName, " ".join(ValidParamNames))) 549 550 ParamName = CanonicalParamNamesMap[CanonicalName] 551 ParamValue = Value 552 553 # Set value... 554 ParamsIDsToLabels[ParamName] = ParamValue 555 556 OptionsInfo["SAPTEnergyIDs"] = ParamsIDs 557 OptionsInfo["SAPTEnergyIDsToTypes"] = ParamsIDsToTypes 558 OptionsInfo["SAPTEnergyIDsToLabels"] = ParamsIDsToLabels 559 560 def ProcessOptions(): 561 """Process and validate command line arguments and options.""" 562 563 MiscUtil.PrintInfo("Processing options...") 564 565 # Validate options... 566 ValidateOptions() 567 568 OptionsInfo["Infile"] = Options["--infile"] 569 ParamsDefaultInfoOverride = {"RemoveHydrogens": False} 570 OptionsInfo["InfileParams"] = MiscUtil.ProcessOptionInfileParameters("--infileParams", Options["--infileParams"], InfileName = Options["--infile"], ParamsDefaultInfo = ParamsDefaultInfoOverride) 571 572 OptionsInfo["Outfile"] = Options["--outfile"] 573 OptionsInfo["OutfileParams"] = MiscUtil.ProcessOptionOutfileParameters("--outfileParams", Options["--outfileParams"]) 574 575 OptionsInfo["Overwrite"] = Options["--overwrite"] 576 577 # Method and basis set... 578 ProcessMethodNameAndBasisSetOptions() 579 580 # BSSEType option... 581 ProcessBSSETypeOption() 582 583 # Reference wavefunction... 584 OptionsInfo["Reference"] = Options["--reference"] 585 OptionsInfo["ReferenceAuto"] = True if re.match("^auto$", Options["--reference"], re.I) else False 586 587 # Run and options parameters... 588 OptionsInfo["Psi4OptionsParams"] = Psi4Util.ProcessPsi4OptionsParameters("--psi4OptionsParams", Options["--psi4OptionsParams"]) 589 OptionsInfo["Psi4RunParams"] = Psi4Util.ProcessPsi4RunParameters("--psi4RunParams", Options["--psi4RunParams"], InfileName = OptionsInfo["Infile"]) 590 591 # Interaction energy units... 592 OptionsInfo["EnergyUnits"] = Options["--energyUnits"] 593 594 # Total interaction energy label... 595 EnergyDataFieldLabel = Options["--energyDataFieldLabel"] 596 if re.match("^auto$", EnergyDataFieldLabel, re.I): 597 EnergyLabel = "Psi4_Interaction_Energy" 598 if OptionsInfo["SAPTMode"]: 599 EnergyLabel = "Psi4_SAPT_Interaction_Energy" 600 elif OptionsInfo["SNSMP2Mode"]: 601 EnergyLabel = "Psi4_SNS-MP2_Interaction_Energy" 602 EnergyDataFieldLabel = "%s %s" % (EnergyLabel, Options["--energyUnits"]) 603 604 OptionsInfo["EnergyDataFieldLabel"] = EnergyDataFieldLabel 605 606 ProcessSAPTEnergyDataFieldLabelsOption() 607 608 OptionsInfo["MPMode"] = True if re.match("^yes$", Options["--mp"], re.I) else False 609 OptionsInfo["MPParams"] = MiscUtil.ProcessOptionMultiprocessingParameters("--mpParams", Options["--mpParams"]) 610 611 OptionsInfo["Precision"] = int(Options["--precision"]) 612 OptionsInfo["QuietMode"] = True if re.match("^yes$", Options["--quiet"], re.I) else False 613 614 def RetrieveOptions(): 615 """Retrieve command line arguments and options.""" 616 617 # Get options... 618 global Options 619 Options = docopt(_docoptUsage_) 620 621 # Set current working directory to the specified directory... 622 WorkingDir = Options["--workingdir"] 623 if WorkingDir: 624 os.chdir(WorkingDir) 625 626 # Handle examples option... 627 if "--examples" in Options and Options["--examples"]: 628 MiscUtil.PrintInfo(MiscUtil.GetExamplesTextFromDocOptText(_docoptUsage_)) 629 sys.exit(0) 630 631 def ValidateOptions(): 632 """Validate option values.""" 633 634 MiscUtil.ValidateOptionTextValue("--bsseType", Options["--bsseType"], "CP noCP VMFC None auto") 635 636 MiscUtil.ValidateOptionTextValue("--energyUnits", Options["--energyUnits"], "Hartrees kcal/mol kJ/mol eV") 637 638 MiscUtil.ValidateOptionFilePath("-i, --infile", Options["--infile"]) 639 MiscUtil.ValidateOptionFileExt("-i, --infile", Options["--infile"], "sdf sd mol") 640 641 MiscUtil.ValidateOptionFileExt("-o, --outfile", Options["--outfile"], "sdf sd") 642 MiscUtil.ValidateOptionsOutputFileOverwrite("-o, --outfile", Options["--outfile"], "--overwrite", Options["--overwrite"]) 643 MiscUtil.ValidateOptionsDistinctFileNames("-i, --infile", Options["--infile"], "-o, --outfile", Options["--outfile"]) 644 645 MiscUtil.ValidateOptionTextValue("--mp", Options["--mp"], "yes no") 646 MiscUtil.ValidateOptionIntegerValue("-p, --precision", Options["--precision"], {">": 0}) 647 648 MiscUtil.ValidateOptionTextValue("-q, --quiet", Options["--quiet"], "yes no") 649 650 # Setup a usage string for docopt... 651 _docoptUsage_ = """ 652 Psi4CalculateInteractionEnergy.py - Calculate interaction energy 653 654 Usage: 655 Psi4CalculateInteractionEnergy.py [--basisSet <text>] [--bsseType <CP, noCP, VMFC, or None>] 656 [--energyDataFieldLabel <text>] [--energySAPTDataFieldLabels <Type,Label,...,...>] 657 [--energyUnits <text>] [--infileParams <Name,Value,...>] [--methodName <text>] 658 [--mp <yes or no>] [--mpParams <Name, Value,...>] [ --outfileParams <Name,Value,...> ] 659 [--overwrite] [--precision <number> ] [--psi4OptionsParams <Name,Value,...>] 660 [--psi4RunParams <Name,Value,...>] [--quiet <yes or no>] 661 [--reference <text>] [-w <dir>] -i <infile> -o <outfile> 662 Psi4CalculateInteractionEnergy.py -h | --help | -e | --examples 663 664 Description: 665 Calculate interaction energy for molecules using a specified method name and 666 basis set. The molecules must contain exactly two fragments or disconnected 667 components for Symmetry Adapted Perturbation Theory (SAPT) [ Ref 154-155 ] 668 and Spin-Network-Scaled MP2 (SNS-MP2) [ Ref 156] calculations and more than 669 one fragment for all other calculations. An arbitrary number of fragments may be 670 present in a molecule for Basis Set Superposition Energy (BSSE) correction 671 calculations. 672 673 The interaction energy is calculated at SAPT0 / jun-cc-pVDZ level of theory by 674 default. The SAPT0 calculations are relatively fast but less accurate. You may 675 want to consider calculating interaction energy at WB97X-D3 / aug-cc-pVTZ, 676 B3LYP-D3 / aug-cc-pVTZ, or higher level of theory [ Ref 157 ] to improve the 677 accuracy of your results. The WB97X-D3 and B3LYP-D3 calculations rely on 678 the presence of DFTD3 and gCP Psi4 plugins in your environment. 679 680 The molecules must have 3D coordinates in input file. The molecular geometry 681 is not optimized before the calculation. In addition, hydrogens must be present 682 for all molecules in input file. The 3D coordinates are not modified during the 683 calculation. 684 685 A Psi4 XYZ format geometry string is automatically generated for each molecule 686 in input file. It contains atom symbols and 3D coordinates for each atom in a 687 molecule. In addition, the formal charge and spin multiplicity are present in the 688 the geometry string. These values are either retrieved from molecule properties 689 named 'FormalCharge' and 'SpinMultiplicty' or dynamically calculated for a 690 molecule. A double dash separates each fragment or component in a molecule. 691 The same formal charge and multiplicity values are assigned to each fragment 692 in a molecule. 693 694 The supported input file formats are: Mol (.mol), SD (.sdf, .sd) 695 696 The supported output file formats are: SD (.sdf, .sd) 697 698 Options: 699 -b, --basisSet <text> [default: auto] 700 Basis set to use for interaction energy calculation. Default: jun-cc-pVDZ for 701 SAPT calculations; None for SNS-MP2 calculations to use its default basis 702 set; otherwise, it must be explicitly specified using this option. The specified 703 value must be a valid Psi4 basis set. No validation is performed. You may set 704 an empty string as a value for the basis set. 705 706 The following list shows a representative sample of basis sets available 707 in Psi4: 708 709 STO-3G, 6-31G, 6-31+G, 6-31++G, 6-31G*, 6-31+G*, 6-31++G*, 710 6-31G**, 6-31+G**, 6-31++G**, 6-311G, 6-311+G, 6-311++G, 711 6-311G*, 6-311+G*, 6-311++G*, 6-311G**, 6-311+G**, 6-311++G**, 712 cc-pVDZ, cc-pCVDZ, aug-cc-pVDZ, cc-pVDZ-DK, cc-pCVDZ-DK, def2-SVP, 713 def2-SVPD, def2-TZVP, def2-TZVPD, def2-TZVPP, def2-TZVPPD 714 715 --bsseType <CP, noCP, VMFC, or None> [default: auto] 716 Type of Basis Set Superposition Energy (BSSE) correction to apply during the 717 calculation of interaction energy. Possible values: 718 719 CP: Counterpoise corrected interaction energy 720 noCP: Supramolecular interaction energy without any CP correction 721 VMFC: Valiron-Mayer Function Counterpoise correction 722 None: The Psi4 option 'bsse_type' is not passed to the energy 723 function during the calculation of interaction energy 724 725 Default values: 726 727 None: SAPT and SNS-MP2 calculations. An explicit bsse_type option is not 728 valid for these calculations. 729 HF3c: noCP to use built-in correction 730 CP: All other calculations 731 732 --energyDataFieldLabel <text> [default: auto] 733 Energy data field label for writing interaction energy values. Default: 734 Psi4_SAPT_Interaction_Energy (<Units>) for SAPT calculation; 735 Psi4_SNS-MP2_Interaction_Energy (<Units>) for SNS-MP2 calculation; 736 otherwise, Psi4_Interaction_Energy (<Units>) 737 --energySAPTDataFieldLabels <Type,Label,...,...> [default: auto] 738 A comma delimted interaction energy type and data field label value pairs 739 for writing individual components of total SAPT interaction energy. 740 741 The supported SAPT energy types along with their default data field label 742 values are shown below: 743 744 ElectrostaticEnergy, Psi4_SAPT_Electrostatic_Energy (<Units>), 745 ExchangeEnergy, Psi4_SAPT_Exchange_Energy (<Units>), 746 InductionEnergy, Psi4_SAPT_Induction_Energy (<Units>), 747 DispersionEnergy, Psi4_SAPT_Dispersion_Energy (<Units>) 748 749 --energyUnits <text> [default: kcal/mol] 750 Energy units. Possible values: Hartrees, kcal/mol, kJ/mol, or eV. 751 -e, --examples 752 Print examples. 753 -h, --help 754 Print this help message. 755 -i, --infile <infile> 756 Input file name. 757 --infileParams <Name,Value,...> [default: auto] 758 A comma delimited list of parameter name and value pairs for reading 759 molecules from files. The supported parameter names for different file 760 formats, along with their default values, are shown below: 761 762 SD, MOL: removeHydrogens,no,sanitize,yes,strictParsing,yes 763 764 -m, --methodName <text> [default: auto] 765 Method to use for interaction energy calculation. Default: SAPT0. The 766 specified value must be a valid Psi4 method name. No validation is 767 performed. 768 769 The following list shows a representative sample of methods available 770 in Psi4: 771 772 SAPT0, SAPT2, SAPT2+, SAPT2+(CCD), SAPT2+DMP2, SAPT2+(CCD)DMP2 773 SAPT2+(3), SAPT2+(3)(CCD), SAPT2+DMP2, SAPT2+(CCD)DMP2, 774 SAPT2+3, SAPT2+3(CCD), SAPT2+(3)DMP2, SAPT2+3(CCD)DMP2, SNS-MP2, 775 B1LYP, B2PLYP, B2PLYP-D3BJ, B2PLYP-D3MBJ, B3LYP, B3LYP-D3BJ, 776 B3LYP-D3MBJ, CAM-B3LYP, CAM-B3LYP-D3BJ, HF, HF-D3BJ, HF3c, M05, 777 M06, M06-2x, M06-HF, M06-L, MN12-L, MN15, MN15-D3BJ,PBE, PBE0, 778 PBEH3c, PW6B95, PW6B95-D3BJ, WB97, WB97X, WB97X-D, WB97X-D3BJ 779 780 --mp <yes or no> [default: no] 781 Use multiprocessing. 782 783 By default, input data is retrieved in a lazy manner via mp.Pool.imap() 784 function employing lazy RDKit data iterable. This allows processing of 785 arbitrary large data sets without any additional requirements memory. 786 787 All input data may be optionally loaded into memory by mp.Pool.map() 788 before starting worker processes in a process pool by setting the value 789 of 'inputDataMode' to 'InMemory' in '--mpParams' option. 790 791 A word to the wise: The default 'chunkSize' value of 1 during 'Lazy' input 792 data mode may adversely impact the performance. The '--mpParams' section 793 provides additional information to tune the value of 'chunkSize'. 794 --mpParams <Name,Value,...> [default: auto] 795 A comma delimited list of parameter name and value pairs to configure 796 multiprocessing. 797 798 The supported parameter names along with their default and possible 799 values are shown below: 800 801 chunkSize, auto 802 inputDataMode, Lazy [ Possible values: InMemory or Lazy ] 803 numProcesses, auto [ Default: mp.cpu_count() ] 804 805 These parameters are used by the following functions to configure and 806 control the behavior of multiprocessing: mp.Pool(), mp.Pool.map(), and 807 mp.Pool.imap(). 808 809 The chunkSize determines chunks of input data passed to each worker 810 process in a process pool by mp.Pool.map() and mp.Pool.imap() functions. 811 The default value of chunkSize is dependent on the value of 'inputDataMode'. 812 813 The mp.Pool.map() function, invoked during 'InMemory' input data mode, 814 automatically converts RDKit data iterable into a list, loads all data into 815 memory, and calculates the default chunkSize using the following method 816 as shown in its code: 817 818 chunkSize, extra = divmod(len(dataIterable), len(numProcesses) * 4) 819 if extra: chunkSize += 1 820 821 For example, the default chunkSize will be 7 for a pool of 4 worker processes 822 and 100 data items. 823 824 The mp.Pool.imap() function, invoked during 'Lazy' input data mode, employs 825 'lazy' RDKit data iterable to retrieve data as needed, without loading all the 826 data into memory. Consequently, the size of input data is not known a priori. 827 It's not possible to estimate an optimal value for the chunkSize. The default 828 chunkSize is set to 1. 829 830 The default value for the chunkSize during 'Lazy' data mode may adversely 831 impact the performance due to the overhead associated with exchanging 832 small chunks of data. It is generally a good idea to explicitly set chunkSize to 833 a larger value during 'Lazy' input data mode, based on the size of your input 834 data and number of processes in the process pool. 835 836 The mp.Pool.map() function waits for all worker processes to process all 837 the data and return the results. The mp.Pool.imap() function, however, 838 returns the the results obtained from worker processes as soon as the 839 results become available for specified chunks of data. 840 841 The order of data in the results returned by both mp.Pool.map() and 842 mp.Pool.imap() functions always corresponds to the input data. 843 -o, --outfile <outfile> 844 Output file name. 845 --outfileParams <Name,Value,...> [default: auto] 846 A comma delimited list of parameter name and value pairs for writing 847 molecules to files. The supported parameter names for different file 848 formats, along with their default values, are shown below: 849 850 SD: kekulize,yes,forceV3000,no 851 852 --overwrite 853 Overwrite existing files. 854 --precision <number> [default: 6] 855 Floating point precision for writing energy values. 856 --psi4OptionsParams <Name,Value,...> [default: none] 857 A comma delimited list of Psi4 option name and value pairs for setting 858 global and module options. The names are 'option_name' for global options 859 and 'module_name__option_name' for options local to a module. The 860 specified option names must be valid Psi4 names. No validation is 861 performed. 862 863 The specified option name and value pairs are processed and passed to 864 psi4.set_options() as a dictionary. The supported value types are float, 865 integer, boolean, or string. The float value string is converted into a float. 866 The valid values for a boolean string are yes, no, true, false, on, or off. 867 --psi4RunParams <Name,Value,...> [default: auto] 868 A comma delimited list of parameter name and value pairs for configuring 869 Psi4 jobs. 870 871 The supported parameter names along with their default and possible 872 values are shown below: 873 874 MemoryInGB, 1 875 NumThreads, 1 876 OutputFile, auto [ Possible values: stdout, quiet, or FileName ] 877 ScratchDir, auto [ Possivle values: DirName] 878 RemoveOutputFile, yes [ Possible values: yes, no, true, or false] 879 880 These parameters control the runtime behavior of Psi4. 881 882 The default file name for 'OutputFile' is <InFileRoot>_Psi4.out. The PID 883 is appended to output file name during multiprocessing as shown: 884 <InFileRoot>_Psi4_<PIDNum>.out. The 'stdout' value for 'OutputType' 885 sends Psi4 output to stdout. The 'quiet' or 'devnull' value suppresses 886 all Psi4 output. 887 888 The default 'Yes' value of 'RemoveOutputFile' option forces the removal 889 of any existing Psi4 before creating new files to append output from 890 multiple Psi4 runs. 891 892 The option 'ScratchDir' is a directory path to the location of scratch 893 files. The default value corresponds to Psi4 default. It may be used to 894 override the deafult path. 895 -q, --quiet <yes or no> [default: no] 896 Use quiet mode. The warning and information messages will not be printed. 897 -r, --reference <text> [default: auto] 898 Reference wave function to use for interaction energy calculation. Default: RHF 899 or UHF. The default values are Restricted Hartree-Fock (RHF) for closed-shell 900 molecules with all electrons paired and Unrestricted Hartree-Fock (UHF) for 901 open-shell molecules with unpaired electrons. 902 903 The specified value must be a valid Psi4 reference wave function. No validation 904 is performed. For example: ROHF, CUHF, RKS, etc. 905 906 The spin multiplicity determines the default value of reference wave function 907 for input molecules. It is calculated from number of free radical electrons using 908 Hund's rule of maximum multiplicity defined as 2S + 1 where S is the total 909 electron spin. The total spin is 1/2 the number of free radical electrons in a 910 molecule. The value of 'SpinMultiplicity' molecule property takes precedence 911 over the calculated value of spin multiplicity. 912 913 The 'SpinMultiplicity' molecule property may contain multiples values 914 corresponding to the number of fragments in a molecule. This property must 915 not be set for automatic determination of the reference wave functionn. 916 -w, --workingdir <dir> 917 Location of working directory which defaults to the current directory. 918 919 Examples: 920 To calculate interaction energy using SAPT0/aug-cc-pVDZ for molecules in a 921 SD file, use RHF and UHF for closed-shell and open-shell molecules, and write 922 a new SD file, type: 923 924 % Psi4CalculateInteractionEnergy.py -i Psi4SampleDimers3D.sdf 925 -o Psi4SampleDimers3DOut.sdf 926 927 To run the first example for freezing core electrons and setting SCF type to DF 928 and write out a new SD file, type: 929 930 % Psi4CalculateInteractionEnergy.py --psi4OptionsParams "scf_type, df, 931 freeze_core, true" -i Psi4SampleDimers3D.sdf -o 932 Psi4SampleDimers3DOut.sdf 933 934 To calculate interaction energy using SNS2-MP methodology for molecules 935 in a SD containing 3D structures and write a new SD file, type: 936 937 % Psi4CalculateInteractionEnergy.py -m "sns-mp2" 938 -i Psi4SampleDimers3D.sdf -o Psi4SampleDimers3DOut.sdf 939 940 To calculate interaction energy at WB97X-D3/aug-cc-pVTZ level of theory, 941 along with explicit Psi4 run time paramaters, for molecules in a SD containing 942 3D structures and write a new SD file, type: 943 944 % Psi4CalculateInteractionEnergy.py -m WB97X-D3 -b aug-cc-pVTZ 945 --bsseType CP --psi4RunParams "NumThreads,4,MemoryInGB,6" 946 -i Psi4SampleDimers3D.sdf -o Psi4SampleDimers3DOut.sdf 947 948 To calculate interaction energy at B3LYP-D3/aug-cc-pVTZ level of theory using 949 default Psi4 run time paramaters for molecules in a SD containing 3D structures 950 and write a new SD file, type: 951 952 % Psi4CalculateInteractionEnergy.py -m B3LYP-D3 -b aug-cc-pVTZ 953 --bsseType CP -i Psi4SampleDimers3D.sdf -o Psi4SampleDimers3DOut.sdf 954 955 To calculate interaction energy at B3LYP-D3/aug-cc-pVTZ level of theory, along 956 with specifying grid resolution using Psi4 options and explicit Psi4 run time 957 paramaters, for molecules in a SD containing 3D structures 958 and write a new SD file, type: 959 960 % Psi4CalculateInteractionEnergy.py -m B3LYP-D3 -b aug-cc-pVTZ 961 --bsseType CP --psi4OptionsParams "dft_spherical_points, 302, 962 dft_radial_points, 75" --psi4RunParams "NumThreads,4,MemoryInGB,6" 963 -i Psi4SampleDimers3D.sdf -o Psi4SampleDimers3DOut.sdf 964 965 To calculate interaction energy at HF3c level of theory using built-in basis set 966 for molecules in a SD containing 3D structures and write a new SD file, type: 967 968 % Psi4CalculateInteractionEnergy.py -m HF3c -b "" --bsseType noCP 969 -i Psi4SampleDimers3D.sdf -o Psi4SampleDimers3DOut.sdf 970 971 To calculate interaction energy at CCSD(T)/aug-cc-pVDZ level of theory using 972 default Psi4 run time paramaters for molecules in a SD containing 3D structures 973 and write a new SD file, type: 974 975 % Psi4CalculateInteractionEnergy.py -m "ccsd(t)" -b "aug-cc-pvdz" 976 -i Psi4SampleDimers3D.sdf -o Psi4SampleDimers3DOut.sdf 977 978 To run the first example in multiprocessing mode on all available CPUs 979 without loading all data into memory and write out a SD file, type: 980 981 % Psi4CalculateInteractionEnergy.py --mp yes -i Psi4SampleDimers3D.sdf 982 -o Psi4SampleDimers3DOut.sdf 983 984 To run the first example in multiprocessing mode on all available CPUs 985 by loading all data into memory and write out a SD file, type: 986 987 % Psi4CalculateInteractionEnergy.py --mp yes --mpParams "inputDataMode, 988 InMemory" -i Psi4SampleDimers3D.sdf -o Psi4SampleDimers3DOut.sdf 989 990 To run the first example in multiprocessing mode on all available CPUs 991 without loading all data into memory along with multiple threads for each 992 Psi4 run and write out a SD file, type: 993 994 % Psi4CalculateInteractionEnergy.py --mp yes --psi4RunParams "NumThreads,2" 995 -i Psi4SampleDimers3D.sdf -o Psi4SampleDimers3DOut.sdf 996 997 Author: 998 Manish Sud(msud@san.rr.com) 999 1000 See also: 1001 Psi4CalculateEnergy.py, Psi4CalculatePartialCharges.py, Psi4PerformMinimization.py, 1002 Psi4GenerateConformers.py 1003 1004 Copyright: 1005 Copyright (C) 2024 Manish Sud. All rights reserved. 1006 1007 The functionality available in this script is implemented using Psi4, an 1008 open source quantum chemistry software package, and RDKit, an open 1009 source toolkit for cheminformatics developed by Greg Landrum. 1010 1011 This file is part of MayaChemTools. 1012 1013 MayaChemTools is free software; you can redistribute it and/or modify it under 1014 the terms of the GNU Lesser General Public License as published by the Free 1015 Software Foundation; either version 3 of the License, or (at your option) any 1016 later version. 1017 1018 """ 1019 1020 if __name__ == "__main__": 1021 main()