Skip to content

Commit

Permalink
Merge pull request #91 from ReactionMechanismGenerator/allow_nonisomo…
Browse files Browse the repository at this point in the history
…rphic_2d

Allow nonisomorphic 2d
  • Loading branch information
alongd committed Mar 13, 2019
2 parents 93ee5a9 + 5cc47d0 commit 178943e
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 17 deletions.
10 changes: 8 additions & 2 deletions arc/main.py
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@ class ARC(object):
`t_count` ``int`` The number of temperature points between t_min and t_max for kinetics computations
`max_job_time` ``int`` The maximal allowed job time on the server in hours
`rmgdb` ``RMGDatabase`` The RMG database object
`allow_nonisomorphic_2d` ``bool`` Whether to optimize species even if they do not have a 3D conformer that is
isomorphic to the 2D graph representation
====================== ========== ==================================================================================
`level_of_theory` is a string representing either sp//geometry levels or a composite method, e.g. 'CBS-QB3',
Expand All @@ -83,7 +85,7 @@ def __init__(self, input_dict=None, project=None, arc_species_list=None, arc_rxn
conformer_level='', composite_method='', opt_level='', freq_level='', sp_level='', scan_level='',
ts_guess_level='', fine=True, generate_conformers=True, scan_rotors=True, use_bac=True,
model_chemistry='', ess_settings=None, initial_trsh=None, t_min=None, t_max=None, t_count=None,
verbose=logging.INFO, project_directory=None, max_job_time=120):
verbose=logging.INFO, project_directory=None, max_job_time=120, allow_nonisomorphic_2d=False):

self.__version__ = '1.0.0'
self.verbose = verbose
Expand All @@ -95,6 +97,7 @@ def __init__(self, input_dict=None, project=None, arc_species_list=None, arc_rxn
self.unique_species_labels = list()
self.rmgdb = rmgdb.make_rmg_database_object()
self.max_job_time = max_job_time
self.allow_nonisomorphic_2d = allow_nonisomorphic_2d

if input_dict is None:
if project is None:
Expand Down Expand Up @@ -359,6 +362,7 @@ def as_dict(self):
restart_dict['t_max'] = self.t_max
restart_dict['t_count'] = self.t_count
restart_dict['max_job_time'] = self.max_job_time
restart_dict['allow_nonisomorphic_2d'] = self.allow_nonisomorphic_2d
return restart_dict

def from_dict(self, input_dict, project=None, project_directory=None):
Expand All @@ -381,6 +385,8 @@ def from_dict(self, input_dict, project=None, project_directory=None):
self.execution_time = None
self.verbose = input_dict['verbose'] if 'verbose' in input_dict else self.verbose
self.max_job_time = input_dict['max_job_time'] if 'max_job_time' in input_dict else 5
self.allow_nonisomorphic_2d = input_dict['allow_nonisomorphic_2d']\
if 'allow_nonisomorphic_2d' in input_dict else False

if self.ess_settings is not None:
self.settings['ssh'] = True
Expand Down Expand Up @@ -559,7 +565,7 @@ def execute(self):
settings=self.settings, generate_conformers=self.generate_conformers,
scan_rotors=self.scan_rotors, initial_trsh=self.initial_trsh, rmgdatabase=self.rmgdb,
restart_dict=self.restart_dict, project_directory=self.project_directory,
max_job_time=self.max_job_time)
max_job_time=self.max_job_time, allow_nonisomorphic_2d=self.allow_nonisomorphic_2d)

self.save_project_info_file()

Expand Down
1 change: 1 addition & 0 deletions arc/mainTest.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ def test_as_dict(self):
't_max': None,
't_count': None,
'use_bac': True,
'allow_nonisomorphic_2d': False,
'species': [{'bond_corrections': {'C-C': 1, 'C-H': 6},
'arkane_file': None,
'E0': None,
Expand Down
39 changes: 26 additions & 13 deletions arc/scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ class Scheduler(object):
`max_job_time` ``int`` The maximal allowed job time on the server in hours
`testing` ``bool`` Used for internal ARC testing (generating the object w/o executing it)
`rmgdb` ``RMGDatabase`` The RMG database object
`allow_nonisomorphic_2d` ``bool`` Whether to optimize species even if they do not have a 3D conformer that is
isomorphic to the 2D graph representation
======================= ========= ==================================================================================
Dictionary structures:
Expand Down Expand Up @@ -107,7 +109,7 @@ class Scheduler(object):
def __init__(self, project, settings, species_list, composite_method, conformer_level, opt_level, freq_level,
sp_level, scan_level, ts_guess_level, project_directory, rmgdatabase, fine=False, scan_rotors=True,
generate_conformers=True, initial_trsh=None, rxn_list=None, restart_dict=None, max_job_time=120,
testing=False):
allow_nonisomorphic_2d=False, testing=False):
self.rmgdb = rmgdatabase
self.restart_dict = restart_dict
self.species_list = species_list
Expand All @@ -119,6 +121,7 @@ def __init__(self, project, settings, species_list, composite_method, conformer_
self.job_dict = dict()
self.servers_jobs_ids = list()
self.running_jobs = dict()
self.allow_nonisomorphic_2d = allow_nonisomorphic_2d
self.testing = testing
if self.restart_dict is not None:
self.output = self.restart_dict['output']
Expand Down Expand Up @@ -689,7 +692,7 @@ def parse_conformer_energy(self, job, label, i):
log = Log(path='')
log.determine_qm_software(fullpath=job.local_path_to_output_file)
e0 = log.software_log.loadEnergy()
self.species_dict[label].conformer_energies[i] = e0
self.species_dict[label].conformer_energies[i] = e0 # in J/mol
else:
logging.warn('Conformer {i} for {label} did not converge!'.format(i=i, label=label))

Expand Down Expand Up @@ -733,9 +736,12 @@ def determine_most_stable_conformer(self, label):
with open(conf_path, 'w') as f:
for i, xyz in enumerate(xyzs):
f.write('conformer {0}:\n'.format(i))
f.write(xyz + '\n')
f.write('SMILES: ' + smiles_list[i] + '\n')
f.write('Relative Energy: {0} kJ/mol\n\n\n'.format((energies[i] - min(energies)) * 2625.50))
if xyz is not None:
f.write(xyz + '\n')
f.write('SMILES: ' + smiles_list[i] + '\n')
f.write('Relative Energy: {0} kJ/mol\n\n\n'.format((energies[i] - min(energies)) * 0.001))
else:
f.write('Failed to converge')
# Run isomorphism checks if a 2D representation is available
if self.species_dict[label].mol is not None:
for i, xyz in enumerate(xyzs):
Expand All @@ -748,27 +754,34 @@ def determine_most_stable_conformer(self, label):
conformer_xyz = xyz
self.output[label]['status'] += 'passed isomorphism check; '
else:
# 2625.50 is the conversion factor from Hartree to kJ/mol
logging.info('A conformer for species {0} was found to be isomorphic '
'with the 2D graph representation {1}. This conformer is {2} kJ/mol '
'above the most stable one (which is not isomorphic). Using the '
'isomorphic conformer for further geometry optimization.'.format(
label, self.species_dict[label].mol.toSMILES(),
(energies[i] - energies[0]) * 2625.50))
(energies[i] - energies[0]) * 0.001))
conformer_xyz = xyz
self.output[label]['status'] += 'passed isomorphism check but not for the most stable conformer; '
self.output[label]['status'] += 'passed isomorphism check but not for the most stable' \
' conformer; '
break
else:
if i == 0:
logging.warn('Most stable conformer for species {0} was found to be NON-isomorphic '
'with the 2D graph representation {1}. Searching for a different '
'conformer that is isomorphic'.format(label, b_mol.toSMILES()))
else:
logging.error('No conformer for {0} was found to be isomorphic with the 2D graph representation'
' {1}. NOT optimizing this species.'.format(
label, self.species_dict[label].mol.toSMILES()))
self.output[label]['status'] += 'Error: No conformer was found to be isomorphic with the 2D graph' \
' representation! '
if self.allow_nonisomorphic_2d:
# we'll optimize the most stable conformer even if it not isomorphic to the 2D graph
logging.error('No conformer for {0} was found to be isomorphic with the 2D graph representation'
' {1}. Optimizing the most stable conformer anyway.'.format(
label, self.species_dict[label].mol.toSMILES()))
conformer_xyz = xyzs[0]
else:
logging.error('No conformer for {0} was found to be isomorphic with the 2D graph representation'
' {1}. NOT optimizing this species.'.format(
label, self.species_dict[label].mol.toSMILES()))
self.output[label]['status'] += 'Error: No conformer was found to be isomorphic with the 2D' \
' graph representation! '
else:
logging.warn('Could not run isomorphism check for species {0} due to missing 2D graph '
'representation. Using the most stable conformer for further geometry'
Expand Down
2 changes: 2 additions & 0 deletions arc/species/converter.py
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,8 @@ def molecules_from_xyz(xyz):
This function is based on the MolGraph.perceive_smiles method
Returns None for b_mol is unsuccessful to infer bond orders
"""
if xyz is None:
return None, None
if not isinstance(xyz, (str, unicode)):
raise SpeciesError('xyz must be a string format, got: {0}'.format(type(xyz)))
xyz = standardize_xyz_string(xyz)
Expand Down
4 changes: 2 additions & 2 deletions arc/species/species.py
Original file line number Diff line number Diff line change
Expand Up @@ -546,9 +546,9 @@ def determine_rotors(self):
self.rotors_dict[self.number_of_rotors] = new_rotor
self.number_of_rotors += 1
if self.number_of_rotors == 1:
logging.info('\nFound 1 rotor for {0}'.format(self.label))
logging.info('\nFound one possible rotor for {0}'.format(self.label))
elif self.number_of_rotors > 1:
logging.info('\nFound {0} rotors for {1}'.format(self.number_of_rotors, self.label))
logging.info('\nFound {0} possible rotors for {1}'.format(self.number_of_rotors, self.label))
if self.number_of_rotors > 0:
logging.info('Pivot list(s) for {0}: {1}\n'.format(self.label,
[self.rotors_dict[i]['pivots'] for i in range(self.number_of_rotors)]))
Expand Down

0 comments on commit 178943e

Please sign in to comment.