1import math
2import re
3
4import numpy as np
5from qcelemental.exceptions import ValidationError
6from qcelemental.util import filter_comments
7
8
9def load_hessian(shess: str, dtype: str) -> np.ndarray:
10    """Construct a Hessian array from any recognized string format.
11
12    Parameters
13    ----------
14    shess
15        Multiline string specification of Hessian in a recognized format.
16    dtype
17        {"fcmfinal", "cfour", "gamess"}
18        Hessian format name.
19
20    Returns
21    -------
22    np.ndarray
23        Hessian array in square shape.
24
25    """
26    # list o'lines w/o comments or blanks
27    shess = filter_comments(shess)
28    lhess = list(filter(None, map(str.strip, shess.splitlines())))
29
30    if dtype in ["fcmfinal", "cfour"]:
31        nat = int(lhess[0].split()[0])
32        ndof = 3 * nat
33        datastr = "\n".join(lhess[1:])
34        nhess = np.fromstring(datastr, sep=" ")
35        nhess = nhess.reshape(ndof, ndof)
36    elif dtype == "gamess":
37        if "ENERGY" in lhess[0]:
38            lhess.pop(0)
39        datastr = []
40        for ln in lhess:
41            numbers = re.findall(r"([-+]?\d+\.\d+[DdEe][-+]\d\d)", ln)
42            if numbers:
43                datastr.extend(numbers)
44
45        nhess = np.fromstring(" ".join(datastr), sep=" ")
46        ndof = int(math.sqrt(len(nhess)))
47        nhess = nhess.reshape((ndof, ndof))
48    else:
49        raise ValidationError("Unknown dtype: {}".format(dtype))
50
51    return nhess
52
53
54def hess_to_string(hess, handle, dtype):
55    nat = hess.shape[0] // 3
56    assert hess.shape == (3 * nat, 3 * nat)
57
58    header = "{:5}{:5}".format(nat, 6 * nat)
59    np.savetxt(handle, hess.reshape((-1, 3)), fmt="%20.10f", delimiter="", newline="\n", header=header, comments="")
60