Repository: MolSSI/QCEngine

Issue:
ncores and jobs_per_node
@maxscheurer brought up in #405 that the default `jobs_per_node = 2` was a little unexpected in that a single job submitted through qcengine would use half the node's resources (config.py: `ncores = task_config.pop("ncores", int(ncores / jobs_per_node))`). That's what the code logic says, but it didn't jive with my experience of cmdline qcng, which is that a single job w/o `task_config` fills the node.

* `jobs_per_node` turned from 1 to 2 very early on in mid 2018 (https://github.com/dgasmith/QCEngine/commit/41e7da039102195a5f17e5526a485f5cdefc6bff). At this point, a default job should have filled half a node because logical cores were being collected, then if processor was Intel, it halved them to remove hyperthreading. Only reason I can think of to have the default=2 is because in practice for clusters the value was usually set outright and having 2 locally exposed errors that serial would have hidden. But I really don't know why the 2. @Lnaden, any institutional memory?
* shortly after that (https://github.com/MolSSI/QCEngine/commit/0cdad20ca649241e1c33ad22475a4449ceea7788), the code switched from assuming Intel==hyperthreading to `psutil.cpu_count(logical=False)`, so with `jobs_per_node=2`, the default is still to fill half a node.
* shortly after that (https://github.com/MolSSI/QCEngine/commit/83d44096d850acd386dd466d377d0b5ee2cc0be5), the code switched to the modern logic of `len(psutil.Process().cpu_affinity())` else `psutil.cpu_count(logical=False)` else `psutil.cpu_count(logical=True)`.  The trouble with that is that the values for my computer (20 physical cores plus hyperthreading) are 40, 20, 40, respectively, so ncores is the logical, not the physical core count.

The net effect is that with ncores a factor of 2 too large (40 from `cpu_affinity` instead of 20 from `cpu_count(logical=False)`) and the unexpected jobs_per_node=2 default a factor of 2 larger than the expected 1, the expected result happens of qcng filling all (20) physical cores.

So by my current understanding, `jobs_per_node` _should_ be reset to 1, since filling the node is the most expected default behavior. _But_ this needs to be accompanied by a modification in how ncores is computed, so that if cpu_affinity = cpu_count(logical=True), then probably the affinity _hasn't_ been set and ncores should be cpu_count(logical=False). In this plan, for default settings on Intel processors, the net effect is unchanged, while the two parameters are finally doing as they claim.

This issue doesn't really affect QCFractal usage as it has explicit settings through executors and managers. I only really detected the issue b/c GAMESS gives up when you run too many threads, and 40 (as the change in #405 handed to `test_local_options_scratch[gamess-model2-keywords2]` is too many :-).

Thoughts? Have I analyzed this right, and is this the right plan? pinging @bennybp , too, in case there are qcf implications I don't see.

Discussion:
codecov[bot]: ## [Codecov](https://app.codecov.io/gh/MolSSI/QCEngine/pull/417?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MolSSI) Report
> Merging [#417](https://app.codecov.io/gh/MolSSI/QCEngine/pull/417?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MolSSI) (67a2fff) into [master](https://app.codecov.io/gh/MolSSI/QCEngine/commit/d18cfda84510360a60bf2f86805da3062b65449c?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=MolSSI) (d18cfda) will **decrease** coverage by `34.90%`.
> The diff coverage is `100.00%`.

<details><summary>Additional details and impacted files</summary>


</details>

Patch:
diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml
index 1163845..bc69efa 100644
--- a/.github/workflows/CI.yml
+++ b/.github/workflows/CI.yml
@@ -7,6 +7,8 @@ on:
   pull_request:
     branches:
       - master
+  schedule:
+    - cron: "9 16 * * 1"
 
 jobs:
   build:
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 0000000..9682647
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,41 @@
+name: "CodeQL"
+
+on:
+  push:
+    branches: [ "master", "gh-pages" ]
+  pull_request:
+    branches: [ "master" ]
+  schedule:
+    - cron: "8 16 * * 2"
+
+jobs:
+  analyze:
+    name: Analyze
+    runs-on: ubuntu-latest
+    permissions:
+      actions: read
+      contents: read
+      security-events: write
+
+    strategy:
+      fail-fast: false
+      matrix:
+        language: [ python ]
+
+    steps:
+      - name: Checkout
+        uses: actions/checkout@v3
+
+      - name: Initialize CodeQL
+        uses: github/codeql-action/init@v2
+        with:
+          languages: ${{ matrix.language }}
+          queries: +security-and-quality
+
+      - name: Autobuild
+        uses: github/codeql-action/autobuild@v2
+
+      - name: Perform CodeQL Analysis
+        uses: github/codeql-action/analyze@v2
+        with:
+          category: "/language:${{ matrix.language }}"
diff --git a/.lgtm.yml b/.lgtm.yml
deleted file mode 100644
index a3872c6..0000000
--- a/.lgtm.yml
+++ /dev/null
@@ -1,11 +0,0 @@
-# Configure LGTM for this package
-
-extraction:
-  python:  # Configure Python
-    python_setup:  # Configure the setup
-      version: 3  # Specify Version 3
-path_classifiers:
-  library:
-    - versioneer.py  # Set Versioneer.py to an external "library" (3rd party code)
-  generated:
-    - qcengine/_version.py
diff --git a/README.md b/README.md
index 113d30f..3aba69c 100644
--- a/README.md
+++ b/README.md
@@ -1,11 +1,11 @@
 QCEngine
 ========
-[![Travis build](https://img.shields.io/travis/MolSSI/QCEngine/master.svg?logo=linux&logoColor=white)](https://travis-ci.org/MolSSI/QCEngine)
+[![Build Status](https://github.com/MolSSI/QCEngine/workflows/CI/badge.svg?branch=master)](https://github.com/MolSSI/QCEngine/actions?query=workflow%3ACI)
 [![codecov](https://img.shields.io/codecov/c/github/MolSSI/QCEngine.svg?logo=Codecov&logoColor=white)](https://codecov.io/gh/MolSSI/QCEngine)
-[![Language grade: Python](https://img.shields.io/lgtm/grade/python/g/MolSSI/QCEngine.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/MolSSI/QCEngine/context:python)
-[![Documentation Status](https://img.shields.io/github/workflow/status/MolSSI/QCEngine/CI/master?label=docs&logo=readthedocs&logoColor=white)](http://docs.qcarchive.molssi.org/projects/qcengine/en/latest/)
+[![Documentation Status](https://img.shields.io/github/actions/workflow/status/MolSSI/QCEngine/CI.yml?label=docs&logo=readthedocs&logoColor=white)](https://molssi.github.io/QCEngine/)
 [![Conda (channel only)](https://img.shields.io/conda/vn/conda-forge/qcengine?color=blue&logo=anaconda&logoColor=white)](https://anaconda.org/conda-forge/qcengine)
 [![Chat on Slack](https://img.shields.io/badge/chat-on_slack-808493.svg?longCache=true&style=flat&logo=slack)](https://join.slack.com/t/qcarchive/shared_invite/enQtNDIzNTQ2OTExODk0LTE3MWI0YzBjNzVhNzczNDM0ZTA5MmQ1ODcxYTc0YTA1ZDQ2MTk1NDhlMjhjMmQ0YWYwOGMzYzJkZTM2NDlmOGM)
+![python](https://img.shields.io/badge/python-3.7+-blue.svg)
 
 <!--[![Azure Build Status](https://dev.azure.com/MolSSI/QCArchive/_apis/build/status/MolSSI.QCEngine?branchName=master)](https://dev.azure.com/MolSSI/QCArchive/_build/latest?definitionId=5&branchName=master)-->
 Quantum chemistry program executor and IO standardizer ([QCSchema](https://github.com/MolSSI/QCSchema)) for quantum chemistry.
@@ -52,7 +52,7 @@ The results contain a complete record of the computation:
 Intel(R) Core(TM) i7-7820HQ CPU @ 2.90GHz
 ```
 
-See the [documentation](https://qcengine.readthedocs.io/en/latest/) for more information.
+See the [documentation](https://molssi.github.io/QCEngine/) for more information.
 
 # License
 
diff --git a/docs/source/changelog.rst b/docs/source/changelog.rst
index 20f9260..70833c1 100644
--- a/docs/source/changelog.rst
+++ b/docs/source/changelog.rst
@@ -1,8 +1,7 @@
 Changelog
 =========
 
-.. vX.Y.0 / 2023-MM-DD
-.. Unreleased
+.. vX.Y.0 / 2023-MM-DD (Unreleased)
 .. --------------------
 ..
 .. Breaking Changes
@@ -16,6 +15,91 @@ Changelog
 ..
 .. Bug Fixes
 .. +++++++++
+..
+.. Misc.
+.. +++++
+..
+.. MUST (Unmerged)
+.. +++++++++++++++
+..
+.. WIP (Unmerged)
+.. ++++++++++++++
+.. - UNMERGED (:pr:`421`) GAMESS - error handling and memory @taylor-a-barnes
+.. - UNMERGED (:pr:`405`, :issue:`415`, :pr:`417`) Config - change default `jobs_per_node` from 2 to more expected 1 so a single job fills the node. Alter CPU count formula to return physical cores on Hyerthreading machines, affecting default `ncores`. The net effect (both changes) for default cores running on Hyperthreading machines is unchanged. @cvsik, @loriab
+.. - UNSOLVED (:issue:`397`) extras failed
+
+
+v0.28.2 / 2023-MM-DD (Unreleased)
+--------------------
+
+Breaking Changes
+++++++++++++++++
+
+New Features
+++++++++++++
+
+Enhancements
+++++++++++++
+
+Bug Fixes
++++++++++
+
+Misc.
++++++
+
+MUST (Unmerged)
++++++++++++++++
+- UNMERGED (:pr:`427`) Config - Once again, expand environment variables (now more flexibly) and newly expand ``~``
+  passed into TaskConfig. Particularly relevant for scratch setting.
+
+
+v0.28.1 / 2023-08-18
+--------------------
+
+Bug Fixes
++++++++++
+- (:pr:`426`) Psi4 - fix ``get_version`` on Windows where whole path and command were getting passed to version parser. @loriab
+
+
+v0.28.0 / 2023-08-15
+--------------------
+
+Breaking Changes
+++++++++++++++++
+
+New Features
+++++++++++++
+- (:pr:`400`) Config - task configuration can now be set via CLI (`qcengine run -h` for details) or
+  by environment variables beginning with `QCENGINE_`. @bennybp
+- (:pr:`393`, :issue:`392`) MCTC-GCP - Adds b973c and r2scan3c methods to the gcp (mctc only, not classic) harness. @hokru
+- (:pr:`393`) DFTD4 - Allows ga, gc, wf parameters to be tweaked (needed for r2scan-3c). This feature requires dftd4 3.5.0. @hokru
+
+Enhancements
+++++++++++++
+- (:pr:`410`, :issue:`408`) TorsionDrive - silence warnings by using the ``task_config`` argument internally. @jthorton
+- (:pr:`409`) Psi4 - improve no-valid-error message so classifies as a RandomError and is eligible for
+  restart. @jthorton
+- (:pr:`405`) Turbomole - correctly enable OpenMP and environment passing. Pass SCF convergence and
+  maximum iterations to define. @cvsik
+- (:pr:`403`, :issue:`402`) PyBerny - fix optimizer to respect the task_config options. @q-posev
+- (:pr:`386`) CI - turn on formerly LGTM now GitHub CodeQL analysis. @lgtm-migrator
+- (:pr:`388`) MRChem - more detailed info about the parallel setup saved to output provenance. @robertodr
+- (:pr:`424`) testing - update SVWN Hessian reference values from Psi4. @loriab
+- (:pr:`423`, :issue:`377`) NWChem - allow two answers for test ``test_atom_labels[nwchem]`` to accommodate SCF
+  solutions in different versions. @loriab
+
+Bug Fixes
++++++++++
+- (:pr:`401`) MDI - fix bug in the shape of the MDI forces structure. @taylor-a-barnes
+- (:issue:`399`, :pr:`401`) MPI - remove MPI setup for MDI. This eliminates a bug where interfering
+  MPI environment variables were getting set upon ``import qcengine`` when pymdi and mpi4py packages
+  were present. @awvwgk, @taylor-a-barnes
+- (:pr:`418`, :pr:`389`, :issue:`292`) Psi4 - make Psi4 exe/module detection and version parsing more robust. @Flamefire, @coltonbh, @loriab
+
+Misc.
++++++
+- (:pr:`419`) CI - remove disabled LGTM and update badges. @loriab
+- (:pr:`422`) CI - turn on crontab CI running to better notice external trouble. @loriab
 
 
 v0.27.0 / 2023-08-02
@@ -172,7 +256,7 @@ Bug Fixes
 - (:pr:`322`) Psi4 - allowed more test cases with gradients and Hessians after a compatibility PR started
   saving them. @loriab
 - (:pr:`323`) Turbomole - learned to store calcinfo_natom so that gradients and Hessians can be computed
-  after QCElemental started using that quantity for shape checking in 
+  after QCElemental started using that quantity for shape checking in
   [v0.22.0](https://github.com/MolSSI/QCElemental/blob/master/docs/source/changelog.rst#0220--2021-08-26)
   @eljost
 
diff --git a/qcengine/cli.py b/qcengine/cli.py
index dc9d43c..70e0e39 100644
--- a/qcengine/cli.py
+++ b/qcengine/cli.py
@@ -30,6 +30,30 @@ def parse_args():
     parser = argparse.ArgumentParser(description="A CLI for the QCEngine.")
     parser.add_argument("--version", action="version", version=f"{__version__}")
 
+    parent_parser = argparse.ArgumentParser(add_help=False)
+    task_group = parent_parser.add_argument_group(
+        "Task Configuration", "Extra configuration related to running the computation"
+    )
+    task_group.add_argument("--ncores", type=int, help="The number of cores to use for the task")
+    task_group.add_argument("--nnodes", type=int, help="The number of nodes to use")
+    task_group.add_argument("--memory", type=float, help="The amount of memory (in GiB) to use")
+    task_group.add_argument("--scratch-directory", type=str, help="Where to store temporary files")
+    task_group.add_argument("--retries", type=int, help="Number of retries for random failures")
+    task_group.add_argument("--mpiexec-command", type=str, help="Command used to launch MPI tasks")
+    task_group.add_argument(
+        "--use-mpiexec",
+        action="store_true",
+        default=None,
+        help="Whether it is necessary to use MPI to run an executable",
+    )
+    task_group.add_argument("--cores-per-rank", type=int, help="Number of cores per MPI rank")
+    task_group.add_argument(
+        "--scratch-messy",
+        action="store_true",
+        default=None,
+        help="Leave the scratch directory and contents on disk after completion",
+    )
+
     subparsers = parser.add_subparsers(dest="command")
 
     info = subparsers.add_parser("info", help="Print information about QCEngine setup, version, and environment.")
@@ -37,7 +61,9 @@ def parse_args():
         "category", nargs="*", default="all", choices=info_choices, help="The information categories to show."
     )
 
-    run = subparsers.add_parser("run", help="Run a program on a given task. Output is printed as a JSON blob.")
+    run = subparsers.add_parser(
+        "run", parents=[parent_parser], help="Run a program on a given task. Output is printed as a JSON blob."
+    )
     run.add_argument("program", type=str, help="The program to run.")
     run.add_argument(
         "data",
@@ -49,7 +75,9 @@ def parse_args():
     )
 
     run_procedure = subparsers.add_parser(
-        "run-procedure", help="Run a procedure on a given task. " "Output is printed as a JSON blob."
+        "run-procedure",
+        parents=[parent_parser],
+        help="Run a procedure on a given task. Output is printed as a JSON blob.",
     )
     run_procedure.add_argument("procedure", type=str, help="The procedure to run.")
     run_procedure.add_argument(
@@ -164,12 +192,29 @@ def main(args=None):
     # Grab CLI args if not present
     if args is None:
         args = parse_args()
+
+    # Break out a task config
+    task_config = {
+        "ncores": args.pop("ncores", None),
+        "memory": args.pop("memory", None),
+        "nnodes": args.pop("nnodes", None),
+        "scratch_directory": args.pop("scratch_directory", None),
+        "retries": args.pop("retries", None),
+        "mpiexec_command": args.pop("mpiexec_command", None),
+        "use_mpiexec": args.pop("use_mpiexec", None),
+        "cores_per_rank": args.pop("cores_per_rank", None),
+        "scratch_messy": args.pop("scratch_messy", None),
+    }
+
+    # Prune None values and let other config functions handle defaults
+    task_config = {k: v for k, v in task_config.items() if v is not None}
+
     command = args.pop("command")
     if command == "info":
         info_cli(args)
     elif command == "run":
-        ret = compute(data_arg_helper(args["data"]), args["program"])
+        ret = compute(data_arg_helper(args["data"]), args["program"], task_config=task_config)
         print(ret.json())
     elif command == "run-procedure":
-        ret = compute_procedure(data_arg_helper(args["data"]), args["procedure"])
+        ret = compute_procedure(data_arg_helper(args["data"]), args["procedure"], task_config=task_config)
         print(ret.json())
diff --git a/qcengine/config.py b/qcengine/config.py
index 47f52d1..a836ddb 100644
--- a/qcengine/config.py
+++ b/qcengine/config.py
@@ -43,6 +43,11 @@ def get_global(key: Optional[str] = None) -> Union[str, Dict[str, Any]]:
         # Work through VMs and logical cores.
         if hasattr(psutil.Process(), "cpu_affinity"):
             cpu_cnt = len(psutil.Process().cpu_affinity())
+            full_physical_cnt = psutil.cpu_count(logical=False)
+            full_logical_cnt = psutil.cpu_count(logical=True)
+            if (cpu_cnt == full_logical_cnt) and (full_physical_cnt is not None):
+                # cpu_affinity isn't capturing deliberate setting but just VMs, so use physical
+                cpu_cnt = full_physical_cnt
         else:
             cpu_cnt = psutil.cpu_count(logical=False)
             if cpu_cnt is None:
@@ -84,7 +89,7 @@ class NodeDescriptor(pydantic.BaseModel):
     
     The default value, ``None``, will allow QCEngine to autodetect the number of cores.""",
     )
-    jobs_per_node: int = 2
+    jobs_per_node: int = 1
     retries: int = 0
 
     # Cluster options
@@ -144,7 +149,7 @@ class NodeDescriptor(pydantic.BaseModel):
         extra = "forbid"
 
 
-class TaskConfig(pydantic.BaseModel):
+class TaskConfig(pydantic.BaseSettings):
     """Description of the configuration used to launch a task."""
 
     # Specifications
@@ -162,8 +167,9 @@ class TaskConfig(pydantic.BaseModel):
         False, description="Leave scratch directory and contents on disk after completion."
     )
 
-    class Config:
+    class Config(pydantic.BaseSettings.Config):
         extra = "forbid"
+        env_prefix = "QCENGINE_"
 
 
 def _load_defaults() -> None:
@@ -258,11 +264,9 @@ def parse_environment(data: Dict[str, Any]) -> Dict[str, Any]:
     """Collects local environment variable values into ``data`` for any keys with RHS starting with ``$``."""
     ret = {}
     for k, var in data.items():
-        if isinstance(var, str) and var.startswith("$"):
-            var = var.replace("$", "", 1)
-            if var in os.environ:
-                var = os.environ[var]
-            else:
+        if isinstance(var, str):
+            var = os.path.expanduser(os.path.expandvars(var))
+            if var.startswith("$"):
                 var = None
 
         ret[k] = var
@@ -270,6 +274,19 @@ def parse_environment(data: Dict[str, Any]) -> Dict[str, Any]:
     return ret
 
 
+def read_qcengine_task_environment() -> Dict[str, Any]:
+    """
+    Reads the qcengine task-related environment variables and returns a dictionary of the values.
+    """
+
+    ret = {}
+    for k, v in os.environ.items():
+        if k.startswith("QCENGINE_"):
+            ret[k[9:].lower()] = v
+
+    return ret
+
+
 def get_config(*, hostname: Optional[str] = None, task_config: Dict[str, Any] = None) -> TaskConfig:
     """
     Returns the configuration key for qcengine.
@@ -278,7 +295,9 @@ def get_config(*, hostname: Optional[str] = None, task_config: Dict[str, Any] =
     if task_config is None:
         task_config = {}
 
-    task_config = parse_environment(task_config)
+    task_config_env = read_qcengine_task_environment()
+    task_config = {**task_config_env, **parse_environment(task_config)}
+
     config = {}
 
     # Node data
@@ -288,7 +307,7 @@ def get_config(*, hostname: Optional[str] = None, task_config: Dict[str, Any] =
     config["retries"] = task_config.pop("retries", node.retries)
 
     # Jobs per node
-    jobs_per_node = task_config.pop("jobs_per_node", None) or node.jobs_per_node
+    jobs_per_node = int(task_config.pop("jobs_per_node", None) or node.jobs_per_node)
 
     # Handle memory
     memory = task_config.pop("memory", None)
@@ -300,12 +319,12 @@ def get_config(*, hostname: Optional[str] = None, task_config: Dict[str, Any] =
     config["memory"] = memory
 
     # Get the number of cores available to each task
-    ncores = task_config.pop("ncores", int(ncores / jobs_per_node))
+    ncores = int(task_config.pop("ncores", int(ncores / jobs_per_node)))
     if ncores < 1:
         raise KeyError("Number of jobs per node exceeds the number of available cores.")
 
     config["ncores"] = ncores
-    config["nnodes"] = task_config.pop("nnodes", 1)
+    config["nnodes"] = int(task_config.pop("nnodes", 1))
 
     # Add in the MPI launch command template
     config["mpiexec_command"] = node.mpiexec_command
diff --git a/qcengine/mdi_server.py b/qcengine/mdi_server.py
index 53f7f71..90fff9e 100644
--- a/qcengine/mdi_server.py
+++ b/qcengine/mdi_server.py
@@ -31,13 +31,6 @@ try:
 except ImportError:
     use_mdi = False
 
-try:
-    from mpi4py import MPI
-
-    use_mpi4py = True
-except ImportError:
-    use_mpi4py = False
-
 
 class MDIServer:
     def __init__(
@@ -104,19 +97,13 @@ class MDIServer:
         # Output of most recent compute call
         self.compute_return = None
 
+        # Set whether the current energy is valid
+        self.energy_is_current = False
+
         # MPI variables
         self.mpi_world = None
         self.world_rank = 0
 
-        # Get correct intra-code MPI communicator
-        if use_mpi4py:
-            self.mpi_world = MDI_MPI_get_world_comm()
-            self.world_rank = self.mpi_world.Get_rank()
-
-            # QCEngine does not currently support multiple MPI ranks
-            if self.mpi_world.Get_size() != 1:
-                MPI.COMM_WORLD.Abort()
-
         # Flag to stop listening for MDI commands
         self.stop_listening = False
 
@@ -124,6 +111,7 @@ class MDIServer:
         self.commands = {
             "<@": self.send_node,
             "<NATOMS": self.send_natoms,
+            ">NATOMS": self.recv_natoms,
             "<COORDS": self.send_coords,
             "<ENERGY": self.send_energy,
             "<FORCES": self.send_forces,
@@ -216,6 +204,26 @@ class MDIServer:
         MDI_Send(natom, 1, MDI_INT, self.comm)
         return natom
 
+    # Respond to the >NATOMS command
+    def recv_natoms(self, natoms: Optional[int] = None) -> None:
+        """Receive the number of atoms in the system through MDI and create a new molecule with them
+
+        Parameters
+        ----------
+        natoms : int, optional
+            New number of atoms. If None, receive through MDI.
+        """
+        natom = len(self.molecule.geometry)
+        if natoms is None:
+            natoms = MDI_Recv(1, MDI_INT, self.comm)
+
+        mol_string = ""
+        for iatom in range(natoms):
+            mol_string += "He " + str(1.0 * iatom) + " 0.0 0.0\n"
+        self.molecule = qcel.models.Molecule.from_data(mol_string)
+
+        self.energy_is_current = False
+
     # Respond to the <COORDS command
     def send_coords(self) -> np.ndarray:
         """Send the nuclear coordinates through MDI
@@ -247,6 +255,7 @@ class MDIServer:
             MDI_Recv(3 * natom, MDI_DOUBLE, self.comm, buf=coords)
         new_geometry = np.reshape(coords, (-1, 3))
         self.molecule = qcel.models.Molecule(**{**self.molecule.dict(), **{"geometry": new_geometry}})
+        self.energy_is_current = False
 
     # Respond to the <ENERGY command
     def send_energy(self) -> float:
@@ -261,7 +270,13 @@ class MDIServer:
         if not self.molecule_validated:
             raise Exception("MDI attempting to compute energy on an unvalidated molecule")
         self.run_energy()
-        energy = self.compute_return.return_result
+
+        # Confirm that the calculation completed successfully
+        if not hasattr(self.compute_return, "properties"):
+            raise Exception("MDI Calculation failed: \n\n" + str(self.compute_return.error.error_message))
+
+        properties = self.compute_return.properties.dict()
+        energy = properties["return_energy"]
         MDI_Send(energy, 1, MDI_DOUBLE, self.comm)
         return energy
 
@@ -277,27 +292,45 @@ class MDIServer:
         # Ensure that the molecule currently passes validation
         if not self.molecule_validated:
             raise Exception("MDI attempting to compute gradients on an unvalidated molecule")
+        self.run_energy()
+        properties = self.compute_return.properties.dict()
+
+        forces = np.reshape(-1.0 * properties["return_gradient"], (-1,))
 
-        input = qcel.models.AtomicInput(
-            molecule=self.molecule, driver="gradient", model=self.model, keywords=self.keywords
-        )
-        self.compute_return = compute(
-            input_data=input, program=self.program, raise_error=self.raise_error, local_options=self.local_options
-        )
+        if len(forces) != 3 * len(self.molecule.geometry):
+            raise Exception(
+                "MDI: The length of the forces is not what was expected.  Expected: "
+                + str(3 * len(self.molecule.geometry))
+                + "   Actual: "
+                + str(len(forces))
+            )
 
-        forces = self.compute_return.return_result
         MDI_Send(forces, len(forces), MDI_DOUBLE, self.comm)
         return forces
 
     # Respond to the SCF command
     def run_energy(self) -> None:
-        """Run an energy calculation"""
-        input = qcel.models.AtomicInput(
-            molecule=self.molecule, driver="energy", model=self.model, keywords=self.keywords
-        )
-        self.compute_return = compute(
-            input_data=input, program=self.program, raise_error=self.raise_error, local_options=self.local_options
-        )
+        if not self.energy_is_current:
+            """Ensure that the orientation of the molecule remains fixed"""
+            self.update_molecule("fix_com", True)
+            self.update_molecule("fix_orientation", True)
+
+            """Run an energy calculation"""
+            input = qcel.models.AtomicInput(
+                molecule=self.molecule, driver="gradient", model=self.model, keywords=self.keywords
+            )
+            self.compute_return = compute(
+                input_data=input, program=self.program, raise_error=self.raise_error, local_options=self.local_options
+            )
+
+            # If there is an error message, print it out
+            if hasattr(self.compute_return, "error"):
+                if self.compute_return.error is not None:
+                    print("---------------- QCEngine Compute Error ----------------\n\n")
+                    print(str(self.compute_return.error.error_message))
+                    print("\n\n-------------- End QCEngine Compute Error --------------", flush=True)
+
+            self.energy_is_current = True
 
     # Respond to the <ELEMENTS command
     def send_elements(self):
@@ -358,6 +391,7 @@ class MDIServer:
         if masses is None:
             masses = MDI_Recv(natom, MDI_DOUBLE, self.comm)
         self.update_molecule("masses", masses)
+        self.energy_is_current = False
 
     # Respond to the <TOTCHARGE command
     def send_total_charge(self) -> float:
@@ -384,6 +418,7 @@ class MDIServer:
         if charge is None:
             charge = MDI_Recv(1, MDI_DOUBLE, self.comm)
         self.total_charge = charge
+        self.energy_is_current = False
 
         # Allow a validation error here, because a future >ELEC_MULT command might resolve it
         try:
@@ -416,6 +451,7 @@ class MDIServer:
         if multiplicity is None:
             multiplicity = MDI_Recv(1, MDI_INT, self.comm)
         self.multiplicity = multiplicity
+        self.energy_is_current = False
 
         # Allow a validation error here, because a future >TOTCHARGE command might resolve it
         try:
@@ -437,8 +473,6 @@ class MDIServer:
                 command = MDI_Recv_Command(self.comm)
             else:
                 command = None
-            if use_mpi4py:
-                command = self.mpi_world.bcast(command, root=0)
             if self.world_rank == 0:
                 print("MDI command received: " + str(command))
 
diff --git a/qcengine/procedures/optking.py b/qcengine/procedures/optking.py
index 91de0ab..34139a3 100644
--- a/qcengine/procedures/optking.py
+++ b/qcengine/procedures/optking.py
@@ -20,7 +20,7 @@ class OptKingProcedure(ProcedureHarness):
             "optking",
             return_bool=True,
             raise_error=raise_error,
-            raise_msg="Please install via `conda install optking -c psi4/label/dev`.",
+            raise_msg="Please install via `conda install optking -c conda-forge`.",
         )
 
     def build_input_model(self, data: Union[Dict[str, Any], "OptimizationInput"]) -> "OptimizationInput":
diff --git a/qcengine/programs/adcc.py b/qcengine/programs/adcc.py
index 8095033..ff641c5 100644
--- a/qcengine/programs/adcc.py
+++ b/qcengine/programs/adcc.py
@@ -50,13 +50,13 @@ class AdccHarness(ProgramHarness):
             "adcc",
             return_bool=True,
             raise_error=raise_error,
-            raise_msg="Please install via `conda install adcc -c adcc`.",
+            raise_msg="Please install via `conda install adcc -c conda-forge`.",
         )
         found_psi4 = which_import(
             "psi4",
             return_bool=True,
             raise_error=raise_error,
-            raise_msg="Please install psi4 for adcc harness via `conda install psi4 -c psi4`.",
+            raise_msg="Please install psi4 for adcc harness via `conda install psi4 -c conda-forge/label/libint_dev -c conda-forge`.",
         )
         return found_adcc and found_psi4
 
diff --git a/qcengine/programs/empirical_dispersion_resources.py b/qcengine/programs/empirical_dispersion_resources.py
index 2812284..c6f60ec 100644
--- a/qcengine/programs/empirical_dispersion_resources.py
+++ b/qcengine/programs/empirical_dispersion_resources.py
@@ -5,6 +5,7 @@ import copy
 from typing import Dict, List, Optional, Union
 
 from ..exceptions import InputError
+from qcelemental.util import parse_version
 
 ## ==> Dispersion Aliases and Parameters <== ##
 
@@ -881,7 +882,17 @@ dashcoeff = {
         "bibtex": "Caldeweyher:2019:154122",
         "doi": "10.1063/1.5090222150",
         "default": collections.OrderedDict(
-            [("a1", 1.0), ("a2", 1.0), ("alp", 16.0), ("s6", 1.0), ("s8", 1.0), ("s9", 1.0)]
+            [
+                ("a1", 1.0),
+                ("a2", 1.0),
+                ("alp", 16.0),
+                ("s6", 1.0),
+                ("s8", 1.0),
+                ("s9", 1.0),
+                ("ga", 3.0),
+                ("gc", 2.0),
+                ("wf", 6.0),
+            ]
         ),
         "definitions": {
             # D4 parameters loaded below from authoritative source below. Keep a couple for reference
@@ -891,6 +902,18 @@ dashcoeff = {
     },
 }
 
+try:
+    from dftd4 import __version__ as d4_version
+
+    new_d4_api = parse_version(d4_version) >= parse_version("3.5.0")
+except (ModuleNotFoundError, ImportError):
+    new_d4_api = False
+
+# different defaults for dftd4 versions < 3.5.0
+if not new_d4_api:
+    dashcoeff["d4bjeeqatm"]["default"] = collections.OrderedDict(
+        [("a1", 1.0), ("a2", 1.0), ("alp", 16.0), ("s6", 1.0), ("s8", 1.0), ("s9", 1.0)]
+    )
 
 # for d3*atm, only skeleton entries with metadata defined above. below copies in parameters from d3*2b
 for d in ["d3zero", "d3bj", "d3mzero", "d3mbj", "d3op"]:
@@ -964,6 +987,13 @@ def _get_d4bj_definitions() -> dict:
         except KeyError:
             continue
 
+    # defaults ga, gc, wf are not in the toml parameter file and need to be provided by qcengine
+    if new_d4_api:
+        for entry in definitions.keys():
+            definitions[entry]["params"]["ga"] = 3.0
+            definitions[entry]["params"]["gc"] = 2.0
+            definitions[entry]["params"]["wf"] = 6.0
+
     return definitions
 
 
diff --git a/qcengine/programs/gcp.py b/qcengine/programs/gcp.py
index 17929d6..368f825 100644
--- a/qcengine/programs/gcp.py
+++ b/qcengine/programs/gcp.py
@@ -160,16 +160,25 @@ class GCPHarness(ProgramHarness):
             # thus code blocks with FILE below are not used yet.
             # 'file',
         ]
+        # some methods not available in legacy version
+        mctc_gcp_levels = ["B973C", "R2SCAN3C"]
+
+        executable = self._defaults["name"].lower()
+        if executable == "mctc-gcp":
+            available_levels.extend(mctc_gcp_levels)
+
         available_levels = [f.upper() for f in available_levels]
         # temp until actual options object
         method = input_model.model.method.upper()
         if method not in available_levels:
-            raise InputError(f"GCP does not have method: {method}")
+            if method in mctc_gcp_levels and executable == "gcp":
+                raise InputError(f"GCP does not have method {method} but MCTC-GCP does.")
+            else:
+                raise InputError(f"GCP does not have method: {method}")
 
         # Need 'real' field later and that's only guaranteed for molrec
         molrec = qcel.molparse.from_schema(input_model.molecule.dict())
 
-        executable = self._defaults["name"].lower()
         calldash = {"gcp": "-", "mctc-gcp": "--"}[executable]
 
         command = [executable, "gcp_geometry.xyz", calldash + "level", method]
diff --git a/qcengine/programs/mrchem.py b/qcengine/programs/mrchem.py
index e2bd460..e52c889 100644
--- a/qcengine/programs/mrchem.py
+++ b/qcengine/programs/mrchem.py
@@ -101,6 +101,7 @@ class MRChemHarness(ProgramHarness):
 
         job_input = self.build_input(input_model, config)
         input_data = copy.deepcopy(job_input["mrchem_json"])
+
         output_data = {
             "keywords": input_data,
             "schema_name": "qcschema_output",
@@ -132,6 +133,10 @@ class MRChemHarness(ProgramHarness):
                 mrchem_output = mrchem_json["output"]
                 output_data["success"] = mrchem_output["success"]
                 output_data["provenance"] = mrchem_output["provenance"]
+                # parallel set up
+                output_data["provenance"].update(job_input["parallel"])
+                # remove nthreads, above info is more detailed anyway
+                output_data["provenance"].pop("nthreads")
                 # update the "routine" under "provenance"
                 output_data["provenance"]["routine"] = " ".join(job_input["command"])
 
@@ -204,8 +209,18 @@ class MRChemHarness(ProgramHarness):
         sys.path.append(exc["stdout"].split()[-1])
         from mrchem import translate_input, validate
 
+        ranks_per_node = config.ncores // config.cores_per_rank if config.use_mpiexec else 1
         mrchemrec = {
             "scratch_directory": config.scratch_directory,
+            # parallel set up
+            "parallel": {
+                "ncores": config.ncores,
+                "nnodes": config.nnodes,
+                "ranks_per_node": ranks_per_node,
+                "cores_per_rank": config.cores_per_rank,
+                "total_cores": config.nnodes * ranks_per_node * config.cores_per_rank,
+                "total_ranks": config.nnodes * ranks_per_node,
+            },
         }
 
         opts = copy.deepcopy(input_model.keywords)
diff --git a/qcengine/programs/psi4.py b/qcengine/programs/psi4.py
index 99b725c..1ba3d7f 100644
--- a/qcengine/programs/psi4.py
+++ b/qcengine/programs/psi4.py
@@ -54,31 +54,46 @@ class Psi4Harness(ProgramHarness):
         """
         psithon = which("psi4", return_bool=True)
         psiapi = which_import("psi4", return_bool=True)
+        error_msg = ""
+        error_which = which
 
         if psithon and not psiapi:
             with popen([which("psi4"), "--module"]) as exc:
                 exc["proc"].wait(timeout=30)
             if "module does not exist" in exc["stderr"]:
-                pass  # --module argument only in Psi4 DDD branch
+                psiapi = True  # --module argument only in Psi4 DDD branch (or >=1.6) so grandfathered in
             else:
-                sys.path.append(exc["stdout"].split()[-1])
+                so, se, rc = exc["stdout"].strip(), exc["stderr"], exc["proc"].returncode
+                error_msg = f" In particular, psi4 command found but unable to load psi4 module into sys.path. stdout: {so}, stderr: {se}"
+                error_which = which_import
+                if (so) and (not se) and (rc == 0):
+                    psimod = Path(so)
+                    if psimod.exists():
+                        sys.path.append(str(psimod))
+                        psiapi = which_import("psi4", return_bool=True)
 
         if psiapi and not psithon:
-            psiimport = str(Path(which_import("psi4")).parent.parent)
-            env = os.environ.copy()
-            env["PYTHONPATH"] = psiimport
-            with popen(["python", "-c", "import psi4; print(psi4.executable[:-5])"], popen_kwargs={"env": env}) as exc:
+            with popen(["python", "-c", "import psi4; print(psi4.executable)"]) as exc:
                 exc["proc"].wait(timeout=30)
-            os.environ["PATH"] += os.pathsep + exc["stdout"].split()[-1]
-
-        if psithon or psiapi:
+            so, se, rc = exc["stdout"].strip(), exc["stderr"], exc["proc"].returncode
+            error_msg = f" In particular, psi4 module found but unable to load psi4 command into PATH. stdout: {so}, stderr: {se}"
+            # yes, everthing up to here could be got from `import psi4; psiexe = psi4.executable`. but, we try not to
+            #   load programs/modules in the `def found` fns.
+            if (so) and (not se) and (rc == 0):
+                psiexe = Path(so)
+                if psiexe.exists():
+                    os.environ["PATH"] += os.pathsep + str(psiexe.parent)
+                    psithon = which("psi4", return_bool=True)
+
+        if psithon and psiapi:
             return True
 
-        return which(
+        return error_which(
             "psi4",
             return_bool=True,
             raise_error=raise_error,
-            raise_msg="Please install via `conda install psi4 -c psi4`. Check it's in your PATH with `which psi4`.",
+            raise_msg="Please install via `conda install psi4 -c conda-forge/label/libint_dev -c conda-forge`. Check it's in your PATH with `which psi4`."
+            + error_msg,
         )
 
     def get_version(self) -> str:
@@ -88,7 +103,12 @@ class Psi4Harness(ProgramHarness):
         if which_prog not in self.version_cache:
             with popen([which_prog, "--version"]) as exc:
                 exc["proc"].wait(timeout=30)
-            self.version_cache[which_prog] = safe_version(exc["stdout"].split()[-1])
+            so, se, rc = exc["stdout"].strip(), exc["stderr"], exc["proc"].returncode
+            if (so) and (not se) and (rc == 0):
+                # Windows echos the command, so split stdout to collect response
+                self.version_cache[which_prog] = safe_version(so.split()[-1])
+            else:
+                raise TypeError(f"Error {rc} retrieving Psi4 version: stdout: {so}, stderr: {se}")
 
         candidate_version = self.version_cache[which_prog]
 
@@ -205,7 +225,7 @@ class Psi4Harness(ProgramHarness):
                     psi4.core.set_num_threads(config.ncores, quiet=True)
                     psi4.set_memory(f"{config.memory}GiB", quiet=True)
                     # psi4.core.IOManager.shared_object().set_default_path(str(tmpdir))
-                    if pversion < parse_version("1.6a2"):  # adjust to where DDD merged
+                    if pversion < parse_version("1.6"):  # adjust to where DDD merged
                         # slightly dangerous in that if `qcng.compute({..., psiapi=True}, "psi4")` called *from psi4
                         #   session*, session could unexpectedly get its own files cleaned away.
                         output_data = psi4.schema_wrapper.run_qcschema(input_model).dict()


Test patch:
diff --git a/qcengine/programs/tests/standard_suite_ref.py b/qcengine/programs/tests/standard_suite_ref.py
index 45723c9..cc0337f 100644
--- a/qcengine/programs/tests/standard_suite_ref.py
+++ b/qcengine/programs/tests/standard_suite_ref.py
@@ -780,44 +780,44 @@ _std_suite = [
             "SVWN TOTAL GRADIENT": np.array(  # psi 99,590
                 [0.0, 0.0, 0.019336350645, -0.0, 0.0, -0.019336301692]
             ).reshape((-1, 3)),
-            "SVWN TOTAL HESSIAN": np.array(  # psi 99,590
+            "SVWN TOTAL HESSIAN": np.array(  # psi v1.8 99,590
                 [
-                    -0.011155104942,
+                    -0.011158529195,
                     -0.0,
                     -0.0,
-                    0.011159037504,
+                    0.011158509954,
                     -0.0,
                     -0.0,
                     -0.0,
-                    -0.011155104942,
-                    0.0,
+                    -0.011158529195,
                     -0.0,
-                    0.011159037504,
+                    0.0,
+                    0.011158509954,
+                    0.0,
                     -0.0,
                     -0.0,
+                    0.642213454497,
                     0.0,
-                    0.642252566624,
                     0.0,
+                    -0.642213457165,
+                    0.011158509954,
                     0.0,
-                    -0.64223885597,
-                    0.011159037504,
-                    -0.0,
                     0.0,
-                    -0.011150492167,
+                    -0.011155887562,
                     -0.0,
                     -0.0,
                     -0.0,
-                    0.011159037504,
+                    0.011158509954,
                     0.0,
                     -0.0,
-                    -0.01115049217,
+                    -0.011155887564,
                     -0.0,
                     -0.0,
-                    -0.0,
-                    -0.64223885597,
+                    0.0,
+                    -0.642213457165,
                     -0.0,
                     -0.0,
-                    0.642235796522,
+                    0.642216280292,
                 ]
             ).reshape((6, 6)),
             "PBE TOTAL ENERGY": -100.33517315116806,  # psi 99,590
@@ -1721,89 +1721,89 @@ _std_suite = [
             "SVWN TOTAL GRADIENT": np.array(  # psi 99,590
                 [0.0, -0.0, 0.01699540452, -0.0, 0.012801478421, -0.008497882106, 0.0, -0.012801478421, -0.008497882106]
             ).reshape((-1, 3)),
-            "SVWN TOTAL HESSIAN": np.array(  # psi 99,590
+            "SVWN TOTAL HESSIAN": np.array(  # psi v1.8 99,590
                 [
-                    -0.01527536,
+                    -0.015282137109,
                     0.0,
                     -0.0,
-                    0.007667,
+                    0.007667256256,
                     0.0,
                     -0.0,
-                    0.007667,
-                    -0.0,
-                    -0.0,
+                    0.007667256256,
                     0.0,
-                    0.71417558,
+                    -0.0,
                     0.0,
+                    0.714169890673,
+                    0.000000000001,
+                    -0.0,
+                    -0.357096356198,
+                    0.282430177213,
+                    -0.0,
+                    -0.357096356198,
+                    -0.282430177213,
                     -0.0,
-                    -0.35709636,
-                    0.28242944,
+                    0.000000000001,
+                    0.45653162932,
                     0.0,
-                    -0.35709636,
-                    -0.28242944,
+                    0.223223468116,
+                    -0.228270944088,
+                    -0.0,
+                    -0.223223468116,
+                    -0.228270944088,
+                    0.007667256256,
                     -0.0,
                     0.0,
-                    0.45653659,
+                    -0.008305196866,
                     0.0,
-                    0.22322552,
-                    -0.22827087,
                     0.0,
-                    -0.22322552,
-                    -0.22827087,
-                    0.007667,
+                    0.000637932765,
                     -0.0,
                     0.0,
-                    -0.00830423,
-                    0.0,
                     0.0,
-                    0.0006383,
+                    -0.357096356198,
+                    0.223223468116,
                     0.0,
+                    0.385967088688,
+                    -0.252826811188,
                     -0.0,
+                    -0.028870808826,
+                    0.029603353817,
+                    -0.0,
+                    0.282430177213,
+                    -0.228270944088,
                     0.0,
-                    -0.35709636,
-                    0.22322552,
+                    -0.252826811188,
+                    0.219004239874,
                     0.0,
-                    0.38596972,
-                    -0.25282844,
+                    -0.029603353817,
+                    0.009266633228,
+                    0.007667256256,
                     -0.0,
-                    -0.02887102,
-                    0.02960182,
                     -0.0,
-                    0.28242944,
-                    -0.22827087,
-                    0.0,
-                    -0.25282844,
-                    0.21900566,
-                    0.0,
-                    -0.02960182,
-                    0.00926715,
-                    0.007667,
-                    0.0,
-                    0.0,
-                    0.0006383,
+                    0.000637932765,
                     -0.0,
                     0.0,
-                    -0.00830423,
-                    0.0,
-                    -0.0,
+                    -0.008305196866,
                     -0.0,
-                    -0.35709636,
-                    -0.22322552,
                     0.0,
-                    -0.02887102,
-                    -0.02960182,
                     0.0,
-                    0.38596972,
-                    0.25282844,
+                    -0.357096356198,
+                    -0.223223468116,
                     -0.0,
-                    -0.28242944,
-                    -0.22827087,
+                    -0.028870808826,
+                    -0.029603353817,
                     -0.0,
-                    0.02960182,
-                    0.00926715,
+                    0.385967088688,
+                    0.252826811188,
                     -0.0,
-                    0.25282844,
-                    0.21900566,
+                    -0.282430177213,
+                    -0.228270944088,
+                    0.0,
+                    0.029603353817,
+                    0.009266633228,
+                    0.0,
+                    0.252826811188,
+                    0.219004239874,
                 ]
             ).reshape((9, 9)),
             "PBE TOTAL ENERGY": -76.35896461348528,  # psi 99,590
@@ -2901,89 +2901,89 @@ _std_suite = [
             "SVWN TOTAL GRADIENT": np.array(  # psi 99,590
                 [0.0, 0.0, 0.01116011934, -0.0, 0.009507405365, -0.005580350828, 0.0, -0.009507405365, -0.005580350828]
             ).reshape((-1, 3)),
-            "SVWN TOTAL HESSIAN": np.array(  # psi 99,590
+            "SVWN TOTAL HESSIAN": np.array(  # psi v1.8 99,590
                 [
-                    -0.01000736,
-                    -0.0,
-                    0.0,
-                    0.00503531,
+                    -0.010015602973,
+                    -0.000000000001,
+                    0.000000000002,
+                    0.005034918743,
                     0.0,
                     -0.0,
-                    0.00503531,
-                    0.0,
+                    0.005034918743,
+                    -0.0,
                     0.0,
+                    -0.000000000001,
+                    0.699200093422,
+                    -0.000000000002,
                     -0.0,
-                    0.69920603,
+                    -0.349611743856,
+                    0.274596771974,
                     -0.0,
-                    0.0,
-                    -0.34961451,
-                    0.27459931,
-                    0.0,
-                    -0.34961451,
-                    -0.27459931,
-                    0.0,
+                    -0.349611743856,
+                    -0.274596771974,
+                    0.000000000002,
+                    -0.000000000002,
+                    0.449624843917,
                     -0.0,
-                    0.4496319,
+                    0.216250731357,
+                    -0.224817271283,
                     -0.0,
-                    0.21625396,
-                    -0.22481826,
+                    -0.216250731357,
+                    -0.224817271283,
+                    0.005034918743,
                     -0.0,
-                    -0.21625396,
-                    -0.22481826,
-                    0.00503531,
-                    0.0,
                     -0.0,
-                    -0.0058381,
+                    -0.005839372129,
                     -0.0,
                     0.0,
-                    0.00080331,
+                    0.000803489613,
                     0.0,
                     0.0,
                     0.0,
-                    -0.34961451,
-                    0.21625396,
+                    -0.349611743856,
+                    0.216250731357,
                     -0.0,
-                    0.37967873,
-                    -0.24542967,
+                    0.379671911068,
+                    -0.245424063175,
                     0.0,
-                    -0.03005974,
-                    0.02917238,
+                    -0.030060195243,
+                    0.029173021276,
                     -0.0,
-                    0.27459931,
-                    -0.22481826,
-                    0.0,
-                    -0.24542967,
-                    0.21540024,
+                    0.274596771974,
+                    -0.224817271283,
                     0.0,
-                    -0.02917238,
-                    0.00942102,
-                    0.00503531,
+                    -0.245424063175,
+                    0.215395274362,
                     0.0,
+                    -0.029173021276,
+                    0.009421810131,
+                    0.005034918743,
                     -0.0,
-                    0.00080331,
+                    -0.0,
+                    0.000803489613,
                     0.0,
                     0.0,
-                    -0.0058381,
+                    -0.005839372129,
                     0.0,
                     -0.0,
+                    -0.0,
+                    -0.349611743856,
+                    -0.216250731357,
                     0.0,
-                    -0.34961451,
-                    -0.21625396,
-                    0.0,
-                    -0.03005974,
-                    -0.02917238,
+                    -0.030060195243,
+                    -0.029173021276,
                     0.0,
-                    0.37967873,
-                    0.24542967,
+                    0.379671911068,
+                    0.245424063175,
                     0.0,
-                    -0.27459931,
-                    -0.22481826,
+                    -0.274596771974,
+                    -0.224817271283,
                     0.0,
-                    0.02917238,
-                    0.00942102,
+                    0.029173021276,
+                    0.009421810131,
                     -0.0,
-                    0.24542967,
-                    0.21540024,
+                    0.245424063175,
+                    0.215395274362,
                 ]
             ).reshape((9, 9)),
             "PBE TOTAL ENERGY": -76.38209089347507,  # psi 99,590
@@ -4482,89 +4482,89 @@ _std_suite = [
                     -0.017729858581,
                 ]
             ).reshape((-1, 3)),
-            "SVWN TOTAL HESSIAN": np.array(  # psi 99,590, findif-5
+            "SVWN TOTAL HESSIAN": np.array(  # psi v1.9 99,590
                 [
-                    -0.030579382195,
-                    0.0,
-                    0.0,
-                    0.015289691097,
-                    0.0,
-                    0.0,
-                    0.015289691097,
-                    0.0,
-                    0.0,
-                    0.0,
-                    0.613663951137,
-                    0.0,
-                    0.0,
-                    -0.306831975569,
-                    0.247172797408,
-                    0.0,
-                    -0.306831975569,
-                    -0.247172797408,
-                    0.0,
-                    0.0,
-                    0.378510939602,
-                    0.0,
-                    0.193986821538,
-                    -0.189255469801,
-                    0.0,
-                    -0.193986821538,
-                    -0.189255469801,
-                    0.015289691097,
-                    0.0,
-                    0.0,
-                    -0.014567116318,
-                    0.0,
-                    0.0,
-                    -0.000722574779,
+                    -0.03056359,
                     0.0,
+                    -0.0,
+                    0.01528971,
+                    -0.0,
+                    -0.0,
+                    0.01528971,
+                    -0.0,
+                    -0.0,
                     0.0,
+                    0.61365123,
+                    -0.0,
                     0.0,
-                    -0.306831975569,
-                    0.193986821538,
+                    -0.30683213,
+                    0.24717277,
                     0.0,
-                    0.332462439675,
-                    -0.220579809473,
+                    -0.30683213,
+                    -0.24717277,
+                    -0.0,
+                    -0.0,
+                    0.37850767,
                     0.0,
-                    -0.025630464106,
-                    0.026592987935,
+                    0.19398671,
+                    -0.18925551,
                     0.0,
-                    0.247172797408,
-                    -0.189255469801,
+                    -0.19398671,
+                    -0.18925551,
+                    0.01528971,
                     0.0,
-                    -0.220579809473,
-                    0.182536700314,
                     0.0,
-                    -0.026592987935,
-                    0.006718769487,
-                    0.015289691097,
+                    -0.01456645,
                     0.0,
+                    -0.0,
+                    -0.00072257,
+                    -0.0,
                     0.0,
-                    -0.000722574779,
+                    -0.0,
+                    -0.30683213,
+                    0.19398671,
                     0.0,
+                    0.3324625,
+                    -0.22057959,
+                    -0.0,
+                    -0.02563036,
+                    0.02659303,
+                    -0.0,
+                    0.24717277,
+                    -0.18925551,
+                    -0.0,
+                    -0.22057959,
+                    0.18253678,
                     0.0,
-                    -0.014567116318,
+                    -0.02659303,
+                    0.00671886,
+                    0.01528971,
                     0.0,
                     0.0,
+                    -0.00072257,
+                    -0.0,
                     0.0,
-                    -0.306831975569,
-                    -0.193986821538,
+                    -0.01456645,
                     0.0,
-                    -0.025630464106,
-                    -0.026592987935,
                     0.0,
-                    0.332462439675,
-                    0.220579809473,
+                    -0.0,
+                    -0.30683213,
+                    -0.19398671,
+                    -0.0,
+                    -0.02563036,
+                    -0.02659303,
                     0.0,
-                    -0.247172797408,
-                    -0.189255469801,
+                    0.3324625,
+                    0.22057959,
+                    -0.0,
+                    -0.24717277,
+                    -0.18925551,
                     0.0,
-                    0.026592987935,
-                    0.006718769487,
+                    0.02659303,
+                    0.00671886,
                     0.0,
-                    0.220579809473,
-                    0.182536700314,
+                    0.22057959,
+                    0.18253678,
                 ]
             ).reshape((9, 9)),
             "PBE TOTAL ENERGY": -55.81473169701641,  # psi 99,590
@@ -4911,89 +4911,89 @@ _std_suite = [
                     -0.014437276469,
                 ]
             ).reshape((-1, 3)),
-            "SVWN TOTAL HESSIAN": np.array(  # psi 99,590, findif-5
+            "SVWN TOTAL HESSIAN": np.array(  # psi v1.9 99,590
                 [
-                    -0.024900525225,
-                    0.0,
-                    0.0,
-                    0.012450262612,
-                    0.0,
-                    0.0,
-                    0.012450262612,
-                    0.0,
-                    0.0,
-                    0.0,
-                    0.593486612872,
-                    0.0,
-                    0.0,
-                    -0.296743306436,
-                    0.237253020083,
-                    0.0,
-                    -0.296743306436,
-                    -0.237253020083,
-                    0.0,
-                    0.0,
-                    0.37094039592,
-                    0.0,
-                    0.185028837929,
-                    -0.18547019796,
-                    0.0,
-                    -0.185028837929,
-                    -0.18547019796,
-                    0.012450262612,
-                    0.0,
-                    0.0,
-                    -0.011707373731,
-                    0.0,
-                    0.0,
-                    -0.000742888881,
-                    0.0,
-                    0.0,
+                    -0.02488189,
+                    -0.0,
                     0.0,
-                    -0.296743306436,
-                    0.185028837929,
+                    0.01245024,
                     0.0,
-                    0.322753427832,
-                    -0.211140929006,
+                    -0.0,
+                    0.01245024,
                     0.0,
-                    -0.026010121396,
-                    0.026112091077,
                     0.0,
-                    0.237253020083,
-                    -0.18547019796,
+                    -0.0,
+                    0.59347392,
+                    -0.0,
                     0.0,
-                    -0.211140929006,
-                    0.178278351827,
+                    -0.29674373,
+                    0.23725288,
+                    -0.0,
+                    -0.29674373,
+                    -0.23725288,
                     0.0,
-                    -0.026112091077,
-                    0.007191846133,
-                    0.012450262612,
+                    -0.0,
+                    0.37093753,
                     0.0,
+                    0.18502874,
+                    -0.18547044,
                     0.0,
-                    -0.000742888881,
+                    -0.18502874,
+                    -0.18547044,
+                    0.01245024,
                     0.0,
                     0.0,
-                    -0.011707373731,
+                    -0.01170876,
+                    -0.0,
+                    -0.0,
+                    -0.00074289,
                     0.0,
                     0.0,
                     0.0,
-                    -0.296743306436,
-                    -0.185028837929,
+                    -0.29674373,
+                    0.18502874,
+                    -0.0,
+                    0.32275381,
+                    -0.21114139,
+                    -0.0,
+                    -0.02601004,
+                    0.02611207,
+                    -0.0,
+                    0.23725288,
+                    -0.18547044,
+                    -0.0,
+                    -0.21114139,
+                    0.17827787,
+                    -0.0,
+                    -0.02611207,
+                    0.00719218,
+                    0.01245024,
+                    -0.0,
                     0.0,
-                    -0.026010121396,
-                    -0.026112091077,
+                    -0.00074289,
+                    -0.0,
+                    -0.0,
+                    -0.01170876,
+                    -0.0,
+                    -0.0,
                     0.0,
-                    0.322753427832,
-                    0.211140929006,
+                    -0.29674373,
+                    -0.18502874,
                     0.0,
-                    -0.237253020083,
-                    -0.18547019796,
+                    -0.02601004,
+                    -0.02611207,
+                    -0.0,
+                    0.32275381,
+                    0.21114139,
                     0.0,
-                    0.026112091077,
-                    0.007191846133,
+                    -0.23725288,
+                    -0.18547044,
                     0.0,
-                    0.211140929006,
-                    0.178278351827,
+                    0.02611207,
+                    0.00719218,
+                    -0.0,
+                    0.21114139,
+                    0.17827787,
                 ]
             ).reshape((9, 9)),
             "PBE TOTAL ENERGY": -55.83097248811423,  # psi 99,590
@@ -12797,44 +12797,44 @@ _std_suite = [
             "SVWN TOTAL GRADIENT": np.array(  # psi 99,590
                 [0.0, -0.0, 0.019359029672, 0.0, 0.0, -0.019358980719]
             ).reshape((-1, 3)),
-            "SVWN TOTAL HESSIAN": np.array(  # psi 99,590
+            "SVWN TOTAL HESSIAN": np.array(  # psi v1.8 99,590
                 [
-                    -0.011168131792,
-                    -0.0,
-                    0.0,
-                    0.011172130726,
+                    -0.011171616682,
                     0.0,
                     -0.0,
-                    -0.0,
-                    -0.011168131791,
-                    -0.0,
-                    -0.0,
-                    0.011172130726,
+                    0.011171597439,
                     0.0,
+                    -0.0,
                     0.0,
+                    -0.011171616682,
                     -0.0,
-                    0.642302311047,
                     -0.0,
+                    0.01117159744,
                     0.0,
-                    -0.642288537528,
-                    0.011172130726,
                     -0.0,
                     -0.0,
-                    -0.011163568945,
+                    0.642262891185,
                     0.0,
+                    0.0,
+                    -0.642262893846,
+                    0.011171597439,
                     -0.0,
                     0.0,
-                    0.011172130726,
+                    -0.011168975069,
+                    0.000000000001,
+                    -0.000000000001,
                     0.0,
+                    0.01117159744,
                     0.0,
-                    -0.011163568946,
+                    0.000000000001,
+                    -0.01116897507,
                     -0.0,
                     -0.0,
                     0.0,
-                    -0.642288537528,
-                    -0.0,
+                    -0.642262893846,
+                    -0.000000000001,
                     -0.0,
-                    0.6422854146,
+                    0.64226571697,
                 ]
             ).reshape((6, 6)),
             "PBE TOTAL ENERGY": -100.33521027,  # psi 99,590
@@ -13019,89 +13019,89 @@ _std_suite = [
             "SVWN TOTAL GRADIENT": np.array(  # psi 99,590
                 [0.0, 0.0, 0.017021972532, -0.0, 0.012817893242, -0.008511166112, 0.0, -0.012817893242, -0.008511166112]
             ).reshape((-1, 3)),
-            "SVWN TOTAL HESSIAN": np.array(  # psi 99,590
+            "SVWN TOTAL HESSIAN": np.array(  # psi v1.8 99,590
                 [
-                    -0.015299334632,
+                    -0.015306108227,
                     -0.0,
-                    -0.000000000002,
-                    0.007678980381,
+                    -0.0,
+                    0.007679241821,
                     -0.0,
                     0.0,
-                    0.007678980385,
-                    0.0,
-                    0.0,
+                    0.007679241834,
+                    -0.0,
                     -0.0,
-                    0.714101517289,
-                    -0.000000000032,
                     -0.0,
-                    -0.357059324641,
-                    0.282410047669,
+                    0.714095826016,
+                    0.000000000011,
+                    -0.0,
+                    -0.357059323956,
+                    0.282410783964,
                     0.0,
-                    -0.357059324634,
-                    -0.282410047587,
-                    -0.000000000002,
-                    -0.000000000032,
-                    0.456490029157,
+                    -0.357059323952,
+                    -0.282410784003,
+                    -0.0,
+                    0.000000000011,
+                    0.456485072062,
                     0.0,
-                    0.22319113684,
-                    -0.228247587643,
+                    0.22318907951,
+                    -0.228247665448,
                     0.0,
-                    -0.223191136802,
-                    -0.228247587644,
-                    0.007678980381,
+                    -0.22318907952,
+                    -0.228247665506,
+                    0.007679241821,
                     -0.0,
                     0.0,
-                    -0.008315956845,
-                    0.0,
+                    -0.008316923332,
+                    -0.0,
+                    -0.0,
+                    0.000637673685,
                     0.0,
-                    0.00063803809,
                     -0.0,
                     -0.0,
+                    -0.357059323956,
+                    0.22318907951,
                     -0.0,
-                    -0.357059324641,
-                    0.22319113684,
-                    0.0,
-                    0.385931772222,
-                    -0.252801553596,
+                    0.3859291338,
+                    -0.252799920245,
                     0.0,
-                    -0.0288700995,
-                    0.029609316084,
+                    -0.028869886253,
+                    0.029610851501,
                     0.0,
-                    0.282410047669,
-                    -0.228247587643,
-                    0.0,
-                    -0.252801553596,
-                    0.218980782707,
+                    0.282410783964,
+                    -0.228247665448,
+                    -0.0,
+                    -0.252799920245,
+                    0.218979358918,
                     -0.0,
-                    -0.029609316078,
-                    0.009268752866,
-                    0.007678980385,
+                    -0.029610851534,
+                    0.009268235563,
+                    0.007679241834,
                     0.0,
                     0.0,
-                    0.00063803809,
+                    0.000637673685,
                     0.0,
                     -0.0,
-                    -0.008315956847,
+                    -0.008316923345,
                     -0.0,
                     -0.0,
+                    -0.0,
+                    -0.357059323952,
+                    -0.22318907952,
                     0.0,
-                    -0.357059324634,
-                    -0.223191136802,
+                    -0.028869886253,
+                    -0.029610851534,
                     -0.0,
-                    -0.0288700995,
-                    -0.029609316078,
+                    0.385929133855,
+                    0.252799920322,
                     -0.0,
-                    0.385931772317,
-                    0.252801553661,
-                    0.0,
-                    -0.282410047587,
-                    -0.228247587644,
+                    -0.282410784003,
+                    -0.228247665506,
                     -0.0,
-                    0.029609316084,
-                    0.009268752866,
+                    0.029610851501,
+                    0.009268235563,
                     -0.0,
-                    0.252801553661,
-                    0.218980782752,
+                    0.252799920322,
+                    0.218979358932,
                 ]
             ).reshape((9, 9)),
             "PBE TOTAL ENERGY": -76.35898912990783,  # psi 99,590
@@ -13286,89 +13286,89 @@ _std_suite = [
             "SVWN TOTAL GRADIENT": np.array(  # psi 99,590
                 [0.0, 0.0, 0.011132147324, -0.0, 0.009489578319, -0.005566364846, 0.0, -0.009489578319, -0.005566364846]
             ).reshape((-1, 3)),
-            "SVWN TOTAL HESSIAN": np.array(  # psi 99,590
+            "SVWN TOTAL HESSIAN": np.array(  # psi v1.8 99,590
                 [
-                    -0.009982123608,
-                    -0.000000000003,
-                    0.000000000001,
-                    0.005022694229,
-                    -0.0,
+                    -0.009990362405,
                     -0.0,
-                    0.005022694229,
+                    0.000000000001,
+                    0.00502229918,
                     -0.0,
                     0.0,
-                    -0.000000000003,
-                    0.699083187256,
-                    -0.000000000003,
-                    -0.0,
-                    -0.349553083271,
-                    0.274541978121,
+                    0.005022299179,
                     0.0,
-                    -0.349553083268,
-                    -0.274541978118,
-                    0.000000000001,
-                    -0.000000000003,
-                    0.449571259443,
                     0.0,
-                    0.216193555918,
-                    -0.224787939359,
-                    -0.0,
-                    -0.216193555917,
-                    -0.224787939349,
-                    0.005022694229,
                     -0.0,
+                    0.699077256021,
                     0.0,
-                    -0.005825563758,
+                    -0.0,
+                    -0.349550325666,
+                    0.274539445833,
                     0.0,
+                    -0.349550325662,
+                    -0.274539445833,
+                    0.000000000001,
                     0.0,
-                    0.000803395893,
+                    0.449564210084,
                     0.0,
+                    0.216190331109,
+                    -0.22478695452,
                     0.0,
+                    -0.216190331109,
+                    -0.224786954525,
+                    0.00502229918,
                     -0.0,
-                    -0.349553083271,
-                    0.216193555918,
                     0.0,
-                    0.379628979061,
-                    -0.245370803861,
+                    -0.005826835703,
+                    0.0,
                     -0.0,
-                    -0.030071414048,
-                    0.029173919817,
+                    0.000803572097,
+                    0.0,
+                    0.0,
                     -0.0,
-                    0.274541978121,
-                    -0.224787939359,
+                    -0.349550325666,
+                    0.216190331109,
                     0.0,
-                    -0.245370803861,
-                    0.21536910855,
+                    0.379622159841,
+                    -0.245365200208,
                     0.0,
-                    -0.029173919811,
-                    0.009421830645,
-                    0.005022694229,
+                    -0.030071862218,
+                    0.029174558331,
                     0.0,
+                    0.274539445833,
+                    -0.22478695452,
                     -0.0,
-                    0.000803395893,
-                    -0.0,
+                    -0.245365200208,
+                    0.215364149782,
+                    0.0,
+                    -0.029174558332,
+                    0.009422617805,
+                    0.005022299179,
+                    0.0,
+                    0.0,
+                    0.000803572097,
                     0.0,
-                    -0.005825563757,
                     0.0,
+                    -0.005826835703,
                     0.0,
                     -0.0,
-                    -0.349553083268,
-                    -0.216193555917,
                     0.0,
-                    -0.030071414048,
-                    -0.029173919811,
+                    -0.349550325662,
+                    -0.216190331109,
                     0.0,
-                    0.379628979061,
-                    0.245370803855,
+                    -0.030071862218,
+                    -0.029174558332,
                     0.0,
-                    -0.274541978118,
-                    -0.224787939349,
+                    0.379622159838,
+                    0.245365200207,
                     0.0,
-                    0.029173919817,
-                    0.009421830645,
+                    -0.274539445833,
+                    -0.224786954525,
                     0.0,
-                    0.245370803855,
-                    0.215369108539,
+                    0.029174558331,
+                    0.009422617805,
+                    -0.0,
+                    0.245365200207,
+                    0.215364149785,
                 ]
             ).reshape((9, 9)),
             "PBE TOTAL ENERGY": -76.38213149,  # psi 99,590
@@ -14023,89 +14023,89 @@ _std_suite = [
             "SVWN TOTAL GRADIENT": np.array(  # psi 99,590
                 [-0.0, 0.0, 0.035469475022, -0.0, 0.020928806811, -0.01773474765, 0.0, -0.020928806811, -0.01773474765]
             ).reshape((-1, 3)),
-            "SVWN TOTAL HESSIAN": np.array(  # psi 99,590, findif-5
+            "SVWN TOTAL HESSIAN": np.array(  # psi v1.9 99,590
                 [
-                    -0.030587815367,
-                    0.0,
-                    0.0,
-                    0.015293907684,
-                    0.0,
-                    0.0,
-                    0.015293907684,
-                    0.0,
-                    0.0,
-                    0.0,
-                    0.613620758584,
-                    0.0,
-                    0.0,
-                    -0.306810379292,
-                    0.247159475157,
-                    0.0,
-                    -0.306810379292,
-                    -0.247159475157,
-                    0.0,
-                    0.0,
-                    0.378480199957,
-                    0.0,
-                    0.193966522798,
-                    -0.189240099979,
-                    0.0,
-                    -0.193966522798,
-                    -0.189240099979,
-                    0.015293907684,
-                    0.0,
-                    0.0,
-                    -0.014571453885,
+                    -0.03057202,
                     0.0,
+                    -0.0,
+                    0.01529392,
                     0.0,
-                    -0.000722453798,
+                    -0.0,
+                    0.01529392,
+                    -0.0,
+                    -0.0,
                     0.0,
+                    0.61360803,
+                    -0.0,
+                    -0.0,
+                    -0.30681053,
+                    0.24715943,
                     0.0,
+                    -0.30681053,
+                    -0.24715943,
+                    -0.0,
+                    -0.0,
+                    0.37847696,
                     0.0,
-                    -0.306810379292,
-                    0.193966522798,
+                    0.19396643,
+                    -0.18924016,
                     0.0,
-                    0.332432750472,
-                    -0.220562998977,
+                    -0.19396643,
+                    -0.18924016,
+                    0.01529392,
+                    -0.0,
                     0.0,
-                    -0.02562237118,
-                    0.02659647618,
+                    -0.01457079,
+                    -0.0,
                     0.0,
-                    0.247159475157,
-                    -0.189240099979,
+                    -0.00072245,
                     0.0,
-                    -0.220562998977,
-                    0.182521675397,
                     0.0,
-                    -0.02659647618,
-                    0.006718424581,
-                    0.015293907684,
                     0.0,
+                    -0.30681053,
+                    0.19396643,
+                    -0.0,
+                    0.33243283,
+                    -0.22056279,
+                    -0.0,
+                    -0.02562228,
+                    0.0265965,
+                    -0.0,
+                    0.24715943,
+                    -0.18924016,
                     0.0,
-                    -0.000722453798,
+                    -0.22056279,
+                    0.18252176,
                     0.0,
+                    -0.0265965,
+                    0.00671853,
+                    0.01529392,
                     0.0,
-                    -0.014571453885,
                     0.0,
+                    -0.00072245,
+                    -0.0,
                     0.0,
+                    -0.01457079,
                     0.0,
-                    -0.306810379292,
-                    -0.193966522798,
                     0.0,
-                    -0.02562237118,
-                    -0.02659647618,
+                    -0.0,
+                    -0.30681053,
+                    -0.19396643,
                     0.0,
-                    0.332432750472,
-                    0.220562998977,
+                    -0.02562228,
+                    -0.0265965,
                     0.0,
-                    -0.247159475157,
-                    -0.189240099979,
+                    0.33243283,
+                    0.22056279,
+                    -0.0,
+                    -0.24715943,
+                    -0.18924016,
                     0.0,
-                    0.02659647618,
-                    0.006718424581,
+                    0.0265965,
+                    0.00671853,
                     0.0,
-                    0.220562998977,
-                    0.182521675397,
+                    0.22056279,
+                    0.18252176,
                 ]
             ).reshape((9, 9)),
             "PBE TOTAL ENERGY": -55.81475290212862,  # psi 99,590
@@ -14296,89 +14296,89 @@ _std_suite = [
                     -0.014427331687,
                 ]
             ).reshape((-1, 3)),
-            "SVWN TOTAL HESSIAN": np.array(  # psi 99,590, findif-5
+            "SVWN TOTAL HESSIAN": np.array(  # psi v1.9 99,590
                 [
-                    -0.024883374093,
-                    0.0,
-                    0.0,
-                    0.012441687046,
-                    0.0,
-                    0.0,
-                    0.012441687046,
-                    0.0,
-                    0.0,
-                    0.0,
-                    0.593390763591,
-                    0.0,
-                    0.0,
-                    -0.296695381795,
-                    0.237209665984,
-                    0.0,
-                    -0.296695381795,
-                    -0.237209665984,
-                    0.0,
+                    -0.02486474,
                     0.0,
-                    0.370911215894,
                     0.0,
-                    0.184982972616,
-                    -0.185455607947,
+                    0.01244166,
                     0.0,
-                    -0.184982972616,
-                    -0.185455607947,
-                    0.012441687046,
-                    0.0,
-                    0.0,
-                    -0.011696790889,
-                    0.0,
-                    0.0,
-                    -0.000744896157,
-                    0.0,
-                    0.0,
-                    0.0,
-                    -0.296695381795,
-                    0.184982972616,
-                    0.0,
-                    0.322707377502,
-                    -0.2110963193,
-                    0.0,
-                    -0.026011995706,
-                    0.026113346684,
+                    -0.0,
+                    0.01244166,
+                    -0.0,
+                    -0.0,
                     0.0,
-                    0.237209665984,
-                    -0.185455607947,
+                    0.59337807,
+                    -0.0,
                     0.0,
-                    -0.2110963193,
-                    0.178260718446,
+                    -0.29669581,
+                    0.23720953,
                     0.0,
-                    -0.026113346684,
-                    0.007194889501,
-                    0.012441687046,
+                    -0.29669581,
+                    -0.23720953,
                     0.0,
+                    -0.0,
+                    0.37090816,
+                    -0.0,
+                    0.18498275,
+                    -0.18545575,
                     0.0,
-                    -0.000744896157,
+                    -0.18498275,
+                    -0.18545575,
+                    0.01244166,
                     0.0,
+                    -0.0,
+                    -0.01169818,
+                    -0.0,
+                    -0.0,
+                    -0.0007449,
                     0.0,
-                    -0.011696790889,
                     0.0,
                     0.0,
+                    -0.29669581,
+                    0.18498275,
+                    -0.0,
+                    0.3227077,
+                    -0.21109672,
+                    -0.0,
+                    -0.02601184,
+                    0.02611339,
+                    -0.0,
+                    0.23720953,
+                    -0.18545575,
+                    -0.0,
+                    -0.21109672,
+                    0.17826019,
+                    -0.0,
+                    -0.02611339,
+                    0.00719517,
+                    0.01244166,
                     0.0,
-                    -0.296695381795,
-                    -0.184982972616,
                     0.0,
-                    -0.026011995706,
-                    -0.026113346684,
+                    -0.0007449,
+                    -0.0,
+                    -0.0,
+                    -0.01169818,
+                    -0.0,
                     0.0,
-                    0.322707377502,
-                    0.2110963193,
+                    -0.0,
+                    -0.29669581,
+                    -0.18498275,
                     0.0,
-                    -0.237209665984,
-                    -0.185455607947,
+                    -0.02601184,
+                    -0.02611339,
+                    -0.0,
+                    0.3227077,
+                    0.21109672,
+                    -0.0,
+                    -0.23720953,
+                    -0.18545575,
                     0.0,
-                    0.026113346684,
-                    0.007194889501,
+                    0.02611339,
+                    0.00719517,
                     0.0,
-                    0.2110963193,
-                    0.178260718446,
+                    0.21109672,
+                    0.17826019,
                 ]
             ).reshape((9, 9)),
             "PBE TOTAL ENERGY": -55.83100498,  # psi 99,590
diff --git a/qcengine/programs/tests/test_ghost.py b/qcengine/programs/tests/test_ghost.py
index 8bd6e6f..a90452a 100644
--- a/qcengine/programs/tests/test_ghost.py
+++ b/qcengine/programs/tests/test_ghost.py
@@ -44,7 +44,7 @@ def test_simple_ghost(driver, program, basis, keywords, hene):
 
     if program == "gamess":
         with pytest.raises(qcng.exceptions.InputError) as e:
-            res = qcng.compute(resi, program, raise_error=True, return_dict=True)
+            qcng.compute(resi, program, raise_error=True, return_dict=True)
         pytest.xfail("no ghosts with gamess")
 
     res = qcng.compute(resi, program, raise_error=True, return_dict=True)
@@ -291,9 +291,24 @@ def test_atom_labels(qcprog, basis, keywords):
     assert compare(nmo, atres.properties.calcinfo_nmo, label="nmo"), f"nmo: {atres.properties.calcinfo_nmo} != {nmo}"
 
     scf = -1.656138508
-    assert compare_values(
-        scf, atres.properties.scf_total_energy, atol=3.0e-6, label="scf ene"
-    ), f"scf ene: {atres.properties.scf_total_energy} != {scf}"
-
+    scf_alt = -1.705577613  # some versions of NWChem land on this value
     mp2 = -1.7926264513
-    assert compare_values(mp2, atres.return_result, atol=3.0e-6, label="ene"), f"ene: {atres.return_result} != {mp2}"
+    mp2_alt = -1.870251459939
+    try:
+        assert compare_values(
+            scf, atres.properties.scf_total_energy, atol=3.0e-6, label="scf ene"
+        ), f"scf ene: {atres.properties.scf_total_energy} != {scf}"
+    except AssertionError as exc:
+        if qcprog == "nwchem":
+            assert compare_values(
+                scf_alt, atres.properties.scf_total_energy, atol=3.0e-6, label="scf ene"
+            ), f"scf ene: {atres.properties.scf_total_energy} != {scf_alt}"
+            assert compare_values(
+                mp2_alt, atres.return_result, atol=3.0e-6, label="ene"
+            ), f"ene: {atres.return_result} != {mp2_alt}"
+        else:
+            raise AssertionError from exc
+    else:
+        assert compare_values(
+            mp2, atres.return_result, atol=3.0e-6, label="ene"
+        ), f"ene: {atres.return_result} != {mp2}"
diff --git a/qcengine/programs/tests/test_programs.py b/qcengine/programs/tests/test_programs.py
index 410fff2..e524930 100644
--- a/qcengine/programs/tests/test_programs.py
+++ b/qcengine/programs/tests/test_programs.py
@@ -73,7 +73,8 @@ def test_psi4_interactive_task():
 
     assert "Final Energy" in ret.stdout
     assert ret.success
-    assert ret.extras.pop("psiapi_evaluated", False)
+    is_psiapi_evaluated = ret.extras.pop("psiapi_evaluated", False)
+    assert is_psiapi_evaluated
 
 
 @using("psi4_runqcsk")
diff --git a/qcengine/testing.py b/qcengine/testing.py
index b4d3c63..3f7ff1f 100644
--- a/qcengine/testing.py
+++ b/qcengine/testing.py
@@ -157,6 +157,7 @@ _programs = {
     "dftd3": which("dftd3", return_bool=True),
     "dftd3_321": is_program_new_enough("dftd3", "3.2.1"),
     "dftd4": which_import("dftd4", return_bool=True),
+    "dftd4_350": is_program_new_enough("dftd4", "3.5.0"),
     "s-dftd3": which_import("dftd3", return_bool=True),
     "qcore": is_program_new_enough("qcore", "0.8.9"),
     "gamess": which("rungms", return_bool=True),
diff --git a/qcengine/tests/test_config.py b/qcengine/tests/test_config.py
index bae420d..083a977 100644
--- a/qcengine/tests/test_config.py
+++ b/qcengine/tests/test_config.py
@@ -3,6 +3,7 @@ Tests the QCEngine compute module configuration
 """
 
 import copy
+import os
 
 try:
     import pydantic.v1 as pydantic
@@ -59,6 +60,31 @@ def test_node_skip_environ():
     assert node.scratch_directory is None
 
 
+@pytest.mark.parametrize(
+    "envvars,scr,ans",
+    [
+        ({"SCRATCH": "/my_scratch"}, "$SCRATCH", "/my_scratch"),
+        ({"SCRATCH": "/my_scratch"}, "${SCRATCH}", "/my_scratch"),
+        # ({"SCRATCH": "/my_scratch"}, "%SCRATCH%", "/my_scratch"),  # only valid on Windows
+        (
+            {"PBS_DIR": "/cluster/scr/job", "JOBNUM": "12345"},
+            "$PBS_DIR/psi_scratch/$JOBNUM",
+            "/cluster/scr/job/psi_scratch/12345",
+        ),
+        ({"QCSCR": "qcscr", "USER": "johndoe"}, "/scratch/${USER}/$QCSCR", "/scratch/johndoe/qcscr"),
+        ({}, "~", f"{os.environ.get('HOME')}"),
+        ({"QCSCR": "qcscr"}, "~/scratch/$QCSCR", f"{os.environ.get('HOME')}/scratch/qcscr"),
+        ({}, "$HOME", f"{os.environ.get('HOME')}"),
+        # ({}, "$RANDOM_NOVAR", "$RANDOM_NOVAR"),  # new behavior?
+        ({}, "$RANDOM_NOVAR", None),  # longstanding behavior
+    ],
+)
+def test_envvar(envvars, scr, ans):
+    with environ_context(env=envvars):
+        tc = qcng.get_config(task_config={"scratch_directory": scr})
+        assert tc.scratch_directory == ans
+
+
 @pytest.fixture
 def opt_state_basic():
     """
diff --git a/qcengine/tests/test_mdi.py b/qcengine/tests/test_mdi.py
index 73c5873..285ecaf 100644
--- a/qcengine/tests/test_mdi.py
+++ b/qcengine/tests/test_mdi.py
@@ -65,9 +65,15 @@ def test_mdi_water():
     # Test the <FORCES command
     forces = engine.send_forces()
     expected = [
-        [0.0, 0.0, -0.00073827952],
-        [0.0, -0.020208584243, 0.00036913976],
-        [-0.0, 0.020208584243, 0.00036913976],
+        -0.0000635769828,
+        0.0,
+        0.000735537025,
+        0.0000317884914,
+        0.0202085843,
+        -0.000367768513,
+        0.0000317884914,
+        -0.0202085843,
+        -0.000367768513,
     ]
     assert compare_values(expected, forces, atol=1.0e-6)
 
diff --git a/qcengine/tests/test_procedures.py b/qcengine/tests/test_procedures.py
index 4963959..92227dc 100644
--- a/qcengine/tests/test_procedures.py
+++ b/qcengine/tests/test_procedures.py
@@ -50,7 +50,7 @@ def test_geometric_psi4(input_data, optimizer, ncores):
     assert ret.provenance.creator.lower() == optimizer
     assert ret.trajectory[0].provenance.creator.lower() == "psi4"
 
-    if optimizer == "optking" and ncores == 4:
+    if optimizer == "optking":
         pytest.xfail("not passing threads to psi4")
     else:
         assert ret.trajectory[0].provenance.nthreads == ncores