Skip to content
10 changes: 7 additions & 3 deletions arkane/encorr/bac.py
Original file line number Diff line number Diff line change
Expand Up @@ -1092,17 +1092,21 @@ def get_confidence_intervals(x: np.ndarray,
weights = np.eye(n)

e = y - ypred # Residuals
sigma2 = e.T @ weights @ e / (n - p) # MSE
dof = n - p
Comment thread
rwest marked this conversation as resolved.
if dof <= 0:
return np.full(p, np.nan), np.full((p, p), np.nan)
sigma2 = e.T @ weights @ e / dof # MSE
cov = sigma2 * np.linalg.inv(x.T @ weights @ x) # covariance matrix
se = np.sqrt(np.diag(cov)) # standard error
tdist = distributions.t.ppf(1 - alpha / 2, n - p) # student-t
tdist = distributions.t.ppf(1 - alpha / 2, dof) # student-t
ci = tdist * se # confidence interval half-width
return ci, cov


def _covariance_to_correlation(cov: np.ndarray) -> np.ndarray:
"""Convert (unscaled) covariance matrix to correlation matrix"""
v = np.sqrt(np.diag(cov))
corr = cov / np.outer(v, v)
with np.errstate(divide='ignore', invalid='ignore'):
corr = cov / np.outer(v, v)
corr[cov == 0] = 0
return corr
48 changes: 30 additions & 18 deletions arkane/output.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,20 @@ def __init__(self, level=0, indent=4):
self.level = level
self.indent = indent

@staticmethod
def _is_string(node):
return isinstance(node, ast.Constant) and isinstance(node.value, str)

@staticmethod
def _is_number(node):
return isinstance(node, ast.Constant) and isinstance(node.value, (int, float, complex)) and not isinstance(node.value, bool)

@classmethod
def _is_simple_constant(cls, node):
return cls._is_string(node) or cls._is_number(node) or (
isinstance(node, ast.Constant) and isinstance(node.value, bool)
)

def visit_Call(self, node):
"""
Return a pretty representation of the class or function call represented by `node`.
Expand Down Expand Up @@ -84,7 +98,7 @@ def visit_List(self, node):
"""
Return a pretty representation of the list represented by `node`.
"""
if any([not isinstance(e, (ast.Str, ast.Num, ast.UnaryOp)) for e in node.elts]):
if any([not (self._is_simple_constant(e) or isinstance(e, ast.UnaryOp)) for e in node.elts]):
# Split elements onto multiple lines
result = '[\n'
self.level += 1
Expand All @@ -105,11 +119,11 @@ def visit_Tuple(self, node):
"""
# If the tuple represents a quantity, keep it on one line
is_quantity = True
if len(node.elts) == 0 or not isinstance(node.elts[0], (ast.Num, ast.List)) or (
if len(node.elts) == 0 or not (self._is_number(node.elts[0]) or isinstance(node.elts[0], ast.List)) or (
isinstance(node.elts[0], ast.List) and
any([not isinstance(e, (ast.Num, ast.UnaryOp)) for e in node.elts[0].elts])):
any([not (self._is_number(e) or isinstance(e, ast.UnaryOp)) for e in node.elts[0].elts])):
is_quantity = False
elif len(node.elts) < 2 or not isinstance(node.elts[1], ast.Str):
elif len(node.elts) < 2 or not self._is_string(node.elts[1]):
is_quantity = False

if not is_quantity:
Expand All @@ -131,8 +145,8 @@ def visit_Dict(self, node):
"""
Return a pretty representation of the dict represented by `node`.
"""
if (any([not isinstance(e, (ast.Str, ast.Num)) for e in node.keys])
or any([not isinstance(e, (ast.Str, ast.Num)) for e in node.values])):
if (any([not self._is_simple_constant(e) for e in node.keys])
or any([not self._is_simple_constant(e) for e in node.values])):
# Split elements onto multiple lines
result = '{\n'
self.level += 1
Expand All @@ -149,20 +163,18 @@ def visit_Dict(self, node):
self.string = result
return result

def visit_Str(self, node):
"""
Return a pretty representation of the string represented by `node`.
"""
result = repr(node.s)
self.string = result
return result

def visit_Num(self, node):
def visit_Constant(self, node):
"""
Return a pretty representation of the number represented by `node`.
Return a pretty representation of the constant represented by `node`.
"""
result = '{0:g}'.format(node.n)
# result = repr(node.n)
if isinstance(node.value, str):
result = repr(node.value)
elif isinstance(node.value, bool):
result = repr(node.value)
elif isinstance(node.value, (int, float, complex)) and not isinstance(node.value, bool):
result = '{0:g}'.format(node.value)
else:
return None
self.string = result
return result

Expand Down
22 changes: 15 additions & 7 deletions rmgpy/data/kinetics/family.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
from copy import deepcopy

import numpy as np
from scipy.optimize import OptimizeWarning
from sklearn.model_selection import KFold

from rmgpy import settings
Expand Down Expand Up @@ -4654,13 +4655,20 @@ def _make_rule(rr):
kin.uncertainty = RateUncertainty(mu=0.0, var=(np.log(fmax) / 2.0) ** 2, N=1, Tref=Tref, data_mean=data_mean, correlation=label)
else:
if isinstance(rs[0].kinetics, Arrhenius):
dlnks = np.array([
np.log(
arr().fit_to_reactions(np.delete(rs, i), recipe=recipe)
.to_arrhenius(rxn.get_enthalpy_of_reaction(Tref))
.get_rate_coefficient(T=Tref) / rxn.get_rate_coefficient(T=Tref)
) for i, rxn in enumerate(rs)
]) # 1) fit to set of reactions without the current reaction (k) 2) compute log(kfit/kactual) at Tref
with warnings.catch_warnings():
# Jackknife refits use sparse samples and only consume fitted rates, not covariance estimates.
warnings.filterwarnings(
"ignore",
message="Covariance of the parameters could not be estimated",
category=OptimizeWarning,
)
dlnks = np.array([
np.log(
arr().fit_to_reactions(np.delete(rs, i), recipe=recipe)
.to_arrhenius(rxn.get_enthalpy_of_reaction(Tref))
.get_rate_coefficient(T=Tref) / rxn.get_rate_coefficient(T=Tref)
) for i, rxn in enumerate(rs)
]) # 1) fit to set of reactions without the current reaction (k) 2) compute log(kfit/kactual) at Tref
else:
dlnks = np.array([
np.log(
Expand Down
2 changes: 1 addition & 1 deletion rmgpy/data/solvation.py
Original file line number Diff line number Diff line change
Expand Up @@ -2381,7 +2381,7 @@ def get_Kfactor_parameters(self, delG298, delH298, delS298, solvent_name, T_tran

# Generate Amatrix and bvector for Ax = b
Amatrix = np.zeros((4, 4))
bvec = np.zeros((4, 1))
bvec = np.zeros(4)
# 1. Tr*ln(K-factor) value at T = 298 K
rho_g_298 = get_gas_saturation_density(solvent_name, 298)
rho_l_298 = get_liquid_saturation_density(solvent_name, 298)
Expand Down
7 changes: 6 additions & 1 deletion rmgpy/rmg/pdep.py
Original file line number Diff line number Diff line change
Expand Up @@ -432,9 +432,14 @@ def solve_ss_network(self, T, P):
ind = isomer_spcs.index(self.source[0])
b[ind] = -1.0 # flux at source
else:
b = -b / b.sum() # 1.0 flux from source
total_source_flux = b.sum()
if total_source_flux == 0:
return None
b = -b / total_source_flux # 1.0 flux from source

if len(b) == 1:
if A[0, 0] == 0:
return None
return np.array([b[0] / A[0, 0]])

con = np.linalg.cond(A)
Expand Down
14 changes: 12 additions & 2 deletions rmgpy/statmech/conformer.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,15 @@ cpdef double phi(double beta, int k, double E, logQ) except -10000000:
T = 1.0 / (constants.R * beta)
return logQ(T) - k * log(beta) + beta * E


def _phi_for_optimizer(beta, int k, double E, logQ):
"""
Evaluate :func:`phi` from SciPy optimizers, which pass the scalar search
coordinate as a one-element array.
"""
return phi(float(np.asarray(beta).item()), k, E, logQ)


@cython.boundscheck(False)
@cython.wraparound(False)
def get_density_of_states_forst(np.ndarray[np.float64_t, ndim=1] e_list, logQ, int order=1):
Expand All @@ -557,6 +566,7 @@ def get_density_of_states_forst(np.ndarray[np.float64_t, ndim=1] e_list, logQ, i

cdef np.ndarray[np.float64_t, ndim=1] dens_states, sum_states
cdef double x, dx, v, E, dE
cdef object opt_result
cdef int i, k

if order != 1 and order != 2:
Expand All @@ -580,10 +590,10 @@ def get_density_of_states_forst(np.ndarray[np.float64_t, ndim=1] e_list, logQ, i

# Find minimum of phi func x0 arg xtol ftol maxi maxf fullout disp retall callback
try:
x = scipy.optimize.fmin(phi, x, (k, E, logQ), 1e-8, 1e-8, 100, 1000, False, False, False, None)
opt_result = scipy.optimize.fmin(_phi_for_optimizer, np.array([x]), (k, E, logQ), 1e-8, 1e-8, 100, 1000, False, False, False, None)
except ValueError:
break
x = float(x)
x = float(opt_result.item())
dx = 1e-2 * x

# Evaluate derivatives needed for steepest descents approximation numerically
Expand Down
4 changes: 2 additions & 2 deletions test/arkane/arkaneOutputTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -146,8 +146,8 @@ def test_prettify(self):
],
'kJ/mol',
),
quantum = None,
semiclassical = None,
quantum = True,
semiclassical = False,
),
],
spin_multiplicity = 2,
Expand Down
25 changes: 12 additions & 13 deletions test/arkane/ess/arkaneGaussianTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -93,10 +93,10 @@ def test_load_ethylene_from_gaussian_log_cbsqb3(self):
trans = [mode for mode in conformer.modes if isinstance(mode, IdealGasTranslation)][0]
rot = [mode for mode in conformer.modes if isinstance(mode, NonlinearRotor)][0]
vib = [mode for mode in conformer.modes if isinstance(mode, HarmonicOscillator)][0]
t_list = np.array([298.15], float)
assert abs(trans.get_partition_function(t_list) - 5.83338e6) < 1e1
assert abs(rot.get_partition_function(t_list) - 2.59622e3) < 1e-2
assert abs(vib.get_partition_function(t_list) - 1.0481e0) < 1e-4
t = 298.15
assert abs(trans.get_partition_function(t) - 5.83338e6) < 1e1
assert abs(rot.get_partition_function(t) - 2.59622e3) < 1e-2
assert abs(vib.get_partition_function(t) - 1.0481e0) < 1e-4

assert round(abs(e0 / constants.Na / constants.E_h - -78.467452), 4) == 0
assert conformer.spin_multiplicity == 1
Expand Down Expand Up @@ -152,10 +152,10 @@ def test_load_oxygen_from_gaussian_log(self):
trans = [mode for mode in conformer.modes if isinstance(mode, IdealGasTranslation)][0]
rot = [mode for mode in conformer.modes if isinstance(mode, LinearRotor)][0]
vib = [mode for mode in conformer.modes if isinstance(mode, HarmonicOscillator)][0]
t_list = np.array([298.15], float)
assert abs(trans.get_partition_function(t_list) - 7.11169e6) < 1e1
assert abs(rot.get_partition_function(t_list) - 7.13316e1) < 1e-4
assert abs(vib.get_partition_function(t_list) - 1.00037e0) < 1e-4
t = 298.15
assert abs(trans.get_partition_function(t) - 7.11169e6) < 1e1
assert abs(rot.get_partition_function(t) - 7.13316e1) < 1e-4
assert abs(vib.get_partition_function(t) - 1.00037e0) < 1e-4

assert round(abs(e0 / constants.Na / constants.E_h - -150.3784877), 4) == 0
assert conformer.spin_multiplicity == 3
Expand All @@ -180,11 +180,10 @@ def test_load_ethylene_from_gaussian_log_g3(self):
trans = [mode for mode in conformer.modes if isinstance(mode, IdealGasTranslation)][0]
rot = [mode for mode in conformer.modes if isinstance(mode, NonlinearRotor)][0]
vib = [mode for mode in conformer.modes if isinstance(mode, HarmonicOscillator)][0]
t_list = np.array([298.15], float)

assert abs(trans.get_partition_function(t_list) - 5.83338e6) < 1e1
assert abs(rot.get_partition_function(t_list) - 2.53410e3) < 1e-2
assert abs(vib.get_partition_function(t_list) - 1.0304e0) < 1e-4
t = 298.15
assert abs(trans.get_partition_function(t) - 5.83338e6) < 1e1
assert abs(rot.get_partition_function(t) - 2.53410e3) < 1e-2
assert abs(vib.get_partition_function(t) - 1.0304e0) < 1e-4

assert round(abs(e0 / constants.Na / constants.E_h - -78.562189), 4) == 0
assert conformer.spin_multiplicity == 1
Expand Down
11 changes: 4 additions & 7 deletions test/arkane/ess/molproTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,6 @@
import os


import numpy as np

import rmgpy.constants as constants
from rmgpy.statmech import (
IdealGasTranslation,
Expand Down Expand Up @@ -129,11 +127,10 @@ def test_load_hosi_from_molpro_log(self):
trans = [mode for mode in conformer.modes if isinstance(mode, IdealGasTranslation)][0]
rot = [mode for mode in conformer.modes if isinstance(mode, NonlinearRotor)][0]
vib = [mode for mode in conformer.modes if isinstance(mode, HarmonicOscillator)][0]
t_list = np.array([298.15], float)

assert abs(trans.get_partition_function(t_list) - 9.175364e7) < 1e1
assert abs(rot.get_partition_function(t_list) - 1.00005557e5) < 1e-2
assert abs(vib.get_partition_function(t_list) - 1.9734989e0) < 1e-4
t = 298.15
assert abs(trans.get_partition_function(t) - 9.175364e7) < 1e1
assert abs(rot.get_partition_function(t) - 1.00005557e5) < 1e-2
assert abs(vib.get_partition_function(t) - 1.9734989e0) < 1e-4

assert round(abs(e0 / constants.Na / constants.E_h - -768.275662), 4) == 0
assert conformer.spin_multiplicity == 1
Expand Down
Loading