From 37534fca880b4261038bbb636f40bc8eb25089d0 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 13:56:18 -0400 Subject: [PATCH 01/28] Style: Simplified boolean expressions --- arkane/explorer.py | 2 +- arkane/gaussian.py | 2 +- arkane/input.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/arkane/explorer.py b/arkane/explorer.py index ee0334d16d..0a9b47798c 100644 --- a/arkane/explorer.py +++ b/arkane/explorer.py @@ -292,7 +292,7 @@ def execute(self, outputFile, plot, format='pdf', print_summary=True, speciesLis if os.path.isfile('network.pdf'): os.rename('network.pdf','network'+str(p)+'.pdf') - if warns != []: + if warns: logging.info('\nOUTPUT WARNINGS:\n') for w in warns: logging.warning(w) diff --git a/arkane/gaussian.py b/arkane/gaussian.py index 86d4bf81e9..006c53f3f0 100644 --- a/arkane/gaussian.py +++ b/arkane/gaussian.py @@ -377,7 +377,7 @@ def loadScanEnergies(self): f.close() #give warning in case this assumption is not true - if rigidScan==True: + if rigidScan: print ' Assuming', os.path.basename(self.path), 'is the output from a rigid scan...' Vlist = numpy.array(Vlist, numpy.float64) diff --git a/arkane/input.py b/arkane/input.py index 30c096e532..b8a77b8186 100644 --- a/arkane/input.py +++ b/arkane/input.py @@ -332,7 +332,7 @@ def reaction(label, reactants, products, transitionState=None, kinetics=None, tu rxns = db.generate_reactions_from_libraries(reactants=rxn.reactants,products=rxn.products) rxns = [r for r in rxns if r.elementary_high_p] - if rxns != []: + if rxns: for r in rxns: if isinstance(rxn.kinetics, PDepKineticsModel): boo = rxn.generate_high_p_limit_kinetics() From d912cd202bf62b02672e9549e9ceb491082b6f81 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 13:59:04 -0400 Subject: [PATCH 02/28] Style: Simplified chained comparisons in Arkane kinetics.py --- arkane/kinetics.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arkane/kinetics.py b/arkane/kinetics.py index 3d8d68ec27..e94bbcc010 100644 --- a/arkane/kinetics.py +++ b/arkane/kinetics.py @@ -609,7 +609,7 @@ def draw(self, reaction, format, path=None): for c in column: top0 = wellRects[c][1] bottom0 = top + wellRects[c][3] - if (top >= top0 and top <= bottom0) or (top <= top0 and top0 <= bottom): + if (top0 <= top <= bottom0) or (top <= top0 <= bottom): # Can't put it in this column break else: @@ -639,7 +639,7 @@ def draw(self, reaction, format, path=None): for c in column: top0 = wellRects[c][1] bottom0 = top0 + wellRects[c][3] - if (top >= top0 and top <= bottom0) or (top <= top0 and top0 <= bottom): + if (top0 <= top <= bottom0) or (top <= top0 <= bottom): # Can't put it in this column break else: From 0c4ef2d90a0e1ab8f4b9b510679bfbaa8d7416a6 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 14:01:58 -0400 Subject: [PATCH 03/28] Style: Define instance attributes inside __init__ in Arkane explorer.py --- arkane/explorer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/arkane/explorer.py b/arkane/explorer.py index 0a9b47798c..094ce97521 100644 --- a/arkane/explorer.py +++ b/arkane/explorer.py @@ -51,6 +51,8 @@ def __init__(self, source, pdepjob, explore_tol, energy_tol=np.inf, flux_tol=0.0 self.energy_tol = energy_tol self.flux_tol = flux_tol self.maximumRadicalElectrons = maximumRadicalElectrons + self.jobRxns = None + self.networks = None self.pdepjob = pdepjob From f71b47342f5cce3ef987bc3f640b1cdf91e04435 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 14:05:28 -0400 Subject: [PATCH 04/28] Style: Changed first parameter in test setUp/tearDown to `cls` --- arkane/commonTest.py | 54 +++++++++++++++++++++--------------------- arkane/pdepTest.py | 20 ++++++++-------- arkane/statmechTest.py | 6 ++--- 3 files changed, 40 insertions(+), 40 deletions(-) diff --git a/arkane/commonTest.py b/arkane/commonTest.py index b9f0eab160..3f0043570d 100644 --- a/arkane/commonTest.py +++ b/arkane/commonTest.py @@ -74,31 +74,31 @@ class TestArkaneJob(unittest.TestCase): Contains unit tests of the Arkane module and its interactions with other RMG modules. """ @classmethod - def setUp(self): + def setUp(cls): arkane = Arkane() jobList = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'methoxy.py')) pdepjob = jobList[-1] - self.kineticsjob = jobList[0] + cls.kineticsjob = jobList[0] pdepjob.activeJRotor = True network = pdepjob.network - self.Nisom = len(network.isomers) - self.Nreac = len(network.reactants) - self.Nprod = len(network.products) - self.Npath = len(network.pathReactions) - self.PathReaction2 = network.pathReactions[2] - self.TminValue = pdepjob.Tmin.value - self.Tmaxvalue = pdepjob.Tmax.value - self.TmaxUnits = pdepjob.Tmax.units - self.TlistValue = pdepjob.Tlist.value - self.PminValue = pdepjob.Pmin.value - self.Pcount = pdepjob.Pcount - self.Tcount = pdepjob.Tcount - self.GenTlist = pdepjob.generateTemperatureList() - self.PlistValue = pdepjob.Plist.value - self.maximumGrainSizeValue = pdepjob.maximumGrainSize.value - self.method = pdepjob.method - self.rmgmode = pdepjob.rmgmode + cls.Nisom = len(network.isomers) + cls.Nreac = len(network.reactants) + cls.Nprod = len(network.products) + cls.Npath = len(network.pathReactions) + cls.PathReaction2 = network.pathReactions[2] + cls.TminValue = pdepjob.Tmin.value + cls.Tmaxvalue = pdepjob.Tmax.value + cls.TmaxUnits = pdepjob.Tmax.units + cls.TlistValue = pdepjob.Tlist.value + cls.PminValue = pdepjob.Pmin.value + cls.Pcount = pdepjob.Pcount + cls.Tcount = pdepjob.Tcount + cls.GenTlist = pdepjob.generateTemperatureList() + cls.PlistValue = pdepjob.Plist.value + cls.maximumGrainSizeValue = pdepjob.maximumGrainSize.value + cls.method = pdepjob.method + cls.rmgmode = pdepjob.rmgmode # test Arkane's interactions with the network module def testNisom(self): @@ -220,13 +220,13 @@ class TestArkaneInput(unittest.TestCase): Contains unit tests for loading and processing Arkane input files. """ @classmethod - def setUp(self): + def setUp(cls): """Preparation for all unit tests in this class.""" - self.directory = os.path.join(os.path.dirname(os.path.dirname(rmgpy.__file__)), 'examples', 'arkane') - self.modelChemistry = "cbs-qb3" - self.frequencyScaleFactor = 0.99 - self.useHinderedRotors = False - self.useBondCorrections = True + cls.directory = os.path.join(os.path.dirname(os.path.dirname(rmgpy.__file__)), 'examples', 'arkane') + cls.modelChemistry = "cbs-qb3" + cls.frequencyScaleFactor = 0.99 + cls.useHinderedRotors = False + cls.useBondCorrections = True def testSpecies(self): """Test loading of species input file.""" @@ -279,9 +279,9 @@ class TestStatmech(unittest.TestCase): Contains unit tests of statmech.py """ @classmethod - def setUp(self): + def setUp(cls): arkane = Arkane() - self.job_list = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), + cls.job_list = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'Benzyl', 'input.py')) def test_gaussian_log_file_error(self): diff --git a/arkane/pdepTest.py b/arkane/pdepTest.py index ab6ed29082..284a95d47f 100644 --- a/arkane/pdepTest.py +++ b/arkane/pdepTest.py @@ -52,16 +52,16 @@ class ArkaneTest(unittest.TestCase): """ @classmethod - def setUp(self): + def setUp(cls): """A function that is run ONCE before all unit tests in this class.""" - self.directory = os.path.join(settings['test_data.directory'], 'arkane', 'tst1', '') - self.input_file = os.path.join(self.directory, 'pdep_sa.py') + cls.directory = os.path.join(settings['test_data.directory'], 'arkane', 'tst1', '') + cls.input_file = os.path.join(cls.directory, 'pdep_sa.py') # clean working folder from all previous test output - dirs = [d for d in os.listdir(self.directory) if not os.path.isfile(os.path.join(self.directory, d))] + dirs = [d for d in os.listdir(cls.directory) if not os.path.isfile(os.path.join(cls.directory, d))] for d in dirs: shutil.rmtree(os.path.join(settings['test_data.directory'], 'arkane', 'tst1', d, '')) - files = [f for f in os.listdir(self.directory) if os.path.isfile(os.path.join(self.directory, f))] + files = [f for f in os.listdir(cls.directory) if os.path.isfile(os.path.join(cls.directory, f))] for f in files: if not 'pdep_sa' in f: os.remove(os.path.join(settings['test_data.directory'], 'arkane', 'tst1', f)) @@ -116,16 +116,16 @@ def testPDepJob(self): self.assertEquals(float(sa_coeff), -8.24e-6) @classmethod - def tearDown(self): + def tearDown(cls): """A function that is run ONCE after all unit tests in this class.""" - self.directory = os.path.join(settings['test_data.directory'], 'arkane', 'tst1', '') - self.input_file = os.path.join(self.directory, 'pdep_sa.py') + cls.directory = os.path.join(settings['test_data.directory'], 'arkane', 'tst1', '') + cls.input_file = os.path.join(cls.directory, 'pdep_sa.py') # clean working folder from all previous test output - dirs = [d for d in os.listdir(self.directory) if not os.path.isfile(os.path.join(self.directory, d))] + dirs = [d for d in os.listdir(cls.directory) if not os.path.isfile(os.path.join(cls.directory, d))] for d in dirs: shutil.rmtree(os.path.join(settings['test_data.directory'], 'arkane', 'tst1', d, '')) - files = [f for f in os.listdir(self.directory) if os.path.isfile(os.path.join(self.directory, f))] + files = [f for f in os.listdir(cls.directory) if os.path.isfile(os.path.join(cls.directory, f))] for f in files: if not 'pdep_sa' in f: os.remove(os.path.join(settings['test_data.directory'], 'arkane', 'tst1', f)) diff --git a/arkane/statmechTest.py b/arkane/statmechTest.py index a3add1f97e..e025fbd742 100644 --- a/arkane/statmechTest.py +++ b/arkane/statmechTest.py @@ -49,10 +49,10 @@ class TestStatmech(unittest.TestCase): Contains unit tests of the StatmechJob class. """ @classmethod - def setUp(self): + def setUp(cls): arkane = Arkane() - self.job_list = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), - 'data', 'Benzyl', 'input.py')) + cls.job_list = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), + 'data', 'Benzyl', 'input.py')) def test_gaussian_log_file_error(self): """Test that the proper error is raised if gaussian geometry and frequency file paths are not the same""" From 6640fc8c1bcf8e15e155d979b5a6e9833592df01 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 14:08:14 -0400 Subject: [PATCH 05/28] Added __init__ call of super class for ArkaneSpecies --- arkane/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/arkane/common.py b/arkane/common.py index e8ab2c8f7b..884a17181a 100644 --- a/arkane/common.py +++ b/arkane/common.py @@ -79,6 +79,7 @@ def __init__(self, species=None, conformer=None, author='', level_of_theory='', products=None, reaction_label=None, is_ts=None): # reactants/products/reaction_label need to be in the init() to avoid error when loading a TS YAML file, # but we don't use them + super(ArkaneSpecies, self).__init__() if species is None and conformer is None: # Expecting to get a species or a TS when generating the object within Arkane, # or a conformer when parsing from YAML. From 9b225c3b221e7ca00efdc6618f459e13233dd817 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 14:31:06 -0400 Subject: [PATCH 06/28] Added various missing docstrings in Arkane --- arkane/__init__.py | 4 ++++ arkane/common.py | 11 +++++++++++ arkane/commonTest.py | 2 ++ arkane/explorer.py | 12 ++++++++++-- arkane/explorerTest.py | 2 +- arkane/gaussian.py | 5 +++++ arkane/input.py | 34 ++++++++++++++++++---------------- arkane/kinetics.py | 5 +++++ arkane/main.py | 2 +- arkane/molpro.py | 5 +++++ arkane/pdep.py | 11 ++++++----- arkane/qchem.py | 5 +++++ arkane/sensitivity.py | 7 +++++++ arkane/statmech.py | 2 ++ arkane/statmechTest.py | 1 + 15 files changed, 83 insertions(+), 25 deletions(-) diff --git a/arkane/__init__.py b/arkane/__init__.py index 7296037809..11c5e81bf2 100644 --- a/arkane/__init__.py +++ b/arkane/__init__.py @@ -1,6 +1,10 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +initialize imports +""" + ############################################################################### # # # RMG - Reaction Mechanism Generator # diff --git a/arkane/common.py b/arkane/common.py index 884a17181a..9303283210 100644 --- a/arkane/common.py +++ b/arkane/common.py @@ -1,6 +1,10 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +Arkane common module +""" + ############################################################################### # # # RMG - Reaction Mechanism Generator # @@ -59,6 +63,9 @@ # Add a custom string representer to use block literals for multiline strings def str_repr(dumper, data): + """ + Repair YAML string representation + """ if len(data.splitlines()) > 1: return dumper.represent_scalar('tag:yaml.org,2002:str', data, style='|') return dumper.represent_scalar('tag:yaml.org,2002:str', data) @@ -183,6 +190,9 @@ def update_species_attributes(self, species=None): 'Cp (cal/mol*K)': cp} def update_xyz_string(self): + """ + Return an xyz string built from self.conformer + """ if self.conformer is not None and self.conformer.number is not None: # generate the xyz-format string from the Conformer coordinates xyz_string = '{0}\n{1}'.format(len(self.conformer.number.value_si), self.label) @@ -280,6 +290,7 @@ def load_yaml(self, path, species, pdep=False): def is_pdep(jobList): + """A helper function to determine whether a job is PressureDependenceJob or not""" for job in jobList: if isinstance(job, PressureDependenceJob): return True diff --git a/arkane/commonTest.py b/arkane/commonTest.py index 3f0043570d..f873413806 100644 --- a/arkane/commonTest.py +++ b/arkane/commonTest.py @@ -75,6 +75,7 @@ class TestArkaneJob(unittest.TestCase): """ @classmethod def setUp(cls): + """A method that is run before each unit test in this class""" arkane = Arkane() jobList = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'methoxy.py')) @@ -280,6 +281,7 @@ class TestStatmech(unittest.TestCase): """ @classmethod def setUp(cls): + """A method that is run before each unit test in this class""" arkane = Arkane() cls.job_list = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'Benzyl', 'input.py')) diff --git a/arkane/explorer.py b/arkane/explorer.py index 094ce97521..ccf640e09d 100644 --- a/arkane/explorer.py +++ b/arkane/explorer.py @@ -1,6 +1,10 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +The Arkane Explorer module +""" + ############################################################################### # # # RMG - Reaction Mechanism Generator # @@ -44,6 +48,9 @@ class ExplorerJob(object): + """ + A representation of an Arkane explorer job. This job is used to explore a potential energy surface (PES). + """ def __init__(self, source, pdepjob, explore_tol, energy_tol=np.inf, flux_tol=0.0, bathGas=None, maximumRadicalElectrons=np.inf): self.source = source @@ -78,8 +85,9 @@ def copy(self): flux_tol=self.flux_tol ) - def execute(self, outputFile, plot, format='pdf', print_summary=True, speciesList=None, thermoLibrary=None, kineticsLibrary=None): - + def execute(self, outputFile, plot, format='pdf', print_summary=True, speciesList=None, thermoLibrary=None, + kineticsLibrary=None): + """Execute an ExplorerJob""" logging.info('Exploring network...') rmg = RMG() diff --git a/arkane/explorerTest.py b/arkane/explorerTest.py index 3d02e33a2b..aa6e2a92c2 100644 --- a/arkane/explorerTest.py +++ b/arkane/explorerTest.py @@ -45,7 +45,7 @@ class testExplorerJob(unittest.TestCase): """ @classmethod def setUpClass(cls): - + """A method that is run before each unit test in this class""" arkane = Arkane() cls.jobList = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)),'data','methoxy_explore.py')) diff --git a/arkane/gaussian.py b/arkane/gaussian.py index 006c53f3f0..e6052931fe 100644 --- a/arkane/gaussian.py +++ b/arkane/gaussian.py @@ -1,6 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +Arkane Gaussian module +Used to parse Gaussian output files +""" + ############################################################################### # # # RMG - Reaction Mechanism Generator # diff --git a/arkane/input.py b/arkane/input.py index b8a77b8186..3123e3b5e4 100644 --- a/arkane/input.py +++ b/arkane/input.py @@ -89,15 +89,9 @@ ################################################################################ -def database( - thermoLibraries = None, - transportLibraries = None, - reactionLibraries = None, - frequenciesLibraries = None, - kineticsFamilies = 'default', - kineticsDepositories = 'default', - kineticsEstimator = 'rate rules', - ): +def database(thermoLibraries = None, transportLibraries = None, reactionLibraries = None, frequenciesLibraries = None, + kineticsFamilies = 'default', kineticsDepositories = 'default', kineticsEstimator = 'rate rules'): + """Load the RMG database""" if isinstance(thermoLibraries, str): thermoLibraries = [thermoLibraries] if isinstance(transportLibraries, str): @@ -150,6 +144,7 @@ def database( def species(label, *args, **kwargs): + """Load a species from an input file""" global speciesDict, jobList if label in speciesDict: raise ValueError('Multiple occurrences of species with label {0!r}.'.format(label)) @@ -256,6 +251,7 @@ def species(label, *args, **kwargs): def transitionState(label, *args, **kwargs): + """Load a transition state from an input file""" global transitionStateDict if label in transitionStateDict: raise ValueError('Multiple occurrences of transition state with label {0!r}.'.format(label)) @@ -301,6 +297,7 @@ def transitionState(label, *args, **kwargs): def reaction(label, reactants, products, transitionState=None, kinetics=None, tunneling=''): + """Load a reaction from an input file""" global reactionDict, speciesDict, transitionStateDict if label in reactionDict: label = label + transitionState @@ -358,6 +355,7 @@ def reaction(label, reactants, products, transitionState=None, kinetics=None, tu def network(label, isomers=None, reactants=None, products=None, pathReactions=None, bathGas=None): + """Load a network from an input file""" global networkDict, speciesDict, reactionDict logging.info('Loading network {0}...'.format(label)) isomers0 = isomers or []; isomers = [] @@ -439,6 +437,7 @@ def network(label, isomers=None, reactants=None, products=None, pathReactions=No def kinetics(label, Tmin=None, Tmax=None, Tlist=None, Tcount=0, sensitivity_conditions=None): + """Generate a kinetics job""" global jobList, reactionDict try: rxn = reactionDict[label] @@ -450,6 +449,7 @@ def kinetics(label, Tmin=None, Tmax=None, Tlist=None, Tcount=0, sensitivity_cond def statmech(label): + """Generate a statmech job""" global jobList, speciesDict, transitionStateDict if label in speciesDict or label in transitionStateDict: for job in jobList: @@ -462,6 +462,7 @@ def statmech(label): def thermo(label, thermoClass): + """Generate a thermo job""" global jobList, speciesDict try: spec = speciesDict[label] @@ -471,13 +472,10 @@ def thermo(label, thermoClass): jobList.append(job) -def pressureDependence(label, - Tmin=None, Tmax=None, Tcount=0, Tlist=None, - Pmin=None, Pmax=None, Pcount=0, Plist=None, - maximumGrainSize=None, minimumGrainCount=0, - method=None, interpolationModel=None, - activeKRotor=True, activeJRotor=True, rmgmode=False, - sensitivity_conditions=None): +def pressureDependence(label, Tmin=None, Tmax=None, Tcount=0, Tlist=None, Pmin=None, Pmax=None, Pcount=0, Plist=None, + maximumGrainSize=None, minimumGrainCount=0, method=None, interpolationModel=None, + activeKRotor=True, activeJRotor=True, rmgmode=False, sensitivity_conditions=None): + """Generate a pressure dependent job""" global jobList, networkDict if isinstance(interpolationModel, str): @@ -498,6 +496,7 @@ def pressureDependence(label, def explorer(source, explore_tol=0.01, energy_tol=np.inf, flux_tol=0.0, bathGas=None, maximumRadicalElectrons=np.inf): + """Generate an explorer job""" global jobList,speciesDict for job in jobList: if isinstance(job, PressureDependenceJob): @@ -519,14 +518,17 @@ def explorer(source, explore_tol=0.01, energy_tol=np.inf, flux_tol=0.0, bathGas= def SMILES(smiles): + """Make a Molecule object from SMILES""" return Molecule().fromSMILES(smiles) def adjacencyList(adj): + """Make a Molecule object from an adjacency list""" return Molecule().fromAdjacencyList(adj) def InChI(inchi): + """Make a Molecule object from InChI""" return Molecule().fromInChI(inchi) diff --git a/arkane/kinetics.py b/arkane/kinetics.py index e94bbcc010..d95e9728aa 100644 --- a/arkane/kinetics.py +++ b/arkane/kinetics.py @@ -1,6 +1,10 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +Arkane kinetics module +""" + ############################################################################### # # # RMG - Reaction Mechanism Generator # @@ -404,6 +408,7 @@ def __init__(self, options=None): self.clear() def clear(self): + """Clear the drawer""" self.reaction = None self.wells = None self.left = 0.0 diff --git a/arkane/main.py b/arkane/main.py index 2e9287f1fa..578eea4a20 100644 --- a/arkane/main.py +++ b/arkane/main.py @@ -312,7 +312,7 @@ def execute(self): self.logFooter() def getLibraries(self): - + """Get RMG kinetics and thermo libraries""" name = 'kineticsjobs' speciesList = self.speciesDict.values() diff --git a/arkane/molpro.py b/arkane/molpro.py index 6dabe4000c..3c6a63eb03 100644 --- a/arkane/molpro.py +++ b/arkane/molpro.py @@ -1,6 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +Arkane Molpro module +Used to parse Molpro output files +""" + ############################################################################### # # # RMG - Reaction Mechanism Generator # diff --git a/arkane/pdep.py b/arkane/pdep.py index 23df9d7732..2c0092947b 100644 --- a/arkane/pdep.py +++ b/arkane/pdep.py @@ -238,7 +238,7 @@ def copy(self): ) def execute(self, outputFile, plot, format='pdf', print_summary=True): - + """Execute a PressureDependenceJob""" for config in self.network.isomers + self.network.reactants + self.network.products: for spec in config.species: if spec.conformer.E0 is None: @@ -319,6 +319,7 @@ def generateTemperatureList(self): return self.Tlist.value_si def initialize(self): + """Initialize a PressureDependenceJob""" for reaction in self.network.pathReactions: tunneling = reaction.transitionState.tunneling # throw descriptive error if tunneling not allowed @@ -388,7 +389,7 @@ def generatePressureList(self): return self.Plist.value_si def fitInterpolationModels(self): - + """Fit all pressure dependent rates with interpolation models""" configurations = [] configurations.extend(self.network.isomers) configurations.extend(self.network.reactants) @@ -424,7 +425,7 @@ def fitInterpolationModels(self): self.network.netReactions.append(reaction) def fitInterpolationModel(self, Tdata, Pdata, kdata, kunits): - + """Fit an interpolation model to a pressure dependent rate""" Tmin = self.Tmin.value_si Tmax = self.Tmax.value_si Pmin = self.Pmin.value_si @@ -444,7 +445,7 @@ def fitInterpolationModel(self, Tdata, Pdata, kdata, kunits): return kinetics def save(self, outputFile): - + """Save the output of a pressure dependent job""" logging.info('Saving pressure dependence results for network {0}...'.format(self.network.label)) f = open(outputFile, 'a') f_chemkin = open(os.path.join(os.path.dirname(outputFile), 'chem.inp'), 'a') @@ -535,7 +536,7 @@ def save(self, outputFile): f_chemkin.close() def plot(self, outputDirectory): - + """Plot pressure dependent rates""" # Skip this step if matplotlib is not installed try: import matplotlib.pyplot as plt diff --git a/arkane/qchem.py b/arkane/qchem.py index cb2be0e999..690b52f386 100644 --- a/arkane/qchem.py +++ b/arkane/qchem.py @@ -1,6 +1,11 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- +""" +Arkane QChem module +Used to parse QChem output files +""" + ############################################################################### # # # RMG - Reaction Mechanism Generator # diff --git a/arkane/sensitivity.py b/arkane/sensitivity.py index c69b3e88a3..2099986fd6 100644 --- a/arkane/sensitivity.py +++ b/arkane/sensitivity.py @@ -106,12 +106,15 @@ def execute(self): self.plot() def perturb(self, species): + """Perturb a species' E0""" species.conformer.E0.value_si += self.perturbation.value_si def unperturb(self, species): + """Return the species' E0 to its original value""" species.conformer.E0.value_si -= self.perturbation.value_si # restore E0 to its original value def save(self): + """Save the SA results as tabulated data""" if not os.path.exists(self.sensitivity_path): os.mkdir(self.sensitivity_path) valid_chars = "-_.()<=> %s%s" % (string.ascii_letters, string.digits) @@ -163,6 +166,7 @@ def save(self): '='*(max_label-10))) def plot(self): + """Plot the SA results as horizontal bars""" try: import matplotlib.pyplot as plt except ImportError: @@ -302,9 +306,11 @@ def perturb(self, entry, unperturb=False): 'J/mol') def unperturb(self, entry): + """A helper function for calling self.perturb cleanly when unperturbing""" self.perturb(entry, unperturb=True) def save(self, wells, transition_states): + """Save the SA output as tabulated data""" if not os.path.exists(os.path.join(self.output_directory, 'sensitivity', '')): os.mkdir(os.path.join(self.output_directory, 'sensitivity', '')) valid_chars = "-_.()<=>+ %s%s" % (string.ascii_letters, string.digits) @@ -340,6 +346,7 @@ def save(self, wells, transition_states): '='*(max_label-10))) def plot(self, wells, transition_states): + """Draw the SA results as horizontal bars""" try: import matplotlib.pyplot as plt except ImportError: diff --git a/arkane/statmech.py b/arkane/statmech.py index 6260e604b9..6f3f43dc3e 100644 --- a/arkane/statmech.py +++ b/arkane/statmech.py @@ -154,10 +154,12 @@ def save(self, angles, energies, angleUnits='radians', energyUnits='kJ/mol'): def hinderedRotor(scanLog, pivots, top, symmetry=None, fit='best'): + """Read a hindered rotor directive, and return the attributes in a list""" return [scanLog, pivots, top, symmetry, fit] def freeRotor(pivots,top,symmetry): + """Read a free rotor directive, and return the attributes in a list""" return [pivots,top,symmetry] diff --git a/arkane/statmechTest.py b/arkane/statmechTest.py index e025fbd742..c9d1c98de5 100644 --- a/arkane/statmechTest.py +++ b/arkane/statmechTest.py @@ -50,6 +50,7 @@ class TestStatmech(unittest.TestCase): """ @classmethod def setUp(cls): + """A method that is run before each unit test in this class""" arkane = Arkane() cls.job_list = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'Benzyl', 'input.py')) From 7e884603d26320d6d656b525436dbfd604d87f43 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 14:34:08 -0400 Subject: [PATCH 07/28] PEP 8 coding style fixes in Arkane common.py --- arkane/common.py | 292 +++++++++++++++++++++++++++++------------------ 1 file changed, 181 insertions(+), 111 deletions(-) diff --git a/arkane/common.py b/arkane/common.py index 9303283210..b99effa5a6 100644 --- a/arkane/common.py +++ b/arkane/common.py @@ -58,6 +58,7 @@ from arkane.pdep import PressureDependenceJob + ################################################################################ @@ -78,6 +79,7 @@ class ArkaneSpecies(RMGObject): """ A class for archiving an Arkane species including its statmech data into .yml files """ + def __init__(self, species=None, conformer=None, author='', level_of_theory='', model_chemistry='', frequency_scale_factor=None, use_hindered_rotors=None, use_bond_corrections=None, atom_energies='', chemkin_thermo_string='', smiles=None, adjacency_list=None, inchi=None, inchi_key=None, xyz=None, @@ -182,7 +184,7 @@ def update_species_attributes(self, species=None): h298 = thermo_data.getEnthalpy(298) / 4184. s298 = thermo_data.getEntropy(298) / 4.184 cp = dict() - for t in [300,400,500,600,800,1000,1500,2000,2400]: + for t in [300, 400, 500, 600, 800, 1000, 1500, 2000, 2400]: temp_str = '{0} K'.format(t) cp[temp_str] = '{0:.2f}'.format(thermo_data.getHeatCapacity(t) / 4.184) self.thermo_data = {'H298': '{0:.2f} kcal/mol'.format(h298), @@ -279,13 +281,14 @@ def load_yaml(self, path, species, pdep=False): if pdep and not self.is_ts and (self.transport_data is None or self.energy_transfer_model is None): raise ValueError('Transport data and an energy transfer model must be given if pressure-dependent ' 'calculations are requested. Check file {0}'.format(path)) - if pdep and not self.is_ts and self.smiles is None and self.adjacency_list is None\ + if pdep and not self.is_ts and self.smiles is None and self.adjacency_list is None \ and self.inchi is None and self.molecular_weight is None: raise ValueError('The molecular weight was not specified, and a structure was not given so it could ' 'not be calculated. Specify either the molecular weight or structure if ' 'pressure-dependent calculations are requested. Check file {0}'.format(path)) logging.debug("Parsed all YAML objects") + ################################################################################ @@ -297,16 +300,19 @@ def is_pdep(jobList): return False -def check_conformer_energy(Vlist,path): +def check_conformer_energy(Vlist, path): """ Check to see that the starting energy of the species in the potential energy scan calculation is not 0.5 kcal/mol (or more) higher than any other energies in the scan. If so, print and log a warning message. - """ + """ Vlist = numpy.array(Vlist, numpy.float64) - Vdiff = (Vlist[0] - numpy.min(Vlist))*constants.E_h*constants.Na/1000 - if Vdiff >= 2: #we choose 2 kJ/mol to be the critical energy - logging.warning('the species corresponding to ' + str(os.path.basename(path)) + ' is different in energy from the lowest energy conformer by ' + "%0.2f" % Vdiff + ' kJ/mol. This can cause significant errors in your computed rate constants. ') + Vdiff = (Vlist[0] - numpy.min(Vlist)) * constants.E_h * constants.Na / 1000 + if Vdiff >= 2: # we choose 2 kJ/mol to be the critical energy + logging.warning('the species corresponding to ' + str(os.path.basename(path)) + + ' is different in energy from the lowest energy conformer by ' + + "%0.2f" % Vdiff + ' kJ/mol. This can cause significant errors in your computed ' + 'rate constants. ') def get_element_mass(input_element, isotope=None): @@ -370,107 +376,171 @@ def get_element_mass(input_element, isotope=None): 111: 'Rg', 112: 'Cn', 113: 'Nh', 114: 'Fl', 115: 'Mc', 116: 'Lv', 117: 'Ts', 118: 'Og'} # Structure of mass_by_symbol items: list(list(isotope1, mass1, weight1), list(isotope2, mass2, weight2), ...) -mass_by_symbol = {'H': [[1, 1.00782503224, 0.999885], [2, 2.01410177812, 0.000115], [3, 3.0160492779, 0]], -'He': [[3, 3.0160293201, 0.00000134], [4, 4.00260325414, 0.99999866]], -'Li': [[6, 6.0151228874, 0.0759], [7, 7.0160034366, 0.9241]], -'Be': [[9, 9.012183066, 1]], -'B': [[10, 10.01293695, 0.199], [11, 11.00930536, 0.801]], -'C': [[12, 12.0000000, 0.9893], [13, 13.00335483507, 0.0107], [14, 14.0032419884, 0]], -'N': [[14, 14.00307400443, 0.99636], [15, 15.00010889889, 0.00364]], -'O': [[16, 15.99491461957, 0.99757], [17, 16.99913175651, 0.00038], [18, 17.99915961287, 0.00205]], -'F': [[19, 18.99840316274, 1]], -'Ne': [[20, 19.9924401762, 0.9048], [21, 20.993846685, 0.0027], [22, 21.991385114, 0.0925]], -'Na': [[23, 22.9897692820, 1]], -'Mg': [[24, 23.985041697, 0.7899], [25, 24.985836976, 0.1000], [26, 25.982592968, 0.1101]], -'Al': [[27, 26.98153853, 1]], -'Si': [[28, 27.97692653465, 0.92223], [29, 28.97649466491, 0.04685], [30, 29.973770136, 0.03092]], -'P': [[31, 30.97376199843, 1]], -'S': [[32, 31.9720711744, 0.9499], [33, 32.9714589098, 0.0075], [34, 33.967867004, 0.0425], [36, 35.96708071, 0.0001]], -'Cl': [[35, 34.968852682, 0.7576], [37, 36.965902603, 0.2424]], -'Ar': [[36, 35.967545105, 0.003336], [38, 37.96273211, 0.000629], [40, 39.9623831237, 0.996035]], -'K': [[39, 38.9637064864, 0.932581], [40, 39.963998167, 0.000117], [41, 40.9618252579, 0.067302]], -'Ca': [[40, 39.962590863, 0.96941], [42, 41.95861783, 0.00647], [43, 42.95876644, 0.00135], [44, 43.95548156, 0.02086], [46, 45.9536890, 0.00004], [48, 47.95252276, 0.00187]], -'Sc': [[45, 44.95590829, 1]], -'Ti': [[46, 45.95262772, 0.0825], [47, 46.95175879, 0.0744], [48, 47.94794198, 0.7372], [49, 48.94786568, 0.0541], [50, 49.94478689, 0.0518]], -'V': [[50, 49.94715602, 0.00250], [51, 50.94395705, 0.99750]], -'Cr': [[50, 49.94604184, 0.04345], [52, 51.94050624, 0.83789], [53, 52.94064816, 0.09501], [54, 53.93887917, 0.02365]], -'Mn': [[55, 54.93804391, 1]], -'Fe': [[54, 53.93960900, 0.05845], [56, 55.93493633, 0.91754], [57, 56.93539284, 0.02119], [58, 57.93327444, 0.00282]], -'Co': [[59, 58.93319430, 1]], -'Ni': [[58, 57.93534242, 0.68077], [60, 59.93078589, 0.26223], [61, 60.93105558, 0.011399], [62, 61.92834538, 0.036346], [64, 63.92796682, 0.009255]], -'Cu': [[63, 62.92959773, 0.6915], [65, 64.92778971, 0.3085]], -'Zn': [[64, 63.92914202, 0.4917], [66, 65.92603382, 0.2773], [67, 66.92712776, 0.0404], [68, 67.92484456, 0.1845], [70, 69.9253192, 0.0061]], -'Ga': [[69, 68.9255735, 0.60108], [71, 70.92470259, 0.39892]], -'Ge': [[70, 69.92424876, 0.2057], [72, 71.922075827, 0.2745], [73, 72.923458957, 0.0775], [74, 73.921177761, 0.3650], [76, 75.921402726, 0.0773]], -'As': [[75, 74.92159458, 1]], -'Se': [[74, 73.922475934, 0.0089], [76, 75.919213704, 0.0937], [77, 76.919914155, 0.0763], [78, 77.91730928, 0.2377], [80, 79.9165218, 0.4961], [82, 81.9166995, 0.0873]], -'Br': [[79, 78.9183376, 0.5069], [81, 80.9162897, 0.4931]], -'Kr': [[78, 77.92036495, 0.00355], [80, 79.91637809, 0.02286], [82, 81.91348274, 0.11593], [83, 82.91412716, 0.11500], [84, 83.9114977282, 0.56987], [86, 85.9106106269, 0.17279]], -'Rb': [[85, 84.9117897380, 0.7217], [87, 86.9091805311, 0.2783]], -'Sr': [[84, 83.9134191, 0.0056], [86, 85.9092606, 0.0986], [87, 86.9088775, 0.0700], [88, 87.9056125, 0.8258]], -'Y': [[89, 88.9058403, 1]], -'Zr': [[90, 89.9046977, 0.5145], [91, 90.9056396, 0.1122], [92, 91.9050347, 0.1715], [94, 93.9063108, 0.1738], [96, 95.9082714, 0.0280]], -'Nb': [[93, 92.9063730, 1]], -'Mo': [[92, 91.90680797, 0.1453], [94, 93.90508490, 0.0915], [95, 94.90583877, 0.1584], [96, 95.90467612, 0.1667], [97, 96.90601812, 0.0960], [98, 97.90540482, 0.2439], [100, 99.9074718, 0.0982]], -'Tc': [[97, 96.9063667,], [98, 97.9072124], [99, 98.9062508]], -'Ru': [[96, 95.90759025, 0.0554], [98, 97.9052869, 0.0187], [99, 98.9059341, 0.1276], [100, 99.9042143, 0.1260], [101, 100.9055769, 0.1706], [102, 101.9043441, 0.3155], [104, 103.9054275, 0.1862]], -'Rh': [[103, 102.905498, 1]], -'Pd': [[102, 101.9056022, 0.0102], [104, 103.9040305, 0.1114], [105, 104.9050796, 0.2233], [106, 105.9034804, 0.2733], [108, 107.9038916, 0.2646], [110, 109.90517221, 0.1172]], -'Ag': [[107, 106.9050916, 0.51839], [109, 108.9047553, 0.48161]], -'Cd': [[106, 105.9064599, 0.0125], [108, 107.9041834, 0.0089], [110, 109.90300662, 0.1249], [111, 110.90418288, 0.1280], [112, 111.9027629, 0.2413], [113, 112.9044081, 0.1222], [114, 113.9033651, 0.2873], [116, 115.9047632, 0.0749]], -'In': [[113, 112.9040618, 0.0429], [115, 114.9038788, 0.9571]], -'Sn': [[112, 111.9048239, 0.0097], [114, 113.9027827, 0.0066], [115, 114.9033447, 0.0034], [116, 115.9017428, 0.1454], [117, 116.902954, 0.0768], [118, 117.9016066, 0.2422], [119, 118.9033112, 0.0859], [120, 119.9022016, 0.3258], [122, 121.9034438, 0.0463], [124, 123.9052766, 0.0579]], -'Sb': [[121, 120.903812, 0.5721], [123, 122.9042132, 0.4279]], -'Te': [[120, 119.9040593, 0.0009], [122, 121.9030435, 0.0255], [123, 122.9042698, 0.0089], [124, 123.9028171, 0.0474], [125, 124.9044299, 0.0707], [126, 125.9033109, 0.1884], [128, 127.9044613, 0.3174], [130, 129.9062227, 0.3408]], -'I': [[127, 126.9044719, 1]], -'Xe': [[124, 123.905892, 0.000952], [126, 125.9042983, 0.000890], [128, 127.903531, 0.019102], [129, 128.9047809, 0.264006], [130, 129.9035093, 0.040710], [131, 130.9050841, 0.212324], [132, 131.9041551, 0.269086], [134, 133.9053947, 0.104357], [136, 135.9072145, 0.088573]], -'Cs': [[133, 132.905452, 1]], -'Ba': [[130, 129.9063207, 0.00106], [132, 131.9050611, 0.00101], [134, 133.9045082, 0.02417], [135, 134.9056884, 0.06592], [136, 135.9045757, 0.07854], [137, 136.9058271, 0.11232], [138, 137.905247, 0.71698]], -'La': [[138, 137.9071149, 0.0008881], [139, 138.9063563, 0.9991119]], -'Ce': [[136, 135.9071292, 0.00185], [138, 137.905991, 0.00251], [140, 139.9054431, 0.88450], [142, 141.9092504, 0.11114]], -'Pr': [[141, 140.9076576, 1]], -'Nd': [[142, 141.907729, 0.27152], [143, 142.90982, 0.12174], [144, 143.910093, 0.23798], [145, 144.9125793, 0.08293], [146, 145.9131226, 0.17189], [148, 147.9168993, 0.05756], [150, 149.9209022, 0.05638]], -'Pm': [[145, 144.9127559], [147, 146.915145]], -'Sm': [[144, 143.9120065, 0.0307], [147, 146.9149044, 0.1499], [148, 147.9148292, 0.1124], [149, 148.9171921, 0.1382], [150, 149.9172829, 0.0738], [152, 151.9197397, 0.2675], [154, 153.9222169, 0.2275]], -'Eu': [[151, 150.9198578, 0.4781], [153, 152.921238, 0.5219]], -'Gd': [[152, 151.9197995, 0.0020], [154, 153.9208741, 0.0218], [155, 154.9226305, 0.1480], [156, 155.9221312, 0.2047], [157, 156.9239686, 0.1565], [158, 157.9241123, 0.2484], [160, 159.9270624, 0.2186]], -'Tb': [[159, 158.9253547, 1]], -'Dy': [[156, 155.9242847, 0.00056], [158, 157.9244159, 0.00095], [160, 159.9252046, 0.02329], [161, 160.9269405, 0.18889], [162, 161.9268056, 0.25475], [163, 162.9287383, 0.24896], [164, 163.9291819, 0.28260]], -'Ho': [[165, 164.9303288, 1]], -'Er': [[162, 161.9287884, 0.00139], [164, 163.9292088, 0.01601], [166, 165.9302995, 0.33503], [167, 166.9320546, 0.22869], [168, 167.9323767, 0.26978], [170, 169.9354702, 0.14910]], -'Tm': [[169, 168.9342179, 1]], -'Yb': [[168, 167.9338896, 0.00123], [170, 169.9347664, 0.02982], [171, 170.9363302, 0.1409], [172, 171.9363859, 0.2168], [173, 172.9382151, 0.16103], [174, 173.9388664, 0.32026], [176, 175.9425764, 0.12996]], -'Lu': [[175, 174.9407752, 0.97401], [176, 175.9426897, 0.02599]], -'Hf': [[174, 173.9400461, 0.0016], [176, 175.9414076, 0.0526], [177, 176.9432277, 0.1860], [178, 177.9437058, 0.2728], [179, 178.9458232, 0.1362], [180, 179.946557, 0.3508]], -'Ta': [[180, 179.9474648, 0.0001201], [181, 180.9479958, 0.9998799]], -'W': [[180, 179.9467108, 0.0012], [182, 181.9482039, 0.2650], [183, 182.9502228, 0.1431], [184, 183.9509309, 0.3064], [186, 185.9543628, 0.2843]], -'Re': [[185, 184.9529545, 0.3740], [187, 186.9557501, 0.6260]], -'Os': [[184, 183.9524885, 0.0002], [186, 185.953835, 0.0159], [187, 186.9557474, 0.0196], [188, 187.9558352, 0.1324], [189, 188.9581442, 0.1615], [190, 189.9584437, 0.2626], [192, 191.961477, 0.4078]], -'Ir': [[191, 190.9605893, 0.373], [193, 192.9629216, 0.627]], -'Pt': [[190, 189.9599297, 0.00012], [192, 191.9610387, 0.00782], [194, 193.9626809, 0.3286], [195, 194.9647917, 0.3378], [196, 195.9649521, 0.2521], [198, 197.9678949, 0.07356]], -'Au': [[197, 196.9665688, 1]], -'Hg': [[196, 195.9658326, 0.0015], [198, 197.9667686, 0.0997], [199, 198.9682806, 0.1687], [200, 199.9683266, 0.2310], [201, 200.9703028, 0.1318], [202, 201.9706434, 0.2986], [204, 203.973494, 0.0687]], -'Tl': [[203, 202.9723446, 0.2952], [205, 204.9744278, 0.7048]], -'Pb': [[204, 203.973044, 0.014], [206, 205.9744657, 0.241], [207, 206.9758973, 0.221], [208, 207.9766525, 0.524]], -'Bi': [[209, 208.9803991, 1]], -'Po': [[209, 208.9824308], [210, 209.9828741]], -'At': [[210, 209.9871479], [211, 210.9874966]], -'Rn': [[211, 210.9906011], [220, 220.0113941], [222, 222.0175782]], -'Fr': [[223, 223.019736]], -'Ra': [[223, 223.0185023], [224, 224.020212], [226, 226.0254103], [228, 228.0310707]], -'Ac': [[227, 227.0277523]], -'Th': [[230, 230.0331341, 0], [232, 232.0380558, 1]], -'Pa': [[231, 231.0358842, 1]], -'U': [[233, 233.0396355, 0], [234, 234.0409523, 0.000054], [235, 235.0439301, 0.007204], [236, 236.0455682, 0], [238, 238.0507884, 0.992742]], -'Np': [[236, 236.04657], [237, 237.0481736]], -'Pu': [[238, 238.0495601], [239, 239.0521636], [240, 240.0538138], [241, 241.0568517], [242, 242.0587428], [244, 244.0642053]], -'Am': [[241, 241.0568293], [243, 243.0613813]], -'Cm': [[243, 243.0613893], [244, 244.0627528], [245, 245.0654915], [246, 246.0672238], [247, 247.0703541], [248, 248.0723499]], -'Bk': [[247, 247.0703073], [249, 249.0749877]], -'Cf': [[249, 249.0748539], [250, 250.0764062], [251, 251.0795886], [252, 252.0816272]], -'Es': [[252, 252.08298]], 'Fm': [[257, 257.0951061]], 'Md': [[258, 258.0984315], [260, 260.10365]], -'No': [[259, 259.10103]], 'Lr': [[262, 262.10961]], 'Rf': [[267, 267.12179]], 'Db': [[268, 268.12567]], -'Sg': [[271, 271.13393]], 'Bh': [[272, 272.13826]], 'Hs': [[270, 270.13429]], 'Mt': [[276, 276.15159]], -'Ds': [[281, 281.16451]], 'Rg': [[280, 280.16514]], 'Cn': [[285, 285.17712]], 'Nh': [[284, 284.17873]], -'Fl': [[289, 289.19042]], 'Mc': [[288, 288.19274]], 'Lv': [[293, 293.20449]], 'Ts': [[292, 292.20746]], -'Og': [[294, 294.21392]]} +mass_by_symbol = { + 'H': [[1, 1.00782503224, 0.999885], [2, 2.01410177812, 0.000115], [3, 3.0160492779, 0]], + 'He': [[3, 3.0160293201, 0.00000134], [4, 4.00260325414, 0.99999866]], + 'Li': [[6, 6.0151228874, 0.0759], [7, 7.0160034366, 0.9241]], + 'Be': [[9, 9.012183066, 1]], + 'B': [[10, 10.01293695, 0.199], [11, 11.00930536, 0.801]], + 'C': [[12, 12.0000000, 0.9893], [13, 13.00335483507, 0.0107], [14, 14.0032419884, 0]], + 'N': [[14, 14.00307400443, 0.99636], [15, 15.00010889889, 0.00364]], + 'O': [[16, 15.99491461957, 0.99757], [17, 16.99913175651, 0.00038], [18, 17.99915961287, 0.00205]], + 'F': [[19, 18.99840316274, 1]], + 'Ne': [[20, 19.9924401762, 0.9048], [21, 20.993846685, 0.0027], [22, 21.991385114, 0.0925]], + 'Na': [[23, 22.9897692820, 1]], + 'Mg': [[24, 23.985041697, 0.7899], [25, 24.985836976, 0.1000], [26, 25.982592968, 0.1101]], + 'Al': [[27, 26.98153853, 1]], + 'Si': [[28, 27.97692653465, 0.92223], [29, 28.97649466491, 0.04685], [30, 29.973770136, 0.03092]], + 'P': [[31, 30.97376199843, 1]], + 'S': [[32, 31.9720711744, 0.9499], [33, 32.9714589098, 0.0075], [34, 33.967867004, 0.0425], + [36, 35.96708071, 0.0001]], + 'Cl': [[35, 34.968852682, 0.7576], [37, 36.965902603, 0.2424]], + 'Ar': [[36, 35.967545105, 0.003336], [38, 37.96273211, 0.000629], [40, 39.9623831237, 0.996035]], + 'K': [[39, 38.9637064864, 0.932581], [40, 39.963998167, 0.000117], [41, 40.9618252579, 0.067302]], + 'Ca': [[40, 39.962590863, 0.96941], [42, 41.95861783, 0.00647], [43, 42.95876644, 0.00135], + [44, 43.95548156, 0.02086], [46, 45.9536890, 0.00004], [48, 47.95252276, 0.00187]], + 'Sc': [[45, 44.95590829, 1]], + 'Ti': [[46, 45.95262772, 0.0825], [47, 46.95175879, 0.0744], [48, 47.94794198, 0.7372], [49, 48.94786568, 0.0541], + [50, 49.94478689, 0.0518]], + 'V': [[50, 49.94715602, 0.00250], [51, 50.94395705, 0.99750]], + 'Cr': [[50, 49.94604184, 0.04345], [52, 51.94050624, 0.83789], [53, 52.94064816, 0.09501], + [54, 53.93887917, 0.02365]], + 'Mn': [[55, 54.93804391, 1]], + 'Fe': [[54, 53.93960900, 0.05845], [56, 55.93493633, 0.91754], [57, 56.93539284, 0.02119], + [58, 57.93327444, 0.00282]], + 'Co': [[59, 58.93319430, 1]], + 'Ni': [[58, 57.93534242, 0.68077], [60, 59.93078589, 0.26223], [61, 60.93105558, 0.011399], + [62, 61.92834538, 0.036346], [64, 63.92796682, 0.009255]], + 'Cu': [[63, 62.92959773, 0.6915], [65, 64.92778971, 0.3085]], + 'Zn': [[64, 63.92914202, 0.4917], [66, 65.92603382, 0.2773], [67, 66.92712776, 0.0404], [68, 67.92484456, 0.1845], + [70, 69.9253192, 0.0061]], + 'Ga': [[69, 68.9255735, 0.60108], [71, 70.92470259, 0.39892]], + 'Ge': [[70, 69.92424876, 0.2057], [72, 71.922075827, 0.2745], [73, 72.923458957, 0.0775], + [74, 73.921177761, 0.3650], [76, 75.921402726, 0.0773]], + 'As': [[75, 74.92159458, 1]], + 'Se': [[74, 73.922475934, 0.0089], [76, 75.919213704, 0.0937], [77, 76.919914155, 0.0763], + [78, 77.91730928, 0.2377], [80, 79.9165218, 0.4961], [82, 81.9166995, 0.0873]], + 'Br': [[79, 78.9183376, 0.5069], [81, 80.9162897, 0.4931]], + 'Kr': [[78, 77.92036495, 0.00355], [80, 79.91637809, 0.02286], [82, 81.91348274, 0.11593], + [83, 82.91412716, 0.11500], [84, 83.9114977282, 0.56987], [86, 85.9106106269, 0.17279]], + 'Rb': [[85, 84.9117897380, 0.7217], [87, 86.9091805311, 0.2783]], + 'Sr': [[84, 83.9134191, 0.0056], [86, 85.9092606, 0.0986], [87, 86.9088775, 0.0700], + [88, 87.9056125, 0.8258]], + 'Y': [[89, 88.9058403, 1]], + 'Zr': [[90, 89.9046977, 0.5145], [91, 90.9056396, 0.1122], [92, 91.9050347, 0.1715], + [94, 93.9063108, 0.1738], [96, 95.9082714, 0.0280]], + 'Nb': [[93, 92.9063730, 1]], + 'Mo': [[92, 91.90680797, 0.1453], [94, 93.90508490, 0.0915], [95, 94.90583877, 0.1584], [96, 95.90467612, 0.1667], + [97, 96.90601812, 0.0960], [98, 97.90540482, 0.2439], [100, 99.9074718, 0.0982]], + 'Tc': [[97, 96.9063667, ], [98, 97.9072124], [99, 98.9062508]], + 'Ru': [[96, 95.90759025, 0.0554], [98, 97.9052869, 0.0187], [99, 98.9059341, 0.1276], [100, 99.9042143, 0.1260], + [101, 100.9055769, 0.1706], [102, 101.9043441, 0.3155], [104, 103.9054275, 0.1862]], + 'Rh': [[103, 102.905498, 1]], + 'Pd': [[102, 101.9056022, 0.0102], [104, 103.9040305, 0.1114], [105, 104.9050796, 0.2233], + [106, 105.9034804, 0.2733], [108, 107.9038916, 0.2646], [110, 109.90517221, 0.1172]], + 'Ag': [[107, 106.9050916, 0.51839], [109, 108.9047553, 0.48161]], + 'Cd': [[106, 105.9064599, 0.0125], [108, 107.9041834, 0.0089], [110, 109.90300662, 0.1249], + [111, 110.90418288, 0.1280], [112, 111.9027629, 0.2413], [113, 112.9044081, 0.1222], + [114, 113.9033651, 0.2873], [116, 115.9047632, 0.0749]], + 'In': [[113, 112.9040618, 0.0429], [115, 114.9038788, 0.9571]], + 'Sn': [[112, 111.9048239, 0.0097], [114, 113.9027827, 0.0066], [115, 114.9033447, 0.0034], + [116, 115.9017428, 0.1454], [117, 116.902954, 0.0768], [118, 117.9016066, 0.2422], + [119, 118.9033112, 0.0859], [120, 119.9022016, 0.3258], [122, 121.9034438, 0.0463], + [124, 123.9052766, 0.0579]], + 'Sb': [[121, 120.903812, 0.5721], [123, 122.9042132, 0.4279]], + 'Te': [[120, 119.9040593, 0.0009], [122, 121.9030435, 0.0255], [123, 122.9042698, 0.0089], + [124, 123.9028171, 0.0474], [125, 124.9044299, 0.0707], [126, 125.9033109, 0.1884], + [128, 127.9044613, 0.3174], [130, 129.9062227, 0.3408]], + 'I': [[127, 126.9044719, 1]], + 'Xe': [[124, 123.905892, 0.000952], [126, 125.9042983, 0.000890], [128, 127.903531, 0.019102], + [129, 128.9047809, 0.264006], [130, 129.9035093, 0.040710], [131, 130.9050841, 0.212324], + [132, 131.9041551, 0.269086], [134, 133.9053947, 0.104357], [136, 135.9072145, 0.088573]], + 'Cs': [[133, 132.905452, 1]], + 'Ba': [[130, 129.9063207, 0.00106], [132, 131.9050611, 0.00101], [134, 133.9045082, 0.02417], + [135, 134.9056884, 0.06592], [136, 135.9045757, 0.07854], [137, 136.9058271, 0.11232], + [138, 137.905247, 0.71698]], + 'La': [[138, 137.9071149, 0.0008881], [139, 138.9063563, 0.9991119]], + 'Ce': [[136, 135.9071292, 0.00185], [138, 137.905991, 0.00251], [140, 139.9054431, 0.88450], + [142, 141.9092504, 0.11114]], + 'Pr': [[141, 140.9076576, 1]], + 'Nd': [[142, 141.907729, 0.27152], [143, 142.90982, 0.12174], [144, 143.910093, 0.23798], + [145, 144.9125793, 0.08293], [146, 145.9131226, 0.17189], [148, 147.9168993, 0.05756], + [150, 149.9209022, 0.05638]], + 'Pm': [[145, 144.9127559], [147, 146.915145]], + 'Sm': [[144, 143.9120065, 0.0307], [147, 146.9149044, 0.1499], [148, 147.9148292, 0.1124], + [149, 148.9171921, 0.1382], [150, 149.9172829, 0.0738], [152, 151.9197397, 0.2675], + [154, 153.9222169, 0.2275]], + 'Eu': [[151, 150.9198578, 0.4781], [153, 152.921238, 0.5219]], + 'Gd': [[152, 151.9197995, 0.0020], [154, 153.9208741, 0.0218], [155, 154.9226305, 0.1480], + [156, 155.9221312, 0.2047], [157, 156.9239686, 0.1565], [158, 157.9241123, 0.2484], + [160, 159.9270624, 0.2186]], + 'Tb': [[159, 158.9253547, 1]], + 'Dy': [[156, 155.9242847, 0.00056], [158, 157.9244159, 0.00095], [160, 159.9252046, 0.02329], + [161, 160.9269405, 0.18889], [162, 161.9268056, 0.25475], [163, 162.9287383, 0.24896], + [164, 163.9291819, 0.28260]], + 'Ho': [[165, 164.9303288, 1]], + 'Er': [[162, 161.9287884, 0.00139], [164, 163.9292088, 0.01601], [166, 165.9302995, 0.33503], + [167, 166.9320546, 0.22869], [168, 167.9323767, 0.26978], [170, 169.9354702, 0.14910]], + 'Tm': [[169, 168.9342179, 1]], + 'Yb': [[168, 167.9338896, 0.00123], [170, 169.9347664, 0.02982], [171, 170.9363302, 0.1409], + [172, 171.9363859, 0.2168], [173, 172.9382151, 0.16103], [174, 173.9388664, 0.32026], + [176, 175.9425764, 0.12996]], + 'Lu': [[175, 174.9407752, 0.97401], [176, 175.9426897, 0.02599]], + 'Hf': [[174, 173.9400461, 0.0016], [176, 175.9414076, 0.0526], [177, 176.9432277, 0.1860], + [178, 177.9437058, 0.2728], [179, 178.9458232, 0.1362], [180, 179.946557, 0.3508]], + 'Ta': [[180, 179.9474648, 0.0001201], [181, 180.9479958, 0.9998799]], + 'W': [[180, 179.9467108, 0.0012], [182, 181.9482039, 0.2650], [183, 182.9502228, 0.1431], + [184, 183.9509309, 0.3064], [186, 185.9543628, 0.2843]], + 'Re': [[185, 184.9529545, 0.3740], [187, 186.9557501, 0.6260]], + 'Os': [[184, 183.9524885, 0.0002], [186, 185.953835, 0.0159], [187, 186.9557474, 0.0196], + [188, 187.9558352, 0.1324], [189, 188.9581442, 0.1615], [190, 189.9584437, 0.2626], + [192, 191.961477, 0.4078]], + 'Ir': [[191, 190.9605893, 0.373], [193, 192.9629216, 0.627]], + 'Pt': [[190, 189.9599297, 0.00012], [192, 191.9610387, 0.00782], [194, 193.9626809, 0.3286], + [195, 194.9647917, 0.3378], [196, 195.9649521, 0.2521], [198, 197.9678949, 0.07356]], + 'Au': [[197, 196.9665688, 1]], + 'Hg': [[196, 195.9658326, 0.0015], [198, 197.9667686, 0.0997], [199, 198.9682806, 0.1687], + [200, 199.9683266, 0.2310], [201, 200.9703028, 0.1318], [202, 201.9706434, 0.2986], + [204, 203.973494, 0.0687]], + 'Tl': [[203, 202.9723446, 0.2952], [205, 204.9744278, 0.7048]], + 'Pb': [[204, 203.973044, 0.014], [206, 205.9744657, 0.241], [207, 206.9758973, 0.221], + [208, 207.9766525, 0.524]], + 'Bi': [[209, 208.9803991, 1]], + 'Po': [[209, 208.9824308], [210, 209.9828741]], + 'At': [[210, 209.9871479], [211, 210.9874966]], + 'Rn': [[211, 210.9906011], [220, 220.0113941], [222, 222.0175782]], + 'Fr': [[223, 223.019736]], + 'Ra': [[223, 223.0185023], [224, 224.020212], [226, 226.0254103], [228, 228.0310707]], + 'Ac': [[227, 227.0277523]], + 'Th': [[230, 230.0331341, 0], [232, 232.0380558, 1]], + 'Pa': [[231, 231.0358842, 1]], + 'U': [[233, 233.0396355, 0], [234, 234.0409523, 0.000054], [235, 235.0439301, 0.007204], + [236, 236.0455682, 0], [238, 238.0507884, 0.992742]], + 'Np': [[236, 236.04657], [237, 237.0481736]], + 'Pu': [[238, 238.0495601], [239, 239.0521636], [240, 240.0538138], [241, 241.0568517], + [242, 242.0587428], [244, 244.0642053]], + 'Am': [[241, 241.0568293], [243, 243.0613813]], + 'Cm': [[243, 243.0613893], [244, 244.0627528], [245, 245.0654915], [246, 246.0672238], + [247, 247.0703541], [248, 248.0723499]], + 'Bk': [[247, 247.0703073], [249, 249.0749877]], + 'Cf': [[249, 249.0748539], [250, 250.0764062], [251, 251.0795886], [252, 252.0816272]], + 'Es': [[252, 252.08298]], + 'Fm': [[257, 257.0951061]], + 'Md': [[258, 258.0984315], [260, 260.10365]], + 'No': [[259, 259.10103]], + 'Lr': [[262, 262.10961]], + 'Rf': [[267, 267.12179]], + 'Db': [[268, 268.12567]], + 'Sg': [[271, 271.13393]], + 'Bh': [[272, 272.13826]], + 'Hs': [[270, 270.13429]], + 'Mt': [[276, 276.15159]], + 'Ds': [[281, 281.16451]], + 'Rg': [[280, 280.16514]], + 'Cn': [[285, 285.17712]], + 'Nh': [[284, 284.17873]], + 'Fl': [[289, 289.19042]], + 'Mc': [[288, 288.19274]], + 'Lv': [[293, 293.20449]], + 'Ts': [[292, 292.20746]], + 'Og': [[294, 294.21392]]} From 602d185cfcf3bcab562a8d6ed117fa7567fd403d Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 14:35:33 -0400 Subject: [PATCH 08/28] PEP 8 coding style fixes in Arkane commonTest.py --- arkane/commonTest.py | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/arkane/commonTest.py b/arkane/commonTest.py index f873413806..7c1077ac54 100644 --- a/arkane/commonTest.py +++ b/arkane/commonTest.py @@ -49,6 +49,7 @@ from arkane.statmech import InputError, StatMechJob from arkane.input import jobList + ################################################################################ @@ -56,14 +57,15 @@ class CommonTest(unittest.TestCase): """ Contains unit tests of Arkane's common functions. """ + def test_check_conformer_energy(self): """ test the check_conformer_energy function with an list of energies. """ v_list = [-272.2779012225, -272.2774933703, -272.2768397635, -272.2778432059, -272.278645477, -272.2789602654, - -272.2788749196, -272.278496709, -272.2779350675, -272.2777008843, -272.2777167286, -272.2780937643, - -272.2784838846, -272.2788050464, -272.2787865352, -272.2785091607, -272.2779977452, -272.2777957743, - -272.2779134906, -272.2781827547, -272.278443339, -272.2788244214, -272.2787748749] + -272.2788749196, -272.278496709, -272.2779350675, -272.2777008843, -272.2777167286, -272.2780937643, + -272.2784838846, -272.2788050464, -272.2787865352, -272.2785091607, -272.2779977452, -272.2777957743, + -272.2779134906, -272.2781827547, -272.278443339, -272.2788244214, -272.2787748749] v_list = numpy.array(v_list, numpy.float64) v_diff = (v_list[0] - numpy.min(v_list)) * constants.E_h * constants.Na / 1000 self.assertAlmostEqual(v_diff / 2.7805169838282797, 1, 5) @@ -73,12 +75,13 @@ class TestArkaneJob(unittest.TestCase): """ Contains unit tests of the Arkane module and its interactions with other RMG modules. """ + @classmethod def setUp(cls): """A method that is run before each unit test in this class""" arkane = Arkane() jobList = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), - 'data', 'methoxy.py')) + 'data', 'methoxy.py')) pdepjob = jobList[-1] cls.kineticsjob = jobList[0] pdepjob.activeJRotor = True @@ -173,7 +176,8 @@ def testPressureList(self): """ Test the pressure list. """ - self.assertEqual(numpy.array_equal(self.PlistValue, numpy.array([0.01, 0.1, 1, 3, 10, 100, 1000])), True, msg=None) + self.assertEqual(numpy.array_equal(self.PlistValue, numpy.array([0.01, 0.1, 1, 3, 10, 100, 1000])), True, + msg=None) def testGenerateTemperatureList(self): """ @@ -220,6 +224,7 @@ class TestArkaneInput(unittest.TestCase): """ Contains unit tests for loading and processing Arkane input files. """ + @classmethod def setUp(cls): """Preparation for all unit tests in this class.""" @@ -263,7 +268,7 @@ def testTransitionState(self): """Test loading of transition state input file.""" ts = input.transitionState('TS', os.path.join(self.directory, 'reactions', 'H+C2H4=C2H5', 'TS.py')) self.assertTrue(isinstance(ts, TransitionState)) - + def testTransitionStateStatmech(self): """Test loading of statmech job from transition state input file.""" job = jobList[-1] @@ -279,12 +284,13 @@ class TestStatmech(unittest.TestCase): """ Contains unit tests of statmech.py """ + @classmethod def setUp(cls): """A method that is run before each unit test in this class""" arkane = Arkane() cls.job_list = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)), - 'data', 'Benzyl', 'input.py')) + 'data', 'Benzyl', 'input.py')) def test_gaussian_log_file_error(self): """Test that the proper error is raised if gaussian geometry and frequency file paths are the same""" @@ -366,7 +372,7 @@ def tearDownClass(cls): item_path = os.path.join(path, name) if os.path.isfile(item_path): extension = name.split('.')[-1] - if name in cls.files_to_delete or\ + if name in cls.files_to_delete or \ (extension in cls.extensions_to_delete and name not in cls.files_to_keep): os.remove(item_path) else: @@ -378,6 +384,7 @@ class TestGetMass(unittest.TestCase): """ Contains unit tests of common.py """ + def test_get_mass(self): """Test that the correct mass/number/isotop is returned from get_element_mass""" self.assertEquals(get_element_mass(1), (1.00782503224, 1)) # test input by integer From 553d20433a881f38bc53a0a36c7ace77bd48667d Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 14:36:16 -0400 Subject: [PATCH 09/28] PEP 8 coding style fixes in Arkane explorer.py --- arkane/explorer.py | 180 +++++++++++++++++++++++++-------------------- 1 file changed, 100 insertions(+), 80 deletions(-) diff --git a/arkane/explorer.py b/arkane/explorer.py index ccf640e09d..56fb3ada36 100644 --- a/arkane/explorer.py +++ b/arkane/explorer.py @@ -44,6 +44,7 @@ from rmgpy.data.rmg import getDB from rmgpy.exceptions import InputError + ################################################################################ @@ -51,7 +52,8 @@ class ExplorerJob(object): """ A representation of an Arkane explorer job. This job is used to explore a potential energy surface (PES). """ - def __init__(self, source, pdepjob, explore_tol, energy_tol=np.inf, flux_tol=0.0, + + def __init__(self, source, pdepjob, explore_tol, energy_tol=np.inf, flux_tol=0.0, bathGas=None, maximumRadicalElectrons=np.inf): self.source = source self.explore_tol = explore_tol @@ -60,12 +62,12 @@ def __init__(self, source, pdepjob, explore_tol, energy_tol=np.inf, flux_tol=0.0 self.maximumRadicalElectrons = maximumRadicalElectrons self.jobRxns = None self.networks = None - + self.pdepjob = pdepjob - - if not hasattr(self.pdepjob,'outputFile'): + + if not hasattr(self.pdepjob, 'outputFile'): self.pdepjob.outputFile = None - + if bathGas: self.bathGas = bathGas elif self.pdepjob.network and self.pdepjob.network.bathGas: @@ -84,47 +86,49 @@ def copy(self): energy_tol=self.energy_tol, flux_tol=self.flux_tol ) - + def execute(self, outputFile, plot, format='pdf', print_summary=True, speciesList=None, thermoLibrary=None, kineticsLibrary=None): """Execute an ExplorerJob""" logging.info('Exploring network...') - + rmg = RMG() - - rmg.speciesConstraints = {'allowed' : ['input species', 'seed mechanisms', 'reaction libraries'], 'maximumRadicalElectrons' : self.maximumRadicalElectrons, 'explicitlyAllowedMolecules': []} + + rmg.speciesConstraints = {'allowed': ['input species', 'seed mechanisms', 'reaction libraries'], + 'maximumRadicalElectrons': self.maximumRadicalElectrons, + 'explicitlyAllowedMolecules': []} rmgpy.rmg.input.rmg = rmg - + reaction_model = CoreEdgeReactionModel() - + reaction_model.pressureDependence = self.pdepjob - + reaction_model.pressureDependence.rmgmode = True - + if outputFile: reaction_model.pressureDependence.outputFile = os.path.dirname(outputFile) - + kineticsDatabase = getDB('kinetics') thermoDatabase = getDB('thermo') - + thermoDatabase.libraries['thermojobs'] = thermoLibrary - thermoDatabase.libraryOrder.insert(0,'thermojobs') - + thermoDatabase.libraryOrder.insert(0, 'thermojobs') + kineticsDatabase.libraries['kineticsjobs'] = kineticsLibrary - kineticsDatabase.libraryOrder.insert(0,('kineticsjobs','Reaction Library')) - + kineticsDatabase.libraryOrder.insert(0, ('kineticsjobs', 'Reaction Library')) + jobRxns = [rxn for rxn in reaction_model.core.reactions] - + self.jobRxns = jobRxns - + if outputFile is not None: - if not os.path.exists(os.path.join(reaction_model.pressureDependence.outputFile,'pdep')): - os.mkdir(os.path.join(reaction_model.pressureDependence.outputFile,'pdep')) + if not os.path.exists(os.path.join(reaction_model.pressureDependence.outputFile, 'pdep')): + os.mkdir(os.path.join(reaction_model.pressureDependence.outputFile, 'pdep')) else: - shutil.rmtree(os.path.join(reaction_model.pressureDependence.outputFile,'pdep')) - os.mkdir(os.path.join(reaction_model.pressureDependence.outputFile,'pdep')) - + shutil.rmtree(os.path.join(reaction_model.pressureDependence.outputFile, 'pdep')) + os.mkdir(os.path.join(reaction_model.pressureDependence.outputFile, 'pdep')) + # get the molecular formula for the network mmol = None for spc in self.source: @@ -134,37 +138,40 @@ def execute(self, outputFile, plot, format='pdf', print_summary=True, speciesLis mmol = spc.molecule[0].copy(deep=True) form = mmol.getFormula() - - for spec in self.bathGas.keys()+self.source: - nspec,isNew = reaction_model.makeNewSpecies(spec,reactive=False) - flags = np.array([s.molecule[0].getFormula()==form for s in reaction_model.core.species]) - reaction_model.enlarge(nspec,reactEdge=False,unimolecularReact=flags, - bimolecularReact=np.zeros((len(reaction_model.core.species),len(reaction_model.core.species)))) - + + for spec in self.bathGas.keys() + self.source: + nspec, isNew = reaction_model.makeNewSpecies(spec, reactive=False) + flags = np.array([s.molecule[0].getFormula() == form for s in reaction_model.core.species]) + reaction_model.enlarge(nspec, reactEdge=False, unimolecularReact=flags, + bimolecularReact=np.zeros((len(reaction_model.core.species), + len(reaction_model.core.species)))) + reaction_model.addSeedMechanismToCore('kineticsjobs') - + for lib in kineticsDatabase.libraryOrder: if lib[0] != 'kineticsjobs': reaction_model.addReactionLibraryToEdge(lib[0]) - + for spc in reaction_model.core.species: - for i,item in enumerate(self.source): + for i, item in enumerate(self.source): if spc.isIsomorphic(item): self.source[i] = spc - + # react initial species if len(self.source) == 1: - flags = np.array([s.molecule[0].getFormula()==form for s in reaction_model.core.species]) - biflags = np.zeros((len(reaction_model.core.species),len(reaction_model.core.species))) + flags = np.array([s.molecule[0].getFormula() == form for s in reaction_model.core.species]) + biflags = np.zeros((len(reaction_model.core.species), len(reaction_model.core.species))) elif len(self.source) == 2: flags = np.array([False for s in reaction_model.core.species]) - biflags = np.array([[False for i in xrange(len(reaction_model.core.species))] for j in xrange(len(reaction_model.core.species))]) - biflags[reaction_model.core.species.index(self.source[0]),reaction_model.core.species.index(self.source[1])] = True + biflags = np.array([[False for i in xrange(len(reaction_model.core.species))] + for j in xrange(len(reaction_model.core.species))]) + biflags[reaction_model.core.species.index(self.source[0]), reaction_model.core.species.index( + self.source[1])] = True else: raise ValueError("Reactant channels with greater than 2 reactants not supported") - reaction_model.enlarge(reactEdge=True,unimolecularReact=flags, - bimolecularReact=biflags) + reaction_model.enlarge(reactEdge=True, unimolecularReact=flags, + bimolecularReact=biflags) # find the networks we're interested in networks = [] @@ -184,54 +191,63 @@ def execute(self, outputFile, plot, format='pdf', print_summary=True, speciesLis self.networks = networks # determine T and P combinations - + if self.pdepjob.Tlist: Tlist = self.pdepjob.Tlist.value_si else: - Tlist = np.linspace(self.pdepjob.Tmin.value_si,self.pdepjob.Tmax.value_si,self.pdepjob.Tcount) - + Tlist = np.linspace(self.pdepjob.Tmin.value_si, self.pdepjob.Tmax.value_si, self.pdepjob.Tcount) + if self.pdepjob.Plist: Plist = self.pdepjob.Plist.value_si else: - Plist = np.linspace(self.pdepjob.Pmin.value_si,self.pdepjob.Pmax.value_si,self.pdepjob.Pcount) - + Plist = np.linspace(self.pdepjob.Pmin.value_si, self.pdepjob.Pmax.value_si, self.pdepjob.Pcount) + # generate the network - + forbiddenStructures = getDB('forbidden') incomplete = True - + while incomplete: incomplete = False for T in Tlist: for P in Plist: for network in self.networks: - kchar = 0.0 #compute the characteristic rate coefficient by summing all rate coefficients from the reactant channel - for rxn in network.netReactions:#reaction_model.core.reactions+reaction_model.edge.reactions: - if set(rxn.reactants) == set(self.source) and rxn.products[0].molecule[0].getFormula() == form: - kchar += rxn.kinetics.getRateCoefficient(T=T,P=P) - elif set(rxn.products) == set(self.source) and rxn.reactants[0].molecule[0].getFormula() == form: - kchar += rxn.generateReverseRateCoefficient(network_kinetics=True).getRateCoefficient(T=T,P=P) - - if network.getLeakCoefficient(T=T,P=P) > self.explore_tol*kchar: + # compute the characteristic rate coefficient by summing all rate coefficients + # from the reactant channel + kchar = 0.0 + for rxn in network.netReactions: # reaction_model.core.reactions+reaction_model.edge.reactions: + if (set(rxn.reactants) == set(self.source) + and rxn.products[0].molecule[0].getFormula() == form): + kchar += rxn.kinetics.getRateCoefficient(T=T, P=P) + elif (set(rxn.products) == set(self.source) + and rxn.reactants[0].molecule[0].getFormula() == form): + kchar += rxn.generateReverseRateCoefficient(network_kinetics=True).getRateCoefficient( + T=T, P=P) + + if network.getLeakCoefficient(T=T, P=P) > self.explore_tol * kchar: incomplete = True - spc = network.getMaximumLeakSpecies(T=T,P=P) + spc = network.getMaximumLeakSpecies(T=T, P=P) if forbiddenStructures.isMoleculeForbidden(spc.molecule[0]): - reaction_model.removeSpeciesFromEdge(reaction_model.reactionSystems,spc) + reaction_model.removeSpeciesFromEdge(reaction_model.reactionSystems, spc) reaction_model.removeEmptyPdepNetworks() logging.error(spc.label) else: logging.info('adding new isomer {0} to network'.format(spc)) - flags = np.array([s.molecule[0].getFormula()==form for s in reaction_model.core.species]) - reaction_model.enlarge((network,spc),reactEdge=False,unimolecularReact=flags, - bimolecularReact=np.zeros((len(reaction_model.core.species),len(reaction_model.core.species)))) - - flags = np.array([s.molecule[0].getFormula()==form for s in reaction_model.core.species]) - reaction_model.enlarge(reactEdge=True,unimolecularReact=flags, - bimolecularReact=np.zeros((len(reaction_model.core.species),len(reaction_model.core.species)))) + flags = np.array([s.molecule[0].getFormula() == form + for s in reaction_model.core.species]) + reaction_model.enlarge((network, spc), reactEdge=False, unimolecularReact=flags, + bimolecularReact=np.zeros((len(reaction_model.core.species), + len(reaction_model.core.species)))) + + flags = np.array( + [s.molecule[0].getFormula() == form for s in reaction_model.core.species]) + reaction_model.enlarge(reactEdge=True, unimolecularReact=flags, + bimolecularReact=np.zeros((len(reaction_model.core.species), + len(reaction_model.core.species)))) for network in self.networks: rmRxns = [] for rxn in network.pathReactions: # remove reactions with forbidden species - for r in rxn.reactants+rxn.products: + for r in rxn.reactants + rxn.products: if forbiddenStructures.isMoleculeForbidden(r.molecule[0]): rmRxns.append(rxn) @@ -241,19 +257,22 @@ def execute(self, outputFile, plot, format='pdf', print_summary=True, speciesLis # clean up output files if outputFile is not None: - path = os.path.join(reaction_model.pressureDependence.outputFile,'pdep') + path = os.path.join(reaction_model.pressureDependence.outputFile, 'pdep') for name in os.listdir(path): if name.endswith('.py') and '_' in name: if name.split('_')[-1].split('.')[0] != str(len(network.isomers)): - os.remove(os.path.join(path,name)) + os.remove(os.path.join(path, name)) else: - os.rename(os.path.join(path,name),os.path.join(path,'network_full{}.py'.format(self.networks.index(network)))) + os.rename(os.path.join(path, name), + os.path.join(path, 'network_full{}.py'.format(self.networks.index(network)))) warns = [] for rxn in jobRxns: if rxn not in network.pathReactions: - warns.append('Reaction {0} in the input file was not explored during network expansion and was not included in the full network. This is likely because your explore_tol value is too high.'.format(rxn)) + warns.append('Reaction {0} in the input file was not explored during network expansion and was ' + 'not included in the full network. This is likely because your explore_tol value is ' + 'too high.'.format(rxn)) # reduction process for network in self.networks: @@ -263,7 +282,7 @@ def execute(self, outputFile, plot, format='pdf', print_summary=True, speciesLis for T in Tlist: if self.energy_tol != np.inf: - rxns = network.get_energy_filtered_reactions(T,self.energy_tol) + rxns = network.get_energy_filtered_reactions(T, self.energy_tol) if rxnSet is not None: rxnSet &= set(rxns) else: @@ -271,7 +290,7 @@ def execute(self, outputFile, plot, format='pdf', print_summary=True, speciesLis for P in Plist: if self.flux_tol != 0.0: - rxns = network.get_rate_filtered_reactions(T,P,self.flux_tol) + rxns = network.get_rate_filtered_reactions(T, P, self.flux_tol) if rxnSet is not None: rxnSet &= set(rxns) else: @@ -281,26 +300,27 @@ def execute(self, outputFile, plot, format='pdf', print_summary=True, speciesLis for rxn in rxnSet: logging.info(rxn) - network.remove_reactions(reaction_model,list(rxnSet)) + network.remove_reactions(reaction_model, list(rxnSet)) for rxn in jobRxns: if rxn not in network.pathReactions: - warns.append('Reaction {0} in the input file was not included in the reduced model.'.format(rxn)) + warns.append( + 'Reaction {0} in the input file was not included in the reduced model.'.format(rxn)) self.networks = networks - for p,network in enumerate(self.networks): + for p, network in enumerate(self.networks): self.pdepjob.network = network if len(self.networks) > 1: - s1,s2 = outputFile.split(".") + s1, s2 = outputFile.split(".") ind = str(self.networks.index(network)) - stot = s1+"{}.".format(ind)+s2 + stot = s1 + "{}.".format(ind) + s2 else: stot = outputFile self.pdepjob.execute(stot, plot, format='pdf', print_summary=True) if os.path.isfile('network.pdf'): - os.rename('network.pdf','network'+str(p)+'.pdf') + os.rename('network.pdf', 'network' + str(p) + '.pdf') if warns: logging.info('\nOUTPUT WARNINGS:\n') From a81eb9317c337c97dcb9dca18f8673f64b927e67 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 14:36:33 -0400 Subject: [PATCH 10/28] PEP 8 coding style fixes in Arkane explorerTest.py --- arkane/explorerTest.py | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/arkane/explorerTest.py b/arkane/explorerTest.py index aa6e2a92c2..9245f49b6c 100644 --- a/arkane/explorerTest.py +++ b/arkane/explorerTest.py @@ -35,6 +35,7 @@ from arkane import Arkane from arkane.explorer import ExplorerJob + ################################################################################ @@ -43,42 +44,45 @@ class testExplorerJob(unittest.TestCase): """ Contains tests for ExplorerJob class execute method """ + @classmethod def setUpClass(cls): """A method that is run before each unit test in this class""" arkane = Arkane() - - cls.jobList = arkane.loadInputFile(os.path.join(os.path.dirname(os.path.abspath(__file__)),'data','methoxy_explore.py')) + + cls.jobList = arkane.loadInputFile( + os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'methoxy_explore.py')) for job in cls.jobList: - if not isinstance(job,ExplorerJob): + if not isinstance(job, ExplorerJob): job.execute(outputFile=None, plot=None) else: - thermoLibrary,kineticsLibrary,speciesList = arkane.getLibraries() - job.execute(outputFile=None, plot=None, speciesList=speciesList, thermoLibrary=thermoLibrary, kineticsLibrary=kineticsLibrary) + thermoLibrary, kineticsLibrary, speciesList = arkane.getLibraries() + job.execute(outputFile=None, plot=None, speciesList=speciesList, thermoLibrary=thermoLibrary, + kineticsLibrary=kineticsLibrary) cls.thermoLibrary = thermoLibrary cls.kineticsLibrary = kineticsLibrary cls.explorerjob = cls.jobList[-1] cls.pdepjob = cls.jobList[-2] - + @classmethod def tearDownClass(cls): """A function that is run ONCE after all unit tests in this class.""" # Reset module level database import rmgpy.data.rmg rmgpy.data.rmg.database.kinetics = None - + def test_reactions(self): """ test that the right number of reactions are in output network """ - self.assertEqual(len(self.explorerjob.networks[0].pathReactions),6) + self.assertEqual(len(self.explorerjob.networks[0].pathReactions), 6) def test_isomers(self): """ test that the right number of isomers are in the output network """ - self.assertEqual(len(self.explorerjob.networks[0].isomers),2) + self.assertEqual(len(self.explorerjob.networks[0].isomers), 2) def test_job_rxns(self): """ @@ -86,7 +90,7 @@ def test_job_rxns(self): ended up in the final network """ for rxn in self.explorerjob.jobRxns: - self.assertIn(rxn,self.explorerjob.networks[0].pathReactions) + self.assertIn(rxn, self.explorerjob.networks[0].pathReactions) if __name__ == '__main__': From 4519edd880becdc152d128e7a6c8fe54c236fca9 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 14:38:11 -0400 Subject: [PATCH 11/28] PEP 8 coding style fixes in Arkane gaussian.py --- arkane/gaussian.py | 84 ++++++++++++++++++++++++++-------------------- 1 file changed, 47 insertions(+), 37 deletions(-) diff --git a/arkane/gaussian.py b/arkane/gaussian.py index e6052931fe..081cfeb9c7 100644 --- a/arkane/gaussian.py +++ b/arkane/gaussian.py @@ -45,6 +45,7 @@ from arkane.common import check_conformer_energy, get_element_mass from arkane.log import Log + ################################################################################ @@ -72,7 +73,8 @@ def getNumberOfAtoms(self): while line != '' and Natoms == 0: # Automatically determine the number of atoms if 'Input orientation:' in line and Natoms == 0: - for i in range(5): line = f.readline() + for i in range(5): + line = f.readline() while '---------------------------------------------------------------------' not in line: Natoms += 1 line = f.readline() @@ -103,18 +105,18 @@ def loadForceConstantMatrix(self): while line != '': # Read force constant matrix if 'Force constants in Cartesian coordinates:' in line: - F = numpy.zeros((Nrows,Nrows), numpy.float64) + F = numpy.zeros((Nrows, Nrows), numpy.float64) for i in range(int(math.ceil(Nrows / 5.0))): # Header row line = f.readline() # Matrix element rows - for j in range(i*5, Nrows): + for j in range(i * 5, Nrows): data = f.readline().split() - for k in range(len(data)-1): - F[j,i*5+k] = float(data[k+1].replace('D', 'E')) - F[i*5+k,j] = F[j,i*5+k] + for k in range(len(data) - 1): + F[j, i * 5 + k] = float(data[k + 1].replace('D', 'E')) + F[i * 5 + k, j] = F[j, i * 5 + k] # Convert from atomic units (Hartree/Bohr_radius^2) to J/m^2 - F *= 4.35974417e-18 / 5.291772108e-11**2 + F *= 4.35974417e-18 / 5.291772108e-11 ** 2 line = f.readline() # Close file when finished f.close() @@ -136,7 +138,8 @@ def loadGeometry(self): # Automatically determine the number of atoms if 'Input orientation:' in line: number, coord = [], [] - for i in range(5): line = f.readline() + for i in range(5): + line = f.readline() while '---------------------------------------------------------------------' not in line: data = line.split() number.append(int(data[1])) @@ -159,7 +162,7 @@ def loadGeometry(self): 'Make sure the output file is not corrupt.\nNote: if your species has ' '50 or more atoms, you will need to add the `iop(2/9=2000)` keyword to your ' 'input file so Gaussian will print the input orientation geomerty.'.format(self.path)) - + return coord, number, mass def loadConformer(self, symmetry=None, spinMultiplicity=0, opticalIsomers=None, label=''): @@ -205,20 +208,22 @@ def loadConformer(self, symmetry=None, spinMultiplicity=0, opticalIsomers=None, # Read molecular mass for external translational modes elif 'Molecular mass:' in line: mass = float(line.split()[2]) - translation = IdealGasTranslation(mass=(mass,"amu")) + translation = IdealGasTranslation(mass=(mass, "amu")) modes.append(translation) # Read moments of inertia for external rotational modes elif 'Rotational constants (GHZ):' in line: inertia = [float(d) for d in line.split()[-3:]] for i in range(3): - inertia[i] = constants.h / (8 * constants.pi * constants.pi * inertia[i] * 1e9) *constants.Na*1e23 - rotation = NonlinearRotor(inertia=(inertia,"amu*angstrom^2"), symmetry=symmetry) + inertia[i] = constants.h / (8 * constants.pi * constants.pi * inertia[i] * 1e9)\ + * constants.Na * 1e23 + rotation = NonlinearRotor(inertia=(inertia, "amu*angstrom^2"), symmetry=symmetry) modes.append(rotation) elif 'Rotational constant (GHZ):' in line: inertia = [float(line.split()[3])] - inertia[0] = constants.h / (8 * constants.pi * constants.pi * inertia[0] * 1e9) *constants.Na*1e23 - rotation = LinearRotor(inertia=(inertia[0],"amu*angstrom^2"), symmetry=symmetry) + inertia[0] = constants.h / (8 * constants.pi * constants.pi * inertia[0] * 1e9)\ + * constants.Na * 1e23 + rotation = LinearRotor(inertia=(inertia[0], "amu*angstrom^2"), symmetry=symmetry) modes.append(rotation) # Read vibrational modes @@ -235,7 +240,7 @@ def loadConformer(self, symmetry=None, spinMultiplicity=0, opticalIsomers=None, if len(frequencies) > 0: frequencies = [freq * 0.695039 for freq in frequencies] # kB = 0.695039 cm^-1/K unscaled_frequencies = frequencies - vibration = HarmonicOscillator(frequencies=(frequencies,"cm^-1")) + vibration = HarmonicOscillator(frequencies=(frequencies, "cm^-1")) modes.append(vibration) # Read ground-state energy @@ -257,10 +262,10 @@ def loadConformer(self, symmetry=None, spinMultiplicity=0, opticalIsomers=None, # Close file when finished f.close() - return Conformer(E0=(E0*0.001,"kJ/mol"), modes=modes, spinMultiplicity=spinMultiplicity, + return Conformer(E0=(E0 * 0.001, "kJ/mol"), modes=modes, spinMultiplicity=spinMultiplicity, opticalIsomers=opticalIsomers), unscaled_frequencies - def loadEnergy(self,frequencyScaleFactor=1.): + def loadEnergy(self, frequencyScaleFactor=1.): """ Load the energy in J/mol from a Gaussian log file. The file is checked for a complete basis set extrapolation; if found, that value is @@ -269,7 +274,9 @@ def loadEnergy(self,frequencyScaleFactor=1.): CBS-QB3 value. """ - E0 = None; E0_cbs = None; scaledZPE = None + E0 = None + E0_cbs = None + scaledZPE = None f = open(self.path, 'r') line = f.readline() @@ -281,13 +288,13 @@ def loadEnergy(self,frequencyScaleFactor=1.): E0_cbs = float(line.split()[3]) * constants.E_h * constants.Na elif 'G3(0 K)' in line: E0_cbs = float(line.split()[2]) * constants.E_h * constants.Na - + # Read the ZPE from the "E(ZPE)=" line, as this is the scaled version. # Gaussian defines the following as # E (0 K) = Elec + E(ZPE), # The ZPE is the scaled ZPE given by E(ZPE) in the log file, # hence to get the correct Elec from E (0 K) we need to subtract the scaled ZPE - + elif 'E(ZPE)' in line: scaledZPE = float(line.split()[1]) * constants.E_h * constants.Na elif '\\ZeroPoint=' in line: @@ -300,15 +307,16 @@ def loadEnergy(self,frequencyScaleFactor=1.): # Close file when finished f.close() - + if E0_cbs is not None: if scaledZPE is None: raise Exception('Unable to find zero-point energy in Gaussian log file.') return E0_cbs - scaledZPE elif E0 is not None: return E0 - else: raise Exception('Unable to find energy in Gaussian log file.') - + else: + raise Exception('Unable to find energy in Gaussian log file.') + def loadZeroPointEnergy(self): """ Load the unscaled zero-point energy in J/mol from a Gaussian log file. @@ -335,7 +343,7 @@ def loadZeroPointEnergy(self): # Close file when finished f.close() - + if ZPE is not None: return ZPE else: @@ -348,7 +356,7 @@ def loadScanEnergies(self): """ optfreq = False - rigidScan=False + rigidScan = False # The array of potentials at each scan angle Vlist = [] @@ -361,15 +369,15 @@ def loadScanEnergies(self): # If the job contains a "freq" then we want to ignore the last energy if ' freq ' in line: optfreq = True - #if # scan is keyword instead of # opt, then this is a rigid scan job - #and parsing the energies is done a little differently + # if # scan is keyword instead of # opt, then this is a rigid scan job + # and parsing the energies is done a little differently if '# scan' in line: - rigidScan=True + rigidScan = True # The lines containing "SCF Done" give the energy at each # iteration (even the intermediate ones) if 'SCF Done:' in line: E = float(line.split()[4]) - #rigid scans will only not optimize, so just append every time it finds an energy. + # rigid scans will only not optimize, so just append every time it finds an energy. if rigidScan: Vlist.append(E) # We want to keep the values of E that come most recently before @@ -380,26 +388,28 @@ def loadScanEnergies(self): line = f.readline() # Close file when finished f.close() - - #give warning in case this assumption is not true + + # give warning in case this assumption is not true if rigidScan: print ' Assuming', os.path.basename(self.path), 'is the output from a rigid scan...' - + Vlist = numpy.array(Vlist, numpy.float64) - # check to see if the scanlog indicates that a one of your reacting species may not be the lowest energy conformer + # check to see if the scanlog indicates that a one of your reacting species may not be + # the lowest energy conformer check_conformer_energy(Vlist, self.path) - + # Adjust energies to be relative to minimum energy conformer # Also convert units from Hartree/particle to J/mol Vlist -= numpy.min(Vlist) Vlist *= constants.E_h * constants.Na - if optfreq: Vlist = Vlist[:-1] + if optfreq: + Vlist = Vlist[:-1] # Determine the set of dihedral angles corresponding to the loaded energies # This assumes that you start at 0.0, finish at 360.0, and take # constant step sizes in between - angle = numpy.arange(0.0, 2*math.pi+0.00001, 2*math.pi/(len(Vlist)-1), numpy.float64) + angle = numpy.arange(0.0, 2 * math.pi + 0.00001, 2 * math.pi / (len(Vlist) - 1), numpy.float64) return Vlist, angle @@ -419,7 +429,7 @@ def loadNegativeFrequency(self): line = f.readline() # Close file when finished f.close() - + frequencies = [float(freq) for freq in frequencies] frequencies.sort() frequency = [freq for freq in frequencies if freq < 0][0] From c27ee75b97ca4d8d7f2a5af063a30bd611742daa Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 14:39:44 -0400 Subject: [PATCH 12/28] PEP 8 coding style fixes in Arkane gaussianTest.py --- arkane/gaussianTest.py | 83 ++++++++++++++++++++++-------------------- 1 file changed, 43 insertions(+), 40 deletions(-) diff --git a/arkane/gaussianTest.py b/arkane/gaussianTest.py index 96a870f46c..2939fc3a6c 100644 --- a/arkane/gaussianTest.py +++ b/arkane/gaussianTest.py @@ -39,6 +39,7 @@ from arkane.gaussian import GaussianLog from arkane.statmech import determine_qm_software + ################################################################################ @@ -47,6 +48,7 @@ class GaussianTest(unittest.TestCase): Contains unit tests for the chempy.io.gaussian module, used for reading and writing Gaussian files. """ + @work_in_progress def testLoadEthyleneFromGaussianLog_CBSQB3(self): """ @@ -54,18 +56,18 @@ def testLoadEthyleneFromGaussianLog_CBSQB3(self): molecular degrees of freedom can be properly read. """ - log = GaussianLog(os.path.join(os.path.dirname(__file__),'data','ethylene.log')) + log = GaussianLog(os.path.join(os.path.dirname(__file__), 'data', 'ethylene.log')) conformer, unscaled_frequencies = log.loadConformer() E0 = log.loadEnergy() - - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,IdealGasTranslation)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,NonlinearRotor)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,HarmonicOscillator)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,HinderedRotor)]) == 0) - - 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] + + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, IdealGasTranslation)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, NonlinearRotor)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, HarmonicOscillator)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, HinderedRotor)]) == 0) + + 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] Tlist = numpy.array([298.15], numpy.float64) self.assertAlmostEqual(trans.getPartitionFunction(Tlist), 5.83338e6, delta=1e1) self.assertAlmostEqual(rot.getPartitionFunction(Tlist), 2.59622e3, delta=1e-2) @@ -81,23 +83,23 @@ def testLoadOxygenFromGaussianLog(self): molecular degrees of freedom can be properly read. """ - log = GaussianLog(os.path.join(os.path.dirname(__file__),'data','oxygen.log')) + log = GaussianLog(os.path.join(os.path.dirname(__file__), 'data', 'oxygen.log')) conformer, unscaled_frequencies = log.loadConformer() E0 = log.loadEnergy() - - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,IdealGasTranslation)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,LinearRotor)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,HarmonicOscillator)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,HinderedRotor)]) == 0) - - 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] + + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, IdealGasTranslation)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, LinearRotor)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, HarmonicOscillator)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, HinderedRotor)]) == 0) + + 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] Tlist = numpy.array([298.15], numpy.float64) self.assertAlmostEqual(trans.getPartitionFunction(Tlist), 7.11169e6, delta=1e1) self.assertAlmostEqual(rot.getPartitionFunction(Tlist), 7.13316e1, delta=1e-4) self.assertAlmostEqual(vib.getPartitionFunction(Tlist), 1.00037e0, delta=1e-4) - + self.assertAlmostEqual(E0 / constants.Na / constants.E_h, -150.3784877, 4) self.assertEqual(conformer.spinMultiplicity, 3) self.assertEqual(conformer.opticalIsomers, 1) @@ -109,20 +111,20 @@ def testLoadEthyleneFromGaussianLog_G3(self): molecular degrees of freedom can be properly read. """ - log = GaussianLog(os.path.join(os.path.dirname(__file__),'data','ethylene_G3.log')) + log = GaussianLog(os.path.join(os.path.dirname(__file__), 'data', 'ethylene_G3.log')) conformer, unscaled_frequencies = log.loadConformer() E0 = log.loadEnergy() - - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,IdealGasTranslation)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,NonlinearRotor)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,HarmonicOscillator)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,HinderedRotor)]) == 0) - - 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] + + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, IdealGasTranslation)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, NonlinearRotor)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, HarmonicOscillator)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, HinderedRotor)]) == 0) + + 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] Tlist = numpy.array([298.15], numpy.float64) - + self.assertAlmostEqual(trans.getPartitionFunction(Tlist), 5.83338e6, delta=1e1) self.assertAlmostEqual(rot.getPartitionFunction(Tlist), 2.53410e3, delta=1e-2) self.assertAlmostEqual(vib.getPartitionFunction(Tlist), 1.0304e0, delta=1e-4) @@ -137,17 +139,17 @@ def testLoadSymmetryAndOptics(self): molecular degrees of freedom can be properly read. """ - log = GaussianLog(os.path.join(os.path.dirname(__file__),'data','oxygen.log')) + log = GaussianLog(os.path.join(os.path.dirname(__file__), 'data', 'oxygen.log')) optical, symmetry = log.get_optical_isomers_and_symmetry_number() - self.assertEqual(optical,1) - self.assertEqual(symmetry,2) + self.assertEqual(optical, 1) + self.assertEqual(symmetry, 2) conf = log.loadConformer()[0] self.assertEqual(conf.opticalIsomers, 1) found_rotor = False for mode in conf.modes: - if isinstance(mode,LinearRotor): - self.assertEqual(mode.symmetry,2) + if isinstance(mode, LinearRotor): + self.assertEqual(mode.symmetry, 2) found_rotor = True self.assertTrue(found_rotor) @@ -155,8 +157,9 @@ def testDetermineQMSoftware(self): """ Ensures that determine_qm_software returns a GaussianLog object """ - log = determine_qm_software(os.path.join(os.path.dirname(__file__),'data','oxygen.log')) - self.assertIsInstance(log,GaussianLog) + log = determine_qm_software(os.path.join(os.path.dirname(__file__), 'data', 'oxygen.log')) + self.assertIsInstance(log, GaussianLog) + if __name__ == '__main__': - unittest.main( testRunner = unittest.TextTestRunner(verbosity=2) ) + unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) From 6e08c91b95dee4c51d763dccb30d5d473322abc5 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:15:58 -0400 Subject: [PATCH 13/28] PEP 8 coding style fixes in Arkane input.py --- arkane/input.py | 199 ++++++++++++++++++++++++++---------------------- 1 file changed, 108 insertions(+), 91 deletions(-) diff --git a/arkane/input.py b/arkane/input.py index 3123e3b5e4..f673815d1a 100644 --- a/arkane/input.py +++ b/arkane/input.py @@ -64,7 +64,7 @@ from rmgpy.kinetics.model import PDepKineticsModel, TunnelingModel from rmgpy.pdep.configuration import Configuration -from rmgpy.pdep.network import Network +from rmgpy.pdep.network import Network from rmgpy.pdep.collision import SingleExponentialDown from rmgpy.molecule import Molecule @@ -86,11 +86,12 @@ networkDict = {} jobList = [] + ################################################################################ -def database(thermoLibraries = None, transportLibraries = None, reactionLibraries = None, frequenciesLibraries = None, - kineticsFamilies = 'default', kineticsDepositories = 'default', kineticsEstimator = 'rate rules'): +def database(thermoLibraries=None, transportLibraries=None, reactionLibraries=None, frequenciesLibraries=None, + kineticsFamilies='default', kineticsDepositories='default', kineticsEstimator='rate rules'): """Load the RMG database""" if isinstance(thermoLibraries, str): thermoLibraries = [thermoLibraries] @@ -100,43 +101,46 @@ def database(thermoLibraries = None, transportLibraries = None, reactionLibrarie reactionLibraries = [reactionLibraries] if isinstance(frequenciesLibraries, str): frequenciesLibraries = [frequenciesLibraries] - + databaseDirectory = settings['database.directory'] thermoLibraries = thermoLibraries or [] transportLibraries = transportLibraries reactionLibraries = reactionLibraries or [] kineticsEstimator = kineticsEstimator - + if kineticsDepositories == 'default': kineticsDepositories = ['training'] elif kineticsDepositories == 'all': kineticsDepositories = None else: - if not isinstance(kineticsDepositories,list): - raise InputError("kineticsDepositories should be either 'default', 'all', or a list of names eg. ['training','PrIMe'].") + if not isinstance(kineticsDepositories, list): + raise InputError( + "kineticsDepositories should be either 'default', 'all', or a list of names eg. ['training','PrIMe'].") kineticsDepositories = kineticsDepositories if kineticsFamilies in ('default', 'all', 'none'): kineticsFamilies = kineticsFamilies else: - if not isinstance(kineticsFamilies,list): - raise InputError("kineticsFamilies should be either 'default', 'all', 'none', or a list of names eg. ['H_Abstraction','R_Recombination'] or ['!Intra_Disproportionation'].") + if not isinstance(kineticsFamilies, list): + raise InputError( + "kineticsFamilies should be either 'default', 'all', 'none', or a list of names eg. " + "['H_Abstraction','R_Recombination'] or ['!Intra_Disproportionation'].") kineticsFamilies = kineticsFamilies database = getDB() or RMGDatabase() database.load( - path = databaseDirectory, - thermoLibraries = thermoLibraries, - transportLibraries = transportLibraries, - reactionLibraries = reactionLibraries, - seedMechanisms = [], - kineticsFamilies = kineticsFamilies, - kineticsDepositories = kineticsDepositories, - depository = False, # Don't bother loading the depository information, as we don't use it - ) - - for family in database.kinetics.families.values(): #load training + path=databaseDirectory, + thermoLibraries=thermoLibraries, + transportLibraries=transportLibraries, + reactionLibraries=reactionLibraries, + seedMechanisms=[], + kineticsFamilies=kineticsFamilies, + kineticsDepositories=kineticsDepositories, + depository=False, # Don't bother loading the depository information, as we don't use it + ) + + for family in database.kinetics.families.values(): # load training family.addKineticsRulesFromTrainingSet(thermoDatabase=database.thermo) for family in database.kinetics.families.values(): @@ -149,7 +153,7 @@ def species(label, *args, **kwargs): if label in speciesDict: raise ValueError('Multiple occurrences of species with label {0!r}.'.format(label)) logging.info('Loading species {0}...'.format(label)) - + spec = Species(label=label) speciesDict[label] = spec @@ -164,7 +168,7 @@ def species(label, *args, **kwargs): raise InputError('species {0} can only have two non-keyword argument ' 'which should be the species label and the ' 'path to a quantum file.'.format(spec.label)) - + if len(kwargs) > 0: # The species parameters are given explicitly structure = None @@ -200,7 +204,7 @@ def species(label, *args, **kwargs): reactive = value else: raise TypeError('species() got an unexpected keyword argument {0!r}.'.format(key)) - + if structure: spec.molecule = [structure] spec.conformer = Conformer(E0=E0, modes=modes, spinMultiplicity=spinMultiplicity, opticalIsomers=opticalIsomers) @@ -216,7 +220,7 @@ def species(label, *args, **kwargs): spec.energyTransferModel = energyTransferModel spec.thermo = thermo spec.reactive = reactive - + if spec.reactive and path is None and spec.thermo is None and spec.conformer.E0 is None: if not spec.molecule: raise InputError('Neither thermo, E0, species file path, nor structure specified, cannot estimate' @@ -258,13 +262,13 @@ def transitionState(label, *args, **kwargs): logging.info('Loading transition state {0}...'.format(label)) ts = TransitionState(label=label) transitionStateDict[label] = ts - + if len(args) == 1 and len(kwargs) == 0: # The argument is a path to a conformer input file path = args[0] job = StatMechJob(species=ts, path=path) jobList.append(job) - + elif len(args) == 0: # The species parameters are given explicitly E0 = None @@ -285,12 +289,13 @@ def transitionState(label, *args, **kwargs): frequency = value else: raise TypeError('transitionState() got an unexpected keyword argument {0!r}.'.format(key)) - - ts.conformer = Conformer(E0=E0, modes=modes, spinMultiplicity=spinMultiplicity, opticalIsomers=opticalIsomers) + + ts.conformer = Conformer(E0=E0, modes=modes, spinMultiplicity=spinMultiplicity, opticalIsomers=opticalIsomers) ts.frequency = frequency else: if len(args) == 0 and len(kwargs) == 0: - raise InputError('The transitionState needs to reference a quantum job file or contain kinetic information.') + raise InputError( + 'The transitionState needs to reference a quantum job file or contain kinetic information.') raise InputError('The transitionState can only link a quantum job or directly input information, not both.') return ts @@ -316,19 +321,21 @@ def reaction(label, reactants, products, transitionState=None, kinetics=None, tu transitionState.tunneling = None elif transitionState and not isinstance(tunneling, TunnelingModel): raise ValueError('Unknown tunneling model {0!r}.'.format(tunneling)) - rxn = Reaction(label=label, reactants=reactants, products=products, transitionState=transitionState, kinetics=kinetics) - + rxn = Reaction(label=label, reactants=reactants, products=products, transitionState=transitionState, + kinetics=kinetics) + if rxn.transitionState is None and rxn.kinetics is None: logging.info('estimating rate of reaction {0} using RMG-database') - if not all([m.molecule != [] for m in rxn.reactants+rxn.products]): - raise ValueError('chemical structures of reactants and products not available for RMG estimation of reaction {0}'.format(label)) - for spc in rxn.reactants+rxn.products: + if not all([m.molecule != [] for m in rxn.reactants + rxn.products]): + raise ValueError('chemical structures of reactants and products not available for RMG estimation of ' + 'reaction {0}'.format(label)) + for spc in rxn.reactants + rxn.products: print spc.label print spc.molecule db = getDB('kinetics') - rxns = db.generate_reactions_from_libraries(reactants=rxn.reactants,products=rxn.products) + rxns = db.generate_reactions_from_libraries(reactants=rxn.reactants, products=rxn.products) rxns = [r for r in rxns if r.elementary_high_p] - + if rxns: for r in rxns: if isinstance(rxn.kinetics, PDepKineticsModel): @@ -336,21 +343,22 @@ def reaction(label, reactants, products, transitionState=None, kinetics=None, tu if boo: rxn = r break - + if rxns == [] or not boo: - logging.info('No library reactions tagged with elementary_high_p found for reaction {0}, generating reactions from RMG families'.format(label)) - rxn = list(db.generate_reactions_from_families(reactants=rxn.reactants,products=rxn.products)) + logging.info('No library reactions tagged with elementary_high_p found for reaction {0}, generating ' + 'reactions from RMG families'.format(label)) + rxn = list(db.generate_reactions_from_families(reactants=rxn.reactants, products=rxn.products)) model = CoreEdgeReactionModel() model.verboseComments = True for r in rxn: model.applyKineticsToReaction(r) - - if isinstance(rxn,Reaction): + + if isinstance(rxn, Reaction): reactionDict[label] = rxn else: for i in xrange(len(rxn)): - reactionDict[label+str(i)] = rxn[i] - + reactionDict[label + str(i)] = rxn[i] + return rxn @@ -358,18 +366,20 @@ def network(label, isomers=None, reactants=None, products=None, pathReactions=No """Load a network from an input file""" global networkDict, speciesDict, reactionDict logging.info('Loading network {0}...'.format(label)) - isomers0 = isomers or []; isomers = [] + isomers0 = isomers or [] + isomers = [] for isomer in isomers0: - if isinstance(isomer, (list,tuple)): + if isinstance(isomer, (list, tuple)): raise ValueError('Only one species can be present in a unimolecular isomer.') isomers.append(speciesDict[isomer]) - - reactants0 = reactants or []; reactants = [] + + reactants0 = reactants or [] + reactants = [] for reactant in reactants0: - if not isinstance(reactant, (list,tuple)): + if not isinstance(reactant, (list, tuple)): reactant = [reactant] reactants.append(sorted([speciesDict[spec] for spec in reactant])) - + if pathReactions is None: # Only add reactions that match reactants and/or isomers pathReactions = [] @@ -378,17 +388,20 @@ def network(label, isomers=None, reactants=None, products=None, pathReactions=No # this reaction is not pressure dependent continue reactant_is_isomer = len(rxn.reactants) == 1 and rxn.reactants[0] in isomers - product_is_isomer = len(rxn.products) == 1 and rxn.products[0] in isomers - reactant_is_reactant = any([frozenset(rxn.reactants) == frozenset(reactant_pair) for reactant_pair in reactants]) - product_is_reactant = any([frozenset(rxn.products ) == frozenset(reactant_pair) for reactant_pair in reactants]) + product_is_isomer = len(rxn.products) == 1 and rxn.products[0] in isomers + reactant_is_reactant = any( + [frozenset(rxn.reactants) == frozenset(reactant_pair) for reactant_pair in reactants]) + product_is_reactant = any( + [frozenset(rxn.products) == frozenset(reactant_pair) for reactant_pair in reactants]) if reactant_is_isomer or reactant_is_reactant or product_is_isomer or product_is_reactant: pathReactions.append(rxn) logging.debug('Path reactions {} were found for network {}'.format([rxn.label for rxn in pathReactions], label)) else: - pathReactions0 = pathReactions; pathReactions = [] + pathReactions0 = pathReactions + pathReactions = [] for rxn in pathReactions0: pathReactions.append(reactionDict[rxn]) - + if products is None: # Figure out which configurations are isomers, reactant channels, and product channels products = [] @@ -411,27 +424,29 @@ def network(label, isomers=None, reactants=None, products=None, pathReactions=No elif len(rxn.products) > 1 and rxn.products not in reactants and rxn.products not in products: products.append(rxn.products) else: - products0 = products or []; products = [] + products0 = products or [] + products = [] for product in products0: - if not isinstance(product, (list,tuple)): + if not isinstance(product, (list, tuple)): product = [product] products.append(sorted([speciesDict[spec] for spec in product])) isomers = [Configuration(species) for species in isomers] reactants = [Configuration(*species) for species in reactants] products = [Configuration(*species) for species in products] - - bathGas0 = bathGas or {}; bathGas = {} + + bathGas0 = bathGas or {} + bathGas = {} for spec, fraction in bathGas0.items(): bathGas[speciesDict[spec]] = fraction - + network = Network( - label = label, - isomers = isomers, - reactants = reactants, - products = products, - pathReactions = pathReactions, - bathGas = bathGas, + label=label, + isomers=isomers, + reactants=reactants, + products=products, + pathReactions=pathReactions, + bathGas=bathGas, ) networkDict[label] = network @@ -477,27 +492,26 @@ def pressureDependence(label, Tmin=None, Tmax=None, Tcount=0, Tlist=None, Pmin=N activeKRotor=True, activeJRotor=True, rmgmode=False, sensitivity_conditions=None): """Generate a pressure dependent job""" global jobList, networkDict - + if isinstance(interpolationModel, str): interpolationModel = (interpolationModel,) - + nwk = None if label in networkDict.keys(): nwk = networkDict[label] - - job = PressureDependenceJob(network = nwk, - Tmin=Tmin, Tmax=Tmax, Tcount=Tcount, Tlist=Tlist, - Pmin=Pmin, Pmax=Pmax, Pcount=Pcount, Plist=Plist, - maximumGrainSize=maximumGrainSize, minimumGrainCount=minimumGrainCount, - method=method, interpolationModel=interpolationModel, - activeKRotor=activeKRotor, activeJRotor=activeJRotor, - rmgmode=rmgmode, sensitivity_conditions=sensitivity_conditions) + + job = PressureDependenceJob(network=nwk, Tmin=Tmin, Tmax=Tmax, Tcount=Tcount, Tlist=Tlist, + Pmin=Pmin, Pmax=Pmax, Pcount=Pcount, Plist=Plist, + maximumGrainSize=maximumGrainSize, minimumGrainCount=minimumGrainCount, + method=method, interpolationModel=interpolationModel, + activeKRotor=activeKRotor, activeJRotor=activeJRotor, + rmgmode=rmgmode, sensitivity_conditions=sensitivity_conditions) jobList.append(job) def explorer(source, explore_tol=0.01, energy_tol=np.inf, flux_tol=0.0, bathGas=None, maximumRadicalElectrons=np.inf): """Generate an explorer job""" - global jobList,speciesDict + global jobList, speciesDict for job in jobList: if isinstance(job, PressureDependenceJob): pdepjob = job @@ -508,12 +522,14 @@ def explorer(source, explore_tol=0.01, energy_tol=np.inf, flux_tol=0.0, bathGas= source = [speciesDict[name] for name in source] if bathGas: - bathGas0 = bathGas or {}; bathGas = {} + bathGas0 = bathGas or {} + bathGas = {} for spec, fraction in bathGas0.items(): bathGas[speciesDict[spec]] = fraction - job = ExplorerJob(source=source,pdepjob=pdepjob,explore_tol=explore_tol, - energy_tol=energy_tol,flux_tol=flux_tol,bathGas=bathGas, maximumRadicalElectrons=maximumRadicalElectrons) + job = ExplorerJob(source=source, pdepjob=pdepjob, explore_tol=explore_tol, + energy_tol=energy_tol, flux_tol=flux_tol, bathGas=bathGas, + maximumRadicalElectrons=maximumRadicalElectrons) jobList.append(job) @@ -539,7 +555,7 @@ def loadNecessaryDatabases(): from rmgpy.data.statmech import StatmechDatabase from rmgpy.data.transport import TransportDatabase - #only load if they are not there already. + # only load if they are not there already. try: getDB('transport') getDB('statmech') @@ -547,10 +563,11 @@ def loadNecessaryDatabases(): logging.info("Databases not found. Making databases") db = RMGDatabase() db.statmech = StatmechDatabase() - db.statmech.load(os.path.join(settings['database.directory'],'statmech')) + db.statmech.load(os.path.join(settings['database.directory'], 'statmech')) db.transport = TransportDatabase() - db.transport.load(os.path.join(settings['database.directory'],'transport')) + db.transport.load(os.path.join(settings['database.directory'], 'transport')) + ################################################################################ @@ -561,15 +578,15 @@ def loadInputFile(path): the jobs defined in that file. """ global speciesDict, transitionStateDict, reactionDict, networkDict, jobList - + # Clear module-level variables speciesDict = {} transitionStateDict = {} reactionDict = {} networkDict = {} jobList = [] - - global_context = { '__builtins__': None } + + global_context = {'__builtins__': None} local_context = { '__builtins__': None, 'True': True, @@ -588,7 +605,7 @@ def loadInputFile(path): 'SphericalTopRotor': SphericalTopRotor, 'HarmonicOscillator': HarmonicOscillator, 'HinderedRotor': HinderedRotor, - 'FreeRotor':FreeRotor, + 'FreeRotor': FreeRotor, # Thermo 'ThermoData': ThermoData, 'Wilhoit': Wilhoit, @@ -605,7 +622,7 @@ def loadInputFile(path): 'statmech': statmech, 'thermo': thermo, 'pressureDependence': pressureDependence, - 'explorer':explorer, + 'explorer': explorer, # Miscellaneous 'SMILES': SMILES, 'adjacencyList': adjacencyList, @@ -633,12 +650,12 @@ def loadInputFile(path): use_atom_corrections = local_context.get('useAtomCorrections', True) use_bond_corrections = local_context.get('useBondCorrections', False) atom_energies = local_context.get('atomEnergies', None) - + directory = os.path.dirname(path) - + for rxn in reactionDict.values(): rxn.elementary_high_p = True - + for job in jobList: if isinstance(job, StatMechJob): job.path = os.path.join(directory, job.path) @@ -661,5 +678,5 @@ def loadInputFile(path): job.arkane_species.use_bond_corrections = use_bond_corrections if atom_energies is not None: job.arkane_species.atom_energies = atom_energies - + return jobList, reactionDict, speciesDict, transitionStateDict, networkDict From e2303b514623528cd558480c69bf9527637c9c38 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:16:06 -0400 Subject: [PATCH 14/28] PEP 8 coding style fixes in Arkane kinetics.py --- arkane/kinetics.py | 145 +++++++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 65 deletions(-) diff --git a/arkane/kinetics.py b/arkane/kinetics.py index d95e9728aa..e6cce76558 100644 --- a/arkane/kinetics.py +++ b/arkane/kinetics.py @@ -37,7 +37,7 @@ import string import logging -from rmgpy.kinetics.arrhenius import Arrhenius, ArrheniusEP, PDepArrhenius, MultiArrhenius, MultiPDepArrhenius +from rmgpy.kinetics.arrhenius import Arrhenius, ArrheniusEP, PDepArrhenius, MultiArrhenius, MultiPDepArrhenius from rmgpy.kinetics.chebyshev import Chebyshev from rmgpy.kinetics.falloff import ThirdBody, Lindemann, Troe from rmgpy.kinetics.kineticsdata import KineticsData, PDepKineticsData @@ -50,6 +50,7 @@ from arkane.output import prettify from arkane.common import ArkaneSpecies + ################################################################################ @@ -61,9 +62,9 @@ class KineticsJob(object): `usedTST` - a boolean representing if TST was used to calculate the kinetics if kinetics is already given in the input, then it is False. """ - - def __init__(self, reaction, - Tmin=None, + + def __init__(self, reaction, + Tmin=None, Tmax=None, Tlist=None, Tcount=0, @@ -73,14 +74,14 @@ def __init__(self, reaction, self.Tmin = quantity.Quantity(Tmin) else: self.Tmin = None - + if Tmax is not None: self.Tmax = quantity.Quantity(Tmax) else: self.Tmax = None - + self.Tcount = Tcount - + if Tlist is not None: self.Tlist = quantity.Quantity(Tlist) self.Tmin = quantity.Quantity(numpy.min(self.Tlist.value_si), "K") @@ -88,16 +89,17 @@ def __init__(self, reaction, self.Tcount = len(self.Tlist.value_si) else: if Tmin and Tmax is not None: - + if self.Tcount <= 3.: self.Tcount = 50 - - stepsize = (self.Tmax.value_si-self.Tmin.value_si) / self.Tcount - - self.Tlist = quantity.Quantity(numpy.arange(self.Tmin.value_si, self.Tmax.value_si+stepsize, stepsize),"K") + + stepsize = (self.Tmax.value_si - self.Tmin.value_si) / self.Tcount + + self.Tlist = quantity.Quantity(numpy.arange(self.Tmin.value_si, + self.Tmax.value_si + stepsize, stepsize), 'K') else: self.Tlist = None - + self.reaction = reaction self.kunits = None @@ -107,31 +109,34 @@ def __init__(self, reaction, self.sensitivity_conditions = None self.arkane_species = ArkaneSpecies(species=self.reaction.transitionState) - + @property def Tmin(self): """The minimum temperature at which the computed k(T) values are valid, or ``None`` if not defined.""" return self._Tmin + @Tmin.setter def Tmin(self, value): self._Tmin = quantity.Temperature(value) - + @property def Tmax(self): """The maximum temperature at which the computed k(T) values are valid, or ``None`` if not defined.""" return self._Tmax + @Tmax.setter def Tmax(self, value): self._Tmax = quantity.Temperature(value) - + @property def Tlist(self): """The temperatures at which the k(T) values are computed.""" return self._Tlist + @Tlist.setter def Tlist(self, value): self._Tlist = quantity.Temperature(value) - + def execute(self, outputFile=None, plot=True): """ Execute the kinetics job, saving the results to the given `outputFile` on disk. @@ -150,25 +155,27 @@ def execute(self, outputFile=None, plot=True): sa(self, os.path.dirname(outputFile)) logging.debug('Finished kinetics job for reaction {0}.'.format(self.reaction)) logging.debug(repr(self.reaction)) - - def generateKinetics(self,Tlist=None): + + def generateKinetics(self, Tlist=None): """ Generate the kinetics data for the reaction and fit it to a modified Arrhenius model. """ if isinstance(self.reaction.kinetics, Arrhenius): return None - self.usedTST=True + self.usedTST = True kineticsClass = 'Arrhenius' - + tunneling = self.reaction.transitionState.tunneling if isinstance(tunneling, Wigner) and tunneling.frequency is None: - tunneling.frequency = (self.reaction.transitionState.frequency.value_si,"cm^-1") + tunneling.frequency = (self.reaction.transitionState.frequency.value_si, "cm^-1") elif isinstance(tunneling, Eckart) and tunneling.frequency is None: - tunneling.frequency = (self.reaction.transitionState.frequency.value_si,"cm^-1") - tunneling.E0_reac = (sum([reactant.conformer.E0.value_si for reactant in self.reaction.reactants])*0.001,"kJ/mol") - tunneling.E0_TS = (self.reaction.transitionState.conformer.E0.value_si*0.001,"kJ/mol") - tunneling.E0_prod = (sum([product.conformer.E0.value_si for product in self.reaction.products])*0.001,"kJ/mol") + tunneling.frequency = (self.reaction.transitionState.frequency.value_si, "cm^-1") + tunneling.E0_reac = (sum([reactant.conformer.E0.value_si + for reactant in self.reaction.reactants]) * 0.001, "kJ/mol") + tunneling.E0_TS = (self.reaction.transitionState.conformer.E0.value_si * 0.001, "kJ/mol") + tunneling.E0_prod = (sum([product.conformer.E0.value_si + for product in self.reaction.products]) * 0.001, "kJ/mol") elif tunneling is not None: if tunneling.frequency is not None: # Frequency was given by the user @@ -177,36 +184,37 @@ def generateKinetics(self,Tlist=None): raise ValueError('Unknown tunneling model {0!r} for reaction {1}.'.format(tunneling, self.reaction)) logging.debug('Generating {0} kinetics model for {1}...'.format(kineticsClass, self.reaction)) if Tlist is None: - Tlist = 1000.0/numpy.arange(0.4, 3.35, 0.05) + Tlist = 1000.0 / numpy.arange(0.4, 3.35, 0.05) klist = numpy.zeros_like(Tlist) for i in range(Tlist.shape[0]): klist[i] = self.reaction.calculateTSTRateCoefficient(Tlist[i]) order = len(self.reaction.reactants) - klist *= 1e6 ** (order-1) + klist *= 1e6 ** (order - 1) self.kunits = {1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)'}[order] - self.Kequnits = {2:'mol^2/cm^6', 1:'mol/cm^3', 0:' ', -1:'cm^3/mol', -2:'cm^6/mol^2'}[len(self.reaction.products)-len(self.reaction.reactants)] + self.Kequnits = {2: 'mol^2/cm^6', 1: 'mol/cm^3', 0: ' ', -1: 'cm^3/mol', -2: 'cm^6/mol^2'}[ + len(self.reaction.products) - len(self.reaction.reactants)] self.krunits = {1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)'}[len(self.reaction.products)] self.reaction.kinetics = Arrhenius().fitToData(Tlist, klist, kunits=self.kunits) self.reaction.elementary_high_p = True - + def save(self, outputFile): """ Save the results of the kinetics job to the file located at `path` on disk. """ reaction = self.reaction - + ks = [] k0s = [] k0revs = [] krevs = [] - + logging.info('Saving kinetics for {0}...'.format(reaction)) - + order = len(self.reaction.reactants) - factor = 1e6 ** (order-1) - + factor = 1e6 ** (order - 1) + f = open(outputFile, 'a') if self.usedTST: @@ -214,13 +222,13 @@ def save(self, outputFile): f.write('# ======= =========== =========== =========== ===============\n') f.write('# Temp. k (TST) Tunneling k (TST+T) Units\n') f.write('# ======= =========== =========== =========== ===============\n') - + if self.Tlist is None: - Tlist = numpy.array([300,400,500,600,800,1000,1500,2000]) + Tlist = numpy.array([300, 400, 500, 600, 800, 1000, 1500, 2000]) else: - Tlist =self.Tlist.value_si + Tlist = self.Tlist.value_si - for T in Tlist: + for T in Tlist: tunneling = reaction.transitionState.tunneling reaction.transitionState.tunneling = None try: @@ -231,10 +239,11 @@ def save(self, outputFile): try: k = reaction.calculateTSTRateCoefficient(T) * factor kappa = k / k0 - except (SpeciesError,ZeroDivisionError): + except (SpeciesError, ZeroDivisionError): k = reaction.getRateCoefficient(T) kappa = 0 - logging.info("The species in reaction {} do not have adequate information for TST, using default kinetics values.".format(reaction)) + logging.info("The species in reaction {} do not have adequate information for TST, " + "using default kinetics values.".format(reaction)) tunneling = reaction.transitionState.tunneling ks.append(k) k0s.append(k0) @@ -242,7 +251,7 @@ def save(self, outputFile): f.write('# {0:4g} K {1:11.3e} {2:11g} {3:11.3e} {4}\n'.format(T, k0, kappa, k, self.kunits)) f.write('# ======= =========== =========== =========== ===============\n') f.write('\n\n') - + f.write('# ======= ============ =========== ============ ============= =========\n') f.write('# Temp. Kc (eq) Units krev (TST) krev (TST+T) Units\n') f.write('# ======= ============ =========== ============ ============= =========\n') @@ -253,34 +262,36 @@ def save(self, outputFile): else: keq_unit_converter = 1 - for n,T in enumerate(Tlist): + for n, T in enumerate(Tlist): k = ks[n] k0 = k0s[n] Keq = keq_unit_converter * reaction.getEquilibriumConstant(T) # getEquilibriumConstant returns SI units - k0rev = k0/Keq - krev = k/Keq + k0rev = k0 / Keq + krev = k / Keq k0revs.append(k0rev) krevs.append(krev) - f.write('# {0:4g} K {1:11.3e} {2} {3:11.3e} {4:11.3e} {5}\n'.format(T, Keq, self.Kequnits, k0rev, krev, self.krunits)) + f.write('# {0:4g} K {1:11.3e} {2} {3:11.3e} {4:11.3e} {5}\n'.format(T, Keq, self.Kequnits, + k0rev, krev, + self.krunits)) f.write('# ======= ============ =========== ============ ============= =========\n') f.write('\n\n') kinetics0rev = Arrhenius().fitToData(Tlist, numpy.array(k0revs), kunits=self.krunits) kineticsrev = Arrhenius().fitToData(Tlist, numpy.array(krevs), kunits=self.krunits) - + f.write('# krev (TST) = {0} \n'.format(kinetics0rev)) f.write('# krev (TST+T) = {0} \n\n'.format(kineticsrev)) # Reaction path degeneracy is INCLUDED in the kinetics itself! string = 'kinetics(label={0!r}, kinetics={1!r})'.format(reaction.label, reaction.kinetics) f.write('{0}\n\n'.format(prettify(string))) - + f.close() - + # Also save the result to chem.inp f = open(os.path.join(os.path.dirname(outputFile), 'chem.inp'), 'a') - + reaction = self.reaction kinetics = reaction.kinetics @@ -294,20 +305,20 @@ def save(self, outputFile): kinetics.n.value_si, kinetics.Ea.value_si / 4184., ) - + f.write('{0}\n'.format(string)) - + f.close() # We're saving a YAML file for TSs iff structures of the respective reactant/s and product/s are known - if all ([spc.molecule is not None and len(spc.molecule) - for spc in self.reaction.reactants + self.reaction.products]): + if all([spc.molecule is not None and len(spc.molecule) + for spc in self.reaction.reactants + self.reaction.products]): self.arkane_species.update_species_attributes(self.reaction.transitionState) self.arkane_species.reaction_label = reaction.label self.arkane_species.reactants = [{'label': spc.label, 'adjacency_list': spc.molecule[0].toAdjacencyList()} for spc in self.reaction.reactants] self.arkane_species.products = [{'label': spc.label, 'adjacency_list': spc.molecule[0].toAdjacencyList()} - for spc in self.reaction.products] + for spc in self.reaction.products] self.arkane_species.save_yaml(path=os.path.dirname(outputFile)) def plot(self, outputDirectory): @@ -325,7 +336,7 @@ def plot(self, outputDirectory): if self.Tlist is not None: t_list = [t for t in self.Tlist.value_si] else: - t_list = 1000.0/numpy.arange(0.4, 3.35, 0.05) + t_list = 1000.0 / numpy.arange(0.4, 3.35, 0.05) klist = numpy.zeros_like(t_list) klist2 = numpy.zeros_like(t_list) for i in xrange(len(t_list)): @@ -333,8 +344,8 @@ def plot(self, outputDirectory): klist2[i] = self.reaction.kinetics.getRateCoefficient(t_list[i]) order = len(self.reaction.reactants) - klist *= 1e6 ** (order-1) - klist2 *= 1e6 ** (order-1) + klist *= 1e6 ** (order - 1) + klist2 *= 1e6 ** (order - 1) t_list = [1000.0 / t for t in t_list] plt.semilogy(t_list, klist, 'ob', label='TST calculation') plt.semilogy(t_list, klist2, '-k', label='Fitted rate') @@ -404,7 +415,8 @@ def __init__(self, options=None): 'TSwidth': 16, 'E0offset': 0.0, } - if options: self.options.update(options) + if options: + self.options.update(options) self.clear() def clear(self): @@ -486,7 +498,8 @@ def __getLabelSize(self, configuration, format='pdf'): plusRect = self.__getTextSize('+', format=format) for rect in boundingRects: - if width < rect[2]: width = rect[2] + if width < rect[2]: + width = rect[2] height += rect[3] + plusRect[3] height -= plusRect[3] @@ -564,9 +577,8 @@ def draw(self, reaction, format, path=None): # Choose multiplier to convert energies to desired units (on figure only) Eunits = self.options['Eunits'] try: - Emult = \ - {'J/mol': 1.0, 'kJ/mol': 0.001, 'cal/mol': 1.0 / 4.184, 'kcal/mol': 1.0 / 4184., 'cm^-1': 1.0 / 11.962}[ - Eunits] + Emult = {'J/mol': 1.0, 'kJ/mol': 0.001, 'cal/mol': 1.0 / 4.184, 'kcal/mol': 1.0 / 4184., + 'cm^-1': 1.0 / 11.962}[Eunits] except KeyError: raise Exception('Invalid value "{0}" for Eunits parameter.'.format(Eunits)) @@ -598,7 +610,8 @@ def draw(self, reaction, format, path=None): for i in range(len(self.wells)): l, t, w, h = labelRects[i] x, y = coordinates[i, :] - if w < wellWidth: w = wellWidth + if w < wellWidth: + w = wellWidth t -= 6 + Eheight h += 6 + Eheight wellRects.append([l + x - 0.5 * w, t + y + 6, w, h]) @@ -748,7 +761,7 @@ def draw(self, reaction, format, path=None): E0 = well.E0 * 0.001 - E0_offset E0 = "{0:.1f}".format(E0 * 1000. * Emult) extents = cr.text_extents(E0) - x = x0 - extents[2] / 2.0; + x = x0 - extents[2] / 2.0 y = y0 - 6.0 cr.rectangle(x + extents[0] - 2.0, y + extents[1] - 2.0, extents[2] + 4.0, extents[3] + 4.0) cr.set_source_rgba(1.0, 1.0, 1.0, 0.75) @@ -770,12 +783,14 @@ def draw(self, reaction, format, path=None): else: surface.finish() + class Well: """ A helper class representing a "well" of species `species_list` is a list of at least one entry `E0 `is the sum of all species' E0 in that list """ + def __init__(self, species_list): self.species_list = species_list self.E0 = sum([species.conformer.E0.value_si for species in species_list]) From 01e944f4802fabe870638f4e8d3a7e90b7f4efbf Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:16:20 -0400 Subject: [PATCH 15/28] PEP 8 coding style fixes in Arkane log.py --- arkane/log.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arkane/log.py b/arkane/log.py index 9f097deec4..2b88f3be37 100644 --- a/arkane/log.py +++ b/arkane/log.py @@ -38,11 +38,13 @@ from rmgpy.qm.qmdata import QMData from rmgpy.qm.symmetry import PointGroupCalculator + class Log(object): """ Represent a general log file. The attribute `path` refers to the location on disk of the log file of interest. """ + def __init__(self, path): self.path = path @@ -116,7 +118,8 @@ def get_optical_isomers_and_symmetry_number(self): """ coordinates, atom_numbers, _ = self.loadGeometry() unique_id = '0' # Just some name that the SYMMETRY code gives to one of its jobs - scr_dir = os.path.join(os.path.abspath('.'), str('scratch')) # Scratch directory that the SYMMETRY code writes its files in + # Scratch directory that the SYMMETRY code writes its files in: + scr_dir = os.path.join(os.path.abspath('.'), str('scratch')) if not os.path.exists(scr_dir): os.makedirs(scr_dir) try: @@ -127,15 +130,20 @@ def get_optical_isomers_and_symmetry_number(self): atomCoords=(coordinates, str('angstrom')), energy=(0.0, str('kcal/mol')) # Only needed to avoid error ) - settings = type(str(''), (), dict(symmetryPath=str('symmetry'), scratchDirectory=scr_dir))() # Creates anonymous class + # Dynamically create custom class to store the settings needed for the point group calculation + # Normally, it expects an rmgpy.qm.main.QMSettings object, but we don't need all of those settings + settings = type(str(''), (), + dict(symmetryPath=str('symmetry'), scratchDirectory=scr_dir))() pgc = PointGroupCalculator(settings, unique_id, qmdata) pg = pgc.calculate() if pg is not None: optical_isomers = 2 if pg.chiral else 1 symmetry = pg.symmetryNumber - logging.debug("Symmetry algorithm found {0} optical isomers and a symmetry number of {1}".format(optical_isomers,symmetry)) + logging.debug("Symmetry algorithm found {0} optical isomers and a symmetry number of {1}".format( + optical_isomers, symmetry)) else: - logging.error("Symmetry algorithm errored when computing point group\nfor log file located at{0}.\nManually provide values in Arkane input.".format(self.path)) + logging.error('Symmetry algorithm errored when computing point group\nfor log file located at{0}.\n' + 'Manually provide values in Arkane input.'.format(self.path)) return optical_isomers, symmetry finally: shutil.rmtree(scr_dir) From 66e42ef944a7c9719d5e9bb933717eff573e5ffb Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:16:40 -0400 Subject: [PATCH 16/28] PEP 8 coding style fixes in Arkane main.py --- arkane/main.py | 162 ++++++++++++++++++++++++++----------------------- 1 file changed, 86 insertions(+), 76 deletions(-) diff --git a/arkane/main.py b/arkane/main.py index 578eea4a20..350e135583 100644 --- a/arkane/main.py +++ b/arkane/main.py @@ -39,8 +39,10 @@ import argparse import time import csv + try: import matplotlib + matplotlib.rc('mathtext', default='regular') except ImportError: pass @@ -59,6 +61,7 @@ from arkane.explorer import ExplorerJob from arkane.common import is_pdep + ################################################################################ @@ -85,55 +88,56 @@ class Arkane: You can also populate the attributes from the command line using the :meth:`parseCommandLineArguments()` method before running :meth:`execute()`. """ - + def __init__(self, inputFile=None, outputDirectory=None, verbose=logging.INFO): self.jobList = [] self.inputFile = inputFile self.outputDirectory = outputDirectory self.verbose = verbose - + def parseCommandLineArguments(self): """ Parse the command-line arguments being passed to Arkane. This uses the :mod:`argparse` module, which ensures that the command-line arguments are sensible, parses them, and returns them. """ - - parser = argparse.ArgumentParser(description= - """ - Arkane is a Python toolkit for computing chemical reaction rates and other - properties used in detailed kinetics models using various methodologies - and theories. + + parser = argparse.ArgumentParser(description=""" + Arkane is a Python toolkit for computing chemical reaction rates + and other properties used in detailed kinetics models + using various methodologies and theories. """) - parser.add_argument('file', metavar='FILE', type=str, nargs=1, - help='a file describing the job to execute') - + parser.add_argument('file', metavar='FILE', type=str, nargs=1, help='a file describing the job to execute') + # Options for controlling the amount of information printed to the console # By default a moderate level of information is printed; you can either # ask for less (quiet), more (verbose), or much more (debug) group = parser.add_mutually_exclusive_group() - group.add_argument('-q', '--quiet', action='store_const', const=logging.WARNING, default=logging.INFO, dest='verbose', help='only print warnings and errors') - group.add_argument('-v', '--verbose', action='store_const', const=logging.DEBUG, default=logging.INFO, dest='verbose', help='print more verbose output') - group.add_argument('-d', '--debug', action='store_const', const=0, default=logging.INFO, dest='verbose', help='print debug information') - + group.add_argument('-q', '--quiet', action='store_const', const=logging.WARNING, default=logging.INFO, + dest='verbose', help='only print warnings and errors') + group.add_argument('-v', '--verbose', action='store_const', const=logging.DEBUG, default=logging.INFO, + dest='verbose', help='print more verbose output') + group.add_argument('-d', '--debug', action='store_const', const=0, default=logging.INFO, dest='verbose', + help='print debug information') + # Add options for controlling what directories files are written to parser.add_argument('-o', '--output-directory', type=str, nargs=1, default='', - metavar='DIR', help='use DIR as output directory') + metavar='DIR', help='use DIR as output directory') # Add options for controlling generation of plots parser.add_argument('-p', '--plot', action='store_true', default=True, help='generate plots of results') args = parser.parse_args() - + # Extract the input file - self.inputFile = args.file[0] - + self.inputFile = args.file[0] + # Extract the log verbosity self.verbose = args.verbose - + # Extract the plot settings self.plot = args.plot - + # Determine the output directory # By default the directory containing the input file is used, unless an # alternate directory is specified using the -o flag @@ -141,7 +145,7 @@ def parseCommandLineArguments(self): self.outputDirectory = os.path.abspath(args.output_directory[0]) else: self.outputDirectory = os.path.dirname(os.path.abspath(args.file[0])) - + def initializeLog(self, verbose=logging.INFO, logFile=None): """ Set up a logger for Arkane to use to print output to stdout. The @@ -151,7 +155,7 @@ def initializeLog(self, verbose=logging.INFO, logFile=None): # Create logger logger = logging.getLogger() logger.setLevel(verbose) - + # Use custom level names for cleaner log output logging.addLevelName(logging.CRITICAL, 'Critical: ') logging.addLevelName(logging.ERROR, 'Error: ') @@ -159,27 +163,27 @@ def initializeLog(self, verbose=logging.INFO, logFile=None): logging.addLevelName(logging.INFO, '') logging.addLevelName(logging.DEBUG, '') logging.addLevelName(0, '') - + # Create formatter and add to handlers formatter = logging.Formatter('%(levelname)s%(message)s') - + # Remove old handlers before adding ours while logger.handlers: logger.removeHandler(logger.handlers[0]) - + # Create console handler; send everything to stdout rather than stderr ch = logging.StreamHandler(sys.stdout) ch.setLevel(verbose) ch.setFormatter(formatter) logger.addHandler(ch) - + # Create file handler; always be at least verbose in the file if logFile: fh = logging.FileHandler(filename=logFile) - fh.setLevel(min(logging.DEBUG,verbose)) + fh.setLevel(min(logging.DEBUG, verbose)) fh.setFormatter(formatter) logger.addHandler(fh) - + def logHeader(self, level=logging.INFO): """ Output a header containing identifying information about Arkane to the log. @@ -187,7 +191,7 @@ def logHeader(self, level=logging.INFO): from rmgpy import __version__ logging.log(level, 'Arkane execution initiated at {0}'.format(time.asctime())) logging.log(level, '') - + logging.log(level, '################################################################') logging.log(level, '# #') logging.log(level, '# Automated Reaction Kinetics and Network Exploration (Arkane) #') @@ -200,7 +204,7 @@ def logHeader(self, level=logging.INFO): logging.log(level, '# #') logging.log(level, '################################################################') logging.log(level, '') - + def logFooter(self, level=logging.INFO): """ Output a footer to the log. @@ -214,27 +218,28 @@ def loadInputFile(self, inputFile): loaded set of jobs as a list. """ self.inputFile = inputFile - self.jobList, self.reactionDict, self.speciesDict, self.transitionStateDict, self.networkDict = loadInputFile(self.inputFile) + self.jobList, self.reactionDict, self.speciesDict, self.transitionStateDict, self.networkDict = loadInputFile( + self.inputFile) logging.info('') return self.jobList - + def execute(self): """ Execute, in order, the jobs found in input file specified by the `inputFile` attribute. """ - + # Initialize the logging system (both to the console and to a file in the # output directory) self.initializeLog(self.verbose, os.path.join(self.outputDirectory, 'arkane.log')) - + # Print some information to the beginning of the log self.logHeader() - + # Load the input file for the job self.jobList = self.loadInputFile(self.inputFile) logging.info('') - + # Initialize (and clear!) the output files for the job if self.outputDirectory is None: self.outputDirectory = os.path.dirname(os.path.abspath(self.inputFile)) @@ -246,12 +251,12 @@ def execute(self): # write the chemkin files and run the thermo and then kinetics jobs with open(chemkinFile, 'w') as f: writeElementsSection(f) - + f.write('SPECIES\n\n') # write each species in species block for job in self.jobList: - if isinstance(job,ThermoJob): + if isinstance(job, ThermoJob): f.write(job.species.toChemkin()) f.write('\n') @@ -276,7 +281,7 @@ def execute(self): supporting_info_file = os.path.join(self.outputDirectory, 'supporting_information.csv') with open(supporting_info_file, 'wb') as csvfile: writer = csv.writer(csvfile, delimiter=',', quotechar='"', quoting=csv.QUOTE_MINIMAL) - writer.writerow(['Label','Rotational constant (cm-1)','Unscaled frequencies (cm-1)']) + writer.writerow(['Label', 'Rotational constant (cm-1)', 'Unscaled frequencies (cm-1)']) for row in supporting_info: label = row[0] rot = '-' @@ -295,82 +300,87 @@ def execute(self): # run kinetics and pdep jobs (also writes reaction blocks to Chemkin file) for job in self.jobList: - if isinstance(job,KineticsJob): + if isinstance(job, KineticsJob): job.execute(outputFile=outputFile, plot=self.plot) - elif isinstance(job, PressureDependenceJob) and not any([isinstance(job,ExplorerJob) for job in self.jobList]): #if there is an explorer job the pdep job will be run in the explorer job + elif isinstance(job, PressureDependenceJob) and not any([isinstance(job, ExplorerJob) for job in + self.jobList]): + # if there is an explorer job the pdep job will be run in the explorer job if job.network is None: - raise InputError('No network matched the label of the pressureDependence block and there is no explorer block to generate a network') + raise InputError( + 'No network matched the label of the pressureDependence block and there is no explorer block ' + 'to generate a network') job.execute(outputFile=outputFile, plot=self.plot) elif isinstance(job, ExplorerJob): - thermoLibrary,kineticsLibrary,speciesList = self.getLibraries() - job.execute(outputFile=outputFile, plot=self.plot, speciesList=speciesList, thermoLibrary=thermoLibrary, kineticsLibrary=kineticsLibrary) + thermoLibrary, kineticsLibrary, speciesList = self.getLibraries() + job.execute(outputFile=outputFile, plot=self.plot, speciesList=speciesList, thermoLibrary=thermoLibrary, + kineticsLibrary=kineticsLibrary) with open(chemkinFile, 'a') as f: f.write('END\n\n') # Print some information to the end of the log self.logFooter() - + def getLibraries(self): """Get RMG kinetics and thermo libraries""" name = 'kineticsjobs' - + speciesList = self.speciesDict.values() reactionList = self.reactionDict.values() # remove duplicate species for rxn in reactionList: - for i,rspc in enumerate(rxn.reactants): + for i, rspc in enumerate(rxn.reactants): for spc in speciesList: if spc.isIsomorphic(rspc): rxn.reactants[i] = spc break - for i,rspc in enumerate(rxn.products): + for i, rspc in enumerate(rxn.products): for spc in speciesList: if spc.isIsomorphic(rspc): rxn.products[i] = spc break del_inds = [] - for i,spc1 in enumerate(speciesList): - for j,spc2 in enumerate(speciesList): - if j>i and spc1.isIsomorphic(spc2): + for i, spc1 in enumerate(speciesList): + for j, spc2 in enumerate(speciesList): + if j > i and spc1.isIsomorphic(spc2): del_inds.append(j) - + for j in sorted(del_inds)[::-1]: del speciesList[j] - + thermoLibrary = ThermoLibrary(name=name) - for i,species in enumerate(speciesList): + for i, species in enumerate(speciesList): if species.thermo: - thermoLibrary.loadEntry(index = i + 1, - label = species.label, - molecule = species.molecule[0].toAdjacencyList(), - thermo = species.thermo, - shortDesc = species.thermo.comment - ) + thermoLibrary.loadEntry(index=i + 1, + label=species.label, + molecule=species.molecule[0].toAdjacencyList(), + thermo=species.thermo, + shortDesc=species.thermo.comment) else: - logging.warning('Species {0} did not contain any thermo data and was omitted from the thermo library.'.format(str(species))) + logging.warning( + 'Species {0} did not contain any thermo data and was omitted from the thermo library.'.format( + str(species))) # load kinetics library entries - kineticsLibrary = KineticsLibrary(name=name,autoGenerated=True) + kineticsLibrary = KineticsLibrary(name=name, autoGenerated=True) kineticsLibrary.entries = {} - for i,reaction in enumerate(reactionList): + for i, reaction in enumerate(reactionList): entry = Entry( - index = i+1, - label = reaction.toLabeledStr(), - item = reaction, - data = reaction.kinetics, - ) + index=i + 1, + label=reaction.toLabeledStr(), + item=reaction, + data=reaction.kinetics) if reaction.kinetics is not None: - if hasattr(reaction,'library') and reaction.library: - entry.longDesc = 'Originally from reaction library: ' +\ + if hasattr(reaction, 'library') and reaction.library: + entry.longDesc = 'Originally from reaction library: ' + \ reaction.library + "\n" + reaction.kinetics.comment else: entry.longDesc = reaction.kinetics.comment - - kineticsLibrary.entries[i+1] = entry - + + kineticsLibrary.entries[i + 1] = entry + kineticsLibrary.label = name - - return thermoLibrary,kineticsLibrary,speciesList + + return thermoLibrary, kineticsLibrary, speciesList From a2fb559250ec8c449017282020c630104d446910 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:16:53 -0400 Subject: [PATCH 17/28] PEP 8 coding style fixes in Arkane output.py --- arkane/output.py | 47 ++++++++++++++++++++++++++--------------------- 1 file changed, 26 insertions(+), 21 deletions(-) diff --git a/arkane/output.py b/arkane/output.py index 227656efb5..5c2106b8be 100644 --- a/arkane/output.py +++ b/arkane/output.py @@ -33,7 +33,8 @@ """ import ast - + + ################################################################################ @@ -43,38 +44,39 @@ class PrettifyVisitor(ast.NodeVisitor): version of the code used to create the tree. Used by the :func:`prettify` function. """ - + def __init__(self, level=0, indent=4): self.string = '' self.level = level self.indent = indent - + def visit_Call(self, node): """ Return a pretty representation of the class or function call represented by `node`. """ result = node.func.id + '(\n' - + keywords = [] for keyword in node.keywords: keywords.append('{0}={1}'.format(keyword.arg, self.visit(keyword.value))) - result = '{0}({1})'.format(node.func.id, ', '.join(keywords)) - + result = '{0}({1})'.format(node.func.id, ', '.join(keywords)) + if len(result) > 80: result = node.func.id + '(\n' - + self.level += 1 for keyword in node.keywords: - result += '{2}{0} = {1},\n'.format(keyword.arg, self.visit(keyword.value), ' ' * (self.level * self.indent)) + result += '{2}{0} = {1},\n'.format(keyword.arg, self.visit(keyword.value), + ' ' * (self.level * self.indent)) self.level -= 1 result += ' ' * (self.level * self.indent) + ')' - + self.string = result - + return result - + def visit_List(self, node): """ Return a pretty representation of the list represented by `node`. @@ -93,19 +95,19 @@ def visit_List(self, node): result = '[{0}]'.format(', '.join([self.visit(e) for e in node.elts])) self.string = result return result - + def visit_Tuple(self, node): """ Return a pretty representation of the tuple represented by `node`. """ # If the tuple represents a quantity, keep it on one line isQuantity = True - if len(node.elts) == 0 or not isinstance(node.elts[0], (ast.Num,ast.List)) or ( - isinstance(node.elts[0], ast.List) and any([not isinstance(e, ast.Num) for e in node.elts[0].elts])): + if len(node.elts) == 0 or not isinstance(node.elts[0], (ast.Num, ast.List)) or ( + isinstance(node.elts[0], ast.List) and any([not isinstance(e, ast.Num) for e in node.elts[0].elts])): isQuantity = False elif len(node.elts) < 2 or not isinstance(node.elts[1], ast.Str): isQuantity = False - + if not isQuantity: # Split elements onto multiple lines result = '(\n' @@ -120,12 +122,13 @@ def visit_Tuple(self, node): result = '({0})'.format(', '.join([self.visit(e) for e in node.elts])) self.string = result return result - + 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 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])): # Split elements onto multiple lines result = '{\n' self.level += 1 @@ -137,10 +140,11 @@ def visit_Dict(self, node): return result else: # Keep elements on one line - result = '{{{0}}}'.format(', '.join(['{0}: {1}'.format(self.visit(key), self.visit(value)) for key, value in zip(node.keys, node.values)])) + result = '{{{0}}}'.format(', '.join(['{0}: {1}'.format(self.visit(key), self.visit(value)) + for key, value in zip(node.keys, node.values)])) self.string = result return result - + def visit_Str(self, node): """ Return a pretty representation of the string represented by `node`. @@ -148,16 +152,17 @@ def visit_Str(self, node): result = repr(node.s) self.string = result return result - + def visit_Num(self, node): """ Return a pretty representation of the number represented by `node`. """ result = '{0:g}'.format(node.n) - #result = repr(node.n) + # result = repr(node.n) self.string = result return result + def prettify(string, indent=4): """ Return a "pretty" version of the given `string`, representing a snippet of From 064ce4415cfadb5e9e8eef83c69f3aad7f87848f Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:17:16 -0400 Subject: [PATCH 18/28] PEP 8 coding style fixes in Arkane pdep.py --- arkane/pdep.py | 305 ++++++++++++++++++++++++++----------------------- 1 file changed, 160 insertions(+), 145 deletions(-) diff --git a/arkane/pdep.py b/arkane/pdep.py index 2c0092947b..a5ab5f74b1 100644 --- a/arkane/pdep.py +++ b/arkane/pdep.py @@ -50,6 +50,7 @@ from arkane.output import prettify from arkane.sensitivity import PDepSensitivity as sa + ################################################################################ @@ -100,22 +101,22 @@ class PressureDependenceJob(object): RMG mode should be turned off by default except in RMG jobs. """ - - def __init__(self, network, - Tmin=None, Tmax=None, Tcount=0, Tlist=None, - Pmin=None, Pmax=None, Pcount=0, Plist=None, - maximumGrainSize=None, minimumGrainCount=0, - method=None, interpolationModel=None, maximumAtoms=None, - activeKRotor=True, activeJRotor=True, rmgmode=False, sensitivity_conditions=None): + + def __init__(self, network, + Tmin=None, Tmax=None, Tcount=0, Tlist=None, + Pmin=None, Pmax=None, Pcount=0, Plist=None, + maximumGrainSize=None, minimumGrainCount=0, + method=None, interpolationModel=None, maximumAtoms=None, + activeKRotor=True, activeJRotor=True, rmgmode=False, sensitivity_conditions=None): self.network = network - + self.Tmin = Tmin self.Tmax = Tmax self.Tcount = Tcount if Tlist is not None: self.Tlist = Tlist - self.Tmin = (numpy.min(self.Tlist.value_si),"K") - self.Tmax = (numpy.max(self.Tlist.value_si),"K") + self.Tmin = (numpy.min(self.Tlist.value_si), "K") + self.Tmax = (numpy.max(self.Tlist.value_si), "K") self.Tcount = len(self.Tlist.value_si) else: self.Tlist = None @@ -125,8 +126,8 @@ def __init__(self, network, self.Pcount = Pcount if Plist is not None: self.Plist = Plist - self.Pmin = (numpy.min(self.Plist.value_si)*1e-5,"bar") - self.Pmax = (numpy.max(self.Plist.value_si)*1e-5,"bar") + self.Pmin = (numpy.min(self.Plist.value_si) * 1e-5, "bar") + self.Pmax = (numpy.max(self.Plist.value_si) * 1e-5, "bar") self.Pcount = len(self.Plist.value_si) else: self.Plist = None @@ -136,11 +137,11 @@ def __init__(self, network, self.Emin = None self.Emax = None self.Elist = None - + self.method = method self.interpolationModel = interpolationModel self.maximumAtoms = maximumAtoms - + self.activeKRotor = activeKRotor self.activeJRotor = activeJRotor self.rmgmode = rmgmode @@ -152,56 +153,62 @@ def __init__(self, network, for condition in sensitivity_conditions] else: self.sensitivity_conditions = None - + if self.Tlist is None and self.Tmin is not None and self.Tmax is not None and self.Tcount is not None: self.generateTemperatureList() if self.Plist is None and self.Pmin is not None and self.Pmax is not None and self.Pcount is not None: self.generatePressureList() - + @property def Tmin(self): """The minimum temperature at which the computed k(T,P) values are valid, or ``None`` if not defined.""" return self._Tmin + @Tmin.setter def Tmin(self, value): self._Tmin = quantity.Temperature(value) - + @property def Tmax(self): """The maximum temperature at which the computed k(T,P) values are valid, or ``None`` if not defined.""" return self._Tmax + @Tmax.setter def Tmax(self, value): self._Tmax = quantity.Temperature(value) - + @property def Tlist(self): """The temperatures at which the k(T,P) values are computed.""" return self._Tlist + @Tlist.setter def Tlist(self, value): self._Tlist = quantity.Temperature(value) - + @property def Pmin(self): """The minimum pressure at which the computed k(T,P) values are valid, or ``None`` if not defined.""" return self._Pmin + @Pmin.setter def Pmin(self, value): self._Pmin = quantity.Pressure(value) - + @property def Pmax(self): """The maximum pressure at which the computed k(T,P) values are valid, or ``None`` if not defined.""" return self._Pmax + @Pmax.setter def Pmax(self, value): self._Pmax = quantity.Pressure(value) - + @property def Plist(self): """The pressures at which the k(T,P) values are computed.""" return self._Plist + @Plist.setter def Plist(self, value): self._Plist = quantity.Pressure(value) @@ -210,6 +217,7 @@ def Plist(self, value): def maximumGrainSize(self): """The maximum allowed energy grain size, or ``None`` if not defined.""" return self._maximumGrainSize + @maximumGrainSize.setter def maximumGrainSize(self, value): self._maximumGrainSize = quantity.Energy(value) @@ -219,22 +227,22 @@ def copy(self): Return a copy of the pressure dependence job. """ return PressureDependenceJob( - network = self.network, - Tmin = self.Tmax, - Tmax = self.Tmax, - Tcount = self.Tcount, - Tlist = self.Tlist, - Pmin = self.Pmin, - Pmax = self.Pmax, - Pcount = self.Pcount, - Plist = self.Plist, - maximumGrainSize = self.maximumGrainSize, - minimumGrainCount = self.minimumGrainCount, - method = self.method, - interpolationModel = self.interpolationModel, - activeKRotor = self.activeKRotor, - activeJRotor = self.activeJRotor, - rmgmode = self.rmgmode, + network=self.network, + Tmin=self.Tmax, + Tmax=self.Tmax, + Tcount=self.Tcount, + Tlist=self.Tlist, + Pmin=self.Pmin, + Pmax=self.Pmax, + Pcount=self.Pcount, + Plist=self.Plist, + maximumGrainSize=self.maximumGrainSize, + minimumGrainCount=self.minimumGrainCount, + method=self.method, + interpolationModel=self.interpolationModel, + activeKRotor=self.activeKRotor, + activeJRotor=self.activeJRotor, + rmgmode=self.rmgmode, ) def execute(self, outputFile, plot, format='pdf', print_summary=True): @@ -248,17 +256,20 @@ def execute(self, outputFile, plot, format='pdf', print_summary=True): for reaction in self.network.pathReactions: transitionState = reaction.transitionState if transitionState.conformer and transitionState.conformer.E0 is None: - transitionState.conformer.E0 = (sum([spec.conformer.E0.value_si for spec in reaction.reactants]) + reaction.kinetics.Ea.value_si,"J/mol") + transitionState.conformer.E0 = (sum([spec.conformer.E0.value_si for spec in reaction.reactants]) + + reaction.kinetics.Ea.value_si, 'J/mol') logging.info('Approximated transitions state E0 for reaction {3} from kinetics ' - 'A={0}, n={1}, Ea={2} J/mol'.format(reaction.kinetics.A.value_si,reaction.kinetics.n.value_si,reaction.kinetics.Ea.value_si,reaction.label)) + 'A={0}, n={1}, Ea={2} J/mol'.format(reaction.kinetics.A.value_si, + reaction.kinetics.n.value_si, + reaction.kinetics.Ea.value_si, reaction.label)) if print_summary: self.network.printSummary() - + if outputFile is not None: self.draw(os.path.dirname(outputFile), format) - + self.initialize() - + self.K = self.network.calculateRateCoefficients(self.Tlist.value_si, self.Plist.value_si, self.method) self.fitInterpolationModels() @@ -276,7 +287,7 @@ def execute(self, outputFile, plot, format='pdf', print_summary=True): except (InvalidMicrocanonicalRateError, ModifiedStrongCollisionError) as exept: logging.warn("Could not complete the sensitivity analysis with a perturbation of {0}" " kcal/mol, trying {1} kcal/mol instead.".format( - perturbation, perturbation / 2.0)) + perturbation, perturbation / 2.0)) perturbation /= 2.0 else: break @@ -308,16 +319,16 @@ def generateTemperatureList(self): # Distribute temperatures on a Gauss-Chebyshev grid Tlist = numpy.zeros(Tcount, numpy.float64) for i in range(Tcount): - T = -math.cos((2*i+1) * math.pi / (2*self.Tcount)) - T = 2.0 / ((1.0/Tmax - 1.0/Tmin) * T + 1.0/Tmax + 1.0/Tmin) + T = -math.cos((2 * i + 1) * math.pi / (2 * self.Tcount)) + T = 2.0 / ((1.0 / Tmax - 1.0 / Tmin) * T + 1.0 / Tmax + 1.0 / Tmin) Tlist[i] = T - self.Tlist = (Tlist,"K") + self.Tlist = (Tlist, "K") else: # Distribute temperatures evenly on a T^-1 domain - Tlist = 1.0/numpy.linspace(1.0/Tmax, 1.0/Tmin, Tcount) - self.Tlist = (Tlist,"K") + Tlist = 1.0 / numpy.linspace(1.0 / Tmax, 1.0 / Tmin, Tcount) + self.Tlist = (Tlist, "K") return self.Tlist.value_si - + def initialize(self): """Initialize a PressureDependenceJob""" for reaction in self.network.pathReactions: @@ -329,12 +340,14 @@ def initialize(self): frequencies/quantum file""".format(reaction.label)) # add tunneling parameters if isinstance(tunneling, Wigner) and tunneling.frequency is None: - tunneling.frequency = (reaction.transitionState.frequency.value_si,"cm^-1") + tunneling.frequency = (reaction.transitionState.frequency.value_si, "cm^-1") elif isinstance(tunneling, Eckart) and tunneling.frequency is None: - tunneling.frequency = (reaction.transitionState.frequency.value_si,"cm^-1") - tunneling.E0_reac = (sum([reactant.conformer.E0.value_si for reactant in reaction.reactants])*0.001,"kJ/mol") - tunneling.E0_TS = (reaction.transitionState.conformer.E0.value_si*0.001,"kJ/mol") - tunneling.E0_prod = (sum([product.conformer.E0.value_si for product in reaction.products])*0.001,"kJ/mol") + tunneling.frequency = (reaction.transitionState.frequency.value_si, "cm^-1") + tunneling.E0_reac = (sum([reactant.conformer.E0.value_si + for reactant in reaction.reactants]) * 0.001, "kJ/mol") + tunneling.E0_TS = (reaction.transitionState.conformer.E0.value_si * 0.001, "kJ/mol") + tunneling.E0_prod = (sum([product.conformer.E0.value_si + for product in reaction.products]) * 0.001, "kJ/mol") elif tunneling is not None: if tunneling.frequency is not None: # Frequency was given by the user @@ -343,22 +356,22 @@ def initialize(self): raise ValueError('Unknown tunneling model {0!r} for path reaction {1}.'.format(tunneling, reaction)) maximumGrainSize = self.maximumGrainSize.value_si if self.maximumGrainSize is not None else 0.0 - + self.network.initialize( - Tmin = self.Tmin.value_si, - Tmax = self.Tmax.value_si, - Pmin = self.Pmin.value_si, - Pmax = self.Pmax.value_si, - maximumGrainSize = maximumGrainSize, - minimumGrainCount = self.minimumGrainCount, - activeJRotor = self.activeJRotor, - activeKRotor = self.activeKRotor, - rmgmode = self.rmgmode, + Tmin=self.Tmin.value_si, + Tmax=self.Tmax.value_si, + Pmin=self.Pmin.value_si, + Pmax=self.Pmax.value_si, + maximumGrainSize=maximumGrainSize, + minimumGrainCount=self.minimumGrainCount, + activeJRotor=self.activeJRotor, + activeKRotor=self.activeKRotor, + rmgmode=self.rmgmode, ) self.generateTemperatureList() self.generatePressureList() - + def generatePressureList(self): """ Returns an array of pressures based on the interpolation `model`, @@ -378,14 +391,14 @@ def generatePressureList(self): # Distribute pressures on a Gauss-Chebyshev grid Plist = numpy.zeros(Pcount, numpy.float64) for i in range(Pcount): - P = -math.cos((2*i+1) * math.pi / (2*self.Pcount)) - P = 10**(0.5 * ((math.log10(Pmax) - math.log10(Pmin)) * P + math.log10(Pmax) + math.log10(Pmin))) + P = -math.cos((2 * i + 1) * math.pi / (2 * self.Pcount)) + P = 10 ** (0.5 * ((math.log10(Pmax) - math.log10(Pmin)) * P + math.log10(Pmax) + math.log10(Pmin))) Plist[i] = P - self.Plist = (Plist*1e-5,"bar") + self.Plist = (Plist * 1e-5, "bar") else: # Distribute pressures evenly on a log domain Plist = 10.0 ** numpy.linspace(math.log10(Pmin), math.log10(Pmax), Pcount) - self.Plist = (Plist*1e-5,"bar") + self.Plist = (Plist * 1e-5, "bar") return self.Plist.value_si def fitInterpolationModels(self): @@ -394,62 +407,61 @@ def fitInterpolationModels(self): configurations.extend(self.network.isomers) configurations.extend(self.network.reactants) configurations.extend(self.network.products) - + self.network.netReactions = [] - + Nreac = self.network.Nisom + self.network.Nreac Nprod = Nreac + self.network.Nprod - + Tmin = self.Tmin.value_si Tmax = self.Tmax.value_si Tdata = self.Tlist.value_si Pmin = self.Pmin.value_si Pmax = self.Pmax.value_si Pdata = self.Plist.value_si - + for prod in range(Nprod): for reac in range(Nreac): - if reac == prod: continue - reaction = Reaction( - reactants = configurations[reac].species, - products = configurations[prod].species, - ) - - kdata = self.K[:,:,prod,reac].copy() + if reac == prod: + continue + reaction = Reaction(reactants=configurations[reac].species, + products=configurations[prod].species) + + kdata = self.K[:, :, prod, reac].copy() order = len(reaction.reactants) - kdata *= 1e6 ** (order-1) + kdata *= 1e6 ** (order - 1) kunits = {1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)'}[order] logging.debug('Fitting master eqn data to kinetics for reaction {}.'.format(reaction)) reaction.kinetics = self.fitInterpolationModel(Tdata, Pdata, kdata, kunits) - + self.network.netReactions.append(reaction) - + def fitInterpolationModel(self, Tdata, Pdata, kdata, kunits): """Fit an interpolation model to a pressure dependent rate""" Tmin = self.Tmin.value_si Tmax = self.Tmax.value_si Pmin = self.Pmin.value_si Pmax = self.Pmax.value_si - + model = self.interpolationModel[0].lower() - + if model == 'chebyshev': kinetics = Chebyshev().fitToData(Tdata, Pdata, kdata, kunits, - self.interpolationModel[1], self.interpolationModel[2], - Tmin, Tmax, Pmin, Pmax, - ) + self.interpolationModel[1], self.interpolationModel[2], + Tmin, Tmax, Pmin, Pmax, + ) elif model == 'pdeparrhenius': kinetics = PDepArrhenius().fitToData(Tdata, Pdata, kdata, kunits) else: raise Exception('Invalid interpolation model {0!r}.'.format(self.interpolationModel[0])) return kinetics - + def save(self, outputFile): """Save the output of a pressure dependent job""" logging.info('Saving pressure dependence results for network {0}...'.format(self.network.label)) f = open(outputFile, 'a') f_chemkin = open(os.path.join(os.path.dirname(outputFile), 'chem.inp'), 'a') - + Nreac = self.network.Nisom + self.network.Nreac Nprod = Nreac + self.network.Nprod Tlist = self.Tlist.value_si @@ -464,25 +476,26 @@ def save(self, outputFile): spcs.extend(rxn.products) for spc in spcs: if spc.thermo: - f.write("#"+spc.label+" SMILES: "+spc.molecule[0].toSMILES()+"\n") - f.write("#"+spc.thermo.comment+"\n") + f.write("#" + spc.label + " SMILES: " + spc.molecule[0].toSMILES() + "\n") + f.write("#" + spc.thermo.comment + "\n") f.write("\n#Path Reactions used: \n") for rxn in self.network.pathReactions: if rxn.kinetics: - f.write("#"+str(rxn)+"\n") + f.write("#" + str(rxn) + "\n") for s in rxn.kinetics.comment.split("\n"): - f.write("#"+s+"\n") + f.write("#" + s + "\n") f.write("\n") count = 0 - printed_reactions = [] # list of rxns already printed + printed_reactions = [] # list of rxns already printed for prod in range(Nprod): for reac in range(Nreac): - if reac == prod: continue + if reac == prod: + continue reaction = self.network.netReactions[count] count += 1 # make sure we aren't double counting any reactions - if not any([reaction.isIsomorphic(other_rxn,checkOnlyLabel=True) \ + if not any([reaction.isIsomorphic(other_rxn, checkOnlyLabel=True) for other_rxn in printed_reactions]): duplicate = False # add reaction to printed reaction @@ -492,35 +505,35 @@ def save(self, outputFile): duplicate = True # write chemkin output. - string = writeKineticsEntry(reaction, speciesList=None, verbose=False, commented = duplicate) + string = writeKineticsEntry(reaction, speciesList=None, verbose=False, commented=duplicate) f_chemkin.write('{0}\n'.format(string)) # write to 'output.py' - kdata = self.K[:,:,prod,reac].copy() + kdata = self.K[:, :, prod, reac].copy() order = len(reaction.reactants) - kdata *= 1e6 ** (order-1) + kdata *= 1e6 ** (order - 1) kunits = {1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)'}[order] - + f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') f.write('# T \ P ') - f.write(' '.join(['{0:11.3e}'.format(P*1e-5) for P in Plist])) + f.write(' '.join(['{0:11.3e}'.format(P * 1e-5) for P in Plist])) f.write('\n') f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') - + for t in range(Tcount): f.write('# {0:11g}'.format(Tlist[t])) for p in range(Pcount): - f.write(' {0:11.3e}'.format(kdata[t,p])) + f.write(' {0:11.3e}'.format(kdata[t, p])) f.write('\n') - + f.write('# =========== ') f.write('=========== ' * Pcount) f.write('\n') - + string = 'pdepreaction(reactants={0!r}, products={1!r}, kinetics={2!r})'.format( [reactant.label for reactant in reaction.reactants], [product.label for product in reaction.products], @@ -529,7 +542,7 @@ def save(self, outputFile): pdep_function = '{0}\n\n'.format(prettify(string)) if duplicate: # add comments to the start of the string - pdep_function = '# ' + pdep_function.replace('\n','\n# ') + pdep_function = '# ' + pdep_function.replace('\n', '\n# ') f.write(pdep_function) f.close() @@ -552,57 +565,59 @@ def plot(self, outputDirectory): Plist = self.Plist.value_si Tcount = Tlist.shape[0] Pcount = Plist.shape[0] - + K = self.K - + count = 0 for prod in range(Nprod): for reac in range(Nreac): - if reac == prod: continue + if reac == prod: + continue reaction = self.network.netReactions[count] count += 1 - + reaction_str = '{0} {1} {2}'.format( ' + '.join([reactant.label for reactant in reaction.reactants]), '<=>' if prod < Nreac else '-->', ' + '.join([product.label for product in reaction.products]), ) - - fig = plt.figure(figsize=(10,6)) - + + fig = plt.figure(figsize=(10, 6)) + K2 = numpy.zeros((Tcount, Pcount)) if reaction.kinetics is not None: for t in range(Tcount): for p in range(Pcount): - K2[t,p] = reaction.kinetics.getRateCoefficient(Tlist[t], Plist[p]) - - K = self.K[:,:,prod,reac].copy() + K2[t, p] = reaction.kinetics.getRateCoefficient(Tlist[t], Plist[p]) + + K = self.K[:, :, prod, reac].copy() order = len(reaction.reactants) - K *= 1e6 ** (order-1) - K2 *= 1e6 ** (order-1) + K *= 1e6 ** (order - 1) + K2 *= 1e6 ** (order - 1) kunits = {1: 's^-1', 2: 'cm^3/(mol*s)', 3: 'cm^6/(mol^2*s)'}[order] - plt.subplot(1,2,1) + plt.subplot(1, 2, 1) for p in xrange(Pcount): - plt.semilogy(1000.0 / Tlist, K[:,p], color=cm(1.*p/(Pcount-1)), marker='o', linestyle='', - label=str('%.2e' % (Plist[p]/1e+5)) + ' bar') + plt.semilogy(1000.0 / Tlist, K[:, p], color=cm(1. * p / (Pcount - 1)), marker='o', linestyle='', + label=str('%.2e' % (Plist[p] / 1e+5)) + ' bar') if reaction.kinetics is not None: - plt.semilogy(1000.0 / Tlist, K2[:,p], color=cm(1.*p/(Pcount-1)), marker='', linestyle='-') + plt.semilogy(1000.0 / Tlist, K2[:, p], color=cm(1. * p / (Pcount - 1)), marker='', + linestyle='-') plt.xlabel('1000 / Temperature (1000/K)') plt.ylabel('Rate coefficient ({0})'.format(kunits)) plt.title(reaction_str) plt.legend() - - plt.subplot(1,2,2) + + plt.subplot(1, 2, 2) for t in xrange(Tcount): - plt.loglog(Plist*1e-5, K[t,:], color=cm(1.*t/(Tcount-1)), marker='o', linestyle='', - label=str('%.0d' % Tlist[t]) + ' K') - plt.loglog(Plist*1e-5, K2[t,:], color=cm(1.*t/(Tcount-1)), marker='', linestyle='-') + plt.loglog(Plist * 1e-5, K[t, :], color=cm(1. * t / (Tcount - 1)), marker='o', linestyle='', + label=str('%.0d' % Tlist[t]) + ' K') + plt.loglog(Plist * 1e-5, K2[t, :], color=cm(1. * t / (Tcount - 1)), marker='', linestyle='-') plt.xlabel('Pressure (bar)') plt.ylabel('Rate coefficient ({0})'.format(kunits)) plt.title(reaction_str) plt.legend() - + fig.subplots_adjust(left=0.10, bottom=0.13, right=0.95, top=0.92, wspace=0.3, hspace=0.3) if not os.path.exists(os.path.join(outputDirectory, 'plots', '')): os.mkdir(os.path.join(outputDirectory, 'plots', '')) @@ -618,7 +633,7 @@ def draw(self, outputDirectory, format='pdf'): You may also generate different formats of drawings, by changing format to one of the following: `pdf`, `svg`, `png`. """ - + # Skip this step if cairo is not installed try: import cairocffi as cairo @@ -627,11 +642,11 @@ def draw(self, outputDirectory, format='pdf'): import cairo except ImportError: return - + from rmgpy.pdep.draw import NetworkDrawer - + path = os.path.join(outputDirectory, 'network.' + format) - + NetworkDrawer().draw(self.network, format=format, path=path) def saveInputFile(self, path): @@ -639,19 +654,19 @@ def saveInputFile(self, path): Save an Arkane input file for the pressure dependence job to `path` on disk. """ speciesList = self.network.getAllSpecies() - + # Add labels for species, reactions, transition states that don't have them for i, spec in enumerate(speciesList): if not spec.label: - spec.label = 'species{0:d}'.format(i+1) + spec.label = 'species{0:d}'.format(i + 1) for i, rxn in enumerate(self.network.pathReactions): if not rxn.label: - rxn.label = 'reaction{0:d}'.format(i+1) + rxn.label = 'reaction{0:d}'.format(i + 1) if not rxn.transitionState.label: - rxn.transitionState.label = 'TS{0:d}'.format(i+1) + rxn.transitionState.label = 'TS{0:d}'.format(i + 1) if not self.network.label: self.network.label = 'network' - + with open(path, 'w') as f: # Write species for spec in speciesList: @@ -674,11 +689,11 @@ def saveInputFile(self, path): if spec.transportData is not None: f.write(' collisionModel = {0!r},\n'.format(spec.transportData)) if spec.energyTransferModel is not None: - f.write(' energyTransferModel = {0!r},\n'.format(spec.energyTransferModel)) + f.write(' energyTransferModel = {0!r},\n'.format(spec.energyTransferModel)) if spec.thermo is not None: - f.write(' thermo = {0!r},\n'.format(spec.thermo)) + f.write(' thermo = {0!r},\n'.format(spec.thermo)) f.write(')\n\n') - + # Write transition states for rxn in self.network.pathReactions: ts = rxn.transitionState @@ -695,9 +710,9 @@ def saveInputFile(self, path): f.write(' spinMultiplicity = {0:d},\n'.format(ts.conformer.spinMultiplicity)) f.write(' opticalIsomers = {0:d},\n'.format(ts.conformer.opticalIsomers)) if ts.frequency is not None: - f.write(' frequency = {0!r},\n'.format(ts.frequency)) + f.write(' frequency = {0!r},\n'.format(ts.frequency)) f.write(')\n\n') - + # Write reactions for rxn in self.network.pathReactions: ts = rxn.transitionState @@ -716,7 +731,7 @@ def saveInputFile(self, path): if ts.tunneling is not None: f.write(' tunneling = {0!r},\n'.format(ts.tunneling.__class__.__name__)) f.write(')\n\n') - + # Write network f.write('network(\n') f.write(' label = {0!r},\n'.format(self.network.label)) @@ -733,7 +748,7 @@ def saveInputFile(self, path): f.write(' {0!r}: {1:g},\n'.format(str(spec), frac)) f.write(' },\n') f.write(')\n\n') - + # Write pressure dependence f.write('pressureDependence(\n') f.write(' label = {0!r},\n'.format(self.network.label)) From 11a7156ab6ff8d0506a173ba5bb241faf94dc108 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:17:23 -0400 Subject: [PATCH 19/28] PEP 8 coding style fixes in Arkane pdepTest.py --- arkane/pdepTest.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arkane/pdepTest.py b/arkane/pdepTest.py index 284a95d47f..44103ded86 100644 --- a/arkane/pdepTest.py +++ b/arkane/pdepTest.py @@ -63,7 +63,7 @@ def setUp(cls): shutil.rmtree(os.path.join(settings['test_data.directory'], 'arkane', 'tst1', d, '')) files = [f for f in os.listdir(cls.directory) if os.path.isfile(os.path.join(cls.directory, f))] for f in files: - if not 'pdep_sa' in f: + if 'pdep_sa' not in f: os.remove(os.path.join(settings['test_data.directory'], 'arkane', 'tst1', f)) def testPDepJob(self): @@ -84,9 +84,9 @@ def testPDepJob(self): self.assertEquals(job.minimumGrainCount, 100) self.assertFalse(job.rmgmode) self.assertTrue(job.activeJRotor) - self.assertEquals(job.network.pathReactions[0].label,'acetylperoxy <=> hydroperoxylvinoxy') - self.assertAlmostEquals(job.network.pathReactions[0].transitionState.tunneling.E0_TS.value_si,-24267.2) - self.assertAlmostEquals(job.network.pathReactions[0].transitionState.tunneling.frequency.value_si,-1679.04) + self.assertEquals(job.network.pathReactions[0].label, 'acetylperoxy <=> hydroperoxylvinoxy') + self.assertAlmostEquals(job.network.pathReactions[0].transitionState.tunneling.E0_TS.value_si, -24267.2) + self.assertAlmostEquals(job.network.pathReactions[0].transitionState.tunneling.frequency.value_si, -1679.04) self.assertEquals(len(job.network.netReactions[0].reactants[0].conformer.modes), 6) # self.assertEquals(self.tst1.frequencyScaleFactor, 0.947) @@ -96,7 +96,7 @@ def testPDepJob(self): # Test the generated network reaction dictionary = {'hydroperoxylvinoxy': Species().fromSMILES('[CH2]C(=O)OO'), - 'acetylperoxy': Species().fromSMILES('CC(=O)O[O]')} + 'acetylperoxy': Species().fromSMILES('CC(=O)O[O]')} with open(os.path.join(self.directory, 'chem.inp'), 'r') as chem: reaction_list = readReactionsBlock(chem, dictionary) rxn = reaction_list[0] @@ -127,5 +127,5 @@ def tearDown(cls): shutil.rmtree(os.path.join(settings['test_data.directory'], 'arkane', 'tst1', d, '')) files = [f for f in os.listdir(cls.directory) if os.path.isfile(os.path.join(cls.directory, f))] for f in files: - if not 'pdep_sa' in f: + if 'pdep_sa' not in f: os.remove(os.path.join(settings['test_data.directory'], 'arkane', 'tst1', f)) From 9a87780c51165e7c96ad7a9ee102cca6d0b893c4 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:17:31 -0400 Subject: [PATCH 20/28] PEP 8 coding style fixes in Arkane qchem.py --- arkane/qchem.py | 48 ++++++++++++++++++++++++++++-------------------- 1 file changed, 28 insertions(+), 20 deletions(-) diff --git a/arkane/qchem.py b/arkane/qchem.py index 690b52f386..5d1a054831 100644 --- a/arkane/qchem.py +++ b/arkane/qchem.py @@ -45,6 +45,7 @@ from arkane.common import check_conformer_energy, get_element_mass from arkane.log import Log + ################################################################################ @@ -72,7 +73,8 @@ def getNumberOfAtoms(self): while line != '' and Natoms == 0: # Automatically determine the number of atoms if 'Standard Nuclear Orientation' in line and Natoms == 0: - for i in range(3): line = f.readline() + for i in range(3): + line = f.readline() while '----------------------------------------------------' not in line: Natoms += 1 line = f.readline() @@ -100,18 +102,18 @@ def loadForceConstantMatrix(self): while line != '': # Read force constant matrix if 'Final Hessian.' in line or 'Hessian of the SCF Energy' in line: - F = numpy.zeros((Nrows,Nrows), numpy.float64) + F = numpy.zeros((Nrows, Nrows), numpy.float64) for i in range(int(math.ceil(Nrows / 6.0))): # Header row line = f.readline() # Matrix element rows - for j in range(Nrows): #for j in range(i*6, Nrows): + for j in range(Nrows): # for j in range(i*6, Nrows): data = f.readline().split() - for k in range(len(data)-1): - F[j,i*6+k] = float(data[k+1]) - #F[i*5+k,j] = F[j,i*5+k] + for k in range(len(data) - 1): + F[j, i * 6 + k] = float(data[k + 1]) + # F[i*5+k,j] = F[j,i*5+k] # Convert from atomic units (Hartree/Bohr_radius^2) to J/m^2 - F *= 4.35974417e-18 / 5.291772108e-11**2 + F *= 4.35974417e-18 / 5.291772108e-11 ** 2 line = f.readline() # Close file when finished f.close() @@ -140,7 +142,8 @@ def loadGeometry(self): break if not completed_job: - raise InputError('Could not find a successfully completed QChem job in QChem output file {0}'.format(self.path)) + raise InputError( + 'Could not find a successfully completed QChem job in QChem output file {0}'.format(self.path)) # Now look for the geometry. # Will return the final geometry in the file under Standard Nuclear Orientation. @@ -148,11 +151,11 @@ def loadGeometry(self): for i in reversed(xrange(len(log))): line = log[i] if 'Standard Nuclear Orientation' in line: - for line in log[(i+3):]: + for line in log[(i + 3):]: if '------------' not in line: data = line.split() atom.append(data[1]) - coord.append([float(c) for c in data [2:]]) + coord.append([float(c) for c in data[2:]]) geometry_flag = True else: break @@ -179,7 +182,11 @@ def loadConformer(self, symmetry=None, spinMultiplicity=0, opticalIsomers=None, you can use the `symmetry` parameter to substitute your own value; if not provided, the value in the QChem output file will be adopted. """ - modes = []; freq = []; mmass = []; rot = []; inertia = [] + modes = [] + freq = [] + mmass = [] + rot = [] + inertia = [] unscaled_frequencies = [] E0 = 0.0 if opticalIsomers is None or symmetry is None: @@ -196,7 +203,8 @@ def loadConformer(self, symmetry=None, spinMultiplicity=0, opticalIsomers=None, line = f.readline() if len(line.split()) == 2: spinMultiplicity = int(float(line.split()[1])) - logging.debug('Conformer {0} is assigned a spin multiplicity of {1}'.format(label,spinMultiplicity)) + logging.debug( + 'Conformer {0} is assigned a spin multiplicity of {1}'.format(label, spinMultiplicity)) # The rest of the data we want is in the Thermochemistry section of the output elif 'VIBRATIONAL ANALYSIS' in line: modes = [] @@ -225,13 +233,13 @@ def loadConformer(self, symmetry=None, spinMultiplicity=0, opticalIsomers=None, frequencies = frequencies[1:] unscaled_frequencies = frequencies - vibration = HarmonicOscillator(frequencies=(frequencies,"cm^-1")) + vibration = HarmonicOscillator(frequencies=(frequencies, "cm^-1")) # modes.append(vibration) freq.append(vibration) # Read molecular mass for external translational modes elif 'Molecular Mass:' in line: mass = float(line.split()[2]) - translation = IdealGasTranslation(mass=(mass,"amu")) + translation = IdealGasTranslation(mass=(mass, "amu")) # modes.append(translation) mmass.append(translation) @@ -267,7 +275,7 @@ def loadConformer(self, symmetry=None, spinMultiplicity=0, opticalIsomers=None, # Close file when finished f.close() modes = mmass + rot + freq - return Conformer(E0=(E0*0.001,"kJ/mol"), modes=modes, spinMultiplicity=spinMultiplicity, + return Conformer(E0=(E0 * 0.001, "kJ/mol"), modes=modes, spinMultiplicity=spinMultiplicity, opticalIsomers=opticalIsomers), unscaled_frequencies def loadEnergy(self, frequencyScaleFactor=1.): @@ -288,7 +296,7 @@ def loadEnergy(self, frequencyScaleFactor=1.): if e0 is None: raise InputError('Unable to find energy in QChem output file.') return e0 - + def loadZeroPointEnergy(self): """ Load the unscaled zero-point energy in J/mol from a QChem output file. @@ -303,7 +311,7 @@ def loadZeroPointEnergy(self): return ZPE else: raise InputError('Unable to find zero-point energy in QChem output file.') - + def loadScanEnergies(self): """ Extract the optimized energies in J/mol from a QChem log file, e.g. the @@ -330,14 +338,14 @@ def loadScanEnergies(self): Vlist = numpy.array(Vlist, numpy.float64) # check to see if the scanlog indicates that one of your reacting species may not be the lowest energy conformer check_conformer_energy(Vlist, self.path) - + # Adjust energies to be relative to minimum energy conformer # Also convert units from Hartree/particle to J/mol Vlist -= numpy.min(Vlist) Vlist *= constants.E_h * constants.Na - angle = numpy.arange(0.0, 2*math.pi+0.00001, 2*math.pi/(len(Vlist)-1), numpy.float64) + angle = numpy.arange(0.0, 2 * math.pi + 0.00001, 2 * math.pi / (len(Vlist) - 1), numpy.float64) return Vlist, angle - + def loadNegativeFrequency(self): """ Return the imaginary frequency from a transition state frequency From afb051b887f7ecb76923749344a7d787a1f7f933 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:17:45 -0400 Subject: [PATCH 21/28] PEP 8 coding style fixes in Arkane qchemTest.py --- arkane/qchemTest.py | 73 +++++++++++++++++++++++---------------------- 1 file changed, 37 insertions(+), 36 deletions(-) diff --git a/arkane/qchemTest.py b/arkane/qchemTest.py index b4f56bd09e..702f3c9ba8 100644 --- a/arkane/qchemTest.py +++ b/arkane/qchemTest.py @@ -28,16 +28,15 @@ # # ############################################################################### -import numpy import unittest import os -from rmgpy.statmech import Conformer, IdealGasTranslation, LinearRotor, NonlinearRotor, HarmonicOscillator, HinderedRotor -import rmgpy.constants as constants -from external.wip import work_in_progress +from rmgpy.statmech import Conformer, IdealGasTranslation, LinearRotor, NonlinearRotor, HarmonicOscillator, \ + HinderedRotor from arkane.qchem import QChemLog + ################################################################################ @@ -46,81 +45,83 @@ class QChemTest(unittest.TestCase): Contains unit tests for the chempy.io.qchem module, used for reading and writing QChem files. """ + def testNumberOfAtomsFromQChemLog(self): """ Uses a QChem log files to test that number of atoms can be properly read. """ - log = QChemLog(os.path.join(os.path.dirname(__file__),'data','npropyl.out')) + log = QChemLog(os.path.join(os.path.dirname(__file__), 'data', 'npropyl.out')) self.assertEqual(log.getNumberOfAtoms(), 10) - log = QChemLog(os.path.join(os.path.dirname(__file__),'data','co.out')) - self.assertEqual(log.getNumberOfAtoms(), 2) + log = QChemLog(os.path.join(os.path.dirname(__file__), 'data', 'co.out')) + self.assertEqual(log.getNumberOfAtoms(), 2) def testEnergyFromQChemLog(self): """ Uses a QChem log files to test that molecular energies can be properly read. - """ - log = QChemLog(os.path.join(os.path.dirname(__file__),'data','npropyl.out')) + """ + log = QChemLog(os.path.join(os.path.dirname(__file__), 'data', 'npropyl.out')) self.assertAlmostEqual(log.loadEnergy(), -310896203.5432524, delta=1e-5) - log = QChemLog(os.path.join(os.path.dirname(__file__),'data','co.out')) + log = QChemLog(os.path.join(os.path.dirname(__file__), 'data', 'co.out')) self.assertAlmostEqual(log.loadEnergy(), -297402545.0217114, delta=1e-5) - log = QChemLog(os.path.join(os.path.dirname(__file__),'data','CH4_sp_qchem.out')) + log = QChemLog(os.path.join(os.path.dirname(__file__), 'data', 'CH4_sp_qchem.out')) self.assertAlmostEqual(log.loadEnergy(), -106356735.53661588, delta=1e-5) - + def testLoadVibrationsFromQChemLog(self): """ Uses a QChem log files to test that molecular energies can be properly read. """ - log = QChemLog(os.path.join(os.path.dirname(__file__),'data','npropyl.out')) + log = QChemLog(os.path.join(os.path.dirname(__file__), 'data', 'npropyl.out')) conformer, unscaled_frequencies = log.loadConformer() - self.assertEqual(len(conformer.modes[2]._frequencies.getValue()), 24) - self.assertEqual(conformer.modes[2]._frequencies.getValue()[5], 881.79) - log = QChemLog(os.path.join(os.path.dirname(__file__),'data','co.out')) + self.assertEqual(len(conformer.modes[2]._frequencies.getValue()), 24) + self.assertEqual(conformer.modes[2]._frequencies.getValue()[5], 881.79) + log = QChemLog(os.path.join(os.path.dirname(__file__), 'data', 'co.out')) conformer, unscaled_frequencies = log.loadConformer() - self.assertEqual(len(conformer.modes[2]._frequencies.getValue()), 1) - self.assertEqual(conformer.modes[2]._frequencies.getValue(), 2253.16) - + self.assertEqual(len(conformer.modes[2]._frequencies.getValue()), 1) + self.assertEqual(conformer.modes[2]._frequencies.getValue(), 2253.16) + def testLoadNpropylModesFromQChemLog(self): """ Uses a QChem log file for npropyl to test that its molecular modes can be properly read. """ - log = QChemLog(os.path.join(os.path.dirname(__file__),'data','npropyl.out')) + log = QChemLog(os.path.join(os.path.dirname(__file__), 'data', 'npropyl.out')) conformer, unscaled_frequencies = log.loadConformer() - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,IdealGasTranslation)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,NonlinearRotor)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,HarmonicOscillator)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,HinderedRotor)]) == 0) - + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, IdealGasTranslation)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, NonlinearRotor)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, HarmonicOscillator)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, HinderedRotor)]) == 0) + def testSpinMultiplicityFromQChemLog(self): """ Uses a QChem log file for npropyl to test that its molecular degrees of freedom can be properly read. """ - log = QChemLog(os.path.join(os.path.dirname(__file__),'data','npropyl.out')) + log = QChemLog(os.path.join(os.path.dirname(__file__), 'data', 'npropyl.out')) conformer, unscaled_frequencies = log.loadConformer() self.assertEqual(conformer.spinMultiplicity, 2) - log = QChemLog(os.path.join(os.path.dirname(__file__),'data','co.out')) + log = QChemLog(os.path.join(os.path.dirname(__file__), 'data', 'co.out')) conformer, unscaled_frequencies = log.loadConformer() self.assertEqual(conformer.spinMultiplicity, 1) - + def testLoadCOModesFromQChemLog(self): """ Uses a QChem log file for CO to test that its molecular degrees of freedom can be properly read. """ - log = QChemLog(os.path.join(os.path.dirname(__file__),'data','co.out')) + log = QChemLog(os.path.join(os.path.dirname(__file__), 'data', 'co.out')) conformer, unscaled_frequencies = log.loadConformer() E0 = log.loadEnergy() - - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,IdealGasTranslation)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,LinearRotor)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,NonlinearRotor)]) == 0) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,HarmonicOscillator)]) == 1) - self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode,HinderedRotor)]) == 0) + + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, IdealGasTranslation)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, LinearRotor)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, NonlinearRotor)]) == 0) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, HarmonicOscillator)]) == 1) + self.assertTrue(len([mode for mode in conformer.modes if isinstance(mode, HinderedRotor)]) == 0) + if __name__ == '__main__': - unittest.main( testRunner = unittest.TextTestRunner(verbosity=2) ) + unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) From 8eaf944b7bba3de5b6a624ba89f0dfd841ad9343 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:18:00 -0400 Subject: [PATCH 22/28] PEP 8 coding style fixes in Arkane sensitivity.py --- arkane/sensitivity.py | 38 ++++++++++++++++++++------------------ 1 file changed, 20 insertions(+), 18 deletions(-) diff --git a/arkane/sensitivity.py b/arkane/sensitivity.py index 2099986fd6..63adf3f12e 100644 --- a/arkane/sensitivity.py +++ b/arkane/sensitivity.py @@ -42,6 +42,7 @@ from rmgpy.species import TransitionState from rmgpy.pdep import Configuration + ################################################################################ @@ -127,7 +128,7 @@ def save(self): sa_f.write("Sensitivity analysis for reaction {0}\n\n" "The semi-normalized sensitivity coefficients are calculated as dln(r)/dE0\n" "by perturbing E0 of each well or TS by {1}, and are given in `mol/J` units.\n\n\n".format( - reaction_str, self.perturbation)) + reaction_str, self.perturbation)) reactants_label = ' + '.join([reactant.label for reactant in self.job.reaction.reactants]) ts_label = self.job.reaction.transitionState.label products_label = ' + '.join([reactant.label for reactant in self.job.reaction.products]) @@ -135,35 +136,35 @@ def save(self): sa_f.write('========================={0}=============================================\n' '| Direction | Well or TS {1}| Temperature (K) | Sensitivity coefficient |\n' '|-----------+------------{2}+-----------------+-------------------------|\n'.format( - '='*(max_label-10), ' '*(max_label-10), '-'*(max_label-10))) + '=' * (max_label - 10), ' ' * (max_label - 10), '-' * (max_label - 10))) for i, condition in enumerate(self.conditions): sa_f.write('| Forward | {0} {1}| {2:6.1f} | {3:+1.2e} |\n'.format( - reactants_label, ' '*(max_label - len(reactants_label)), condition.value_si, + reactants_label, ' ' * (max_label - len(reactants_label)), condition.value_si, self.f_sa_coefficients[self.job.reaction.reactants[0]][i])) for i, condition in enumerate(self.conditions): sa_f.write('| Forward | {0} {1}| {2:6.1f} | {3:+1.2e} |\n'.format( - products_label, ' '*(max_label - len(products_label)), condition.value_si, + products_label, ' ' * (max_label - len(products_label)), condition.value_si, self.f_sa_coefficients[self.job.reaction.products[0]][i])) for i, condition in enumerate(self.conditions): sa_f.write('| Forward | {0} {1}| {2:6.1f} | {3:+1.2e} |\n'.format( - ts_label, ' '*(max_label - len(ts_label)), condition.value_si, + ts_label, ' ' * (max_label - len(ts_label)), condition.value_si, self.f_sa_coefficients[self.job.reaction.transitionState][i])) sa_f.write('|-----------+------------{0}+-----------------+-------------------------|\n'.format( - '-'*(max_label-10))) + '-' * (max_label - 10))) for i, condition in enumerate(self.conditions): sa_f.write('| Reverse | {0} {1}| {2:6.1f} | {3:+1.2e} |\n'.format( - reactants_label, ' '*(max_label - len(reactants_label)), condition.value_si, + reactants_label, ' ' * (max_label - len(reactants_label)), condition.value_si, self.r_sa_coefficients[self.job.reaction.reactants[0]][i])) for i, condition in enumerate(self.conditions): sa_f.write('| Reverse | {0} {1}| {2:6.1f} | {3:+1.2e} |\n'.format( - products_label, ' '*(max_label - len(products_label)), condition.value_si, + products_label, ' ' * (max_label - len(products_label)), condition.value_si, self.r_sa_coefficients[self.job.reaction.products[0]][i])) for i, condition in enumerate(self.conditions): sa_f.write('| Reverse | {0} {1}| {2:6.1f} | {3:+1.2e} |\n'.format( - ts_label, ' '*(max_label - len(ts_label)), condition.value_si, + ts_label, ' ' * (max_label - len(ts_label)), condition.value_si, self.r_sa_coefficients[self.job.reaction.transitionState][i])) sa_f.write('========================={0}=============================================\n'.format( - '='*(max_label-10))) + '=' * (max_label - 10))) def plot(self): """Plot the SA results as horizontal bars""" @@ -321,29 +322,29 @@ def save(self, wells, transition_states): sa_f.write("Sensitivity analysis for network {0}\n\n" "The semi-normalized sensitivity coefficients are calculated as dln(r)/dE0\n" "by perturbing E0 of each well or TS by {1},\n and are given in `mol/J` units.\n\n\n".format( - network_str, self.perturbation)) + network_str, self.perturbation)) for rxn in self.job.network.netReactions: reactants_label = ' + '.join([reactant.label for reactant in rxn.reactants]) products_label = ' + '.join([reactant.label for reactant in rxn.products]) reaction_str = '{0} {1} {2}'.format(reactants_label, '<=>', products_label) - sa_f.write(' Sensitivity of network reaction '+reaction_str+' :'+'\n') + sa_f.write(' Sensitivity of network reaction ' + reaction_str + ' :' + '\n') max_label = 40 sa_f.write('========================={0}==================================================\n' '| Well or TS {1}| Temperature (K) | Pressure (bar) | Sensitivity coefficient |\n' '|------------{2}+-----------------+----------------+-------------------------|\n'.format( - '='*(max_label-10), ' '*(max_label-10), '-'*(max_label-10))) + '=' * (max_label - 10), ' ' * (max_label - 10), '-' * (max_label - 10))) for entry in wells + transition_states: if isinstance(entry, TransitionState): entry_label = '(TS) ' + entry.label elif isinstance(entry, Configuration): entry_label = ' + '.join([species.label for species in entry.species]) - entry_label += ' '*(max_label - len(entry_label)) + entry_label += ' ' * (max_label - len(entry_label)) for i, condition in enumerate(self.conditions): sa_f.write('| {0} | {1:6.1f} | {2:8.2f} | {3:+1.2e} |\n'.format( entry_label, condition[0].value_si, condition[1].value_si * 1e-5, self.sa_coefficients[str(rxn)][entry][i])) - sa_f.write('========================={0}==================================================\n\n\n'.format( - '='*(max_label-10))) + sa_f.write('========================={0}==================================================' + '\n\n\n'.format('=' * (max_label - 10))) def plot(self, wells, transition_states): """Draw the SA results as horizontal bars""" @@ -364,13 +365,14 @@ def plot(self, wells, transition_states): min_sa = sa_condition if max_sa < sa_condition: max_sa = sa_condition - colors = ['b','g','r','c','m','y','k'] + colors = ['b', 'g', 'r', 'c', 'm', 'y', 'k'] for i, condition in enumerate(self.conditions): values = [self.sa_coefficients[str(rxn)][conf][i] for conf in wells + transition_states] y_pos = np.arange(len(labels)) if len(self.conditions) > 1: axis = ax[i] - else: axis = ax + else: + axis = ax axis.barh(y_pos, values, align='center', color=colors[i % len(colors)]) axis.set_yticks(y_pos) axis.set_yticklabels(labels) From c41547560e7e265de53e1943e49ec086c792ce7a Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:19:19 -0400 Subject: [PATCH 23/28] PEP 8 coding style fixes in Arkane statmech.py --- arkane/statmech.py | 630 +++++++++++++++++++++++++-------------------- 1 file changed, 356 insertions(+), 274 deletions(-) diff --git a/arkane/statmech.py b/arkane/statmech.py index 6f3f43dc3e..194851e9d0 100644 --- a/arkane/statmech.py +++ b/arkane/statmech.py @@ -60,6 +60,7 @@ from arkane.common import symbol_by_number from arkane.common import ArkaneSpecies + ################################################################################ @@ -77,13 +78,13 @@ class ScanLog(object): } energyFactors = { 'J/mol': 1.0, - 'kJ/mol': 1.0/1000., - 'cal/mol': 1.0/4.184, - 'kcal/mol': 1.0/4184., - 'cm^-1': 1.0/(constants.h * constants.c * 100. * constants.Na), - 'hartree': 1.0/(constants.E_h * constants.Na), + 'kJ/mol': 1.0 / 1000., + 'cal/mol': 1.0 / 4.184, + 'kcal/mol': 1.0 / 4184., + 'cm^-1': 1.0 / (constants.h * constants.c * 100. * constants.Na), + 'hartree': 1.0 / (constants.E_h * constants.Na), } - + def __init__(self, path): self.path = path @@ -92,20 +93,20 @@ def load(self): Load the scan energies from the file. Returns arrays containing the angles (in radians) and energies (in J/mol). """ - angles = []; energies = [] - angleUnits = None; energyUnits = None - angleFactor = None; energyFactor = None - + angles, energies = [], [] + angleUnits, energyUnits, angleFactor, energyFactor = None, None, None, None + with open(self.path, 'r') as stream: for line in stream: line = line.strip() - if line == '': continue - + if line == '': + continue + tokens = line.split() if angleUnits is None or energyUnits is None: angleUnits = tokens[1][1:-1] energyUnits = tokens[3][1:-1] - + try: angleFactor = ScanLog.angleFactors[angleUnits] except KeyError: @@ -114,17 +115,17 @@ def load(self): energyFactor = ScanLog.energyFactors[energyUnits] except KeyError: raise ValueError('Invalid energy units {0!r}.'.format(energyUnits)) - + else: angles.append(float(tokens[0]) / angleFactor) energies.append(float(tokens[1]) / energyFactor) - + angles = numpy.array(angles) energies = numpy.array(energies) energies -= energies[0] - + return angles, energies - + def save(self, angles, energies, angleUnits='radians', energyUnits='kJ/mol'): """ Save the scan energies to the file using the given `angles` in radians @@ -132,7 +133,7 @@ def save(self, angles, energies, angleUnits='radians', energyUnits='kJ/mol'): use the given `angleUnits` for angles and `energyUnits` for energies. """ assert len(angles) == len(energies) - + try: angleFactor = ScanLog.angleFactors[angleUnits] except KeyError: @@ -141,7 +142,7 @@ def save(self, angles, energies, angleUnits='radians', energyUnits='kJ/mol'): energyFactor = ScanLog.energyFactors[energyUnits] except KeyError: raise ValueError('Invalid energy units {0!r}.'.format(energyUnits)) - + with open(self.path, 'w') as stream: stream.write('{0:>24} {1:>24}\n'.format( 'Angle ({0})'.format(angleUnits), @@ -150,6 +151,7 @@ def save(self, angles, energies, angleUnits='radians', energyUnits='kJ/mol'): for angle, energy in zip(angles, energies): stream.write('{0:23.10f} {1:23.10f}\n'.format(angle * angleFactor, energy * energyFactor)) + ################################################################################ @@ -158,9 +160,9 @@ def hinderedRotor(scanLog, pivots, top, symmetry=None, fit='best'): return [scanLog, pivots, top, symmetry, fit] -def freeRotor(pivots,top,symmetry): +def freeRotor(pivots, top, symmetry): """Read a free rotor directive, and return the attributes in a list""" - return [pivots,top,symmetry] + return [pivots, top, symmetry] class StatMechJob(object): @@ -169,6 +171,7 @@ class StatMechJob(object): to compute and save the statistical mechanics information for a single species or transition state. """ + def __init__(self, species, path): self.species = species self.path = path @@ -288,9 +291,9 @@ def load(self, pdep=False): '{1!r}.'.format(self.modelChemistry, path)) E0_withZPE, E0 = None, None energyLog = None - if isinstance(energy, Log) and not isinstance(energy, (GaussianLog,QChemLog,MolproLog)): + if isinstance(energy, Log) and not isinstance(energy, (GaussianLog, QChemLog, MolproLog)): energyLog = determine_qm_software(os.path.join(directory, energy.path)) - elif isinstance(energy, (GaussianLog,QChemLog,MolproLog)): + elif isinstance(energy, (GaussianLog, QChemLog, MolproLog)): energyLog = energy energyLog.path = os.path.join(directory, energyLog.path) elif isinstance(energy, float): @@ -298,23 +301,22 @@ def load(self, pdep=False): elif isinstance(energy, tuple) and len(energy) == 2: # this is likely meant to be a quantity object with ZPE already accounted for energy_temp = Quantity(energy) - E0_withZPE = energy_temp.value_si # in J/mol + E0_withZPE = energy_temp.value_si # in J/mol elif isinstance(energy, tuple) and len(energy) == 3: if energy[2] == 'E0': energy_temp = Quantity(energy[:2]) - E0 = energy_temp.value_si / constants.E_h / constants.Na# convert J/mol to Hartree + E0 = energy_temp.value_si / constants.E_h / constants.Na # convert J/mol to Hartree elif energy[2] == 'E0-ZPE': energy_temp = Quantity(energy[:2]) - E0_withZPE = energy_temp.value_si # in J/mol + E0_withZPE = energy_temp.value_si # in J/mol else: - raise InputError('The third argument for E0 energy value should '\ - 'be E0 (for energy w/o ZPE) or E0-ZPE. Value '\ - 'entered {0}'.format(energy[2])) + raise InputError('The third argument for E0 energy value should be E0 (for energy w/o ZPE) or E0-ZPE. ' + 'Value entered: {0}'.format(energy[2])) try: geomLog = local_context['geometry'] except KeyError: raise InputError('Required attribute "geometry" not found in species file {0!r}.'.format(path)) - if isinstance(geomLog, Log) and not isinstance(energy, (GaussianLog,QChemLog,MolproLog)): + if isinstance(geomLog, Log) and not isinstance(energy, (GaussianLog, QChemLog, MolproLog)): geomLog = determine_qm_software(os.path.join(directory, geomLog.path)) else: geomLog.path = os.path.join(directory, geomLog.path) @@ -323,7 +325,7 @@ def load(self, pdep=False): statmechLog = local_context['frequencies'] except KeyError: raise InputError('Required attribute "frequencies" not found in species file {0!r}.'.format(path)) - if isinstance(statmechLog, Log) and not isinstance(energy, (GaussianLog,QChemLog,MolproLog)): + if isinstance(statmechLog, Log) and not isinstance(energy, (GaussianLog, QChemLog, MolproLog)): statmechLog = determine_qm_software(os.path.join(directory, statmechLog.path)) else: statmechLog.path = os.path.join(directory, statmechLog.path) @@ -355,9 +357,9 @@ def load(self, pdep=False): ' log for both geometry and frequency, or remove rotors.'.format( self.species.label, geomLog.path, statmechLog.path)) elif isinstance(statmechLog, QChemLog): - logging.warning('QChem log will be used for Hessian of {0!r}. Please verify that the geometry' - ' and Hessian of {0!r} are defined in the same coordinate system'.format( - self.species.label)) + logging.warning('QChem log will be used for Hessian of {0!r}. Please verify that the geometry' + ' and Hessian of {0!r} are defined in the same coordinate system'.format( + self.species.label)) logging.debug(' Reading molecular degrees of freedom...') conformer, unscaled_frequencies = statmechLog.loadConformer(symmetry=externalSymmetry, @@ -391,9 +393,9 @@ def load(self, pdep=False): if isinstance(self.species, Species): self.species.props['elementCounts'] = atoms - conformer.coordinates = (coordinates,"angstroms") + conformer.coordinates = (coordinates, "angstroms") conformer.number = number - conformer.mass = (mass,"amu") + conformer.mass = (mass, "amu") logging.debug(' Reading energy...') if E0_withZPE is None: @@ -401,7 +403,7 @@ def load(self, pdep=False): if E0 is None: E0 = energyLog.loadEnergy(self.frequencyScaleFactor) else: - E0 = E0 * constants.E_h * constants.Na # Hartree/particle to J/mol + E0 = E0 * constants.E_h * constants.Na # Hartree/particle to J/mol if not self.applyAtomEnergyCorrections: logging.warning('Atom corrections are not being used. Do not trust energies and thermo.') E0 = applyEnergyCorrections(E0, @@ -424,7 +426,7 @@ def load(self, pdep=False): logging.debug(' ZPE (0 K) = {0:g} kcal/mol'.format(ZPE / 4184.)) logging.debug(' E0 (0 K) = {0:g} kcal/mol'.format(E0_withZPE / 4184.)) - conformer.E0 = (E0_withZPE*0.001,"kJ/mol") + conformer.E0 = (E0_withZPE * 0.001, "kJ/mol") # If loading a transition state, also read the imaginary frequency if is_ts: @@ -448,7 +450,7 @@ def load(self, pdep=False): # No potential scan is given, this is a free rotor pivots, top, symmetry = q inertia = conformer.getInternalReducedMomentOfInertia(pivots, top) * constants.Na * 1e23 - rotor = FreeRotor(inertia=(inertia,"amu*angstrom^2"), symmetry=symmetry) + rotor = FreeRotor(inertia=(inertia, "amu*angstrom^2"), symmetry=symmetry) conformer.modes.append(rotor) rotorCount += 1 elif len(q) in [4, 5]: @@ -459,19 +461,19 @@ def load(self, pdep=False): # the symmetry number will be derived from the scan scanLog, pivots, top, fit = q # Load the hindered rotor scan energies - if isinstance(scanLog, Log) and not isinstance(energy, (GaussianLog,QChemLog,MolproLog)): + if isinstance(scanLog, Log) and not isinstance(energy, (GaussianLog, QChemLog, MolproLog)): scanLog = determine_qm_software(os.path.join(directory, scanLog.path)) if isinstance(scanLog, GaussianLog): scanLog.path = os.path.join(directory, scanLog.path) v_list, angle = scanLog.loadScanEnergies() scanLogOutput = ScanLog(os.path.join(directory, '{0}_rotor_{1}.txt'.format( - self.species.label, rotorCount+1))) + self.species.label, rotorCount + 1))) scanLogOutput.save(angle, v_list) elif isinstance(scanLog, QChemLog): scanLog.path = os.path.join(directory, scanLog.path) v_list, angle = scanLog.loadScanEnergies() scanLogOutput = ScanLog(os.path.join(directory, '{0}_rotor_{1}.txt'.format( - self.species.label, rotorCount+1))) + self.species.label, rotorCount + 1))) scanLogOutput.save(angle, v_list) elif isinstance(scanLog, ScanLog): scanLog.path = os.path.join(directory, scanLog.path) @@ -483,9 +485,9 @@ def load(self, pdep=False): symmetry = determine_rotor_symmetry(v_list, self.species.label, pivots) inertia = conformer.getInternalReducedMomentOfInertia(pivots, top) * constants.Na * 1e23 - cosineRotor = HinderedRotor(inertia=(inertia,"amu*angstrom^2"), symmetry=symmetry) + cosineRotor = HinderedRotor(inertia=(inertia, "amu*angstrom^2"), symmetry=symmetry) cosineRotor.fitCosinePotentialToData(angle, v_list) - fourierRotor = HinderedRotor(inertia=(inertia,"amu*angstrom^2"), symmetry=symmetry) + fourierRotor = HinderedRotor(inertia=(inertia, "amu*angstrom^2"), symmetry=symmetry) fourierRotor.fitFourierPotentialToData(angle, v_list) Vlist_cosine = numpy.zeros_like(angle) @@ -505,7 +507,7 @@ def load(self, pdep=False): elif fit == 'best': rms_cosine = numpy.sqrt(numpy.sum((Vlist_cosine - v_list) * (Vlist_cosine - v_list)) / (len(v_list) - 1)) / 4184. - rms_fourier = numpy.sqrt(numpy.sum((Vlist_fourier - v_list) * (Vlist_fourier - v_list))/ + rms_fourier = numpy.sqrt(numpy.sum((Vlist_fourier - v_list) * (Vlist_fourier - v_list)) / (len(v_list) - 1)) / 4184. # Keep the rotor with the most accurate potential @@ -513,7 +515,7 @@ def load(self, pdep=False): # However, keep the cosine rotor if it is accurate enough, the # fourier rotor is not significantly more accurate, and the cosine # rotor has the correct symmetry - if rms_cosine < 0.05 and rms_cosine / rms_fourier < 2.0 and rms_cosine / rms_fourier < 4.0\ + if rms_cosine < 0.05 and rms_cosine / rms_fourier < 2.0 and rms_cosine / rms_fourier < 4.0 \ and symmetry == cosineRotor.symmetry: rotor = cosineRotor @@ -545,7 +547,7 @@ def load(self, pdep=False): for mode in conformer.modes: if isinstance(mode, HarmonicOscillator): - mode.frequencies = (frequencies * self.frequencyScaleFactor,"cm^-1") + mode.frequencies = (frequencies * self.frequencyScaleFactor, "cm^-1") self.species.conformer = conformer @@ -564,9 +566,9 @@ def save(self, outputFile): f.write('# Coordinates for {0} in Input Orientation (angstroms):\n'.format(self.species.label)) for i in range(coordinates.shape[0]): - x = coordinates[i,0] - y = coordinates[i,1] - z = coordinates[i,2] + x = coordinates[i, 0] + y = coordinates[i, 1] + z = coordinates[i, 2] f.write('# {0} {1:9.4f} {2:9.4f} {3:9.4f}\n'.format(symbol_by_number[number[i]], x, y, z)) result = 'conformer(label={0!r}, E0={1!r}, modes={2!r}, spinMultiplicity={3:d}, opticalIsomers={4:d}'.format( @@ -578,7 +580,8 @@ def save(self, outputFile): ) try: result += ', frequency={0!r}'.format(self.species.frequency) - except AttributeError: pass + except AttributeError: + pass result += ')' f.write('{0}\n\n'.format(prettify(result))) f.close() @@ -601,26 +604,28 @@ def plotHinderedRotor(self, angle, v_list, cosineRotor, fourierRotor, rotor, rot Vlist_cosine[i] = cosineRotor.getPotential(phi[i]) Vlist_fourier[i] = fourierRotor.getPotential(phi[i]) - fig = pylab.figure(figsize=(6,5)) + fig = pylab.figure(figsize=(6, 5)) pylab.plot(angle, v_list / 4184., 'ok') linespec = '-r' if rotor is cosineRotor else '--r' pylab.plot(phi, Vlist_cosine / 4184., linespec) linespec = '-b' if rotor is fourierRotor else '--b' pylab.plot(phi, Vlist_fourier / 4184., linespec) pylab.legend(['scan', 'cosine', 'fourier'], loc=1) - pylab.xlim(0, 2*constants.pi) + pylab.xlim(0, 2 * constants.pi) pylab.xlabel('Angle') pylab.ylabel('Potential (kcal/mol)') - pylab.title('{0} hindered rotor #{1:d}'.format(self.species.label, rotorIndex+1)) + pylab.title('{0} hindered rotor #{1:d}'.format(self.species.label, rotorIndex + 1)) axes = fig.get_axes()[0] - axes.set_xticks([float(j*constants.pi/4) for j in range(0,9)]) - axes.set_xticks([float(j*constants.pi/8) for j in range(0,17)], minor=True) - axes.set_xticklabels(['$0$', '$\pi/4$', '$\pi/2$', '$3\pi/4$', '$\pi$', '$5\pi/4$', '$3\pi/2$', '$7\pi/4$', '$2\pi$']) + axes.set_xticks([float(j * constants.pi / 4) for j in range(0, 9)]) + axes.set_xticks([float(j * constants.pi / 8) for j in range(0, 17)], minor=True) + axes.set_xticklabels( + ['$0$', '$\pi/4$', '$\pi/2$', '$3\pi/4$', '$\pi$', '$5\pi/4$', '$3\pi/2$', '$7\pi/4$', '$2\pi$']) - pylab.savefig(os.path.join(directory, '{0}_rotor_{1:d}.pdf'.format(self.species.label, rotorIndex+1))) + pylab.savefig(os.path.join(directory, '{0}_rotor_{1:d}.pdf'.format(self.species.label, rotorIndex + 1))) pylab.close() + ################################################################################ @@ -643,126 +648,183 @@ def applyEnergyCorrections(E0, modelChemistry, atoms, bonds, if applyAtomEnergyCorrections: # Spin orbit correction (SOC) in Hartrees - # Values taken from ref 22 of http://dx.doi.org/10.1063/1.477794 and converted to hartrees - # Values in millihartree are also available (with fewer significant figures) from table VII of http://dx.doi.org/10.1063/1.473182 - # Iodine SOC calculated as a weighted average of the electronic spin splittings of the lowest energy state. The splittings are - # obtained from Huber, K.P.; Herzberg, G., Molecular Spectra and Molecular Structure. IV. Constants of Diatomic Molecules, Van Nostrand Reinhold Co., 1979 - SOC = {'H': 0.0, 'N': 0.0, 'O': -0.000355, 'C': -0.000135, 'S': -0.000893, 'P': 0.0, 'I':-0.011547226,} + # Values taken from ref 22 of http://dx.doi.org/10.1063/1.477794 and converted to Hartrees + # Values in milli-Hartree are also available (with fewer significant figures) from table VII of + # http://dx.doi.org/10.1063/1.473182 + # Iodine SOC calculated as a weighted average of the electronic spin splittings of the lowest energy state. + # The splittings are obtained from Huber, K.P.; Herzberg, G., Molecular Spectra and Molecular Structure. IV. + # Constants of Diatomic Molecules, Van Nostrand Reinhold Co., 1979 + SOC = {'H': 0.0, 'N': 0.0, 'O': -0.000355, 'C': -0.000135, 'S': -0.000893, 'P': 0.0, 'I': -0.011547226, } # Step 1: Reference all energies to a model chemistry-independent basis # by subtracting out that model chemistry's atomic energies # All model chemistries here should be lower-case because the user input is changed to lower-case if atomEnergies is None: - # Note: If your model chemistry does not include spin orbit coupling, you should add the corrections to the energies here - if modelChemistry.startswith('cbs-qb3'): # only check start of string to allow different bond corrections (see below) - atomEnergies = {'H':-0.499818 + SOC['H'], 'N':-54.520543 + SOC['N'], 'O':-74.987624+ SOC['O'], 'C':-37.785385+ SOC['C'], 'P':-340.817186+ SOC['P'], 'S': -397.657360+ SOC['S']} + # Note: If your model chemistry does not include spin orbit coupling, you should add the corrections + # to the energies here + if modelChemistry.startswith('cbs-qb3'): + # only check start of string to allow different bond corrections (see below) + atomEnergies = {'H': -0.499818 + SOC['H'], 'N': -54.520543 + SOC['N'], 'O': -74.987624 + SOC['O'], + 'C': -37.785385 + SOC['C'], 'P': -340.817186 + SOC['P'], 'S': -397.657360 + SOC['S']} elif modelChemistry == 'm06-2x/cc-pvtz': - atomEnergies = {'H':-0.498135 + SOC['H'], 'N':-54.586780 + SOC['N'], 'O':-75.064242+ SOC['O'], 'C':-37.842468+ SOC['C'], 'P':-341.246985+ SOC['P'], 'S': -398.101240+ SOC['S']} + atomEnergies = {'H': -0.498135 + SOC['H'], 'N': -54.586780 + SOC['N'], 'O': -75.064242 + SOC['O'], + 'C': -37.842468 + SOC['C'], 'P': -341.246985 + SOC['P'], 'S': -398.101240 + SOC['S']} elif modelChemistry == 'g3': - atomEnergies = {'H':-0.5010030, 'N':-54.564343, 'O':-75.030991, 'C':-37.827717, 'P':-341.116432, 'S': -397.961110} - elif modelChemistry == 'm08so/mg3s*': # * indicates that the grid size used in the [QChem] electronic - #structure calculation utilized 75 radial points and 434 angular points - #(i.e,, this is specified in the $rem section of the [qchem] input file as: XC_GRID 000075000434) - atomEnergies = {'H':-0.5017321350 + SOC['H'], 'N':-54.5574039365 + SOC['N'], 'O':-75.0382931348+ SOC['O'], 'C':-37.8245648740+ SOC['C'], 'P':-341.2444299005+ SOC['P'], 'S':-398.0940312227+ SOC['S'] } + atomEnergies = {'H': -0.5010030, 'N': -54.564343, 'O': -75.030991, 'C': -37.827717, 'P': -341.116432, + 'S': -397.961110} + elif modelChemistry == 'm08so/mg3s*': + # * indicates that the grid size used in the [QChem] electronic + # structure calculation utilized 75 radial points and 434 angular points + # (i.e,, this is specified in the $rem section of the [qchem] input file as: XC_GRID 000075000434) + atomEnergies = {'H': -0.5017321350 + SOC['H'], 'N': -54.5574039365 + SOC['N'], + 'O': -75.0382931348 + SOC['O'], 'C': -37.8245648740 + SOC['C'], + 'P': -341.2444299005 + SOC['P'], 'S': -398.0940312227 + SOC['S']} elif modelChemistry == 'klip_1': - atomEnergies = {'H':-0.50003976 + SOC['H'], 'N':-54.53383153 + SOC['N'], 'O':-75.00935474+ SOC['O'], 'C':-37.79266591+ SOC['C']} + atomEnergies = {'H': -0.50003976 + SOC['H'], 'N': -54.53383153 + SOC['N'], 'O': -75.00935474 + SOC['O'], + 'C': -37.79266591 + SOC['C']} elif modelChemistry == 'klip_2': - #Klip QCI(tz,qz) - atomEnergies = {'H':-0.50003976 + SOC['H'], 'N':-54.53169400 + SOC['N'], 'O':-75.00714902+ SOC['O'], 'C':-37.79060419+ SOC['C']} + # Klip QCI(tz,qz) + atomEnergies = {'H': -0.50003976 + SOC['H'], 'N': -54.53169400 + SOC['N'], 'O': -75.00714902 + SOC['O'], + 'C': -37.79060419 + SOC['C']} elif modelChemistry == 'klip_3': - #Klip QCI(dz,tz) - atomEnergies = {'H':-0.50005578 + SOC['H'], 'N':-54.53128140 + SOC['N'], 'O':-75.00356581+ SOC['O'], 'C':-37.79025175+ SOC['C']} + # Klip QCI(dz,tz) + atomEnergies = {'H': -0.50005578 + SOC['H'], 'N': -54.53128140 + SOC['N'], 'O': -75.00356581 + SOC['O'], + 'C': -37.79025175 + SOC['C']} elif modelChemistry == 'klip_2_cc': - #Klip CCSD(T)(tz,qz) - atomEnergies = {'H':-0.50003976 + SOC['H'], 'O':-75.00681155+ SOC['O'], 'C':-37.79029443+ SOC['C']} + # Klip CCSD(T)(tz,qz) + atomEnergies = {'H': -0.50003976 + SOC['H'], 'O': -75.00681155 + SOC['O'], 'C': -37.79029443 + SOC['C']} elif modelChemistry == 'ccsd(t)-f12/cc-pvdz-f12_h-tz': - atomEnergies = {'H':-0.499946213243 + SOC['H'], 'N':-54.526406291655 + SOC['N'], 'O':-74.995458316117+ SOC['O'], 'C':-37.788203485235+ SOC['C']} + atomEnergies = {'H': -0.499946213243 + SOC['H'], 'N': -54.526406291655 + SOC['N'], + 'O': -74.995458316117 + SOC['O'], 'C': -37.788203485235 + SOC['C']} elif modelChemistry == 'ccsd(t)-f12/cc-pvdz-f12_h-qz': - atomEnergies = {'H':-0.499994558325 + SOC['H'], 'N':-54.526406291655 + SOC['N'], 'O':-74.995458316117+ SOC['O'], 'C':-37.788203485235+ SOC['C']} + atomEnergies = {'H': -0.499994558325 + SOC['H'], 'N': -54.526406291655 + SOC['N'], + 'O': -74.995458316117 + SOC['O'], 'C': -37.788203485235 + SOC['C']} # We are assuming that SOC is included in the Bond Energy Corrections elif modelChemistry == 'ccsd(t)-f12/cc-pvdz-f12': - atomEnergies = {'H':-0.499811124128, 'N':-54.526406291655, 'O':-74.995458316117, 'C':-37.788203485235, 'S':-397.663040369707} + atomEnergies = {'H': -0.499811124128, 'N': -54.526406291655, 'O': -74.995458316117, + 'C': -37.788203485235, 'S': -397.663040369707} elif modelChemistry == 'ccsd(t)-f12/cc-pvtz-f12': - atomEnergies = {'H':-0.499946213243, 'N':-54.53000909621, 'O':-75.004127673424, 'C':-37.789862146471, 'S':-397.675447487865} + atomEnergies = {'H': -0.499946213243, 'N': -54.53000909621, 'O': -75.004127673424, + 'C': -37.789862146471, 'S': -397.675447487865} elif modelChemistry == 'ccsd(t)-f12/cc-pvqz-f12': - atomEnergies = {'H':-0.499994558325, 'N':-54.530515226371, 'O':-75.005600062003, 'C':-37.789961656228, 'S':-397.676719774973} + atomEnergies = {'H': -0.499994558325, 'N': -54.530515226371, 'O': -75.005600062003, + 'C': -37.789961656228, 'S': -397.676719774973} elif modelChemistry == 'ccsd(t)-f12/cc-pcvdz-f12': - atomEnergies = {'H':-0.499811124128 + SOC['H'], 'N':-54.582137180344 + SOC['N'], 'O':-75.053045547421 + SOC['O'], 'C':-37.840869118707+ SOC['C']} + atomEnergies = {'H': -0.499811124128 + SOC['H'], 'N': -54.582137180344 + SOC['N'], + 'O': -75.053045547421 + SOC['O'], 'C': -37.840869118707 + SOC['C']} elif modelChemistry == 'ccsd(t)-f12/cc-pcvtz-f12': - atomEnergies = {'H':-0.499946213243 + SOC['H'], 'N':-54.588545831900 + SOC['N'], 'O':-75.065995072347 + SOC['O'], 'C':-37.844662139972+ SOC['C']} + atomEnergies = {'H': -0.499946213243 + SOC['H'], 'N': -54.588545831900 + SOC['N'], + 'O': -75.065995072347 + SOC['O'], 'C': -37.844662139972 + SOC['C']} elif modelChemistry == 'ccsd(t)-f12/cc-pcvqz-f12': - atomEnergies = {'H':-0.499994558325 + SOC['H'], 'N':-54.589137594139+ SOC['N'], 'O':-75.067412234737+ SOC['O'], 'C':-37.844893820561+ SOC['C']} + atomEnergies = {'H': -0.499994558325 + SOC['H'], 'N': -54.589137594139 + SOC['N'], + 'O': -75.067412234737 + SOC['O'], 'C': -37.844893820561 + SOC['C']} elif modelChemistry == 'ccsd(t)-f12/cc-pvtz-f12(-pp)': - atomEnergies = {'H':-0.499946213243 + SOC['H'], 'N':-54.53000909621 + SOC['N'], 'O':-75.004127673424 + SOC['O'], 'C':-37.789862146471 + SOC['C'], 'S':-397.675447487865 + SOC['S'], 'I':-294.81781766 + SOC['I']} - #ccsd(t)/aug-cc-pvtz(-pp) atomic energies were fit to a set of 8 small molecules: CH4, CH3OH, H2S, H2O, SO2, HI, I2, CH3I + atomEnergies = {'H': -0.499946213243 + SOC['H'], 'N': -54.53000909621 + SOC['N'], + 'O': -75.004127673424 + SOC['O'], 'C': -37.789862146471 + SOC['C'], + 'S': -397.675447487865 + SOC['S'], 'I': -294.81781766 + SOC['I']} + # ccsd(t)/aug-cc-pvtz(-pp) atomic energies were fit to a set of 8 small molecules: + # CH4, CH3OH, H2S, H2O, SO2, HI, I2, CH3I elif modelChemistry == 'ccsd(t)/aug-cc-pvtz(-pp)': - atomEnergies = {'H':-0.499821176024 + SOC['H'], 'O':-74.96738492 + SOC['O'], 'C':-37.77385697 + SOC['C'], 'S':-397.6461604 + SOC['S'], 'I':-294.7958443 + SOC['I']} - - elif modelChemistry == 'ccsd(t)-f12/aug-cc-pvdz': # note that all atom corrections but S are fitted, the correction for S is calculated - atomEnergies = {'H':-0.499459066131 + SOC['H'], 'N':-54.524279516472 + SOC['N'], 'O':-74.992097308083+ SOC['O'], 'C':-37.786694171716+ SOC['C'], 'S':-397.648733842400 + SOC['S']} + atomEnergies = {'H': -0.499821176024 + SOC['H'], 'O': -74.96738492 + SOC['O'], + 'C': -37.77385697 + SOC['C'], 'S': -397.6461604 + SOC['S'], + 'I': -294.7958443 + SOC['I']} + + elif modelChemistry == 'ccsd(t)-f12/aug-cc-pvdz': + # note that all atom corrections but S are fitted, the correction for S is calculated + atomEnergies = {'H': -0.499459066131 + SOC['H'], 'N': -54.524279516472 + SOC['N'], + 'O': -74.992097308083 + SOC['O'], 'C': -37.786694171716 + SOC['C'], + 'S': -397.648733842400 + SOC['S']} elif modelChemistry == 'ccsd(t)-f12/aug-cc-pvtz': - atomEnergies = {'H':-0.499844820798 + SOC['H'], 'N':-54.527419359906 + SOC['N'], 'O':-75.000001429806 + SOC['O'], 'C':-37.788504810868 + SOC['C'], 'S':-397.666903000231 + SOC['S']} + atomEnergies = {'H': -0.499844820798 + SOC['H'], 'N': -54.527419359906 + SOC['N'], + 'O': -75.000001429806 + SOC['O'], 'C': -37.788504810868 + SOC['C'], + 'S': -397.666903000231 + SOC['S']} elif modelChemistry == 'ccsd(t)-f12/aug-cc-pvqz': - atomEnergies = {'H':-0.499949526073 + SOC['H'], 'N':-54.529569719016 + SOC['N'], 'O':-75.004026586610+ SOC['O'], 'C':-37.789387892348+ SOC['C'], 'S':-397.671214204994 + SOC['S']} - + atomEnergies = {'H': -0.499949526073 + SOC['H'], 'N': -54.529569719016 + SOC['N'], + 'O': -75.004026586610 + SOC['O'], 'C': -37.789387892348 + SOC['C'], + 'S': -397.671214204994 + SOC['S']} elif modelChemistry == 'b-ccsd(t)-f12/cc-pvdz-f12': - atomEnergies = {'H':-0.499811124128 + SOC['H'], 'N':-54.523269942190 + SOC['N'], 'O':-74.990725918500 + SOC['O'], 'C':-37.785409916465 + SOC['C'], 'S': -397.658155086033 + SOC['S']} + atomEnergies = {'H': -0.499811124128 + SOC['H'], 'N': -54.523269942190 + SOC['N'], + 'O': -74.990725918500 + SOC['O'], 'C': -37.785409916465 + SOC['C'], + 'S': -397.658155086033 + SOC['S']} elif modelChemistry == 'b-ccsd(t)-f12/cc-pvtz-f12': - atomEnergies = {'H':-0.499946213243 + SOC['H'], 'N':-54.528135889213 + SOC['N'], 'O':-75.001094055506 + SOC['O'], 'C':-37.788233578503 + SOC['C'], 'S':-397.671745425929 + SOC['S']} + atomEnergies = {'H': -0.499946213243 + SOC['H'], 'N': -54.528135889213 + SOC['N'], + 'O': -75.001094055506 + SOC['O'], 'C': -37.788233578503 + SOC['C'], + 'S': -397.671745425929 + SOC['S']} elif modelChemistry == 'b-ccsd(t)-f12/cc-pvqz-f12': - atomEnergies = {'H':-0.499994558325 + SOC['H'], 'N':-54.529425753163 + SOC['N'], 'O':-75.003820485005 + SOC['O'], 'C':-37.789006506290 + SOC['C'], 'S':-397.674145126931 + SOC['S']} + atomEnergies = {'H': -0.499994558325 + SOC['H'], 'N': -54.529425753163 + SOC['N'], + 'O': -75.003820485005 + SOC['O'], 'C': -37.789006506290 + SOC['C'], + 'S': -397.674145126931 + SOC['S']} elif modelChemistry == 'b-ccsd(t)-f12/cc-pcvdz-f12': - atomEnergies = {'H':-0.499811124128 + SOC['H'], 'N':-54.578602780288 + SOC['N'], 'O':-75.048064317367+ SOC['O'], 'C':-37.837592033417+ SOC['C']} + atomEnergies = {'H': -0.499811124128 + SOC['H'], 'N': -54.578602780288 + SOC['N'], + 'O': -75.048064317367 + SOC['O'], 'C': -37.837592033417 + SOC['C']} elif modelChemistry == 'b-ccsd(t)-f12/cc-pcvtz-f12': - atomEnergies = {'H':-0.499946213243 + SOC['H'], 'N':-54.586402551258 + SOC['N'], 'O':-75.062767632757+ SOC['O'], 'C':-37.842729156944+ SOC['C']} + atomEnergies = {'H': -0.499946213243 + SOC['H'], 'N': -54.586402551258 + SOC['N'], + 'O': -75.062767632757 + SOC['O'], 'C': -37.842729156944 + SOC['C']} elif modelChemistry == 'b-ccsd(t)-f12/cc-pcvqz-f12': - atomEnergies = {'H':-0.49999456 + SOC['H'], 'N':-54.587781507581 + SOC['N'], 'O':-75.065397706471+ SOC['O'], 'C':-37.843634971592+ SOC['C']} + atomEnergies = {'H': -0.49999456 + SOC['H'], 'N': -54.587781507581 + SOC['N'], + 'O': -75.065397706471 + SOC['O'], 'C': -37.843634971592 + SOC['C']} elif modelChemistry == 'b-ccsd(t)-f12/aug-cc-pvdz': - atomEnergies = {'H':-0.499459066131 + SOC['H'], 'N':-54.520475581942 + SOC['N'], 'O':-74.986992215049+ SOC['O'], 'C':-37.783294495799+ SOC['C']} + atomEnergies = {'H': -0.499459066131 + SOC['H'], 'N': -54.520475581942 + SOC['N'], + 'O': -74.986992215049 + SOC['O'], 'C': -37.783294495799 + SOC['C']} elif modelChemistry == 'b-ccsd(t)-f12/aug-cc-pvtz': - atomEnergies = {'H':-0.499844820798 + SOC['H'], 'N':-54.524927371700 + SOC['N'], 'O':-74.996328829705+ SOC['O'], 'C':-37.786320700792+ SOC['C']} + atomEnergies = {'H': -0.499844820798 + SOC['H'], 'N': -54.524927371700 + SOC['N'], + 'O': -74.996328829705 + SOC['O'], 'C': -37.786320700792 + SOC['C']} elif modelChemistry == 'b-ccsd(t)-f12/aug-cc-pvqz': - atomEnergies = {'H':-0.499949526073 + SOC['H'], 'N':-54.528189769291 + SOC['N'], 'O':-75.001879610563+ SOC['O'], 'C':-37.788165047059+ SOC['C']} + atomEnergies = {'H': -0.499949526073 + SOC['H'], 'N': -54.528189769291 + SOC['N'], + 'O': -75.001879610563 + SOC['O'], 'C': -37.788165047059 + SOC['C']} elif modelChemistry == 'mp2_rmp2_pvdz': - atomEnergies = {'H':-0.49927840 + SOC['H'], 'N':-54.46141996 + SOC['N'], 'O':-74.89408254+ SOC['O'], 'C':-37.73792713+ SOC['C']} + atomEnergies = {'H': -0.49927840 + SOC['H'], 'N': -54.46141996 + SOC['N'], 'O': -74.89408254 + SOC['O'], + 'C': -37.73792713 + SOC['C']} elif modelChemistry == 'mp2_rmp2_pvtz': - atomEnergies = {'H':-0.49980981 + SOC['H'], 'N':-54.49615972 + SOC['N'], 'O':-74.95506980+ SOC['O'], 'C':-37.75833104+ SOC['C']} + atomEnergies = {'H': -0.49980981 + SOC['H'], 'N': -54.49615972 + SOC['N'], 'O': -74.95506980 + SOC['O'], + 'C': -37.75833104 + SOC['C']} elif modelChemistry == 'mp2_rmp2_pvqz': - atomEnergies = {'H':-0.49994557 + SOC['H'], 'N':-54.50715868 + SOC['N'], 'O':-74.97515364+ SOC['O'], 'C':-37.76533215+ SOC['C']} + atomEnergies = {'H': -0.49994557 + SOC['H'], 'N': -54.50715868 + SOC['N'], 'O': -74.97515364 + SOC['O'], + 'C': -37.76533215 + SOC['C']} elif modelChemistry == 'ccsd-f12/cc-pvdz-f12': - atomEnergies = {'H':-0.499811124128 + SOC['H'], 'N':-54.524325513811 + SOC['N'], 'O':-74.992326577897+ SOC['O'], 'C':-37.786213495943+ SOC['C']} + atomEnergies = {'H': -0.499811124128 + SOC['H'], 'N': -54.524325513811 + SOC['N'], + 'O': -74.992326577897 + SOC['O'], 'C': -37.786213495943 + SOC['C']} elif modelChemistry == 'ccsd(t)-f12/cc-pvdz-f12_noscale': - atomEnergies = {'H':-0.499811124128 + SOC['H'], 'N':-54.526026290887 + SOC['N'], 'O':-74.994751897699+ SOC['O'], 'C':-37.787881871511+ SOC['C']} + atomEnergies = {'H': -0.499811124128 + SOC['H'], 'N': -54.526026290887 + SOC['N'], + 'O': -74.994751897699 + SOC['O'], 'C': -37.787881871511 + SOC['C']} elif modelChemistry == 'g03_pbepbe_6-311++g_d_p': - atomEnergies = {'H':-0.499812273282 + SOC['H'], 'N':-54.5289567564 + SOC['N'], 'O':-75.0033596764+ SOC['O'], 'C':-37.7937388736+ SOC['C']} + atomEnergies = {'H': -0.499812273282 + SOC['H'], 'N': -54.5289567564 + SOC['N'], + 'O': -75.0033596764 + SOC['O'], 'C': -37.7937388736 + SOC['C']} elif modelChemistry == 'fci/cc-pvdz': - atomEnergies = {'C':-37.789527+ SOC['C']} + atomEnergies = {'C': -37.789527 + SOC['C']} elif modelChemistry == 'fci/cc-pvtz': - atomEnergies = {'C':-37.781266669684+ SOC['C']} + atomEnergies = {'C': -37.781266669684 + SOC['C']} elif modelChemistry == 'fci/cc-pvqz': - atomEnergies = {'C':-37.787052110598+ SOC['C']} + atomEnergies = {'C': -37.787052110598 + SOC['C']} elif modelChemistry in ['bmk/cbsb7', 'bmk/6-311g(2d,d,p)']: - atomEnergies = {'H':-0.498618853119+ SOC['H'], 'N':-54.5697851544+ SOC['N'], 'O':-75.0515210278+ SOC['O'], 'C':-37.8287310027+ SOC['C'], 'P':-341.167615941+ SOC['P'], 'S': -398.001619915+ SOC['S']} + atomEnergies = {'H': -0.498618853119 + SOC['H'], 'N': -54.5697851544 + SOC['N'], + 'O': -75.0515210278 + SOC['O'], 'C': -37.8287310027 + SOC['C'], + 'P': -341.167615941 + SOC['P'], 'S': -398.001619915 + SOC['S']} elif modelChemistry == 'b3lyp/6-31g**': # Fitted to small molecules - atomEnergies = {'H':-0.500426155, 'C':-37.850331697831, 'O':-75.0535872748806, 'S':-398.100820107242} + atomEnergies = {'H': -0.500426155, 'C': -37.850331697831, 'O': -75.0535872748806, + 'S': -398.100820107242} elif modelChemistry == 'b3lyp/6-311+g(3df,2p)': # Calculated atomic energies - atomEnergies = {'H':-0.502155915123 + SOC['H'], 'C':-37.8574709934 + SOC['C'], 'N':-54.6007233609 + SOC['N'], 'O':-75.0909131284 + SOC['O'], 'P':-341.281730319 + SOC['P'], 'S':-398.134489850 + SOC['S']} + atomEnergies = {'H': -0.502155915123 + SOC['H'], 'C': -37.8574709934 + SOC['C'], + 'N': -54.6007233609 + SOC['N'], 'O': -75.0909131284 + SOC['O'], + 'P': -341.281730319 + SOC['P'], 'S': -398.134489850 + SOC['S']} elif modelChemistry == 'wb97x-d/aug-cc-pvtz': - atomEnergies = {'H':-0.502803+ SOC['H'], 'N':-54.585652+ SOC['N'], 'O':-75.068286+ SOC['O'], 'C':-37.842014+ SOC['C']} + atomEnergies = {'H': -0.502803 + SOC['H'], 'N': -54.585652 + SOC['N'], 'O': -75.068286 + SOC['O'], + 'C': -37.842014 + SOC['C']} elif modelChemistry == 'MRCI+Davidson/aug-cc-pV(T+d)Z': # Calculated atomic energies (unfitted) - atomEnergies = {'H':-0.49982118 + SOC['H'], 'C':-37.78321274 + SOC['C'], 'N':-54.51729444 + SOC['N'], 'O':-74.97847534 + SOC['O'], 'S':-397.6571654 + SOC['S']} + atomEnergies = {'H': -0.49982118 + SOC['H'], 'C': -37.78321274 + SOC['C'], 'N': -54.51729444 + SOC['N'], + 'O': -74.97847534 + SOC['O'], 'S': -397.6571654 + SOC['S']} else: raise Exception('Unknown model chemistry "{}".'.format(modelChemistry)) @@ -786,20 +848,22 @@ def applyEnergyCorrections(E0, modelChemistry, atoms, bonds, # Codata: Cox, J. D., Wagman, D. D., and Medvedev, V. A., CODATA Key Values for Thermodynamics, Hemisphere # Publishing Corp., New York, 1989. (http://www.science.uwaterloo.ca/~cchieh/cact/tools/thermodata.html) atom_hf = {'H': 51.63, 'He': -1.481, - 'Li': 37.69, 'Be': 76.48, 'B': 136.2, 'C': 169.98, 'N': 112.53, 'O': 58.99, 'F': 18.47, 'Ne': -1.481, - 'Na': 25.69, 'Mg': 34.87, 'Al': 78.23, 'Si': 106.6, 'P': 75.42, 'S': 65.66, 'Cl': 28.59, - 'K': 36.841, 'Ca': 41.014, 'Ti': 111.2, 'Cu': 79.16, 'Zn': 29.685, 'Ge': 87.1, 'Br': 25.26, 'Kr': -1.481, - 'Rb': 17.86, 'Ag': 66.61, 'Cd': 25.240, 'Sn': 70.50, 'I': 24.04, 'Xe': -1.481, - 'Cs': 16.80, 'Hg': 13.19, 'Pb': 15.17} + 'Li': 37.69, 'Be': 76.48, 'B': 136.2, 'C': 169.98, 'N': 112.53, 'O': 58.99, 'F': 18.47, 'Ne': -1.481, + 'Na': 25.69, 'Mg': 34.87, 'Al': 78.23, 'Si': 106.6, 'P': 75.42, 'S': 65.66, 'Cl': 28.59, + 'K': 36.841, 'Ca': 41.014, 'Ti': 111.2, 'Cu': 79.16, 'Zn': 29.685, 'Ge': 87.1, 'Br': 25.26, + 'Kr': -1.481, + 'Rb': 17.86, 'Ag': 66.61, 'Cd': 25.240, 'Sn': 70.50, 'I': 24.04, 'Xe': -1.481, + 'Cs': 16.80, 'Hg': 13.19, 'Pb': 15.17} # Thermal contribution to enthalpy Hss(298 K) - Hss(0 K) reported by Gaussian thermo whitepaper # This will be subtracted from the corresponding value in atom_hf to produce an enthalpy used in calculating # the enthalpy of formation at 298 K atom_thermal = {'H': 1.01, 'He': 1.481, - 'Li': 1.1, 'Be': 0.46, 'B': 0.29, 'C': 0.25, 'N': 1.04, 'O': 1.04, 'F': 1.05, 'Ne': 1.481, - 'Na': 1.54, 'Mg': 1.19, 'Al': 1.08, 'Si': 0.76, 'P': 1.28, 'S': 1.05, 'Cl': 1.1, - 'K': 1.481, 'Ca': 1.481, 'Ti': 1.802, 'Cu': 1.481, 'Zn': 1.481, 'Ge': 1.768, 'Br': 1.481, 'Kr': 1.481, - 'Rb': 1.481, 'Ag': 1.481, 'Cd': 1.481, 'Sn': 1.485, 'I': 1.481, 'Xe': 1.481, - 'Cs': 1.481, 'Hg': 1.481, 'Pb': 1.481} + 'Li': 1.1, 'Be': 0.46, 'B': 0.29, 'C': 0.25, 'N': 1.04, 'O': 1.04, 'F': 1.05, 'Ne': 1.481, + 'Na': 1.54, 'Mg': 1.19, 'Al': 1.08, 'Si': 0.76, 'P': 1.28, 'S': 1.05, 'Cl': 1.1, + 'K': 1.481, 'Ca': 1.481, 'Ti': 1.802, 'Cu': 1.481, 'Zn': 1.481, 'Ge': 1.768, 'Br': 1.481, + 'Kr': 1.481, + 'Rb': 1.481, 'Ag': 1.481, 'Cd': 1.481, 'Sn': 1.485, 'I': 1.481, 'Xe': 1.481, + 'Cs': 1.481, 'Hg': 1.481, 'Pb': 1.481} # Total energy correction used to reach gas-phase reference state # Note: Spin orbit coupling is no longer included in these energies, since some model chemistries include it # automatically @@ -821,42 +885,50 @@ def applyEnergyCorrections(E0, modelChemistry, atoms, bonds, # 'S-H', 'C-S', 'C=S', 'S-S', 'O-S', 'O=S', 'O=S=O' taken from http://hdl.handle.net/1721.1/98155 (both for # 'CCSD(T)-F12/cc-pVDZ-F12' and 'CCSD(T)-F12/cc-pVTZ-F12') if modelChemistry == 'ccsd(t)-f12/cc-pvdz-f12': - bondEnergies = { 'C-H': -0.46, 'C-C': -0.68, 'C=C': -1.90, 'C#C': -3.13, - 'O-H': -0.51, 'C-O': -0.23, 'C=O': -0.69, 'O-O': -0.02, 'C-N': -0.67, - 'C=N': -1.46, 'C#N': -2.79, 'N-O': 0.74, 'N_O': -0.23, 'N=O': -0.51, - 'N-H': -0.69, 'N-N': -0.47, 'N=N': -1.54, 'N#N': -2.05, 'S-H': 0.87, - 'C-S': 0.42, 'C=S': 0.51, 'S-S': 0.86, 'O-S': 0.23, 'O=S': -0.53, - 'O=S=O': 1.95, } + bondEnergies = {'C-H': -0.46, 'C-C': -0.68, 'C=C': -1.90, 'C#C': -3.13, + 'O-H': -0.51, 'C-O': -0.23, 'C=O': -0.69, 'O-O': -0.02, 'C-N': -0.67, + 'C=N': -1.46, 'C#N': -2.79, 'N-O': 0.74, 'N_O': -0.23, 'N=O': -0.51, + 'N-H': -0.69, 'N-N': -0.47, 'N=N': -1.54, 'N#N': -2.05, 'S-H': 0.87, + 'C-S': 0.42, 'C=S': 0.51, 'S-S': 0.86, 'O-S': 0.23, 'O=S': -0.53, + 'O=S=O': 1.95, } elif modelChemistry == 'ccsd(t)-f12/cc-pvtz-f12': - bondEnergies = { 'C-H': -0.09, 'C-C': -0.27, 'C=C': -1.03, 'C#C': -1.79, - 'O-H': -0.06, 'C-O': 0.14, 'C=O': -0.19, 'O-O': 0.16, 'C-N': -0.18, - 'C=N': -0.41, 'C#N': -1.41, 'N-O': 0.87, 'N_O': -0.09, 'N=O': -0.23, - 'N-H': -0.01, 'N-N': -0.21, 'N=N': -0.44, 'N#N': -0.76, 'S-H': 0.52, - 'C-S': 0.13, 'C=S': -0.12, 'S-S': 0.30, 'O-S': 0.15, 'O=S': -2.61, - 'O=S=O': 0.27, } + bondEnergies = {'C-H': -0.09, 'C-C': -0.27, 'C=C': -1.03, 'C#C': -1.79, + 'O-H': -0.06, 'C-O': 0.14, 'C=O': -0.19, 'O-O': 0.16, 'C-N': -0.18, + 'C=N': -0.41, 'C#N': -1.41, 'N-O': 0.87, 'N_O': -0.09, 'N=O': -0.23, + 'N-H': -0.01, 'N-N': -0.21, 'N=N': -0.44, 'N#N': -0.76, 'S-H': 0.52, + 'C-S': 0.13, 'C=S': -0.12, 'S-S': 0.30, 'O-S': 0.15, 'O=S': -2.61, + 'O=S=O': 0.27, } elif modelChemistry == 'ccsd(t)-f12/cc-pvqz-f12': - bondEnergies = { 'C-H': -0.08, 'C-C': -0.26, 'C=C': -1.01, 'C#C': -1.66, - 'O-H': 0.07, 'C-O': 0.25, 'C=O': -0.03, 'O-O': 0.26, 'C-N': -0.20, - 'C=N': -0.30, 'C#N': -1.33, 'N-O': 1.01, 'N_O': -0.03, 'N=O': -0.26, - 'N-H': 0.06, 'N-N': -0.23, 'N=N': -0.37, 'N#N': -0.64,} + bondEnergies = {'C-H': -0.08, 'C-C': -0.26, 'C=C': -1.01, 'C#C': -1.66, + 'O-H': 0.07, 'C-O': 0.25, 'C=O': -0.03, 'O-O': 0.26, 'C-N': -0.20, + 'C=N': -0.30, 'C#N': -1.33, 'N-O': 1.01, 'N_O': -0.03, 'N=O': -0.26, + 'N-H': 0.06, 'N-N': -0.23, 'N=N': -0.37, 'N#N': -0.64, } elif modelChemistry == 'cbs-qb3': bondEnergies = { - 'C-H': -0.11, 'C-C': -0.30, 'C=C': -0.08, 'C#C': -0.64, 'O-H' : 0.02, 'C-O': 0.33, 'C=O': 0.55, # Table IX: Petersson GA (1998) J. of Chemical Physics, DOI: 10.1063/1.477794 - 'N-H': -0.42, 'C-N': -0.13, 'C#N': -0.89, 'C-F': 0.55, 'C-Cl': 1.29, 'S-H': 0.0, 'C-S': 0.43, 'O=S': -0.78, - 'N=O': 1.11, 'N-N': -1.87, 'N=N': -1.58, 'N-O': 0.35, #Table 2: Ashcraft R (2007) J. Phys. Chem. B; DOI: 10.1021/jp073539t - 'N#N': -2.0, 'O=O': -0.2, 'H-H': 1.1, # Unknown source + 'C-H': -0.11, 'C-C': -0.30, 'C=C': -0.08, 'C#C': -0.64, 'O-H': 0.02, 'C-O': 0.33, 'C=O': 0.55, + # Table IX: Petersson GA (1998) J. of Chemical Physics, DOI: 10.1063/1.477794 + 'N-H': -0.42, 'C-N': -0.13, 'C#N': -0.89, 'C-F': 0.55, 'C-Cl': 1.29, 'S-H': 0.0, 'C-S': 0.43, + 'O=S': -0.78, + 'N=O': 1.11, 'N-N': -1.87, 'N=N': -1.58, 'N-O': 0.35, + # Table 2: Ashcraft R (2007) J. Phys. Chem. B; DOI: 10.1021/jp073539t + 'N#N': -2.0, 'O=O': -0.2, 'H-H': 1.1, # Unknown source } - elif modelChemistry == 'cbs-qb3-paraskevas': # NOTE: The Paraskevas corrections are inaccurate for non-oxygenated hydrocarbons, and may do poorly in combination with the Petersson corrections + elif modelChemistry == 'cbs-qb3-paraskevas': + # NOTE: The Paraskevas corrections are inaccurate for non-oxygenated hydrocarbons, + # and may do poorly in combination with the Petersson corrections bondEnergies = { - 'C-C': -0.495,'C-H': -0.045,'C=C': -0.825,'C-O': 0.378,'C=O': 0.743,'O-H': -0.423, #Table2: Paraskevas, PD (2013). Chemistry-A European J., DOI: 10.1002/chem.201301381 - 'C#C': -0.64, 'C#N': -0.89, 'C-S': 0.43, 'O=S': -0.78,'S-H': 0.0, 'C-N': -0.13, 'C-Cl': 1.29, 'C-F': 0.55, # Table IX: Petersson GA (1998) J. of Chemical Physics, DOI: 10.1063/1.477794 - 'N-H': -0.42, 'N=O': 1.11, 'N-N': -1.87, 'N=N': -1.58,'N-O': 0.35, #Table 2: Ashcraft R (2007) J. Phys. Chem. B; DOI: 10.1021/jp073539t - 'N#N': -2.0, 'O=O': -0.2, 'H-H': 1.1, # Unknown source - } + 'C-C': -0.495, 'C-H': -0.045, 'C=C': -0.825, 'C-O': 0.378, 'C=O': 0.743, 'O-H': -0.423, + # Table2: Paraskevas, PD (2013). Chemistry-A European J., DOI: 10.1002/chem.201301381 + 'C#C': -0.64, 'C#N': -0.89, 'C-S': 0.43, 'O=S': -0.78, 'S-H': 0.0, 'C-N': -0.13, 'C-Cl': 1.29, + 'C-F': 0.55, # Table IX: Petersson GA (1998) J. of Chemical Physics, DOI: 10.1063/1.477794 + 'N-H': -0.42, 'N=O': 1.11, 'N-N': -1.87, 'N=N': -1.58, 'N-O': 0.35, + # Table 2: Ashcraft R (2007) J. Phys. Chem. B; DOI: 10.1021/jp073539t + 'N#N': -2.0, 'O=O': -0.2, 'H-H': 1.1, # Unknown source + } elif modelChemistry in ['b3lyp/cbsb7', 'b3lyp/6-311g(2d,d,p)', 'b3lyp/6-311+g(3df,2p)', 'b3lyp/6-31g**']: - bondEnergies = { 'C-H': 0.25, 'C-C': -1.89, 'C=C': -0.40, 'C#C': -1.50, - 'O-H': -1.09, 'C-O': -1.18, 'C=O': -0.01, 'N-H': 1.36, 'C-N': -0.44, - 'C#N': 0.22, 'C-S': -2.35, 'O=S': -5.19, 'S-H': -0.52, } + bondEnergies = {'C-H': 0.25, 'C-C': -1.89, 'C=C': -0.40, 'C#C': -1.50, + 'O-H': -1.09, 'C-O': -1.18, 'C=O': -0.01, 'N-H': 1.36, 'C-N': -0.44, + 'C#N': 0.22, 'C-S': -2.35, 'O=S': -5.19, 'S-H': -0.52, } else: logging.warning('No bond energy correction found for model chemistry: {0}'.format(modelChemistry)) @@ -870,6 +942,7 @@ def applyEnergyCorrections(E0, modelChemistry, atoms, bonds, return E0 + def determine_qm_software(fullpath): """ Given a path to the log file of a QM software, determine whether it is Gaussian, Molpro, or QChem @@ -892,7 +965,8 @@ def determine_qm_software(fullpath): break line = f.readline() else: - raise InputError("File at {0} could not be identified as a Gaussian, QChem or Molpro log file.".format(fullpath)) + raise InputError( + "File at {0} could not be identified as a Gaussian, QChem or Molpro log file.".format(fullpath)) return software_log @@ -914,104 +988,103 @@ def projectRotors(conformer, F, rotors, linear, is_ts): mass = conformer.mass.value_si coordinates = conformer.coordinates.getValue() - # Put origin in center of mass - xm=0.0 - ym=0.0 - zm=0.0 - totmass=0.0 + xm = 0.0 + ym = 0.0 + zm = 0.0 + totmass = 0.0 for i in range(Natoms): - xm+=mass[i]*coordinates[i,0] - ym+=mass[i]*coordinates[i,1] - zm+=mass[i]*coordinates[i,2] - totmass+=mass[i] + xm += mass[i] * coordinates[i, 0] + ym += mass[i] * coordinates[i, 1] + zm += mass[i] * coordinates[i, 2] + totmass += mass[i] - xm/=totmass - ym/=totmass - zm/=totmass + xm /= totmass + ym /= totmass + zm /= totmass for i in range(Natoms): - coordinates[i,0]-=xm - coordinates[i,1]-=ym - coordinates[i,2]-=zm + coordinates[i, 0] -= xm + coordinates[i, 1] -= ym + coordinates[i, 2] -= zm # Make vector with the root of the mass in amu for each atom - amass=numpy.sqrt(mass/constants.amu) + amass = numpy.sqrt(mass / constants.amu) # Rotation matrix - I=conformer.getMomentOfInertiaTensor() + I = conformer.getMomentOfInertiaTensor() PMoI, Ixyz = numpy.linalg.eigh(I) - external=6 + external = 6 if linear: - external=5 + external = 5 - D = numpy.zeros((Natoms*3,external), numpy.float64) + D = numpy.zeros((Natoms * 3, external), numpy.float64) - P = numpy.zeros((Natoms,3), numpy.float64) + P = numpy.zeros((Natoms, 3), numpy.float64) # Transform the coordinates to the principal axes - P = numpy.dot(coordinates,Ixyz) + P = numpy.dot(coordinates, Ixyz) for i in range(Natoms): # Projection vectors for translation - D[3*i+0,0] = amass[i] - D[3*i+1,1] = amass[i] - D[3*i+2,2] = amass[i] + D[3 * i + 0, 0] = amass[i] + D[3 * i + 1, 1] = amass[i] + D[3 * i + 2, 2] = amass[i] # Construction of the projection vectors for external rotation for i in range(Natoms): - D[3*i,3] = (P[i,1]*Ixyz[0,2]-P[i,2]*Ixyz[0,1])*amass[i] - D[3*i+1,3] = (P[i,1]*Ixyz[1,2]-P[i,2]*Ixyz[1,1])*amass[i] - D[3*i+2,3] = (P[i,1]*Ixyz[2,2]-P[i,2]*Ixyz[2,1])*amass[i] - D[3*i,4] = (P[i,2]*Ixyz[0,0]-P[i,0]*Ixyz[0,2])*amass[i] - D[3*i+1,4] = (P[i,2]*Ixyz[1,0]-P[i,0]*Ixyz[1,2])*amass[i] - D[3*i+2,4] = (P[i,2]*Ixyz[2,0]-P[i,0]*Ixyz[2,2])*amass[i] + D[3 * i, 3] = (P[i, 1] * Ixyz[0, 2] - P[i, 2] * Ixyz[0, 1]) * amass[i] + D[3 * i + 1, 3] = (P[i, 1] * Ixyz[1, 2] - P[i, 2] * Ixyz[1, 1]) * amass[i] + D[3 * i + 2, 3] = (P[i, 1] * Ixyz[2, 2] - P[i, 2] * Ixyz[2, 1]) * amass[i] + D[3 * i, 4] = (P[i, 2] * Ixyz[0, 0] - P[i, 0] * Ixyz[0, 2]) * amass[i] + D[3 * i + 1, 4] = (P[i, 2] * Ixyz[1, 0] - P[i, 0] * Ixyz[1, 2]) * amass[i] + D[3 * i + 2, 4] = (P[i, 2] * Ixyz[2, 0] - P[i, 0] * Ixyz[2, 2]) * amass[i] if not linear: - D[3*i,5] = (P[i,0]*Ixyz[0,1]-P[i,1]*Ixyz[0,0])*amass[i] - D[3*i+1,5] = (P[i,0]*Ixyz[1,1]-P[i,1]*Ixyz[1,0])*amass[i] - D[3*i+2,5] = (P[i,0]*Ixyz[2,1]-P[i,1]*Ixyz[2,0])*amass[i] + D[3 * i, 5] = (P[i, 0] * Ixyz[0, 1] - P[i, 1] * Ixyz[0, 0]) * amass[i] + D[3 * i + 1, 5] = (P[i, 0] * Ixyz[1, 1] - P[i, 1] * Ixyz[1, 0]) * amass[i] + D[3 * i + 2, 5] = (P[i, 0] * Ixyz[2, 1] - P[i, 1] * Ixyz[2, 0]) * amass[i] # Make sure projection matrix is orthonormal import scipy.linalg - I = numpy.identity(Natoms*3, numpy.float64) + I = numpy.identity(Natoms * 3, numpy.float64) - P = numpy.zeros((Natoms*3,3*Natoms+external), numpy.float64) + P = numpy.zeros((Natoms * 3, 3 * Natoms + external), numpy.float64) - P[:,0:external] = D[:,0:external] - P[:,external:external+3*Natoms] = I[:,0:3*Natoms] + P[:, 0:external] = D[:, 0:external] + P[:, external:external + 3 * Natoms] = I[:, 0:3 * Natoms] - for i in range(3*Natoms+external): - norm=0.0 - for j in range(3*Natoms): - norm+=P[j,i]*P[j,i] - for j in range(3*Natoms): - if (norm>1E-15): - P[j,i]/=numpy.sqrt(norm) + for i in range(3 * Natoms + external): + norm = 0.0 + for j in range(3 * Natoms): + norm += P[j, i] * P[j, i] + for j in range(3 * Natoms): + if (norm > 1E-15): + P[j, i] /= numpy.sqrt(norm) else: - P[j,i]=0.0 - for j in range(i+1,3*Natoms+external): - proj=0.0 - for k in range(3*Natoms): - proj+=P[k,i]*P[k,j] - for k in range(3*Natoms): - P[k,j]-=proj*P[k,i] + P[j, i] = 0.0 + for j in range(i + 1, 3 * Natoms + external): + proj = 0.0 + for k in range(3 * Natoms): + proj += P[k, i] * P[k, j] + for k in range(3 * Natoms): + P[k, j] -= proj * P[k, i] # Order D, there will be vectors that are 0.0 - i=0 - while i < 3*Natoms: - norm=0.0 - for j in range(3*Natoms): - norm+=P[j,i]*P[j,i] - if (norm<0.5): - P[:,i:3*Natoms+external-1] = P[:,i+1:3*Natoms+external] + i = 0 + while i < 3 * Natoms: + norm = 0.0 + for j in range(3 * Natoms): + norm += P[j, i] * P[j, i] + if (norm < 0.5): + P[:, i:3 * Natoms + external - 1] = P[:, i + 1:3 * Natoms + external] else: - i+=1 + i += 1 # T is the transformation vector from cartesian to internal coordinates - T = numpy.zeros((Natoms*3,3*Natoms-external), numpy.float64) + T = numpy.zeros((Natoms * 3, 3 * Natoms - external), numpy.float64) - T[:,0:3*Natoms-external] = P[:,external:3*Natoms] + T[:, 0:3 * Natoms - external] = P[:, external:3 * Natoms] # Generate mass-weighted force constant matrix # This converts the axes to mass-weighted Cartesian axes @@ -1021,23 +1094,23 @@ def projectRotors(conformer, F, rotors, linear, is_ts): for j in range(Natoms): for u in range(3): for v in range(3): - Fm[3*i+u,3*j+v] /= math.sqrt(mass[i] * mass[j]) + Fm[3 * i + u, 3 * j + v] /= math.sqrt(mass[i] * mass[j]) - Fint = numpy.dot(T.T, numpy.dot(Fm,T)) + Fint = numpy.dot(T.T, numpy.dot(Fm, T)) # Get eigenvalues of internal force constant matrix, V = 3N-6 * 3N-6 eig, V = numpy.linalg.eigh(Fint) logging.debug('Frequencies from internal Hessian') - for i in range(3*Natoms-external): + for i in range(3 * Natoms - external): with numpy.warnings.catch_warnings(): numpy.warnings.filterwarnings('ignore', r'invalid value encountered in sqrt') - logging.debug(numpy.sqrt(eig[i])/(2 * math.pi * constants.c * 100)) + logging.debug(numpy.sqrt(eig[i]) / (2 * math.pi * constants.c * 100)) # Now we can start thinking about projecting out the internal rotations - Dint=numpy.zeros((3*Natoms,Nrotors), numpy.float64) + Dint = numpy.zeros((3 * Natoms, Nrotors), numpy.float64) - counter=0 + counter = 0 for i, rotor in enumerate(rotors): if len(rotor) == 5: scanLog, pivots, top, symmetry, fit = rotor @@ -1050,58 +1123,59 @@ def projectRotors(conformer, F, rotors, linear, is_ts): elif pivots[1] in top: pivot1 = pivots[1] pivot2 = pivots[0] - else: raise Exception('Could not determine pivot atom.') + else: + raise Exception('Could not determine pivot atom.') # Projection vectors for internal rotation - e12 = coordinates[pivot1-1,:] - coordinates[pivot2-1,:] + e12 = coordinates[pivot1 - 1, :] - coordinates[pivot2 - 1, :] for j in range(Natoms): - atom=j+1 + atom = j + 1 if atom in top: - e31 = coordinates[atom-1,:] - coordinates[pivot1-1,:] - Dint[3*(atom-1):3*(atom-1)+3,counter] = numpy.cross(e31, e12)*amass[atom-1] + e31 = coordinates[atom - 1, :] - coordinates[pivot1 - 1, :] + Dint[3 * (atom - 1):3 * (atom - 1) + 3, counter] = numpy.cross(e31, e12) * amass[atom - 1] else: - e31 = coordinates[atom-1,:] - coordinates[pivot2-1,:] - Dint[3*(atom-1):3*(atom-1)+3,counter] = numpy.cross(e31, -e12)*amass[atom-1] - counter+=1 + e31 = coordinates[atom - 1, :] - coordinates[pivot2 - 1, :] + Dint[3 * (atom - 1):3 * (atom - 1) + 3, counter] = numpy.cross(e31, -e12) * amass[atom - 1] + counter += 1 # Normal modes in mass weighted cartesian coordinates - Vmw = numpy.dot(T,V) - eigM = numpy.zeros((3*Natoms-external,3*Natoms-external), numpy.float64) + Vmw = numpy.dot(T, V) + eigM = numpy.zeros((3 * Natoms - external, 3 * Natoms - external), numpy.float64) - for i in range(3*Natoms-external): - eigM[i,i]=eig[i] - - Fm=numpy.dot(Vmw,numpy.dot(eigM,Vmw.T)) + for i in range(3 * Natoms - external): + eigM[i, i] = eig[i] + + Fm = numpy.dot(Vmw, numpy.dot(eigM, Vmw.T)) # Internal rotations are not normal modes => project them on the normal modes and orthogonalize # Dintproj = (3N-6) x (3N) x (3N) x (Nrotors) - Dintproj=numpy.dot(Vmw.T,Dint) + Dintproj = numpy.dot(Vmw.T, Dint) # Reconstruct Dint for i in range(Nrotors): - for j in range (3*Natoms): - Dint[j,i]=0 - for k in range(3*Natoms-external): - Dint[j,i]+=Dintproj[k,i]*Vmw[j,k] + for j in range(3 * Natoms): + Dint[j, i] = 0 + for k in range(3 * Natoms - external): + Dint[j, i] += Dintproj[k, i] * Vmw[j, k] # Ortho normalize for i in range(Nrotors): - norm=0.0 - for j in range(3*Natoms): - norm+=Dint[j,i]*Dint[j,i] - for j in range(3*Natoms): - Dint[j,i]/=numpy.sqrt(norm) - for j in range(i+1,Nrotors): - proj=0.0 - for k in range (3*Natoms): - proj+=Dint[k,i]*Dint[k,j] - for k in range(3*Natoms): - Dint[k,j]-=proj*Dint[k,i] - - Dintproj=numpy.dot(Vmw.T,Dint) + norm = 0.0 + for j in range(3 * Natoms): + norm += Dint[j, i] * Dint[j, i] + for j in range(3 * Natoms): + Dint[j, i] /= numpy.sqrt(norm) + for j in range(i + 1, Nrotors): + proj = 0.0 + for k in range(3 * Natoms): + proj += Dint[k, i] * Dint[k, j] + for k in range(3 * Natoms): + Dint[k, j] -= proj * Dint[k, i] + + Dintproj = numpy.dot(Vmw.T, Dint) Proj = numpy.dot(Dint, Dint.T) - I = numpy.identity(Natoms*3, numpy.float64) - Proj = I - Proj - Fm=numpy.dot(Proj, numpy.dot(Fm,Proj)) + I = numpy.identity(Natoms * 3, numpy.float64) + Proj = I - Proj + Fm = numpy.dot(Proj, numpy.dot(Fm, Proj)) # Get eigenvalues of mass-weighted force constant matrix eig, V = numpy.linalg.eigh(Fm) eig.sort() @@ -1110,11 +1184,11 @@ def projectRotors(conformer, F, rotors, linear, is_ts): # Only keep the modes that don't correspond to translation, rotation, or internal rotation logging.debug('Frequencies from projected Hessian') - for i in range(3*Natoms): + for i in range(3 * Natoms): with numpy.warnings.catch_warnings(): numpy.warnings.filterwarnings('ignore', r'invalid value encountered in sqrt') - logging.debug(numpy.sqrt(eig[i])/(2 * math.pi * constants.c * 100)) - + logging.debug(numpy.sqrt(eig[i]) / (2 * math.pi * constants.c * 100)) + return numpy.sqrt(eig[-Nvib:]) / (2 * math.pi * constants.c * 100) @@ -1134,17 +1208,24 @@ def assign_frequency_scale_factor(model_chemistry): # 'klip_2_cc': , # 'ccsd(t)-f12/cc-pvdz-f12_h-tz': , # 'ccsd(t)-f12/cc-pvdz-f12_h-qz': , - 'ccsd(t)-f12/cc-pvdz-f12': 0.979, # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/cc-pvdz' - 'ccsd(t)-f12/cc-pvtz-f12': 0.984, # Taken from https://comp.chem.umn.edu/freqscale/version3b2.htm as CCSD(T)-F12a/cc-pVTZ-F12 - 'ccsd(t)-f12/cc-pvqz-f12': 0.970, # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/cc-pvqz' - 'ccsd(t)-f12/cc-pcvdz-f12': 0.971, # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/cc-pcvdz' + 'ccsd(t)-f12/cc-pvdz-f12': 0.979, + # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/cc-pvdz' + 'ccsd(t)-f12/cc-pvtz-f12': 0.984, + # Taken from https://comp.chem.umn.edu/freqscale/version3b2.htm as CCSD(T)-F12a/cc-pVTZ-F12 + 'ccsd(t)-f12/cc-pvqz-f12': 0.970, + # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/cc-pvqz' + 'ccsd(t)-f12/cc-pcvdz-f12': 0.971, + # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/cc-pcvdz' 'ccsd(t)-f12/cc-pcvtz-f12': 0.966, # 'ccsd(t)-f12/cc-pcvqz-f12': , # 'ccsd(t)-f12/cc-pvtz-f12(-pp)': , # 'ccsd(t)/aug-cc-pvtz(-pp)': , - 'ccsd(t)-f12/aug-cc-pvdz': 0.963, # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/aug-cc-pvdz' - 'ccsd(t)-f12/aug-cc-pvtz': 0.970, # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/aug-cc-pvtz' - 'ccsd(t)-f12/aug-cc-pvqz': 0.975, # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/aug-cc-pvqz' + 'ccsd(t)-f12/aug-cc-pvdz': 0.963, + # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/aug-cc-pvdz' + 'ccsd(t)-f12/aug-cc-pvtz': 0.970, + # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/aug-cc-pvtz' + 'ccsd(t)-f12/aug-cc-pvqz': 0.975, + # http://cccbdb.nist.gov/vibscalejust.asp, taken as 'ccsd(t)/aug-cc-pvqz' # 'b-ccsd(t)-f12/cc-pvdz-f12': , # 'b-ccsd(t)-f12/cc-pvtz-f12': , # 'b-ccsd(t)-f12/cc-pvqz-f12': , @@ -1167,7 +1248,8 @@ def assign_frequency_scale_factor(model_chemistry): # 'bmk/6-311g(2d,d,p)': , 'b3lyp/6-31g**': 0.961, # http://cccbdb.nist.gov/vibscalejust.asp 'b3lyp/6-311+g(3df,2p)': 0.967, # http://cccbdb.nist.gov/vibscalejust.asp - 'wb97x-d/aug-cc-pvtz': 0.974, # Taken from https://comp.chem.umn.edu/freqscale/version3b2.htm as ωB97X-D/maug-cc-pVTZ + 'wb97x-d/aug-cc-pvtz': 0.974, + # Taken from https://comp.chem.umn.edu/freqscale/version3b2.htm as ωB97X-D/maug-cc-pVTZ } scale_factor = freq_dict.get(model_chemistry.lower(), 1) if scale_factor == 1: @@ -1175,7 +1257,7 @@ def assign_frequency_scale_factor(model_chemistry): model_chemistry)) else: logging.info('Assigned a frequency scale factor of {0} for model chemistry {1}'.format( - scale_factor,model_chemistry)) + scale_factor, model_chemistry)) return scale_factor From e0a88ddec368b646304330e5170c21357b0c4063 Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:19:31 -0400 Subject: [PATCH 24/28] PEP 8 coding style fixes in Arkane thermo.py --- arkane/thermo.py | 61 ++++++++++++++++++++++++------------------------ 1 file changed, 31 insertions(+), 30 deletions(-) diff --git a/arkane/thermo.py b/arkane/thermo.py index 30e25b2195..797dad5196 100644 --- a/arkane/thermo.py +++ b/arkane/thermo.py @@ -55,6 +55,7 @@ from arkane.output import prettify from arkane.common import ArkaneSpecies + ################################################################################ @@ -63,12 +64,12 @@ class ThermoJob(object): A representation of an Arkane thermodynamics job. This job is used to compute and save the thermodynamics information for a single species. """ - + def __init__(self, species, thermoClass): self.species = species self.thermoClass = thermoClass self.arkane_species = ArkaneSpecies(species=species) - + def execute(self, outputFile=None, plot=False): """ Execute the thermodynamics job, saving the results to the @@ -86,7 +87,7 @@ def execute(self, outputFile=None, plot=False): self.arkane_species.save_yaml(path=os.path.dirname(outputFile)) if plot: self.plot(os.path.dirname(outputFile)) - + def generateThermo(self): """ Generate the thermodynamic data for the species and fit it to the @@ -95,15 +96,15 @@ def generateThermo(self): """ if self.thermoClass.lower() not in ['wilhoit', 'nasa']: raise Exception('Unknown thermodynamic model "{0}".'.format(self.thermoClass)) - + species = self.species - + logging.debug('Generating {0} thermo model for {1}...'.format(self.thermoClass, species)) - + if species.thermo is not None: logging.info("Thermo already generated for species {}. Skipping thermo generation.".format(species)) return None - + Tlist = np.arange(10.0, 3001.0, 10.0, np.float64) Cplist = np.zeros_like(Tlist) H298 = 0.0 @@ -113,7 +114,7 @@ def generateThermo(self): Cplist[i] += conformer.getHeatCapacity(Tlist[i]) H298 += conformer.getEnthalpy(298.) + conformer.E0.value_si S298 += conformer.getEntropy(298.) - + if not any([isinstance(mode, (LinearRotor, NonlinearRotor)) for mode in conformer.modes]): # Monatomic species linear = False @@ -128,19 +129,19 @@ def generateThermo(self): Nrotors = len(conformer.modes[3:]) Cp0 = (3.5 if linear else 4.0) * constants.R CpInf = Cp0 + (Nfreq + 0.5 * Nrotors) * constants.R - + wilhoit = Wilhoit() if Nfreq == 0 and Nrotors == 0: - wilhoit.Cp0 = (Cplist[0],"J/(mol*K)") - wilhoit.CpInf = (Cplist[0],"J/(mol*K)") - wilhoit.B = (500.,"K") - wilhoit.H0 = (0.0,"J/mol") - wilhoit.S0 = (0.0,"J/(mol*K)") - wilhoit.H0 = (H298 -wilhoit.getEnthalpy(298.15), "J/mol") - wilhoit.S0 = (S298 - wilhoit.getEntropy(298.15),"J/(mol*K)") + wilhoit.Cp0 = (Cplist[0], "J/(mol*K)") + wilhoit.CpInf = (Cplist[0], "J/(mol*K)") + wilhoit.B = (500., "K") + wilhoit.H0 = (0.0, "J/mol") + wilhoit.S0 = (0.0, "J/(mol*K)") + wilhoit.H0 = (H298 - wilhoit.getEnthalpy(298.15), "J/mol") + wilhoit.S0 = (S298 - wilhoit.getEntropy(298.15), "J/(mol*K)") else: wilhoit.fitToData(Tlist, Cplist, Cp0, CpInf, H298, S298, B0=500.0) - + if self.thermoClass.lower() == 'nasa': species.thermo = wilhoit.toNASA(Tmin=10.0, Tmax=3000.0, Tint=500.0) else: @@ -153,9 +154,9 @@ def save(self, outputFile): """ species = self.species logging.info('Saving thermo for {0}...'.format(species.label)) - + f = open(outputFile, 'a') - + f.write('# Thermodynamics for {0}:\n'.format(species.label)) H298 = species.getThermoData().getEnthalpy(298) / 4184. S298 = species.getThermoData().getEntropy(298) / 4.184 @@ -165,7 +166,7 @@ def save(self, outputFile): f.write('# Temperature Heat cap. Enthalpy Entropy Free energy\n') f.write('# (K) (cal/mol*K) (kcal/mol) (cal/mol*K) (kcal/mol)\n') f.write('# =========== =========== =========== =========== ===========\n') - for T in [300,400,500,600,800,1000,1500,2000,2400]: + for T in [300, 400, 500, 600, 800, 1000, 1500, 2000, 2400]: try: Cp = species.getThermoData().getHeatCapacity(T) / 4.184 H = species.getThermoData().getEnthalpy(T) / 4184. @@ -173,12 +174,12 @@ def save(self, outputFile): G = species.getThermoData().getFreeEnergy(T) / 4184. f.write('# {0:11g} {1:11.3f} {2:11.3f} {3:11.3f} {4:11.3f}\n'.format(T, Cp, H, S, G)) except ValueError: - logging.debug("Valid thermo for {0} is outside range for temperature {1}".format(species,T)) + logging.debug("Valid thermo for {0} is outside range for temperature {1}".format(species, T)) f.write('# =========== =========== =========== =========== ===========\n') thermo_string = 'thermo(label={0!r}, thermo={1!r})'.format(species.label, species.getThermoData()) f.write('{0}\n\n'.format(prettify(thermo_string))) - + f.close() # write chemkin file f = open(os.path.join(os.path.dirname(outputFile), 'chem.inp'), 'a') @@ -217,7 +218,7 @@ def plot(self, outputDirectory): import matplotlib.pyplot as plt except ImportError: return - + Tlist = np.arange(10.0, 2501.0, 10.0) Cplist = np.zeros_like(Tlist) Cplist1 = np.zeros_like(Tlist) @@ -227,7 +228,7 @@ def plot(self, outputDirectory): Slist1 = np.zeros_like(Tlist) Glist = np.zeros_like(Tlist) Glist1 = np.zeros_like(Tlist) - + conformer = self.species.conformer thermo = self.species.getThermoData() for i in range(Tlist.shape[0]): @@ -240,28 +241,28 @@ def plot(self, outputDirectory): Slist1[i] = thermo.getEntropy(Tlist[i]) Hlist1[i] = thermo.getEnthalpy(Tlist[i]) * 0.001 Glist1[i] = thermo.getFreeEnergy(Tlist[i]) * 0.001 - except (ValueError,AttributeError): + except (ValueError, AttributeError): continue - fig = plt.figure(figsize=(10,8)) + fig = plt.figure(figsize=(10, 8)) fig.suptitle('{0}'.format(self.species.label)) - plt.subplot(2,2,1) + plt.subplot(2, 2, 1) plt.plot(Tlist, Cplist / 4.184, '-r', Tlist, Cplist1 / 4.184, '-b') plt.xlabel('Temperature (K)') plt.ylabel('Heat capacity (cal/mol*K)') plt.legend(['statmech', 'fitted'], loc=4) - plt.subplot(2,2,2) + plt.subplot(2, 2, 2) plt.plot(Tlist, Slist / 4.184, '-r', Tlist, Slist1 / 4.184, '-b') plt.xlabel('Temperature (K)') plt.ylabel('Entropy (cal/mol*K)') - plt.subplot(2,2,3) + plt.subplot(2, 2, 3) plt.plot(Tlist, Hlist / 4.184, '-r', Tlist, Hlist1 / 4.184, '-b') plt.xlabel('Temperature (K)') plt.ylabel('Enthalpy (kcal/mol)') - plt.subplot(2,2,4) + plt.subplot(2, 2, 4) plt.plot(Tlist, Glist / 4.184, '-r', Tlist, Glist1 / 4.184, '-b') plt.xlabel('Temperature (K)') plt.ylabel('Gibbs free energy (kcal/mol)') From ec041391fb9dcb7c72e993ca57d84b46f3c9301c Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:20:38 -0400 Subject: [PATCH 25/28] Style: Removed redundant paranthesis in Arkane statmech.py --- arkane/statmech.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/arkane/statmech.py b/arkane/statmech.py index 194851e9d0..1196dbcbb8 100644 --- a/arkane/statmech.py +++ b/arkane/statmech.py @@ -984,7 +984,7 @@ def projectRotors(conformer, F, rotors, linear, is_ts): Nrotors = len(rotors) Natoms = len(conformer.mass.value) - Nvib = 3 * Natoms - (5 if linear else 6) - Nrotors - (1 if (is_ts) else 0) + Nvib = 3 * Natoms - (5 if linear else 6) - Nrotors - (1 if is_ts else 0) mass = conformer.mass.value_si coordinates = conformer.coordinates.getValue() @@ -1059,7 +1059,7 @@ def projectRotors(conformer, F, rotors, linear, is_ts): for j in range(3 * Natoms): norm += P[j, i] * P[j, i] for j in range(3 * Natoms): - if (norm > 1E-15): + if norm > 1E-15: P[j, i] /= numpy.sqrt(norm) else: P[j, i] = 0.0 @@ -1076,7 +1076,7 @@ def projectRotors(conformer, F, rotors, linear, is_ts): norm = 0.0 for j in range(3 * Natoms): norm += P[j, i] * P[j, i] - if (norm < 0.5): + if norm < 0.5: P[:, i:3 * Natoms + external - 1] = P[:, i + 1:3 * Natoms + external] else: i += 1 From 41e19136897e127ff8d16777541df8d3f64dcc9f Mon Sep 17 00:00:00 2001 From: alongd Date: Thu, 9 May 2019 15:27:13 -0400 Subject: [PATCH 26/28] Minor: Renamed 'string' as 'rxn_str' to avoid shadowing reserved word --- arkane/kinetics.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/arkane/kinetics.py b/arkane/kinetics.py index e6cce76558..7765eed5be 100644 --- a/arkane/kinetics.py +++ b/arkane/kinetics.py @@ -284,8 +284,8 @@ def save(self, outputFile): f.write('# krev (TST+T) = {0} \n\n'.format(kineticsrev)) # Reaction path degeneracy is INCLUDED in the kinetics itself! - string = 'kinetics(label={0!r}, kinetics={1!r})'.format(reaction.label, reaction.kinetics) - f.write('{0}\n\n'.format(prettify(string))) + rxn_str = 'kinetics(label={0!r}, kinetics={1!r})'.format(reaction.label, reaction.kinetics) + f.write('{0}\n\n'.format(prettify(rxn_str))) f.close() @@ -295,18 +295,18 @@ def save(self, outputFile): reaction = self.reaction kinetics = reaction.kinetics - string = '' + rxn_str = '' if reaction.kinetics.comment: for line in reaction.kinetics.comment.split("\n"): - string += "! {0}\n".format(line) - string += '{0!s:51} {1:9.3e} {2:9.3f} {3:9.3f}\n'.format( + rxn_str += "! {0}\n".format(line) + rxn_str += '{0!s:51} {1:9.3e} {2:9.3f} {3:9.3f}\n'.format( reaction, kinetics.A.value_si * factor, kinetics.n.value_si, kinetics.Ea.value_si / 4184., ) - f.write('{0}\n'.format(string)) + f.write('{0}\n'.format(rxn_str)) f.close() From 7a34b5a36f5a36040945c7b72317efe80fef9e3b Mon Sep 17 00:00:00 2001 From: alongd Date: Fri, 10 May 2019 14:24:03 -0400 Subject: [PATCH 27/28] Changed warning in Arkane common.py to the string.format method --- arkane/common.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/arkane/common.py b/arkane/common.py index b99effa5a6..cc7e524cd6 100644 --- a/arkane/common.py +++ b/arkane/common.py @@ -309,10 +309,9 @@ def check_conformer_energy(Vlist, path): Vlist = numpy.array(Vlist, numpy.float64) Vdiff = (Vlist[0] - numpy.min(Vlist)) * constants.E_h * constants.Na / 1000 if Vdiff >= 2: # we choose 2 kJ/mol to be the critical energy - logging.warning('the species corresponding to ' + str(os.path.basename(path)) - + ' is different in energy from the lowest energy conformer by ' - + "%0.2f" % Vdiff + ' kJ/mol. This can cause significant errors in your computed ' - 'rate constants. ') + logging.warning('the species corresponding to {path} is different in energy from the lowest energy conformer ' + 'by {diff} kJ/mol. This can cause significant errors in your computed rate constants.'.format( + path=os.path.basename(path), diff=Vdiff)) def get_element_mass(input_element, isotope=None): From 0982f5744db53e0a89b20449ade5057262c32f02 Mon Sep 17 00:00:00 2001 From: alongd Date: Fri, 10 May 2019 14:35:50 -0400 Subject: [PATCH 28/28] Arkane common test: Removed `msg=None` Also replaced assertEqual(x, True) with assertTrue(x) --- arkane/commonTest.py | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/arkane/commonTest.py b/arkane/commonTest.py index 7c1077ac54..18eb2742aa 100644 --- a/arkane/commonTest.py +++ b/arkane/commonTest.py @@ -109,99 +109,98 @@ def testNisom(self): """ Test the number of isomers identified. """ - self.assertEqual(self.Nisom, 2, msg=None) + self.assertEqual(self.Nisom, 2) def testNreac(self): """ Test the number of reactants identified. """ - self.assertEqual(self.Nreac, 1, msg=None) + self.assertEqual(self.Nreac, 1) def testNprod(self): """ Test the number of products identified. """ - self.assertEqual(self.Nprod, 1, msg=None) + self.assertEqual(self.Nprod, 1) def testNpathReactions(self): """ Test the whether or not RMG mode is turned on. """ - self.assertEqual(self.Npath, 3, msg=None) + self.assertEqual(self.Npath, 3) def testPathReactions(self): """ Test a path reaction label """ - self.assertEqual(str(self.PathReaction2), 'CH2OH <=> methoxy', msg=None) + self.assertEqual(str(self.PathReaction2), 'CH2OH <=> methoxy') # test Arkane's interactions with the pdep module def testTemperaturesUnits(self): """ Test the Temperature Units. """ - self.assertEqual(str(self.TmaxUnits), 'K', msg=None) + self.assertEqual(str(self.TmaxUnits), 'K') def testTemperaturesValue(self): """ Test the temperature value. """ - self.assertEqual(self.TminValue, 450.0, msg=None) + self.assertEqual(self.TminValue, 450.0) def testTemperaturesList(self): """ Test the temperature list. """ - self.assertEqual(numpy.array_equal(self.TlistValue, numpy.array([450, 500, 678, 700])), True, msg=None) + self.assertTrue(numpy.array_equal(self.TlistValue, numpy.array([450, 500, 678, 700]))) def testPminValue(self): """ Test the minimum pressure value. """ - self.assertEqual("%0.7f" % self.PminValue, str(0.0101325), msg=None) + self.assertEqual("%0.7f" % self.PminValue, str(0.0101325)) def testPcount(self): """ Test the number pressures specified. """ - self.assertEqual(self.Pcount, 7, msg=None) + self.assertEqual(self.Pcount, 7) def testTcount(self): """ Test the number temperatures specified. """ - self.assertEqual(self.Tcount, 4, msg=None) + self.assertEqual(self.Tcount, 4) def testPressureList(self): """ Test the pressure list. """ - self.assertEqual(numpy.array_equal(self.PlistValue, numpy.array([0.01, 0.1, 1, 3, 10, 100, 1000])), True, - msg=None) + self.assertTrue(numpy.array_equal(self.PlistValue, numpy.array([0.01, 0.1, 1, 3, 10, 100, 1000]))) def testGenerateTemperatureList(self): """ Test the generated temperature list. """ - self.assertEqual(list(self.GenTlist), [450.0, 500.0, 678.0, 700.0], msg=None) + self.assertEqual(list(self.GenTlist), [450.0, 500.0, 678.0, 700.0]) def testmaximumGrainSizeValue(self): """ Test the max grain size value. """ - self.assertEqual(self.maximumGrainSizeValue, 0.5, msg=None) + self.assertEqual(self.maximumGrainSizeValue, 0.5) def testMethod(self): """ Test the master equation solution method chosen. """ - self.assertEqual(self.method, 'modified strong collision', msg=None) + self.assertEqual(self.method, 'modified strong collision') def testRmgmode(self): """ Test the whether or not RMG mode is turned on. """ - self.assertEqual(self.rmgmode, False, msg=None) + self.assertEqual(self.rmgmode, False) # Test Arkane's interactions with the kinetics module def testCalculateTSTRateCoefficient(self): @@ -209,15 +208,15 @@ def testCalculateTSTRateCoefficient(self): Test the calculation of the high-pressure limit rate coef for one of the kinetics jobs at Tmin and Tmax. """ self.assertEqual("%0.7f" % self.kineticsjob.reaction.calculateTSTRateCoefficient(self.TminValue), - str(46608.5904933), msg=None) + str(46608.5904933)) self.assertEqual("%0.5f" % self.kineticsjob.reaction.calculateTSTRateCoefficient(self.Tmaxvalue), - str(498796.64535), msg=None) + str(498796.64535)) def testTunneling(self): """ Test the whether or not tunneling has been included in a specific kinetics job. """ - self.assertEqual(self.kineticsjob.reaction.transitionState.tunneling, None, msg=None) + self.assertEqual(self.kineticsjob.reaction.transitionState.tunneling, None) class TestArkaneInput(unittest.TestCase):