Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix for QCFractal next beta10 #2929

Merged
merged 5 commits into from
May 1, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ecosystem.yml
Original file line number Diff line number Diff line change
Expand Up @@ -242,7 +242,7 @@ jobs:
# "next" packages aren't self-contained, and "0.15.8" not available fro py310. try again someday
# sed -i "s;- qcfractal;;g" aux.yaml
# sed -i "s;- qcportal;;g" aux.yaml
sed -i "s;- qcfractal;- qcarchive/label/next::qcfractal=0.50b7;g" aux.yaml
sed -i "s;- qcfractal;- qcarchive/label/next::qcfractal;g" aux.yaml # >=0.50b10
sed -i "s;- qcportal;- postgresql;g" aux.yaml
fi
if [[ "${{ runner.os }}" == "macOS" ]]; then
Expand Down
2 changes: 1 addition & 1 deletion external/upstream/libxc/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ else()
# Default: use a stable release tarball of libxc. To use the
# development version of libxc, instead, comment the URL line,
# and uncomment the GIT lines.
URL https://gitlab.com/libxc/libxc/-/archive/6.0.0/libxc-6.0.0.tar.gz
URL https://gitlab.com/libxc/libxc/-/archive/6.1.0/libxc-6.1.0.tar.gz
#GIT_REPOSITORY https://gitlab.com/libxc/libxc.git
#GIT_TAG 5.1.5
#UPDATE_COMMAND ""
Expand Down
2 changes: 1 addition & 1 deletion psi4/driver/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -847,7 +847,7 @@ def calc(self, coords, dirname, read_data=False):
step_coordinates = []

# Make sure the molecule the user provided is the active one
molecule = kwargs.get('molecule', core.get_active_molecule())
molecule = kwargs.pop('molecule', core.get_active_molecule())

# Do not change orientation or COM
molecule.fix_orientation(True)
Expand Down
12 changes: 8 additions & 4 deletions psi4/driver/driver_cbs.py
Original file line number Diff line number Diff line change
Expand Up @@ -1635,10 +1635,10 @@ def _prepare_results(self, client: Optional["qcportal.FractalClient"] = None):
mc['f_gradient'] = task.extras['qcvars']['CURRENT GRADIENT']

if 'CURRENT DIPOLE' in task.extras['qcvars']:
mc['f_dipole'] = np.array(task.extras['qcvars']['CURRENT DIPOLE'])
mc['f_dipole'] = task.extras['qcvars']['CURRENT DIPOLE']

if 'CURRENT DIPOLE GRADIENT' in task.extras['qcvars']:
mc['f_dipder'] = np.array(task.extras['qcvars']['CURRENT DIPOLE GRADIENT'])
mc['f_dipder'] = task.extras['qcvars']['CURRENT DIPOLE GRADIENT']

# Fill in energies for subsumed methods
if self.metameta['ptype'] == 'energy':
Expand Down Expand Up @@ -1746,7 +1746,11 @@ def get_results(self, client: Optional["qcportal.FractalClient"] = None) -> Atom

return cbs_model

def get_psi_results(self, return_wfn: bool = False) -> EnergyGradientHessianWfnReturn:
def get_psi_results(
self,
client: Optional["qcportal.FractalClient"] = None,
*,
return_wfn: bool = False) -> EnergyGradientHessianWfnReturn:
"""Called by driver to assemble results into Composite-flavored QCSchema,
then reshape and return them in the customary Psi4 driver interface: ``(e/g/h, wfn)``.

Expand All @@ -1770,7 +1774,7 @@ def get_psi_results(self, return_wfn: bool = False) -> EnergyGradientHessianWfnR
Wavefunction described above when *return_wfn* specified.

"""
cbs_model = self.get_results()
cbs_model = self.get_results(client=client)

if cbs_model.driver == 'energy':
ret_ptype = cbs_model.return_result
Expand Down
8 changes: 6 additions & 2 deletions psi4/driver/driver_findif.py
Original file line number Diff line number Diff line change
Expand Up @@ -1459,7 +1459,11 @@ def get_results(self, client: Optional["qcportal.FractalClient"] = None) -> Atom

return findif_model

def get_psi_results(self, return_wfn: bool = False) -> EnergyGradientHessianWfnReturn:
def get_psi_results(
self,
client: Optional["qcportal.FractalClient"] = None,
*,
return_wfn: bool = False) -> EnergyGradientHessianWfnReturn:
"""Called by driver to assemble results into FiniteDifference-flavored QCSchema,
then reshape and return them in the customary Psi4 driver interface: ``(e/g/h, wfn)``.

Expand All @@ -1483,7 +1487,7 @@ def get_psi_results(self, return_wfn: bool = False) -> EnergyGradientHessianWfnR
Wavefunction described above when *return_wfn* specified.

"""
findif_model = self.get_results()
findif_model = self.get_results(client=client)

ret_ptype = core.Matrix.from_array(findif_model.return_result)
wfn = _findif_schema_to_wfn(findif_model)
Expand Down
8 changes: 6 additions & 2 deletions psi4/driver/driver_nbody.py
Original file line number Diff line number Diff line change
Expand Up @@ -1417,7 +1417,11 @@ def get_results(self, client: Optional["qcportal.FractalClient"] = None) -> Atom

return nbody_model

def get_psi_results(self, return_wfn: bool = False) -> EnergyGradientHessianWfnReturn:
def get_psi_results(
self,
client: Optional["qcportal.FractalClient"] = None,
*,
return_wfn: bool = False) -> EnergyGradientHessianWfnReturn:
"""Called by driver to assemble results into ManyBody-flavored QCSchema,
then reshape and return them in the customary Psi4 driver interface: ``(e/g/h, wfn)``.

Expand All @@ -1440,7 +1444,7 @@ def get_psi_results(self, return_wfn: bool = False) -> EnergyGradientHessianWfnR
Wavefunction described above when *return_wfn* specified.

"""
nbody_model = self.get_results()
nbody_model = self.get_results(client=client)
ret = nbody_model.return_result

wfn = core.Wavefunction.build(self.molecule, "def2-svp", quiet=True)
Expand Down
51 changes: 0 additions & 51 deletions psi4/driver/p4util/procutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
"prepare_options_for_modules",
"prepare_options_for_set_options",
"provenance_stamp",
"plump_qcvar",
"state_to_atomicinput",
]

Expand Down Expand Up @@ -730,53 +729,3 @@ def provenance_stamp(routine: str, module: str = None) -> Dict[str, str]:
prov["module"] = module

return prov


def plump_qcvar(
val: Union[float, str, List],
shape_clue: str,
ret: str = 'np') -> Union[float, np.ndarray, core.Matrix]:
"""Prepare serialized QCVariable for :py:func:`~psi4.core.set_variable` by
converting flat arrays into shaped ones and floating strings.

Parameters
----------
val
flat (?, ) list or scalar or string, probably from JSON storage.
shape_clue
Label that includes (case insensitive) one of the following as
a clue to the array's natural dimensions: 'gradient', 'hessian'
ret
{'np', 'psi4'}
Whether for arrays to return :py:class:`numpy.ndarray` or
:py:class:`psi4.core.Matrix`.

Returns
-------
float or numpy.ndarray or Matrix
Reshaped array of type `ret` with natural dimensions of `shape_clue`.

"""
if isinstance(val, (np.ndarray, core.Matrix)):
raise TypeError
elif isinstance(val, list):
tgt = np.asarray(val)
else:
# presumably scalar. may be string
return float(val)
# TODO choose float vs Decimal for return if string?

if 'gradient' in shape_clue.lower():
reshaper = (-1, 3)
elif 'hessian' in shape_clue.lower():
ndof = int(math.sqrt(len(tgt)))
reshaper = (ndof, ndof)
else:
raise ValidationError(f'Uncertain how to reshape array: {shape_clue}')

if ret == 'np':
return tgt.reshape(reshaper)
elif ret == 'psi4':
return core.Matrix.from_array(tgt.reshape(reshaper))
else:
raise ValidationError(f'Return type not among [np, psi4]: {ret}')
62 changes: 61 additions & 1 deletion psi4/driver/p4util/python_helpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
__all__ = [
"basis_helper",
"pcm_helper",
"plump_qcvar",
"set_options",
"set_module_options",
"temp_circular_import_blocker", # retire ASAP
Expand All @@ -52,6 +53,7 @@
import os
import re
import sys
import math
import uuid
import warnings
from collections import Counter
Expand Down Expand Up @@ -839,6 +841,64 @@ def _qcvar_warnings(key: str) -> str:
return key


def plump_qcvar(
key: str,
val: Union[float, str, List]) -> Union[float, np.ndarray]:
"""Prepare serialized QCVariables for QCSchema AtomicResult.extras["qcvars"] by
converting flat arrays into numpy, shaped ones and floating strings.
Unlike _qcvar_reshape_get/set, multipoles aren't compressed or plumped, only reshaped.

Parameters
----------
key
Shape clue (usually QCVariable key) that includes (case insensitive) an identifier like
'gradient' as a clue to the array's natural dimensions.
val
flat (?, ) list or scalar or string, probably from JSON storage.

Returns
-------
float or numpy.ndarray
Reshaped array of `val` with natural dimensions of `key`.

"""
if isinstance(val, (np.ndarray, core.Matrix)):
raise TypeError
elif isinstance(val, list):
tgt = np.asarray(val)
else:
# presumably scalar. may be string
return float(val)

if key.upper().startswith("MBIS"):
if key.upper().endswith("CHARGES"):
reshaper = (-1, )
elif key.upper().endswith("DIPOLES"):
reshaper = (-1, 3)
elif key.upper().endswith("QUADRUPOLES"):
reshaper = (-1, 3, 3)
elif key.upper().endswith("OCTUPOLES"):
reshaper = (-1, 3, 3, 3)
elif key.upper().endswith("DIPOLE") or "DIPOLE -" in key.upper():
reshaper = (3, )
elif "QUADRUPOLE POLARIZABILITY TENSOR" in key.upper():
reshaper = (3, 3, 3)
elif any((key.upper().endswith(p) or f"{p} -" in key.upper()) for p in _multipole_order):
p = [p for p in _multipole_order if (key.upper().endswith(p) or f"{p} -" in key.upper())]
reshaper = tuple([3] * _multipole_order.index(p[0]))
elif key.upper() in ["MULLIKEN_CHARGES", "LOWDIN_CHARGES", "MULLIKEN CHARGES", "LOWDIN CHARGES"]:
reshaper = (-1, )
elif "GRADIENT" in key.upper():
reshaper = (-1, 3)
elif "HESSIAN" in key.upper():
ndof = int(math.sqrt(len(tgt)))
reshaper = (ndof, ndof)
else:
raise ValidationError(f'Uncertain how to reshape array: {key}')

return tgt.reshape(reshaper)


_multipole_order = ["dummy", "dummy", "QUADRUPOLE", "OCTUPOLE", "HEXADECAPOLE"]
for order in range(5, 10):
_multipole_order.append(f"{int(2**order)}-POLE")
Expand Down Expand Up @@ -881,7 +941,7 @@ def _qcvar_reshape_set(key: str, val: np.ndarray) -> np.ndarray:
return val


def _qcvar_reshape_get(key: str, val: Union[core.Matrix, np.ndarray]) -> Union[core.Matrix, np.ndarray]:
def _qcvar_reshape_get(key: str, val: core.Matrix) -> Union[core.Matrix, np.ndarray]:
"""For QCVariables where the 2D :py:class:`psi4.core.Matrix` shape is
unnatural, convert to natural shape in :class:`numpy.ndarray`.

Expand Down
37 changes: 12 additions & 25 deletions psi4/driver/task_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import abc
import copy
import logging
import pprint
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is pprint used or just a debug leftover?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a debug leftover that I keep adding again and again, so I thought I'd leave it (until some linter confiscates it).

from typing import Any, Dict, Optional, Tuple, Union, TYPE_CHECKING

from pydantic import Field, validator
Expand All @@ -44,6 +45,7 @@
import qcengine as qcng

from psi4 import core
from psi4.driver import p4util

if TYPE_CHECKING:
import qcportal
Expand Down Expand Up @@ -253,31 +255,16 @@ def get_results(self, client: Optional["qcportal.FractalClient"] = None) -> Atom
return self.result


def _singlepointrecord_to_atomicresult(spr) -> AtomicResult:
extras = spr.raw_data.extras
extras.pop("_qcfractal_compressed_outputs", None)

atres = {
"driver": spr.raw_data.specification.driver,
"model": {
"method": spr.raw_data.specification.method,
"basis": spr.raw_data.specification.basis,
},
"molecule": spr.molecule,
"keywords": spr.raw_data.specification.keywords,
"properties": spr.properties,
"protocols": spr.raw_data.specification.protocols,
"return_result": spr.return_result,
"extras": extras,
"stdout": spr.stdout,
"native_files": spr.native_files,
"wavefunction": spr.wavefunction,
"provenance": spr.raw_data.compute_history[0].provenance,
"success": spr.status == "complete",
}

from qcelemental.models import AtomicResult
atres = AtomicResult(**atres)
def _singlepointrecord_to_atomicresult(spr: "qcportal.singlepoint.SinglepointRecord") -> AtomicResult:
atres = spr.to_qcschema_result()

# QCFractal `next` database stores return_result, properties, and extras["qcvars"] merged
# together and with lowercase keys. `to_qcschema_result` partitions properties back out,
# but we need to restore qcvars keys, types, and dimensions.
qcvars = atres.extras.pop("extra_properties")
qcvars.pop("return_result")
qcvars = {k.upper(): p4util.plump_qcvar(k, v) for k, v in qcvars.items()}
atres.extras["qcvars"] = qcvars

return atres

Expand Down
7 changes: 4 additions & 3 deletions pytest.ini
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ markers =
cisd
cubeprop
dct
# ddd: "findif and cbs and nbody" (not defined, so use equiv. expansion)
df: "tests that employ density-fitting"
dfccd
dfccd-grad
Expand Down Expand Up @@ -66,7 +67,7 @@ markers =
extern: "tests that use the ExternalPotential object"
fci
fcidump
findif
findif: "tests that run through the finite_difference wrapper"
fnocc
frac
freq
Expand Down Expand Up @@ -160,7 +161,7 @@ markers =
snsmp2
v2rdm_casscf
qcdb
qcfractal: "tests suing QCFractal software; skip if unavailable"
qcportal: "tests suing QCPortal software; skip if unavailable"
qcfractal: "tests using QCFractal software; skip if unavailable"
qcportal: "tests using QCPortal software; skip if unavailable"
psi4

Loading