Source code for psi4.driver.p4util.fchk
#
# @BEGIN LICENSE
#
# Psi4: an open-source quantum chemistry software package
#
# Copyright (c) 2007-2021 The Psi4 Developers.
#
# The copyrights for code used from other parties are included in
# the corresponding files.
#
# This file is part of Psi4.
#
# Psi4 is free software; you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published by
# the Free Software Foundation, version 3.
#
# Psi4 is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License along
# with Psi4; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# @END LICENSE
#
"""Module with utility functions for FCHK files."""
import numpy as np
from psi4.driver.p4util.testing import compare_strings, compare_arrays, compare_values, compare_integers
from psi4 import core
from .exceptions import ValidationError
__all__ = ['fchkfile_to_string','compare_fchkfiles']
def _consume_fchk_section(input_list, index):
"""compare a float or integer matrix section"""
n = int(input_list[index].split()[-1])
kind = input_list[index].split()[-3]
if "R" in kind:
dtype = np.float64
format_counter = 5
elif "I" in kind:
dtype = np.float64
format_counter = 6
else:
raise ValidationError('Unknow field type in FCHK reader\n')
extra = 0 if n <= format_counter else n % format_counter
lines = 1 if n <= format_counter else int(n / format_counter)
offset = lines + 1 if extra > 0 else lines
string = ''
for j in range(lines):
string += "".join(str(x) for x in input_list[index + 1 + j])
if extra > 0:
string += "".join(str(x) for x in input_list[index + 1 + lines])
field = np.fromiter(string.split(), dtype=dtype)
return offset + 1, field
[docs]def fchkfile_to_string(fname):
""" Load FCHK file into a string"""
with open(fname, 'r') as handle:
fchk_string = handle.read()
return fchk_string
[docs]def compare_fchkfiles(expected, computed, digits, label):
# """Function to compare two FCHK files.
# an older format description can be found here
# http://wild.life.nctu.edu.tw/~jsyu/compchem/g09/g09ur/f_formchk.htm
# It lists more fields (logical, character) that are not included in this
# test function. They should be covered by the string comparison.
# This function is only meant to work with PSI4's FCHK files.
#
# :param expected: reference FCHK file name
# :param computed: computed FCHK file name
# :param digits: tolerance for high accuracy fields -- 1.e-8 or 1.e-9 suitable
# :param label: string labelling the test
# """
fchk_ref = fchkfile_to_string(expected).splitlines()
fchk_calc = fchkfile_to_string(computed).splitlines()
high_accuracy = digits
low_accuracy = 3
# Those listed below need super high scf convergence (d_conv 1e-12) and might
# show machine dependence. They will be tested with low_accuracy.
sensitive = ['Current cartesian coordinates', 'MO coefficients']
if len(fchk_ref) != len(fchk_calc):
raise ValidationError('The two FCHK files to compare have a different file length! \n')
index = 0
max_length = len(fchk_calc)
tests = []
for start in range(max_length):
if index >= max_length:
break
line = fchk_calc[index]
if "N=" in line:
offset, calc = _consume_fchk_section(fchk_calc, index)
_, ref = _consume_fchk_section(fchk_ref, index)
if any(x in line for x in sensitive):
test = compare_arrays(ref, calc, low_accuracy, f" matrix section: {line}")
else:
test = compare_arrays(ref, calc, high_accuracy, f" matrix section: {line}")
index += offset
elif " R " in line and not "N=" in line:
calc = line.split()[-1]
ref = fchk_ref[index].split()[-1]
test = compare_values(ref, calc, high_accuracy, f" float value: {line}")
index += 1
elif " I " in line and not "N=" in line:
calc = line.split()[-1]
ref = fchk_ref[index].split()[-1]
test = compare_integers(ref, calc, f" int value: {line}")
index += 1
else:
test = compare_strings(line, fchk_ref[index], f"FCK text line {index+1}.")
index += 1
tests.append(test)
return compare_integers(True, all(tests), label)