interaction_eda_step package#

Subpackages#

Submodules#

interaction_eda_step.fragments module#

The fragments of a structure for EDA.

By default each molecule of the configuration is a fragment. The molecules come from the bonds, and their charges from the atoms’ formal charges or, for known molecules (water, carbonates, Li⁺, BF₄⁻, PF₆⁻, monatomic ions), from seamm_mbe’s catalog, which also checks that every fragment has a sensible number of electrons. Alternatively an integer atom column (e.g. “fragment”) assigns the atoms to fragments, with charges summed from the formal charges.

class interaction_eda_step.fragments.Fragment(index: int, name: str, atoms: list, symbols: list, coordinates: ndarray, charge: int = 0, multiplicity: int = 1)[source]#

Bases: object

One fragment.

Variables:
  • index (int) – 0-based.

  • name (str) – e.g. “Li+”, “EC”, or the formula.

  • atoms ([int]) – 0-based atom indices in the configuration, ascending.

  • symbols ([str])

  • coordinates (numpy.ndarray) – (n, 3) Cartesian, Å.

  • charge (int)

  • multiplicity (int)

atoms: list#
charge: int = 0#
coordinates: ndarray#
index: int#
label()[source]#

A short label, e.g. ‘0:Li+’.

multiplicity: int = 1#
property n_electrons#
name: str#
symbols: list#
exception interaction_eda_step.fragments.FragmentError[source]#

Bases: ValueError

The fragments cannot be made from the structure.

interaction_eda_step.fragments.from_configuration(configuration, column=None, charges=None)[source]#

The fragments of a configuration.

Parameters:
  • configuration (molsystem._Configuration) – A cluster (periodicity 0).

  • column (str or None) – An integer atom column assigning the atoms to fragments; None to use the molecules.

  • charges ({str: int} or None) – Charges by molecule type (molecules) or by fragment number as a string (column), overriding the formal charges and the catalog.

Return type:

[Fragment]

interaction_eda_step.fragments.min_distance(a, b)[source]#

The shortest atom-atom distance between two fragments, Å.

interaction_eda_step.fragments.triples_within(fragments, cutoff)[source]#

The triples whose three pairs are all within cutoff (Å, shortest atom-atom distance); all triples when cutoff is None.

interaction_eda_step.installer module#

Installer for the Interaction EDA plug-in.

The GPU4PySCF backend runs in its own conda environment, seamm-gpu4pyscf by default, which this installer creates and registers in gpu4pyscf.ini. The environment holds Python 3.12 from conda-forge and, from PyPI, GPU4PySCF with CuPy, cuTENSOR and the CUDA libraries for the machine’s NVIDIA driver, plus pyscf-dispersion for D3/D4. It needs Linux and an NVIDIA GPU with good double precision; on macOS nothing is installed.

interaction_eda_step.installer.BUILDS = {'cuda12x': ('gpu4pyscf-cuda12x>=1.9.1', 'cupy-cuda12x[ctk]', 'cutensor-cu12', 'pyscf-dispersion'), 'cuda13x': ('gpu4pyscf-cuda13x>=1.9.1', 'cupy-cuda13x[ctk]', 'cutensor-cu13', 'pyscf-dispersion')}#

The pip requirements for each CUDA build. cuda12x is the validated one (ARC, 2026-11-07: gpu4pyscf 1.9.1, cupy 14.2, cuTENSOR 2.8, CUDA 12.9).

class interaction_eda_step.installer.Installer(logger=<Logger interaction_eda_step.installer (WARNING)>)[source]#

Bases: InstallerBase

Handle the installation of GPU4PySCF for the Interaction EDA step.

  1. install creates the conda environment seamm-gpu4pyscf (Python 3.12) and installs GPU4PySCF in it for the machine’s NVIDIA driver, then checks that it imports and can use the GPU, and writes gpu4pyscf.ini. cuda-build in gpu4pyscf.ini (or --cuda-build) forces a build, e.g. on a cluster login node without a GPU.

  2. update upgrades GPU4PySCF and its CUDA libraries in that environment.

  3. check and show say what is installed and whether it works.

An environment named in gpu4pyscf.ini that SEAMM did not create, or an installation = local Python, is never changed.

check()[source]#

Check that gpu4pyscf.ini points at a working GPU4PySCF.

exe_version(config)[source]#

The version of GPU4PySCF in its environment.

install()[source]#

Create the environment and install GPU4PySCF for this machine.

setup_parser()[source]#

Parse the command line into the options.

update()[source]#

Upgrade GPU4PySCF and its CUDA libraries in the environment.

Links the unversioned libcusolver.so to the versioned library in the NVIDIA wheels. GPU4PySCF loads it by the bare name, which the wheels do not provide (“Unable to load libcusolver”).

interaction_eda_step.installer.MINIMUM_GPU4PYSCF = '1.9.1'#

The GPU4PySCF version the step was validated with; ALMO-EDA2 needs 1.9.

interaction_eda_step.installer.PROBE = '\nimport json\nout = {}\ntry:\n    import cupy\n    out["cupy"] = cupy.__version__\n    n = cupy.cuda.runtime.getDeviceCount()\n    out["gpus"] = [\n        cupy.cuda.runtime.getDeviceProperties(i)["name"].decode() for i in range(n)\n    ]\n    a = cupy.arange(10, dtype=cupy.float64)\n    out["gpu_ok"] = float((a * a).sum()) == 285.0\nexcept Exception as e:\n    out["gpu_error"] = f"{type(e).__name__}: {e}"\ntry:\n    import pyscf\n    import gpu4pyscf\n    from gpu4pyscf.properties import eda\n    out["gpu4pyscf"] = gpu4pyscf.__version__\n    out["pyscf"] = pyscf.__version__\n    out["almo_eda2"] = hasattr(eda, "eval_ALMO_EDA_2_energies")\nexcept Exception as e:\n    out["import_error"] = f"{type(e).__name__}: {e}"\nprint("PROBE" + json.dumps(out))\n'#

Imports GPU4PySCF and, if there is a GPU, does a small calculation on it.

interaction_eda_step.installer.assess(probe, have_driver=True)[source]#

Lines describing a probe of the environment, and whether it is usable.

Parameters:
  • probe (dict or None) – From PROBE.

  • have_driver (bool) – Whether this machine has an NVIDIA driver. Without one, failing to import CuPy or GPU4PySCF is expected and is not an error.

Return type:

(bool, [str])

interaction_eda_step.installer.choose_build(forced=None, system=None, driver='detect')[source]#

Which CUDA build of GPU4PySCF to install.

Parameters:
  • forced (str, optional) – cuda12x or cuda13x from gpu4pyscf.ini or the command line; auto, "" or None to decide from the driver.

  • system (str, optional) – platform.system(); for tests.

  • driver ((int, int) or None or "detect") – The driver’s CUDA version; "detect" runs nvidia-smi.

Returns:

The build, or None if GPU4PySCF cannot be installed here, and why.

Return type:

(str or None, str)

interaction_eda_step.installer.low_fp64(name)[source]#

Whether a GPU has poor double precision, using the driver’s own test.

interaction_eda_step.installer.parse(output, tag)[source]#

The JSON (or repr) after tag in a script’s output, or None.

interaction_eda_step.interaction_eda module#

Non-graphical part of the Interaction EDA step in a SEAMM flowchart

class interaction_eda_step.interaction_eda.InteractionEda(flowchart=None, title='Interaction EDA', extension=None, logger=<Logger interaction_eda_step.interaction_eda (WARNING)>)[source]#

Bases: Node

The non-graphical part of a Interaction EDA step in a flowchart.

Variables:
  • parser (configargparse.ArgParser) – The parser object.

  • options (tuple) – It contains a two item tuple containing the populated namespace and the list of remaining argument strings.

  • subflowchart (seamm.Flowchart) – A SEAMM Flowchart object that represents a subflowchart, if needed.

  • parameters (InteractionEdaParameters) – The control parameters for Interaction EDA.

See also

TkInteractionEda, InteractionEda, InteractionEdaParameters

backend_settings(P)[source]#

The backend’s settings from the parameters.

Settings that do not apply to the chosen backend (see the parameters’ rules) are left out, so the backend’s own defaults hold, e.g. no VV10 in Psi4’s response kernel.

check_ini(backend)[source]#

Make sure the backend’s ini file exists here, writing the default from the package’s data if there is one.

description_text(P=None)[source]#

Create the text description of what this step will do.

Parameters:

P (dict) – An optional dictionary of the current values of the control parameters.

Returns:

A description of the current step.

Return type:

str

finish_structure(s, backend, scheme, settings, P, single)[source]#

Analyze, print, write and store one structure’s results; returns the number of its calculations that failed.

property git_revision#

The git version of this module.

json_record(fragments, results, mb, scheme, method, settings, structure=None)[source]#

The eda.json record of one structure.

n_cores(available)[source]#

The cores to use: those available, capped by SEAMM’s ncores option.

ncores in the [DEFAULT] section of seamm.ini (or --ncores) limits every step, e.g. to a laptop’s performance cores.

print_fragments(fragments)[source]#
print_results(mb, scheme, fragments)[source]#

Print the many-body table and the pairs, by term.

run()[source]#

Run the Interaction EDA step.

Every calculation – each set of fragments of each selected structure – is a seamm_exec task, sized by its number of basis functions. The tasks run together: in the job’s own cores, or bundled on the job’s queue, and a rerun keeps those already finished.

Returns:

The next node object in the flowchart.

Return type:

seamm.Node

structure_calculations(index, configuration, P, backend)[source]#

The fragments and calculations of one structure.

property version#

The semantic version of this module.

write_extxyz(path, fragments, mb, scheme, method, results=None, structure=None, append=False)[source]#

One frame per computed set of fragments, with the EDA terms as labels EDA_<scheme>_<term> (kJ/mol), plus EDA_<scheme>_mod_pauli, the SAPT-comparable Pauli; the cluster’s frame also has the many-body parts, and each frame says where it was computed (EDA_platform) and which structure it came from (system_name, configuration_name).

interaction_eda_step.interaction_eda.platform_text(data)[source]#

Where a calculation ran, e.g. ‘GPU4PySCF 1.9.1, PySCF 2.15.0, CuPy 14.2.0 on NVIDIA A30 (sm 8.0, CUDA 12.9, driver 580.82.07)’ or ‘Psi4 1.11 on CPU, 8 threads’, from a backend’s record; ‘’ if it says nothing.

interaction_eda_step.interaction_eda.svd_warning(settings, fragments)[source]#

A warning when the FERF SVD threshold is looser than 1e-4 with a cation.

The polarization/charge-transfer split for Li+-PF6- moved 0.062 kJ/mol between 1e-4 and 1e-3; at 1e-4 it is converged to 1e-8.

interaction_eda_step.interaction_eda_parameters module#

Control parameters for the Interaction EDA step in a SEAMM flowchart

class interaction_eda_step.interaction_eda_parameters.InteractionEdaParameters(defaults={}, data=None)[source]#

Bases: Parameters

The control parameters for Interaction EDA.

You need to replace the “time” entry in dictionary below these comments with the definitions of parameters to control this step. The keys are parameters for the current plugin,the values are dictionaries as outlined below.

Examples

parameters = {
    "time": {
        "default": 100.0,
        "kind": "float",
        "default_units": "ps",
        "enumeration": tuple(),
        "format_string": ".1f",
        "description": "Simulation time:",
        "help_text": ("The time to simulate in the dynamics run.")
    },
}
parameters{str: {str: str}}

A dictionary containing the parameters for the current step. Each key of the dictionary is a dictionary that contains the the following keys:

parameters[“default”] :

The default value of the parameter, used to reset it.

parameters[“kind”]enum()

Specifies the kind of a variable. One of “integer”, “float”, “string”, “boolean”, or “enum”

While the “kind” of a variable might be a numeric value, it may still have enumerated custom values meaningful to the user. For instance, if the parameter is a convergence criterion for an optimizer, custom values like “normal”, “precise”, etc, might be adequate. In addition, any parameter can be set to a variable of expression, indicated by having “$” as the first character in the field. For example, $OPTIMIZER_CONV.

parameters[“default_units”]str

The default units, used for resetting the value.

parameters[“enumeration”]tuple

A tuple of enumerated values.

parameters[“format_string”]str

A format string for “pretty” output.

parameters[“description”]str

A short string used as a prompt in the GUI.

parameters[“help_text”]str

A longer string to display as help for the user.

See also

InteractionEda, TkInteractionEda, InteractionEdaParameters, InteractionEdaStep

functional_suggestions(values=None)[source]#

The functionals to offer in the dialog: no meta-GGAs with Psi4.

not_applicable_reason(key, values=None)[source]#

Why a setting does not apply, in the user’s terms.

parameters = {'backend': {'default': 'GPU4PySCF', 'default_units': '', 'description': 'Code:', 'enumeration': ('GPU4PySCF', 'Psi4'), 'format_string': 's', 'help_text': 'The code that does the EDA. GPU4PySCF runs second-generation ALMO-EDA on a GPU with good double precision (A100, A30, H100/H200, B200). Psi4 runs the same EDA on CPUs, more slowly, for GGA and hybrid functionals such as wB97X-V (not meta-GGAs such as wB97M-V) and Hartree-Fock.', 'kind': 'enumeration'}, 'basis': {'default': 'def2-TZVPD', 'default_units': '', 'description': 'Basis set:', 'enumeration': ('def2-TZVPD', 'def2-TZVPPD', 'def2-SVPD', 'def2-QZVPPD'), 'format_string': 's', 'help_text': "The orbital basis set, in PySCF's names.", 'kind': 'string'}, 'calculations': {'default': 'cluster and pairs', 'default_units': '', 'description': 'Calculations:', 'enumeration': ('cluster and pairs', 'cluster, pairs and triples', 'cluster', 'pairs'), 'format_string': 's', 'help_text': 'Which sets of fragments to compute. The cluster and all pairs give the exact ≥3-body part of each term; triples add the 3-body increments, a truncated estimate.', 'kind': 'enumeration'}, 'cores per calculation': {'applies_when': {'backend': 'Psi4'}, 'default': 'automatic', 'default_units': '', 'description': 'Cores per calculation:', 'enumeration': ('automatic',), 'format_string': 'd', 'help_text': "Threads for each EDA calculation. 'automatic' uses 8 up to 400 basis functions, 16 up to 800 and 32 above, from the measured scaling of Psi4.", 'kind': 'integer'}, 'density fitting': {'default': 'no', 'default_units': '', 'description': 'Density fitting:', 'enumeration': ('no', 'def2-universal-jkfit'), 'format_string': 's', 'help_text': "'no' for exact integrals (the validated default), or the auxiliary basis for density fitting.", 'kind': 'string'}, 'dispersion': {'applies_when': {'backend': 'GPU4PySCF'}, 'default': 'none', 'default_units': '', 'description': 'Dispersion correction:', 'enumeration': ('none', 'd4', 'd3bj'), 'format_string': 's', 'help_text': "An empirical dispersion correction added to the functional, in PySCF's names (e.g. 'd4', or 'd4:wb97x' for a parameter set). It is included in the dispersion term; D4's three-body (ATM) part shows up in the ≥3-body dispersion.", 'kind': 'string'}, 'ferf response': {'default': 'coupled', 'default_units': '', 'description': 'FERF response:', 'enumeration': ('coupled', 'uncoupled'), 'format_string': 's', 'help_text': "How the fragment electric-field response functions (FERF-DQ) that define the polarization space are made: 'coupled' solves the coupled-perturbed equations (the validated default); 'uncoupled' uses orbital-energy denominators without the XC kernel. Only the split between polarization and charge transfer changes: uncoupled moves energy from polarization into charge transfer (+1.4 kJ/mol for Li+-EC at equilibrium, up to 6 at short range), so its terms are not comparable with coupled ones.", 'kind': 'enumeration'}, 'fragment column': {'applies_when': {'fragments': 'atom column'}, 'default': 'fragment', 'default_units': '', 'description': 'Atom column:', 'enumeration': (), 'format_string': 's', 'help_text': "The integer atom column giving each atom's fragment.", 'kind': 'string'}, 'fragments': {'default': 'molecules', 'default_units': '', 'description': 'Fragments:', 'enumeration': ('molecules', 'atom column'), 'format_string': 's', 'help_text': 'Each molecule (bonded group of atoms) is a fragment, with its charge from the formal charges or the known ions; or an integer atom column assigns the atoms to fragments.', 'kind': 'enumeration'}, 'functional': {'default': 'wB97M-V', 'default_units': '', 'description': 'Functional:', 'enumeration': ('wB97M-V', 'wB97X-V', 'B97M-V', 'wB97X-D3BJ', 'B3LYP'), 'format_string': 's', 'help_text': "The density functional, in PySCF's names (case does not matter). wB97M-V/def2-TZVPD is the validated default.", 'kind': 'string'}, 'integration grid': {'applies_when': {'backend': 'GPU4PySCF'}, 'default': 'fine', 'default_units': '', 'description': 'Integration grid:', 'enumeration': ('fine', 'standard'), 'format_string': 's', 'help_text': "The DFT integration grids. 'fine' is (150,974) for the exchange-correlation and (99,590) for VV10, converged to about 0.01 kJ/mol for compact clusters. 'standard' is GPU4PySCF's default, (99,590) and (50,194) pruned, about 7 times faster on a cluster but 0.1-0.4 kJ/mol off in the frozen and dispersion terms.", 'kind': 'enumeration'}, 'low fp64 gpus': {'applies_when': {'backend': 'GPU4PySCF'}, 'default': 'refuse', 'default_units': '', 'description': 'GPUs with little FP64:', 'enumeration': ('refuse', 'allow'), 'format_string': 's', 'help_text': "GPUs made for single precision (T4, L4, L40S, A10, A40, RTX ...) run the EDA tens of times slower. 'refuse' stops before any calculation on such a GPU; 'allow' runs anyway.", 'kind': 'enumeration'}, 'memory per calculation': {'applies_when': {'backend': 'Psi4'}, 'default': 'automatic', 'default_units': 'GB', 'description': 'Memory per calculation:', 'enumeration': ('automatic',), 'format_string': '.1f', 'help_text': "Memory for each EDA calculation; Psi4 is given 65 % of it. 'automatic' sizes it from the density-fitted integrals.", 'kind': 'float'}, 'results': {'default': {}, 'default_units': '', 'description': 'results', 'enumeration': (), 'format_string': '', 'help_text': 'The results to save to variables or in tables.', 'kind': 'dictionary'}, 'source configuration name': {'default': '', 'default_units': '', 'description': '', 'enumeration': (), 'format_string': 's', 'help_text': 'The configuration name, wildcard pattern or regular expression.', 'kind': 'string'}, 'source configurations': {'default': 'current', 'default_units': '', 'description': 'Configurations:', 'enumeration': ('current', 'all', 'last', 'first', 'name is', 'name matches', 'name regexp'), 'format_string': 's', 'help_text': 'Which configurations of each selected system to use: its current configuration, all of them, the last or first, or those whose name is / matches (shell wildcards) / matches the regular expression given.', 'kind': 'string'}, 'source system name': {'default': '', 'default_units': '', 'description': '', 'enumeration': (), 'format_string': 's', 'help_text': 'The system name, wildcard pattern or regular expression.', 'kind': 'string'}, 'source systems': {'default': 'current', 'default_units': '', 'description': 'Systems:', 'enumeration': ('current', 'all', 'name is', 'name matches', 'name regexp'), 'format_string': 's', 'help_text': 'Which systems to take the structures from: the current system, all systems, or those whose name is / matches (shell wildcards) / matches the regular expression given. A variable ($name) holding a list of configurations or of systems may also be given.', 'kind': 'string'}, 'svd threshold': {'default': 0.0001, 'default_units': '', 'description': 'FERF singular-value threshold:', 'enumeration': (), 'format_string': '.1e', 'help_text': "Virtual singular values below this are dropped from the polarization space (GPU4PySCF's default, 1e-4, is the validated one).", 'kind': 'float'}, 'triples cutoff': {'applies_when': {'calculations': 'cluster, pairs and triples'}, 'default': 'all', 'default_units': 'Å', 'description': 'Triples within:', 'enumeration': ('all',), 'format_string': '.2f', 'help_text': "Use only the triples whose three pairs are all within this distance (shortest atom-atom distance), or 'all'.", 'kind': 'float'}, 'vv10': {'applies_when': {'backend': 'GPU4PySCF'}, 'default': 'as in the functional', 'default_units': '', 'description': 'VV10 nonlocal correlation:', 'enumeration': ('as in the functional', 'off (whole functional)'), 'format_string': 's', 'help_text': "Whether to keep the VV10 nonlocal correlation that a -V functional includes. 'off (whole functional)' removes it everywhere, which is a different functional with different energies, e.g. wB97X-V with D4 dispersion (Najibi and Goerigk's wB97X-D4).", 'kind': 'enumeration'}, 'vv10 in response': {'applies_when': {'backend': 'GPU4PySCF', 'vv10': 'as in the functional'}, 'default': 'on', 'default_units': '', 'description': 'VV10 in the FERF response:', 'enumeration': ('on', 'off'), 'format_string': 's', 'help_text': "Whether the FERF response kernel includes VV10. 'off' drops it from the response only; the SCF and SCF-MI energies keep the full functional. This matches codes without a VV10 response kernel (Psi4); on shell A it moved energy between polarization and charge transfer by at most 0.0014 kJ/mol.", 'kind': 'enumeration'}}#
problems(values=None)[source]#

The base checks, and a meta-GGA functional with Psi4.

psi4_default_functional = 'wB97X-V'#

The functional the dialog switches to when Psi4 cannot run the chosen one.

interaction_eda_step.interaction_eda_step module#

class interaction_eda_step.interaction_eda_step.InteractionEdaStep(flowchart=None, gui=None)[source]#

Bases: object

Helper class needed for the stevedore integration.

This must provide a description() method that returns a dict containing a description of this node, and create_node() and create_tk_node() methods for creating the graphical and non-graphical nodes.

The dictionary for the description is the class variable just below these comments. The felds are as follows:

my_description{str, str}

A human-readable description of this step. It can be several lines long, and needs to be clear to non-expert users. It contains the following keys: description, group, name.

my_description[“description”]tuple

A description of the Interaction EDA step. It must be clear to non-experts.

my_description[“group”]str

Which group in the menus to put this step. If the group does not exist it will be created. Common groups are “Building”, “Control”, “Custom”, “Data”, and “Simulations”.

my_description[“name”]str

The name of this step, to be displayed in the menus.

create_node(flowchart=None, **kwargs)[source]#

Create and return the new node object.

Parameters:
  • flowchart (seamm.Node) – A non-graphical SEAMM node

  • **kwargs (keyword arguments) – Various keyword arguments such as title, namespace or extension representing the title displayed in the flowchart, the namespace for the plugins of a subflowchart and the extension, respectively.

Return type:

InteractionEda

create_tk_node(canvas=None, **kwargs)[source]#

Create and return the graphical Tk node object.

Parameters:
  • canvas (tk.Canvas) – The Tk Canvas widget

  • **kwargs (keyword arguments) – Various keyword arguments such as tk_flowchart, node, x, y, w, h representing a graphical flowchart object, a non-graphical node for a step, and dimensions of the graphical node.

Return type:

TkInteractionEda

description()[source]#

Return a description of what this step does.

Returns:

description

Return type:

dict(str, str)

my_description = {'description': 'An interface for Interaction EDA', 'group': 'Simulations', 'name': 'Interaction EDA'}#

interaction_eda_step.manybody module#

Many-body bookkeeping of EDA interaction energies, term by term.

Every EDA number is an interaction energy of a set of fragments, relative to the same fragments alone at the same geometry, so single fragments contribute nothing. For the fragments i, j, k, … of a cluster:

  • the 2-body part of a term is the sum over the pairs, E(ij);

  • ≥3-body (exact) = E(cluster) - Σ pairs E(ij). It needs the cluster and every pair, and it is exact;

  • the 3-body increment of a triple is, by inclusion–exclusion, ΔE(ijk) = E(ijk) - E(ij) - E(ik) - E(jk). Summed over the triples that were computed (e.g. those within a cutoff) it is the 3-body (triples, truncated) estimate. It is a truncated sum and must not be read as the ≥3-body total; with all triples, the difference between the two is the ≥4-body part.

Fragment sets are tuples of 0-based fragment indices in ascending order.

class interaction_eda_step.manybody.ManyBody(n_fragments: int, terms: tuple, cluster: dict = None, pairs: dict = <factory>, triples: dict = <factory>, sum_pairs: dict = None, ge3_exact: dict = None, three_body: dict = <factory>, sum_three_body: dict = None, n_triples_total: int = 0)[source]#

Bases: object

The many-body analysis of one structure.

Variables:
  • n_fragments (int)

  • terms ((str, ...)) – The terms analyzed, in order.

  • cluster ({str: float} or None) – The whole cluster’s terms.

  • pairs ({(int, int): {str: float}})

  • triples ({(int, int, int): {str: float}}) – The triples’ own interaction energies.

  • sum_pairs ({str: float} or None) – Σ over all pairs; None unless every pair is present.

  • ge3_exact ({str: float} or None) – cluster - Σ pairs; None unless the cluster and every pair are present.

  • three_body ({(int, int, int): {str: float}}) – The 3-body increment of each triple whose pairs are present.

  • sum_three_body ({str: float} or None) – Σ of the 3-body increments over the triples computed (truncated).

  • n_triples_total (int) – How many triples the cluster has, to show how truncated the sum is.

property all_pairs#
cluster: dict = None#
ge3_exact: dict = None#
n_fragments: int#
n_triples_total: int = 0#
pairs: dict#
sum_pairs: dict = None#
sum_three_body: dict = None#
terms: tuple#
three_body: dict#
triples: dict#
exception interaction_eda_step.manybody.ManyBodyError[source]#

Bases: ValueError

Results needed for a many-body term are missing.

interaction_eda_step.manybody.analyze(results, n_fragments, terms=None)[source]#

Do the many-body bookkeeping.

Parameters:
  • results ({tuple(int, ...): {str: float}}) – The terms (kJ/mol) of each computed set of fragments, keyed by the ascending fragment indices. The whole cluster’s key is tuple(range(n_fragments)).

  • n_fragments (int) – The number of fragments in the cluster.

  • terms ([str] or None) – The terms to analyze; default those common to all results, in the order of the first result.

Return type:

ManyBody

interaction_eda_step.manybody.fragment_sets(n_fragments, sets=('cluster', 'pairs'), triples=None)[source]#

The sets of fragments to compute.

Parameters:
  • n_fragments (int)

  • sets ([str]) – Any of “cluster”, “pairs” and “triples”.

  • triples ([(int, int, int)] or None) – The triples to use when “triples” is asked for; default all of them.

Returns:

Each set once, the cluster first, then pairs and triples in order.

Return type:

[tuple(int, …)]

interaction_eda_step.metadata module#

Metadata describing the results of the Interaction EDA step.

The results are the common EDA terms (see interaction_eda_step.terms) of the whole cluster, their 2-body part (the sum over the pairs), their exact ≥3-body part (cluster - Σ pairs) and the truncated 3-body estimate from the triples that were computed. All energies are in kJ/mol.

interaction_eda_step.resolver module#

Resolvers for the EDA tasks, so they run wherever SEAMM runs them.

Each EDA calculation is a seamm_exec task whose program is psi4_eda or gpu4pyscf_eda. There is no ini file of that name: on the machine that runs the task, the resolver reads the code’s own ini file (psi4.ini, the Psi4 step’s, or gpu4pyscf.ini) and points code at the Python of that environment, as the backend does for a run in the step itself. Registered as entry points in the group org.molssi.seamm.exec.resolvers.

interaction_eda_step.sizing module#

How big an EDA calculation is, and what to ask the queue for.

Each calculation (a set of fragments) runs as its own task, so the step must say before it runs how many cores, how much memory and how much time the task needs. The size is the number of basis functions (and, with density fitting, auxiliary functions), counted from the per-element table in data/basis_functions.json (from basis_set_exchange). The cost and memory models are fits to measured runs: see the developer notes in docs.

interaction_eda_step.sizing.DEFAULT_AUX = 'def2-universal-jkfit'#

The auxiliary basis used to size density-fitted runs when none is named.

interaction_eda_step.sizing.PEAK_OVER_JK = 1.9#

The peak memory of a Psi4 EDA is about 1.9 times its in-core integrals (shell A, 1121 nbf: 98 GB at 51 GB, 2026-11-09): the integrals, plus the grids, the matrices and the threads’ buffers. Asked for with 30 % to spare. The driver gives the integrals 75 % of Psi4’s memory (65 % of this), so they fit in core.

interaction_eda_step.sizing.PSI4_FIXED_GB = 4.0#

6.3 GB on 16 threads, 21 GB on 32, 2026-11-09).

Type:

Memory besides the JK

Type:

about 4 GB plus 0.5 GB per thread (EC-EC

interaction_eda_step.sizing.PSI4_MAX_GB = 240.0#

above it the EDA engine reads its integrals from disk (DISK_DF) rather than the task waiting for a bigger node.

Type:

The largest memory to ask for

interaction_eda_step.sizing.PSI4_MIN_GB_PER_THREAD = 2.0#

solvent-solvent pairs on 16 threads were killed by the cgroup at 17-19 GB (ChemAI 5681, 2026-11-10).

Type:

At least this much per thread

interaction_eda_step.sizing.PSI4_SPEEDUP = {4: 0.41, 8: 0.85, 16: 1.0, 32: 1.6, 64: 2.4}#

Speed-up relative to 16 threads.

interaction_eda_step.sizing.PSI4_T16 = ((116, 66.0), (284, 400.0), (552, 956.0), (1121, 5008.0))#

Wall time of a pair on 16 threads, by nbf; the 1121-nbf point is shell A (5 fragments, 7712 s) divided by fragment_factor(5).

interaction_eda_step.sizing.SCREENED = 0.75#

Psi4’s screening keeps about 3/4 of the function pairs (shell A, 1121 nbf: 47.6 GiB needed against 62.8 for all pairs, 2026-11-09).

interaction_eda_step.sizing.TASK_OVERHEAD_SECONDS = 60.0#

the batch job starting and staging the environments, launching the program, and writing and collecting the results. Measured on TinkerCliffs (ChemAI 5680/5681, 425 tasks, 2026-11-10): launch and collection 7 s median, 41 s at most; a bundle’s start before its first task 6 s median, 14 s at the 90th percentile.

Type:

Time per task outside the calculation itself, added to every estimate

interaction_eda_step.sizing.atomic_numbers(symbols)[source]#
interaction_eda_step.sizing.df_bytes(nbf, naux, range_separated=True)[source]#

The in-core MEM_DF tensors of the EDA engine: 8 * naux * nbf**2 bytes for all function pairs, three of them for a range-separated functional.

interaction_eda_step.sizing.fragment_factor(n_fragments)[source]#

More fragments, more SCF-MI and FERF work at the same size: na6_min (7 fragments, 383 nbf) took 1362 s on 8 threads (ChemAI 5679), about twice a pair; 0.18 per extra fragment covers it with the task overhead.

interaction_eda_step.sizing.gpu_seconds(nbf, n_fragments=2)[source]#

Estimated wall time of a GPU4PySCF EDA task, with the task’s overhead.

interaction_eda_step.sizing.n_functions(atomic_numbers, basis)[source]#

The number of (spherical) basis functions of basis on these atoms, or None if the basis or an element is not in the table.

interaction_eda_step.sizing.psi4_cores(nbf, cores='automatic')[source]#

Threads for a Psi4 EDA of nbf basis functions.

interaction_eda_step.sizing.psi4_memory(nbf, naux, density_fitting=True, memory='automatic', cores=16)[source]#

Bytes of memory for a Psi4 EDA task (what the queue is asked for).

Enough for the peak, about 1.9 times the screened in-core integrals, with 30 % to spare, and at least 2 GB per thread. Psi4 gets 65 % of it, and the EDA engine’s in-core JK 75 % of that, so the integrals stay in core (MEM_DF) rather than being read from disk. The SCFs use DiskDFJK, which needs less. Shell A (1121 nbf) peaked at 98 GB with 160 GB for Psi4; this gives 127 GB.

interaction_eda_step.sizing.psi4_seconds(nbf, cores, n_fragments=2)[source]#

Estimated wall time of a Psi4 EDA task, with the task’s overhead.

interaction_eda_step.sizing.size(symbols, basis, auxbasis=None)[source]#

(nbf, naux) of a set of atoms: the basis functions, and the auxiliary functions of auxbasis (or of the default fitting basis, for sizing).

interaction_eda_step.substep module#

Base class for substeps in the Interaction EDA step.

class interaction_eda_step.substep.Substep(flowchart=None, title='no title', extension=None, logger=<Logger interaction_eda_step.substep (WARNING)>, module=None)[source]#

Bases: Node

A base class for substeps in the Interaction EDA subflowchart.

The top-level InteractionEda step iterates over the substeps of its subflowchart and calls each substep’s run() method. Each substep is responsible for preparing its own input, invoking Interaction EDA, analyzing its output, and storing its results.

This base class provides:

  • is_runable - whether the top-level loop should call run() on this substep. Override to return False for substeps that only contribute input (e.g., an Initialization step) rather than invoking the code.

  • input_only - a flag for “write input but don’t run” mode, useful for debugging and testing.

  • options / global_options - delegated to the parent step so that command-line options reach substeps uniformly.

  • header - a printable header for this section of step.out.

  • version / git_revision - delegated to the plug-in package so that every substep reports the plug-in’s version, not seamm.Node’s.

property git_revision#

The git revision of the interaction_eda_step package.

property global_options#

The global SEAMM options, delegated to the parent step.

property header#

A printable header for this section of output.

property input_only#

Whether to write the input only, not run Interaction EDA.

property is_runable#

Whether this substep should be run by the top-level loop.

Override to return False for substeps that only contribute input (e.g., an Initialization step) rather than invoking Interaction EDA themselves.

property options#

The Interaction EDA options, delegated to the parent step.

property version#

The semantic version of the interaction_eda_step package.

interaction_eda_step.terms module#

The energy terms of each EDA scheme, and how they map onto common terms.

Each scheme keeps its own (“native”) terms, with the names the code uses. A few common terms let results from different schemes be put side by side, but only where the physics really is the same:

  • SAPT’s induction contains both polarization and charge transfer, so it maps to ALMO’s polarization plus charge transfer (“induction” here). Only schemes that split induction apart (ALMO-EDA) fill “polarization” and “charge transfer”; SAPT never does. Treating SAPT induction as polarization is the lumping that hides charge-transfer problems, e.g. for Li⁺.

  • “frozen” is ALMO’s frozen term (electrostatics + Pauli + dispersion). SAPT has no such term and leaves it empty.

  • SAPT’s electrostatics is the Coulomb interaction of the isolated monomers’ densities, which is ALMO’s classical electrostatic term (Q-Chem’s CLS ELEC). ALMO’s own “electrostatic” and “pauli” come from an orthogonal decomposition of the frozen wavefunction (Horn, Mao and Head-Gordon 2016; Q-Chem’s ELEC and PAULI) and are not comparable with SAPT: for PF6⁻–EC each differs from SAPT by 36 kJ/mol. So the common “electrostatics” is the classical term and the common “Pauli” is frozen − classical electrostatic − dispersion (Q-Chem’s MOD PAULI), within 2 kJ/mol of SAPT exchange. frozen = electrostatics + Pauli + dispersion holds in both sets, and the common ≥3-body electrostatics is exactly 0.

All energies are in kJ/mol.

class interaction_eda_step.terms.Scheme(name: str, terms: tuple, common: dict = <factory>, identities: tuple = (), pairwise_additive: tuple = (), max_fragments: int = None, notes: tuple = ())[source]#

Bases: object

An EDA scheme: its native terms, identities, and common-term map.

Variables:
  • name (str) – e.g. “ALMO-EDA2”.

  • terms ((str, ...)) – The native terms, in the code’s names and print order.

  • common ({str: (str, ...)}) – Each common term as the sum of native terms; a name starting with “-” is subtracted.

  • identities (((str, (str, ...)), ...)) – Native term = sum of other native terms, which hold exactly.

  • pairwise_additive ((str, ...)) – Native terms that are exactly pairwise additive (no ≥3-body part).

  • max_fragments (int or None) – The most fragments one calculation can have; None for no limit.

  • notes ((str, ...)) – What the terms mean, for the output and the extxyz labels.

check(energies, tolerance=1e-06)[source]#

The identities that do not hold, as (term, value, sum of parts).

Parameters:
  • energies ({str: float}) – Native terms, kJ/mol.

  • tolerance (float) – kJ/mol.

Returns:

Empty when everything is consistent.

Return type:

[(str, float, float)]

common: dict#
identities: tuple = ()#
max_fragments: int = None#
name: str#
notes: tuple = ()#
pairwise_additive: tuple = ()#
terms: tuple#
to_common(energies)[source]#

The common terms of one result.

Parameters:

energies ({str: float}) – Native terms, kJ/mol.

Returns:

{str – The common terms this scheme defines.

Return type:

float}

interaction_eda_step.tk_interaction_eda module#

The graphical part of a Interaction EDA step

interaction_eda_step.tk_interaction_eda.FRAGMENTS = ('fragments', 'fragment column', 'calculations', 'triples cutoff')#

The settings for the fragments and calculations.

interaction_eda_step.tk_interaction_eda.METHOD = ('backend', 'functional', 'basis', 'density fitting', 'vv10', 'vv10 in response', 'dispersion', 'ferf response', 'svd threshold', 'integration grid', 'low fp64 gpus')#

The settings of the method, in display order.

interaction_eda_step.tk_interaction_eda.RESOURCES = ('cores per calculation', 'memory per calculation')#

The resources of each calculation (the structures come first, in the same frame).

class interaction_eda_step.tk_interaction_eda.TkInteractionEda(tk_flowchart=None, node=None, canvas=None, x=None, y=None, w=200, h=50)[source]#

Bases: TkNode

The graphical part of a Interaction EDA step in a flowchart.

Variables:
  • tk_flowchart (TkFlowchart = None) – The flowchart that we belong to.

  • node (Node = None) – The corresponding node of the non-graphical flowchart

  • namespace (str) – The namespace of the current step.

  • tk_subflowchart (TkFlowchart) – A graphical Flowchart representing a subflowchart

  • canvas (tkCanvas = None) – The Tk Canvas to draw on

  • dialog (Dialog) – The Pmw dialog object

  • x (int = None) – The x-coordinate of the center of the picture of the node

  • y (int = None) – The y-coordinate of the center of the picture of the node

  • w (int = 200) – The width in pixels of the picture of the node

  • h (int = 50) – The height in pixels of the picture of the node

  • self[widget] (dict) – A dictionary of tk widgets built using the information contained in Interaction EDA_parameters.py

See also

InteractionEda, TkInteractionEda, InteractionEdaParameters

create_dialog()[source]#

Create the dialog. A set of widgets will be chosen by default based on what is specified in the Interaction EDA_parameters module.

Parameters:

None

Return type:

None

reset_dialog(widget=None)[source]#

Lay out the widgets, showing only the settings that apply.

Which settings apply, which choices are valid and which values follow from others come from the parameters’ rules (InteractionEdaParameters), which the flowchart tools use too: e.g. the atom column only for fragments from an atom column, the triples cutoff only with triples, and with Psi4 no GPU, VV10 or dispersion settings and no meta-GGA functionals (a meta-GGA becomes wB97X-V).

right_click(event)[source]#

Handles the right click event on the node.

Parameters:

event (Tk Event)

Return type:

None

See also

TkInteractionEda.edit

Module contents#

interaction_eda_step A SEAMM plug-in for Interaction EDA