Skip to content

Commit 1ea52dd

Browse files
committed
add ability to load BEEF correlations for UQ
1 parent 731b402 commit 1ea52dd

1 file changed

Lines changed: 83 additions & 3 deletions

File tree

rmgpy/tools/uncertainty.py

Lines changed: 83 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
###############################################################################
2929

3030
import os
31-
import re
31+
import pickle
3232

3333
import numpy as np
3434

@@ -43,7 +43,7 @@ class ThermoParameterUncertainty(object):
4343
This class is an engine that generates the species uncertainty based on its thermo sources.
4444
"""
4545

46-
def __init__(self, dG_library=1.5, dG_QM=3.0, dG_GAV=1.5, dG_group=0.7159, dG_ADS_correction=6.918, dG_surf_lib=6.918):
46+
def __init__(self, dG_library=1.5, dG_QM=3.0, dG_GAV=1.5, dG_group=0.7159, dG_ADS_correction=6.918, dG_surf_lib=6.918, other_covariances=None):
4747
"""
4848
Initialize the different uncertainties dG_library, dG_QM, dG_GAV, and dG_other with set values
4949
in units of kcal/mol.
@@ -57,6 +57,7 @@ def __init__(self, dG_library=1.5, dG_QM=3.0, dG_GAV=1.5, dG_group=0.7159, dG_AD
5757
self.dG_group = dG_group
5858
self.dG_ADS_correction = dG_ADS_correction
5959
self.dG_surf_lib = dG_surf_lib
60+
self.other_covariances = other_covariances # storage of covariances as a dict. Keys are sorted tuples of parameter labels and values are covariances
6061

6162
def get_uncertainty_value(self, source):
6263
"""
@@ -172,6 +173,12 @@ def _get_covariance_qq(self, q_label1, q_label2):
172173
if corr_type1 is None or corr_type2 is None:
173174
raise ValueError(f'Could not determine the type of the correlated parameters from their labels {q_label1} and {q_label2}')
174175

176+
if self.other_covariances is not None:
177+
# check if covariance is specified in other_covariances dict
178+
sorted_labels = tuple(sorted([q_label1, q_label2]))
179+
if sorted_labels in self.other_covariances:
180+
return self.other_covariances[sorted_labels]
181+
175182
if corr_type1 != corr_type2:
176183
return 0
177184
elif q_label1 == q_label2:
@@ -394,11 +401,13 @@ class Uncertainty(object):
394401
for a single RMG-generated mechanism.
395402
"""
396403

397-
def __init__(self, species_list=None, reaction_list=None, output_directory=''):
404+
def __init__(self, species_list=None, reaction_list=None, output_directory='', thermo_covariance_libraries=None, kinetic_covariance_libraries=None):
398405
"""
399406
`species_list`: list of RMG species objects
400407
`reaction_list`: list of RMG reaction objects
401408
`outputDirectoy`: directory path for saving output files from the analyses
409+
`thermo_covariance_libraries`: list of library paths to pull additional thermo covariances from
410+
`kinetic_covariance_libraries`: list of library paths to pull additional kinetic covariances from
402411
"""
403412
self.database = None
404413
self.species_list = species_list
@@ -418,6 +427,10 @@ def __init__(self, species_list=None, reaction_list=None, output_directory=''):
418427
self.all_thermo_intermediates = None # list of labels of underlying thermo parameters
419428
self.all_kinetics_intermediates = None # list of labels of underlying kinetic parameters
420429
self.output_directory = output_directory if output_directory else os.getcwd()
430+
self.thermo_covariance_libraries = thermo_covariance_libraries
431+
self.kinetic_covariance_libraries = kinetic_covariance_libraries
432+
self.thermo_covariances_dict = {} # dictionary to store covariances from covariance libraries
433+
self.kinetic_covariances_dict = {} # dictionary to store covariances from covariance libraries
421434

422435
# For extra species needed for correlated analysis but not in model
423436
self.extra_species = []
@@ -507,6 +520,63 @@ def retrieve_saturated_species_from_list(self, species):
507520
else:
508521
raise Exception('Could not retrieve saturated species form of {0} from the species list'.format(species))
509522

523+
def load_thermo_covariances_from_libraries(self):
524+
assert self.database is not None, 'Must load database before loading covariance libraries, since we need the path to the covariance libraries from the database'
525+
if self.thermo_covariance_libraries is not None:
526+
for cov_lib in self.thermo_covariance_libraries:
527+
library_name = os.path.basename(cov_lib)
528+
if library_name in self.database.thermo.libraries:
529+
library = self.database.thermo.libraries[library_name]
530+
else:
531+
raise ValueError(f'Thermo covariance library {library_name} not found in the loaded database')
532+
533+
covariance_file = os.path.join(cov_lib, 'covariance.npy')
534+
covariance_molecules = os.path.join(cov_lib, 'molecules.pickle')
535+
if not os.path.isfile(covariance_file):
536+
raise ValueError(f'Thermo covariance file {covariance_file} not found in library {cov_lib}')
537+
if not os.path.isfile(covariance_molecules):
538+
raise ValueError(f'Thermo molecules file {covariance_molecules} not found in library {cov_lib}')
539+
cov_data = np.load(covariance_file)
540+
with open(covariance_molecules, 'rb') as f:
541+
sp_adj_lists = pickle.load(f)
542+
cov_specs = [Species().from_adjacency_list(adj_list) for adj_list in sp_adj_lists]
543+
544+
# quick check to make sure the covariance data and molecule data are consistent with each other
545+
if cov_data.shape[0] != len(cov_specs):
546+
raise ValueError(f'Covariance data and molecule data in library {cov_lib} are inconsistent: covariance data has shape {cov_data.shape} but molecule data has length {len(cov_specs)}')
547+
548+
# load the labels, but only include species in the model
549+
subset_indices = [] # keep track of indices relevant to the model
550+
for i_lib, lib_species in enumerate(cov_specs):
551+
i_sp = get_i_thing(lib_species, self.species_list)
552+
if i_sp < 0:
553+
continue
554+
555+
# make sure the species actually comes from this library, otherwise skip
556+
result = self.database.thermo.get_thermo_data_from_library(lib_species, library)
557+
if result is not None:
558+
# match the label as constructed in assign_intermediate_uncertainties,
559+
# where the number corresponds to the index of the species in species_list
560+
try:
561+
label = 'Library {}'.format(self.species_list[i_sp].to_chemkin())
562+
except IndexError:
563+
label = 'Library {}'.format(self.extra_species[i_sp - len(self.species_list)].to_chemkin())
564+
lib_species.label = label
565+
subset_indices.append(i_lib)
566+
567+
# fill in the dictionary of covariances from the covariance libraries,
568+
# with keys being sorted tuples of the labels of the correlated parameters
569+
# and values being the covariance between those parameters
570+
tolerance = 1e-12 # consider anything with covariance less than this to be uncorrelated
571+
for i, index_i in enumerate(subset_indices):
572+
for j in range(i, len(subset_indices)):
573+
index_j = subset_indices[j]
574+
if cov_data[index_i, index_j] > tolerance:
575+
label1 = cov_specs[index_i].label
576+
label2 = cov_specs[index_j].label
577+
covariance = cov_data[index_i, index_j]
578+
self.covariances_dict[tuple(sorted([label1, label2]))] = covariance
579+
510580
def extract_sources_from_model(self):
511581
"""
512582
Extract the source data from the model using its comments.
@@ -626,6 +696,10 @@ def extract_sources_from_model(self):
626696
for spc in self.extra_species:
627697
self.species_list.remove(spc)
628698

699+
# -------------------- load covariance libraries ------------------------#
700+
self.load_thermo_covariances_from_libraries()
701+
self.load_kinetic_covariances_from_libraries()
702+
629703
def compile_all_sources(self):
630704
"""
631705
Compile two dictionaries composed of all the thermo and kinetic sources. Must
@@ -1455,3 +1529,9 @@ def process_local_results(results, sensitive_species, number=10):
14551529
output += '================================================================================\n\n'
14561530

14571531
return processed_results, output
1532+
1533+
def get_i_thing(thing, thing_list):
1534+
for i in range(len(thing_list)):
1535+
if thing.is_isomorphic(thing_list[i]):
1536+
return i
1537+
return -1

0 commit comments

Comments
 (0)