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