Skip to content

Commit

Permalink
Merge pull request #25 from molssi-seamm/dev
Browse files Browse the repository at this point in the history
Updating for running from containers
  • Loading branch information
seamm authored Jan 12, 2024
2 parents c4fce67 + 20e8ef4 commit f10072e
Show file tree
Hide file tree
Showing 8 changed files with 138 additions and 98 deletions.
3 changes: 3 additions & 0 deletions HISTORY.rst
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
=======
History
=======
2024.1.11 -- Changes to allow running in containers.
* Moved to the new executor and ensured it still runs directly.
* Fixed bugs in printing the summary output.

2023.8.23 -- Fix for installation of Psi4
* Psi4 is now available on CondaForge, so install from there if requested.
Expand Down
6 changes: 3 additions & 3 deletions devtools/conda-envs/test_env.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ dependencies:
# Of the code
- numpy
- optking
- psutil
- scipy
- seamm
- tabulate
Expand All @@ -29,5 +28,6 @@ dependencies:

# Pip-only installs
- pip:
# Documentation
- sphinx-copybutton
- seamm-exec
# Documentation
- sphinx-copybutton
34 changes: 17 additions & 17 deletions psi4_step/data/references.bib
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
@article{doi:10.1063/5.0006002,
author = {Smith,Daniel G. A. and Burns,Lori A. and Simmonett,Andrew C. and
Parrish,Robert M. and Schieber,Matthew C. and Galvelis,Raimondas and
Kraus,Peter and Kruse,Holger and Di Remigio,Roberto and Alenaizan,Asem
and James,Andrew M. and Lehtola,Susi and Misiewicz,Jonathon P. and
Scheurer,Maximilian and Shaw,Robert A. and Schriber,Jeffrey B. and
Xie,Yi and Glick,Zachary L. and Sirianni,Dominic A. and
O’Brien,Joseph Senan and Waldrop,Jonathan M. and Kumar,Ashutosh and
Hohenstein,Edward G. and Pritchard,Benjamin P. and Brooks,Bernard R.
and Schaefer,Henry F. and Sokolov,Alexander Yu. and Patkowski,Konrad
and DePrince,A. Eugene and Bozkaya,Uğur and King,Rollin A. and
Evangelista,Francesco A. and Turney,Justin M. and Crawford,T. Daniel
and Sherrill,C. David },
author = {Smith, Daniel G. A. and Burns, Lori A. and Simmonett, Andrew C. and
Parrish, Robert M. and Schieber, Matthew C. and Galvelis, Raimondas and
Kraus, Peter and Kruse, Holger and Di Remigio, Roberto and Alenaizan, Asem and
James, Andrew M. and Lehtola, Susi and Misiewicz, Jonathon P. and
Scheurer, Maximilian and Shaw, Robert A. and Schriber, Jeffrey B. and
Xie, Yi and Glick, Zachary L. and Sirianni, Dominic A. and
O’Brien, Joseph Senan and Waldrop, Jonathan M. and Kumar, Ashutosh and
Hohenstein, Edward G. and Pritchard, Benjamin P. and Brooks, Bernard R. and
Schaefer, Henry F. and Sokolov, Alexander Yu. and Patkowski, Konrad and
DePrince, A. Eugene and Bozkaya, Uğur and King, Rollin A. and
Evangelista, Francesco A. and Turney, Justin M. and Crawford, T. Daniel and
Sherrill, C. David},
title = {PSI4 1.4: Open-source software for high-throughput quantum chemistry},
journal = {The Journal of Chemical Physics},
volume = {152},
Expand All @@ -21,13 +21,13 @@ @article{doi:10.1063/5.0006002
URL = {https://doi.org/10.1063/5.0006002},
eprint = {https://doi.org/10.1063/5.0006002}
}
@Misc{packmol_step,
author = {Saxe, P.},
@Misc{psi4_step,
author = {Paul Saxe},
title = {Psi4 plug-in for SEAMM},
month = {oct},
year = 2020,
month = {$month},
year = {$year},
organization = {Molecular Sciences Software Institute (MolSSI)},
url = {https://github.com/molssi-seamm/psi4_step},
address = {Blacksburg, VA, USA},
version = {2020.10.6}
version = {$version}
}
47 changes: 40 additions & 7 deletions psi4_step/energy.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,10 +52,15 @@ def git_revision(self):
"""The git version of this module."""
return psi4_step.__git_revision__

def description_text(self, P=None, calculation_type="Single-point energy"):
def description_text(
self,
P=None,
calculation_type="Single-point energy",
configuration=None,
):
"""Prepare information about what this node will do"""

if not P:
if P is not None:
P = self.parameters.values_to_dict()

if P["level"] == "recommended":
Expand All @@ -75,7 +80,8 @@ def description_text(self, P=None, calculation_type="Single-point energy"):
text = f"{calculation_type} using {method} with an "
text += f"exchange-correlation potential of {functional}"
if (
len(psi4_step.dft_functionals[functional]["dispersion"]) > 1
functional in psi4_step.dft_functionals
and len(psi4_step.dft_functionals[functional]["dispersion"]) > 1
and P["dispersion"] != "none"
):
text += f" with the {P['dispersion']} dispersion correction."
Expand All @@ -87,6 +93,17 @@ def description_text(self, P=None, calculation_type="Single-point energy"):
# Spin
if P["spin-restricted"] == "yes":
text += " The spin will be restricted to a pure eigenstate."
elif P["spin-restricted"] == "default":
if configuration is not None:
if configuration.spin_multiplicity == 1:
text += " The spin will be restricted to a pure eigenstate."
else:
text += " The spin will not be restricted and may not be a "
text += "proper eigenstate."
else:
text += " The spin will be restricted to a pure "
text += "eigenstate for singlet states. Otherwise it will not "
text += "be restricted and may not be a proper eigenstate."
elif self.is_expr(P["spin-restricted"]):
text += " Whether the spin will be restricted to a pure "
text += "eigenstate will be determined by {P['spin-restricted']}"
Expand All @@ -95,11 +112,21 @@ def description_text(self, P=None, calculation_type="Single-point energy"):
text += "proper eigenstate."

# Plotting
if P["density"]:
if P["orbitals"]:
if isinstance(P["density"], str):
density = P["density"] != "no"
else:
density = P["density"]

if isinstance(P["orbitals"], str):
orbitals = P["orbitals"] != "no"
else:
orbitals = P["orbitals"]

if density:
if orbitals:
text += "\nThe alpha and beta electron, total, and spin densities, "
text += f"and orbitals {P['selected orbitals']} will be plotted."
elif P["orbitals"]:
elif orbitals:
text += f"\nThe orbitals {P['selected orbitals']} will be plotted."

return self.header + "\n" + __(text, **P, indent=4 * " ").__str__()
Expand All @@ -122,7 +149,13 @@ def get_input(self, calculation_type="energy", restart=None):
PP[key] = "{:~P}".format(PP[key])

self.description = []
self.description.append(__(self.description_text(PP), **PP, indent=self.indent))
self.description.append(
__(
self.description_text(PP, configuration=configuration),
**PP,
indent=self.indent,
)
)

lines = []
if calculation_type == "energy":
Expand Down
21 changes: 17 additions & 4 deletions psi4_step/optimization.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,22 @@ def __init__(

self.description = "A geometry optimization"

def description_text(self, P=None):
def description_text(
self,
P=None,
calculation_type="Geometry optimization",
configuration=None,
):
"""Prepare information about what this node will do"""

if not P:
P = self.parameters.values_to_dict()

text = super().description_text(P=P, calculation_type="Geometry optimization")
text = super().description_text(
P=P, calculation_type=calculation_type, configuration=configuration
)

added = "The geometry optimization will use the {optimization method} "
added = "\nThe geometry optimization will use the {optimization method} "
if P["max geometry steps"] == "default":
added += "method, using the default maximum number of steps, which"
added += " is based on the system size."
Expand Down Expand Up @@ -89,7 +96,13 @@ def get_input(self, calculation_type="optimize"):
PP[key] = "{:~P}".format(PP[key])

self.description = []
self.description.append(__(self.description_text(PP), **PP, indent=self.indent))
self.description.append(
__(
self.description_text(PP, configuration=configuration),
**PP,
indent=self.indent,
)
)

lines = []
lines.append("")
Expand Down
103 changes: 47 additions & 56 deletions psi4_step/psi4.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,15 @@
"""Non-graphical part of the Psi4 step in a SEAMM flowchart
"""

import configparser
import json
import logging
from pathlib import Path
import pprint

import psutil

import psi4_step
import seamm
from seamm_util import ureg, Q_ # noqa: F401
import seamm_exec
import seamm_util.printing as printing
from seamm_util.printing import FormattedText as __

Expand Down Expand Up @@ -236,13 +235,6 @@ def create_parser(self):
return result

# Options for Psi4
parser.add_argument(
parser_name,
"--psi4-path",
default="",
help="the path to the Psi4 executable",
)

parser.add_argument(
parser_name,
"--ncores",
Expand Down Expand Up @@ -324,7 +316,7 @@ def run(self):
printer.important(self.header)
printer.important("")

# Add the main citation for DFTB+
# Add the main citation for Psi4
self.references.cite(
raw=self._bibliography["doi:10.1063/5.0006002"],
alias="psi4",
Expand All @@ -344,41 +336,39 @@ def run(self):
options = self.options
seamm_options = self.global_options

# How many processors does this node have?
n_cores = psutil.cpu_count(logical=False)
self.logger.info("The number of cores is {}".format(n_cores))
# Get the computational environment and set limits
ce = seamm_exec.computational_environment()

# How many threads to use
# Maximum number of threads
n_threads = ce["NTASKS"]
if options["ncores"] == "available":
n_threads = n_cores
pass
else:
n_threads = int(options["ncores"])
if n_threads > n_cores:
n_threads = n_cores
if n_threads < 1:
n_threads = 1
if n_threads < 1:
n_threads = 1
if seamm_options["ncores"] != "available":
n_threads = min(n_threads, int(options["ncores"]))
self.logger.info(f"Psi4 will use {n_threads} threads.")

# How much memory to use
svmem = psutil.virtual_memory()
tmp = int(seamm_options["ncores"])
if tmp < n_threads:
n_threads = tmp
ce["NTASKS"] = n_threads

# And memory
if seamm_options["memory"] == "all":
mem_limit = svmem.total
mem_limit = ce["MEM_PER_NODE"]
elif seamm_options["memory"] == "available":
# For the default, 'available', use in proportion to number of
# cores used
mem_limit = svmem.total * (n_threads / n_cores)
mem_limit = n_threads * ce["MEM_PER_CPU"]
else:
mem_limit = dehumanize(seamm_options["memory"])

if options["memory"] == "all":
memory = svmem.total
memory = ce["MEM_PER_NODE"]
elif options["memory"] == "available":
# For the default, 'available', use in proportion to number of
# cores used
memory = svmem.total * (n_threads / n_cores)
memory = n_threads * ce["MEM_PER_CPU"]
else:
memory = dehumanize(options["memory"])

Expand All @@ -395,12 +385,9 @@ def run(self):
min_memory = dehumanize("250 MiB")
if min_memory > memory:
memory = min_memory
ce["MEM_PER_NODE"] = memory
memory = humanize(memory, kilo=1024)

printer.important(
self.indent + f" Psi4 will use {n_threads} threads and {memory} memory\n"
)

# Work through the subflowchart to find out what to do.
self.subflowchart.root_directory = self.flowchart.root_directory

Expand All @@ -409,15 +396,6 @@ def run(self):
# Get the first real node
node0 = self.subflowchart.get_node("1").next()

# See if this is a normal or special run
# node = node0
# while node is not None:
# if isinstance(node, psi4_step.AcceleratedOptimization):
# node.run(node0, memory, n_threads)
# return next_node

# node = node.next()

# Start the input data
input_data = []
input_data.append("import json")
Expand Down Expand Up @@ -474,24 +452,37 @@ def run(self):
result["stderr"] = ""
failed = False
else:
exe_path = Path(options["psi4_path"])
env = {
"PSIPATH": str(exe_path),
"PATH": str(exe_path),
}

local = seamm.ExecLocal()
exe = exe_path / "psi4"
result = local.run(
cmd=[str(exe), f"-n {n_threads}"],
executor = self.flowchart.executor

# Read configuration file for Psi4
ini_dir = Path(seamm_options["root"]).expanduser()
full_config = configparser.ConfigParser()
full_config.read(ini_dir / "psi4.ini")
executor_type = executor.name
if executor_type not in full_config:
raise RuntimeError(
f"No section for '{executor_type}' in Psi4 ini file "
f"({ini_dir / 'psi4.ini'})"
)
config = dict(full_config.items(executor_type))

printer.important(
self.indent
+ f" Psi4 will use {ce['NTASKS']} threads and {memory} memory\n"
)

result = executor.run(
cmd=["{code}"],
config=config,
directory=self.directory,
files=files,
return_files=return_files,
env=env,
directory=directory,
in_situ=True,
) # yapf: disable
shell=True,
ce=ce,
)

if result is None:
if not result:
self.logger.error("There was an error running Psi4")
raise RuntimeError("There was an error running Psi4")

Expand Down
Loading

0 comments on commit f10072e

Please sign in to comment.