diff --git a/.conda/bld.bat b/.conda/bld.bat deleted file mode 100644 index 6de1123c89..0000000000 --- a/.conda/bld.bat +++ /dev/null @@ -1,7 +0,0 @@ -:: Install RMG -mingw32-make install - -:: lazy "install" of everything in our 'external' folder. -:: most of which should probably be elsewhere -mkdir %SP_DIR%\external -xcopy %SRC_DIR%\external %SP_DIR%\external /E /Y diff --git a/.coveragerc b/.coveragerc deleted file mode 100644 index b5e8023971..0000000000 --- a/.coveragerc +++ /dev/null @@ -1,35 +0,0 @@ -# .coveragerc to control coverage.py -[run] -plugins = Cython.Coverage -branch = True -source = - arkane - Arkane.py - rmgpy - rmg.py -omit = - *Test.py - */test_data/* - arkane/data/* - -[report] -show_missing = False -exclude_lines = - pragma: no cover - def __repr__ - if self.debug: - if settings.DEBUG - raise AssertionError - raise NotImplementedError - if 0: - if __name__ == .__main__.: -include = - arkane/* - rmgpy/* -omit = - *Test.py - */test_data/* - arkane/data/* - -[html] -directory = testing/coverage diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml index f13f4cdb54..5a73b44dd4 100644 --- a/.github/workflows/CI.yml +++ b/.github/workflows/CI.yml @@ -149,20 +149,19 @@ jobs: make # RMS installation and linking to Julia - # Allow these installs to 'fail' (as they do in RMG-Tests) with the command || True trick - name: Install and link Julia dependencies timeout-minutes: 120 # this usually takes 20-45 minutes (or hangs for 6+ hours). run: | - python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install()" || true - julia -e 'using Pkg; Pkg.add(PackageSpec(name="ReactionMechanismSimulator",rev="main")); using ReactionMechanismSimulator' || true + python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install()" + julia -e 'using Pkg; Pkg.add(PackageSpec(name="ReactionMechanismSimulator",rev="for_rmg")); using ReactionMechanismSimulator' + + - name: Install Q2DTor + run: echo "" | make q2dtor # non-regression testing - - name: Unit tests - run: make test-unittests - - name: Functional tests - run: make test-functional - - name: Database tests - run: make test-database + - name: Run Unit, Functional, and Database Tests + # aggregate into one command so we only have to eat the collection time once + run: make test-all # Regression Testing - Test Execution - name: Regression Tests - Execution diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index 3a1da9440e..82c694d42b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -16,10 +16,6 @@ jobs: shell: bash -l {0} steps: - uses: actions/checkout@v2 - - name: Patch the environment file - run: | - echo -e "\n - libstdcxx-ng < 13\n" >> environment.yml - cat environment.yml - name: Setup Mambaforge Python 3.7 uses: conda-incubator/setup-miniconda@v2 with: diff --git a/.gitignore b/.gitignore index 97e993156b..d52d5c680f 100644 --- a/.gitignore +++ b/.gitignore @@ -27,10 +27,8 @@ documentation/build/* # (These will be unique to each developer's setup) make.inc -# Example output files -examples/* -!examples/*/input.py -!examples/**/*.ipynb +# output files +rmgpy/output/* # NetBeans project files nbproject/* @@ -88,11 +86,34 @@ RMG_Py.egg-info/* # RMG configuration file rmgpy/rmgrc +# treegen log files scripts/treegen.log - scripts/treegen_backup.log # regression testing files - ignore everything but input and regression input test/regression/* !test/regression/*/input.py !test/regression/*/regression_input.py + +# testing files +test/arkane/data/two_parameter_arrhenius_fit/arkane.log +test/arkane/data/two_parameter_arrhenius_fit/output.py +test/arkane/data/two_parameter_arrhenius_fit/chem.inp +test/rmgpy/test_data/temp_dir_for_testing/cantera/chem001.yaml +rmgpy/test_data/copied_kinetic_lib/ +testing/qm/* +test_log.txt + +# example directory - save the inputs but not the outputs +# cantera input files +examples/**/chem.inp +# log files from the runs +examples/**/arkane.log +# results from the runs +examples/**/species_dictionary.txt +examples/**/output*py +examples/**/network*py +examples/**/dictionary.txt +examples/**/reactions.py +examples/**/RMG_libraries +examples/**/species diff --git a/Dockerfile b/Dockerfile index 803374c02a..ab9792b3ab 100644 --- a/Dockerfile +++ b/Dockerfile @@ -62,7 +62,7 @@ ENV PATH="$RUNNER_CWD/RMG-Py:$PATH" # 1. Build RMG # 2. Install and link Julia dependencies for RMS RUN make && \ - julia -e 'using Pkg; Pkg.add(PackageSpec(name="PyCall",rev="master")); Pkg.add(PackageSpec(name="ReactionMechanismSimulator",rev="main")); using ReactionMechanismSimulator' && \ + julia -e 'using Pkg; Pkg.add(PackageSpec(name="PyCall",rev="master")); Pkg.add(PackageSpec(name="ReactionMechanismSimulator",rev="for_rmg")); using ReactionMechanismSimulator' && \ python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install()" # RMG-Py should now be installed and ready - trigger precompilation and test run diff --git a/Makefile b/Makefile index 7ec4bae352..c573fc3b47 100644 --- a/Makefile +++ b/Makefile @@ -4,7 +4,7 @@ # ################################################################################ -.PHONY : all minimal main solver check pycheck arkane clean install decython documentation mopac_travis test +.PHONY : all minimal main solver check pycheck arkane clean install decython documentation test q2dtor all: pycheck main solver check @@ -50,24 +50,25 @@ q2dtor: and HinderedRotor2D within Arkane please cite: \n\nD. Ferro-Costas, M. N. D. S.Cordeiro, D. G. Truhlar, A.\ Fernández-Ramos, Comput. Phys. Commun. 232, 190-205, 2018.\n" @ read -p "Press ENTER to continue" dummy - @ git clone https://github.com/mjohnson541/Q2DTor.git external/Q2DTor --branch arkanepy3 - + @ mkdir -p external + @ git clone https://github.com/cathedralpkg/Q2DTor external/Q2DTor + decython: # de-cythonize all but the 'minimal'. Helpful for debugging in "pure python" mode. find . -name *.so ! \( -name _statmech.so -o -name quantity.so -o -regex '.*rmgpy/solver/.*' \) -exec rm -f '{}' \; find . -name *.pyc -exec rm -f '{}' \; test-all: - nosetests --nocapture --nologcapture --all-modules --verbose --with-coverage --cover-inclusive --cover-erase --cover-html --cover-html-dir=testing/coverage --exe rmgpy arkane + python-jl -m pytest test test-unittests: - nosetests --nocapture --nologcapture --all-modules -A 'not functional' --verbose --with-coverage --cover-inclusive --cover-erase --cover-html --cover-html-dir=testing/coverage --exe rmgpy arkane + python-jl -m pytest -m "not functional and not database" test-functional: - nosetests --nologcapture --all-modules -A 'functional' --verbose --exe rmgpy arkane + python-jl -m pytest -m "functional" test-database: - nosetests --nocapture --nologcapture --verbose --detailed-errors testing/databaseTest.py + python-jl -m pytest -m "database" eg0: all mkdir -p testing/eg0 @@ -85,25 +86,22 @@ eg1: all coverage run rmg.py -p testing/eg1/input.py coverage report coverage html + eg2: all mkdir -p testing/eg2 rm -rf testing/eg2/* cp examples/rmg/1,3-hexadiene/input.py testing/eg2/input.py coverage erase - @ echo "Running eg2: 1,3-hexadiene example with coverage tracking AND profiling" - coverage run rmg.py -p testing/eg2/input.py - coverage report - coverage html + @ echo "Running eg2: 1,3-hexadiene example with profiling" + python rmg.py -p testing/eg2/input.py eg3: all mkdir -p testing/eg3 rm -rf testing/eg3/* cp examples/rmg/liquid_phase/input.py testing/eg3/input.py coverage erase - @ echo "Running eg3: liquid_phase example with coverage tracking AND profiling" - coverage run rmg.py -p testing/eg3/input.py - coverage report - coverage html + @ echo "Running eg3: liquid_phase example with profiling" + python rmg.py -p testing/eg3/input.py eg5: all mkdir -p testing/eg5 diff --git a/arkane/common.py b/arkane/common.py index ef42544220..5227298895 100644 --- a/arkane/common.py +++ b/arkane/common.py @@ -367,7 +367,7 @@ def check_conformer_energy(energies, path): is not 0.5 kcal/mol (or more) higher than any other energies in the scan. If so, print and log a warning message. """ - energies = np.array(energies, np.float64) + energies = np.array(energies, float) e_diff = (energies[0] - np.min(energies)) * constants.E_h * constants.Na / 1000 if e_diff >= 2: # we choose 2 kJ/mol to be the critical energy logging.warning(f'The species corresponding to {os.path.basename(path)} is different in energy from the ' @@ -628,7 +628,7 @@ def get_center_of_mass(coords, numbers=None, symbols=None): raise IndexError('Either symbols or numbers must be given.') if numbers is not None: symbols = [symbol_by_number[number] for number in numbers] - center, total_mass = np.zeros(3, np.float64), 0 + center, total_mass = np.zeros(3, float), 0 for coord, symbol in zip(coords, symbols): mass = get_element_mass(symbol)[0] center += mass * coord @@ -661,7 +661,7 @@ def get_moment_of_inertia_tensor(coords, numbers=None, symbols=None): if len(coords) != len(symbols): raise InputError(f'The number of atoms ({len(symbols)}) is not equal to the number of ' f'atomic coordinates ({len(list(coords))})') - tensor = np.zeros((3, 3), np.float64) + tensor = np.zeros((3, 3), float) center_of_mass = get_center_of_mass(coords=coords, numbers=numbers, symbols=symbols) for symbol, coord in zip(symbols, coords): mass = get_element_mass(symbol)[0] diff --git a/arkane/commonTest.py b/arkane/commonTest.py deleted file mode 100644 index 3a1af6e27f..0000000000 --- a/arkane/commonTest.py +++ /dev/null @@ -1,572 +0,0 @@ -#!/usr/bin/env python3 - -############################################################################### -# # -# RMG - Reaction Mechanism Generator # -# # -# Copyright (c) 2002-2023 Prof. William H. Green (whgreen@mit.edu), # -# Prof. Richard H. West (r.west@neu.edu) and the RMG Team (rmg_dev@mit.edu) # -# # -# Permission is hereby granted, free of charge, to any person obtaining a # -# copy of this software and associated documentation files (the 'Software'), # -# to deal in the Software without restriction, including without limitation # -# the rights to use, copy, modify, merge, publish, distribute, sublicense, # -# and/or sell copies of the Software, and to permit persons to whom the # -# Software is furnished to do so, subject to the following conditions: # -# # -# The above copyright notice and this permission notice shall be included in # -# all copies or substantial portions of the Software. # -# # -# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # -# DEALINGS IN THE SOFTWARE. # -# # -############################################################################### - -""" -This module contains unit tests of the :mod:`arkane.common` module. -""" - -import logging -import os -import shutil -import unittest - -import numpy as np - -import rmgpy -import rmgpy.constants as constants -from rmgpy.pdep.collision import SingleExponentialDown -from rmgpy.quantity import ScalarQuantity -from rmgpy.species import Species, TransitionState -from rmgpy.thermo import NASA, ThermoData - -from arkane import Arkane, input -from arkane.common import (ArkaneSpecies, - convert_imaginary_freq_to_negative_float, - get_element_mass, - get_center_of_mass, - get_moment_of_inertia_tensor, - get_principal_moments_of_inertia, - ) -from arkane.input import job_list -from arkane.modelchem import LevelOfTheory -from arkane.statmech import InputError, StatMechJob - -################################################################################ - - -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] - v_list = np.array(v_list, np.float64) - v_diff = (v_list[0] - np.min(v_list)) * constants.E_h * constants.Na / 1000 - self.assertAlmostEqual(v_diff / 2.7805169838282797, 1, 5) - - -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() - job_list = arkane.load_input_file(os.path.join(os.path.dirname(os.path.abspath(__file__)), - 'data', 'methoxy.py')) - pdepjob = job_list[-1] - cls.kineticsjob = job_list[0] - pdepjob.active_j_rotor = True - network = pdepjob.network - cls.Nisom = len(network.isomers) - cls.Nreac = len(network.reactants) - cls.Nprod = len(network.products) - cls.Npath = len(network.path_reactions) - cls.PathReaction2 = network.path_reactions[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.generate_T_list() - cls.PlistValue = pdepjob.Plist.value - cls.maximum_grain_size_value = pdepjob.maximum_grain_size.value - cls.method = pdepjob.method - cls.rmgmode = pdepjob.rmgmode - - # test Arkane's interactions with the network module - def test_num_isom(self): - """ - Test the number of isomers identified. - """ - self.assertEqual(self.Nisom, 2) - - def test_num_reac(self): - """ - Test the number of reactants identified. - """ - self.assertEqual(self.Nreac, 1) - - def test_num_prod(self): - """ - Test the number of products identified. - """ - self.assertEqual(self.Nprod, 1) - - def test_n_path_reactions(self): - """ - Test the whether or not RMG mode is turned on. - """ - self.assertEqual(self.Npath, 3) - - def test_path_reactions(self): - """ - Test a path reaction label - """ - self.assertEqual(str(self.PathReaction2), 'CH2OH <=> methoxy') - - # test Arkane's interactions with the pdep module - def test_temperatures_units(self): - """ - Test the Temperature Units. - """ - self.assertEqual(str(self.TmaxUnits), 'K') - - def test_temperatures_value(self): - """ - Test the temperature value. - """ - self.assertEqual(self.TminValue, 450.0) - - def test_temperatures_list(self): - """ - Test the temperature list. - """ - self.assertTrue(np.array_equal(self.TlistValue, np.array([450, 500, 678, 700]))) - - def test_min_pressure_value(self): - """ - Test the minimum pressure value. - """ - self.assertEqual("%0.7f" % self.PminValue, str(0.0101325)) - - def test_pressure_count(self): - """ - Test the number pressures specified. - """ - self.assertEqual(self.Pcount, 7) - - def test_temperature_count(self): - """ - Test the number temperatures specified. - """ - self.assertEqual(self.Tcount, 4) - - def test_pressure_list(self): - """ - Test the pressure list. - """ - self.assertTrue(np.array_equal(self.PlistValue, np.array([0.01, 0.1, 1, 3, 10, 100, 1000]))) - - def test_generate_temperature_list(self): - """ - Test the generated temperature list. - """ - self.assertEqual(list(self.GenTlist), [450.0, 500.0, 678.0, 700.0]) - - def test_maximum_grain_size_value(self): - """ - Test the max grain size value. - """ - self.assertEqual(self.maximum_grain_size_value, 0.5) - - def test_method(self): - """ - Test the master equation solution method chosen. - """ - self.assertEqual(self.method, 'modified strong collision') - - def test_rmg_mode(self): - """ - Test the whether or not RMG mode is turned on. - """ - self.assertEqual(self.rmgmode, False) - - # Test Arkane's interactions with the kinetics module - def test_calculate_tst_rate_coefficient(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.calculate_tst_rate_coefficient(self.TminValue), - str(46608.5904933)) - self.assertEqual("%0.5f" % self.kineticsjob.reaction.calculate_tst_rate_coefficient(self.Tmaxvalue), - str(498796.64535)) - - def test_tunneling(self): - """ - Test the whether or not tunneling has been included in a specific kinetics job. - """ - self.assertEqual(self.kineticsjob.reaction.transition_state.tunneling, None) - - -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.""" - cls.directory = os.path.join(os.path.dirname(os.path.dirname(rmgpy.__file__)), 'examples', 'arkane') - cls.level_of_theory = LevelOfTheory("cbs-qb3") - cls.frequencyScaleFactor = 0.99 - cls.useHinderedRotors = False - cls.useBondCorrections = True - - def test_species(self): - """Test loading of species input file.""" - spec = input.species('C2H4', os.path.join(self.directory, 'species', 'C2H4', 'ethene.py')) - self.assertTrue(isinstance(spec, Species)) - self.assertEqual(len(spec.molecule), 0) - - def test_species_statmech(self): - """Test loading of statmech job from species input file.""" - job = job_list[-1] - self.assertTrue(isinstance(job, StatMechJob)) - job.level_of_theory = self.level_of_theory - job.frequencyScaleFactor = self.frequencyScaleFactor - job.includeHinderedRotors = self.useHinderedRotors - job.applyBondEnergyCorrections = self.useBondCorrections - job.load() - self.assertTrue(isinstance(job.species.props['element_counts'], dict)) - self.assertEqual(job.species.props['element_counts']['C'], 2) - self.assertEqual(job.species.props['element_counts']['H'], 4) - - def test_species_thermo(self): - """Test thermo job execution for species from separate input file.""" - input.thermo('C2H4', 'NASA') - job = job_list[-1] - filepath = os.path.join(self.directory, 'reactions', 'H+C2H4=C2H5') - job.execute(output_directory=filepath) - self.assertTrue(os.path.isfile(os.path.join(filepath, 'output.py'))) - self.assertTrue(os.path.isfile(os.path.join(filepath, 'chem.inp'))) - os.remove(os.path.join(filepath, 'output.py')) - os.remove(os.path.join(filepath, 'chem.inp')) - - def test_transition_state(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 test_transition_state_statmech(self): - """Test loading of statmech job from transition state input file.""" - job = job_list[-1] - self.assertTrue(isinstance(job, StatMechJob)) - job.level_of_theory = self.level_of_theory - job.frequencyScaleFactor = self.frequencyScaleFactor - job.includeHinderedRotors = self.useHinderedRotors - job.applyBondEnergyCorrections = self.useBondCorrections - job.load() - - -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.load_input_file(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 the same""" - job = self.job_list[-2] - self.assertTrue(isinstance(job, StatMechJob)) - with self.assertRaises(InputError): - job.load() - - -class TestArkaneSpecies(unittest.TestCase): - """ - Contains YAML dump and load unit tests for :class:ArkaneSpecies - """ - - @classmethod - def setUpClass(cls): - """ - A method that is run ONCE before all unit tests in this class. - """ - cls.arkane = Arkane() - path = os.path.join(os.path.dirname(os.path.dirname(rmgpy.__file__)), - 'examples', 'arkane', 'species') - cls.dump_path = os.path.join(path, 'C2H6') - cls.dump_input_path = os.path.join(cls.dump_path, 'input.py') - cls.dump_output_file = os.path.join(cls.dump_path, 'output.py') - cls.dump_yaml_file = os.path.join(cls.dump_path, 'species', 'C2H6.yml') - - cls.load_path = os.path.join(path, 'C2H6_from_yaml') - cls.load_input_path = os.path.join(cls.load_path, 'input.py') - cls.load_output_file = os.path.join(cls.load_path, 'output.py') - - cls.data_path = os.path.join(os.path.dirname(os.path.dirname(rmgpy.__file__)), 'arkane', 'data') - - if os.path.exists(cls.dump_yaml_file): - logging.debug('removing existing yaml file {0} before running tests'.format(cls.dump_yaml_file)) - os.remove(cls.dump_yaml_file) - - def test_dump_yaml(self): - """ - Test properly dumping the ArkaneSpecies object and respective sub-objects - """ - job_list = self.arkane.load_input_file(self.dump_input_path) - for job in job_list: - job.execute(output_directory=self.dump_path) - self.assertTrue(os.path.isfile(self.dump_output_file)) - - def test_create_and_load_yaml(self): - """ - Test properly loading the ArkaneSpecies object and respective sub-objects - """ - # Create YAML file by running Arkane - job_list = self.arkane.load_input_file(self.dump_input_path) - for job in job_list: - job.execute(output_directory=self.dump_path) - - # Load in newly created YAML file - arkane_spc_old = job_list[0].arkane_species - arkane_spc = ArkaneSpecies.__new__(ArkaneSpecies) - arkane_spc.load_yaml(path=os.path.join(self.dump_path, 'species', arkane_spc_old.label + '.yml')) - - self.assertIsInstance(arkane_spc, ArkaneSpecies) # checks make_object - self.assertIsInstance(arkane_spc.molecular_weight, ScalarQuantity) - self.assertIsInstance(arkane_spc.thermo, NASA) - self.assertNotEqual(arkane_spc.author, '') - self.assertEqual(arkane_spc.inchi, 'InChI=1S/C2H6/c1-2/h1-2H3') - self.assertEqual(arkane_spc.inchi_key, 'OTMSDBZUPAUEDD-UHFFFAOYSA-N') - self.assertEqual(arkane_spc.smiles, 'CC') - self.assertTrue('8 H u0 p0 c0 {2,S}' in arkane_spc.adjacency_list) - self.assertEqual(arkane_spc.label, 'C2H6') - self.assertEqual(arkane_spc.frequency_scale_factor, 0.99 * 1.014) # checks float conversion - self.assertFalse(arkane_spc.use_bond_corrections) - self.assertAlmostEqual(arkane_spc.conformer.modes[2].frequencies.value_si[0], 830.38202, 4) # HarmonicOsc. - self.assertIsInstance(arkane_spc.energy_transfer_model, SingleExponentialDown) - self.assertFalse(arkane_spc.is_ts) - self.assertEqual(arkane_spc.level_of_theory, LevelOfTheory('cbs-qb3')) - self.assertIsInstance(arkane_spc.thermo_data, ThermoData) - self.assertTrue(arkane_spc.use_hindered_rotors) - self.assertIsInstance(arkane_spc.chemkin_thermo_string, str) - expected_xyz = """8 -C2H6 -C 0.00075400 0.00119300 0.00055200 -H 0.00074000 0.00117100 1.09413800 -H 1.04376600 0.00117100 -0.32820200 -H -0.44760300 0.94289500 -0.32825300 -C -0.76014200 -1.20389600 -0.55748300 -H -0.76012800 -1.20387400 -1.65106900 -H -0.31178500 -2.14559800 -0.22867800 -H -1.80315400 -1.20387400 -0.22872900""" - self.assertEqual(arkane_spc.xyz, expected_xyz) - - def test_load_existing_yaml(self): - """ - Test that existing Arkane YAML files can still be loaded - """ - # Load in YAML file - arkane_spc = ArkaneSpecies.__new__(ArkaneSpecies) - arkane_spc.load_yaml(path=os.path.join(self.load_path, 'C2H6.yml')) - - self.assertIsInstance(arkane_spc, ArkaneSpecies) # checks make_object - self.assertIsInstance(arkane_spc.molecular_weight, ScalarQuantity) - self.assertIsInstance(arkane_spc.thermo, NASA) - self.assertNotEqual(arkane_spc.author, '') - self.assertEqual(arkane_spc.inchi, 'InChI=1S/C2H6/c1-2/h1-2H3') - self.assertEqual(arkane_spc.inchi_key, 'OTMSDBZUPAUEDD-UHFFFAOYSA-N') - self.assertEqual(arkane_spc.smiles, 'CC') - self.assertTrue('8 H u0 p0 c0 {2,S}' in arkane_spc.adjacency_list) - self.assertEqual(arkane_spc.label, 'C2H6') - self.assertEqual(arkane_spc.frequency_scale_factor, 0.99) # checks float conversion - self.assertFalse(arkane_spc.use_bond_corrections) - self.assertAlmostEqual(arkane_spc.conformer.modes[2].frequencies.value_si[0], 818.91718, 4) # HarmonicOsc. - self.assertIsInstance(arkane_spc.energy_transfer_model, SingleExponentialDown) - self.assertFalse(arkane_spc.is_ts) - self.assertTrue(arkane_spc.use_hindered_rotors) - self.assertTrue('C 7.54e-14 1.193e-13 5.52e-14' in arkane_spc.xyz) - self.assertIsInstance(arkane_spc.chemkin_thermo_string, str) - - def test_loading_different_versions_of_yaml(self): - """Test loading a YAML file generated by RMG v 2.4.1 and by a more recent version""" - arkane_spc_v_241 = ArkaneSpecies.__new__(ArkaneSpecies) - arkane_spc_v_241.load_yaml(path=os.path.join(self.data_path, 'vinoxy_v_2.4.1.yml')) - self.assertIsInstance(arkane_spc_v_241, ArkaneSpecies) # checks make_object - self.assertEqual(arkane_spc_v_241.conformer.spin_multiplicity, 2) - - arkane_current = ArkaneSpecies.__new__(ArkaneSpecies) - arkane_current.load_yaml(path=os.path.join(self.data_path, 'vinoxy_current.yml')) - self.assertIsInstance(arkane_current, ArkaneSpecies) # checks make_object - self.assertEqual(arkane_current.conformer.spin_multiplicity, 2) - - @classmethod - def tearDownClass(cls): - """ - A method that is run ONCE after all unit tests in this class. - """ - path = os.path.join(os.path.dirname(os.path.dirname(rmgpy.__file__)), - 'examples', 'arkane', 'species') - cls.dump_path = os.path.join(path, 'C2H6') - cls.load_path = os.path.join(path, 'C2H6_from_yaml') - cls.extensions_to_delete = ['pdf', 'txt', 'inp', 'csv'] - cls.files_to_delete = ['arkane.log', 'output.py'] - cls.files_to_keep = ['C2H6.yml'] - for path in [cls.dump_path, cls.load_path]: - for name in os.listdir(path): - 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 \ - (extension in cls.extensions_to_delete and name not in cls.files_to_keep): - os.remove(item_path) - else: - # This is a sub-directory. remove. - shutil.rmtree(item_path) - - -class TestMomentOfInertia(unittest.TestCase): - """ - Contains unit tests for attaining moments of inertia from the 3D coordinates. - """ - - def test_get_mass(self): - """Test that the correct mass/number/isotope is returned from get_element_mass""" - self.assertEqual(get_element_mass(1), (1.00782503224, 1)) # test input by integer - self.assertEqual(get_element_mass('Si'), (27.97692653465, 14)) # test string input and most common isotope - self.assertEqual(get_element_mass('SI'), (27.97692653465, 14)) # test string in all caps - self.assertEqual(get_element_mass('C', 13), (13.00335483507, 6)) # test specific isotope - self.assertEqual(get_element_mass('Bk'), (247.0703073, 97)) # test a two-element array (no isotope data) - - def test_get_center_of_mass(self): - """Test attaining the center of mass""" - symbols = ['C', 'H', 'H', 'H', 'H'] - coords = np.array([[0.0000000, 0.0000000, 0.0000000], - [0.6269510, 0.6269510, 0.6269510], - [-0.6269510, -0.6269510, 0.6269510], - [-0.6269510, 0.6269510, -0.6269510], - [0.6269510, -0.6269510, -0.6269510]], np.float64) - center_of_mass = get_center_of_mass(coords=coords, symbols=symbols) - for cm_coord in center_of_mass: - self.assertEqual(cm_coord, 0.0) - - symbols = ['O', 'C', 'C', 'H', 'H', 'H', 'H', 'H', 'H'] - coords = np.array([[1.28706525, 0.52121353, 0.04219198], - [0.39745682, -0.35265044, -0.63649234], - [0.36441173, -1.68197093, 0.08682400], - [-0.59818222, 0.10068325, -0.65235399], - [0.74799641, -0.48357798, -1.66461710], - [0.03647269, -1.54932006, 1.12314420], - [-0.31340646, -2.38081353, -0.41122551], - [1.36475837, -2.12581592, 0.12433596], - [2.16336803, 0.09985803, 0.03295192]], np.float64) - center_of_mass = get_center_of_mass(coords=coords, symbols=symbols) - self.assertAlmostEqual(center_of_mass[0], 0.7201, 3) - self.assertAlmostEqual(center_of_mass[1], -0.4880, 3) - self.assertAlmostEqual(center_of_mass[2], -0.1603, 3) - - numbers = [6, 6, 8, 1, 1, 1, 1, 1, 1] - coords = np.array([[1.1714680, -0.4048940, 0.0000000], - [0.0000000, 0.5602500, 0.0000000], - [-1.1945070, -0.2236470, 0.0000000], - [-1.9428910, 0.3834580, 0.0000000], - [2.1179810, 0.1394450, 0.0000000], - [1.1311780, -1.0413680, 0.8846660], - [1.1311780, -1.0413680, -0.8846660], - [0.0448990, 1.2084390, 0.8852880], - [0.0448990, 1.2084390, -0.8852880]], np.float64) - center_of_mass = get_center_of_mass(coords=coords, numbers=numbers) - self.assertAlmostEqual(center_of_mass[0], -0.0540, 3) - self.assertAlmostEqual(center_of_mass[1], -0.0184, 3) - self.assertAlmostEqual(center_of_mass[2], -0.0000, 3) - - def test_get_moment_of_inertia_tensor(self): - """Test calculating the moment of inertia tensor""" - symbols = ['O', 'C', 'C', 'H', 'H', 'H', 'H', 'H', 'H'] - coords = np.array([[1.28706525, 0.52121353, 0.04219198], - [0.39745682, -0.35265044, -0.63649234], - [0.36441173, -1.68197093, 0.08682400], - [-0.59818222, 0.10068325, -0.65235399], - [0.74799641, -0.48357798, -1.66461710], - [0.03647269, -1.54932006, 1.12314420], - [-0.31340646, -2.38081353, -0.41122551], - [1.36475837, -2.12581592, 0.12433596], - [2.16336803, 0.09985803, 0.03295192]], np.float64) - tensor = get_moment_of_inertia_tensor(coords=coords, symbols=symbols) - expected_tensor = [[50.24197604, -15.43600683, -3.07977736], - [-15.43600683, 22.20416597, 2.5935549], - [-3.07977736, 2.5935549, 55.49144794]] - np.testing.assert_almost_equal(tensor, expected_tensor) - - def test_get_principal_moments_of_inertia(self): - """Test calculating the principal moments of inertia""" - numbers = [6, 6, 8, 1, 1, 1, 1, 1, 1] - coords = np.array([[1.235366, -0.257231, -0.106315], - [0.083698, 0.554942, 0.046628], - [-1.210594, -0.239505, -0.021674], - [0.132571, 1.119728, 0.987719], - [0.127795, 1.278999, -0.769346], - [-1.272620, -0.962700, 0.798216], - [-2.074974, 0.426198, 0.055846], - [-1.275744, -0.785745, -0.965493], - [1.241416, -0.911257, 0.593856]], np.float64) - principal_moments_of_inertia = get_principal_moments_of_inertia(coords=coords, numbers=numbers)[0] - expected_principal_moments_of_inertia = [60.98026894, 53.83156297, 14.48858465] - for moment, expected_moment in zip(principal_moments_of_inertia, expected_principal_moments_of_inertia): - self.assertAlmostEqual(moment, expected_moment) - - symbols = ['N', 'O', 'O'] # test a linear molecule - coords = np.array([[0.000000, 0.000000, 1.106190], - [0.000000, 0.000000, -0.072434], - [0.000000, 0.000000, -1.191782]], np.float64) - with self.assertRaises(InputError): - get_principal_moments_of_inertia(coords=coords, numbers=numbers) - principal_moments_of_inertia, axes = get_principal_moments_of_inertia(coords=coords, symbols=symbols) - expected_principal_moments_of_inertia = [39.4505153, 39.4505153, 0.0] - expected_axes = [[1, 0, 0], [0, 1, 0], [0, 0, 1]] - for moment, expected_moment in zip(principal_moments_of_inertia, expected_principal_moments_of_inertia): - self.assertAlmostEqual(moment, expected_moment) - for axis, expected_axis in zip(axes, expected_axes): - for entry, expected_entry in zip(axis, expected_axis): - self.assertAlmostEqual(entry, expected_entry) - self.assertIsInstance(principal_moments_of_inertia, tuple) - self.assertIsInstance(axes, tuple) - - def test_convert_imaginary_freq_to_negative_float(self): - self.assertEqual(convert_imaginary_freq_to_negative_float(1), 1) - self.assertEqual(convert_imaginary_freq_to_negative_float(-5.2), -5.2) - self.assertEqual(convert_imaginary_freq_to_negative_float('-5.2'), -5.2) - self.assertEqual(convert_imaginary_freq_to_negative_float('5.2'), 5.2) - self.assertEqual(convert_imaginary_freq_to_negative_float('5.2i'), -5.2) - self.assertEqual(convert_imaginary_freq_to_negative_float('635.8i'), -635.8) - -################################################################################ - - -if __name__ == '__main__': - unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arkane/encorr/isodesmic.py b/arkane/encorr/isodesmic.py index e9dcb07784..83a9164e17 100644 --- a/arkane/encorr/isodesmic.py +++ b/arkane/encorr/isodesmic.py @@ -379,6 +379,10 @@ def _find_error_canceling_reaction(self, reference_subset, milp_software=None): except ValueError: # This is not being run in the main thread, so we cannot reset signal pass + except TypeError: + print( + "Failed to reset signal handling in LPSolve - are you running pytest?" + ) # Return the solution if a valid reaction is found. Otherwise continue to next solver if status == 0: diff --git a/arkane/encorr/isodesmicTest.py b/arkane/encorr/isodesmicTest.py deleted file mode 100644 index 0cae224ca7..0000000000 --- a/arkane/encorr/isodesmicTest.py +++ /dev/null @@ -1,280 +0,0 @@ -#!/usr/bin/env python3 - -############################################################################### -# # -# RMG - Reaction Mechanism Generator # -# # -# Copyright (c) 2002-2023 Prof. William H. Green (whgreen@mit.edu), # -# Prof. Richard H. West (r.west@neu.edu) and the RMG Team (rmg_dev@mit.edu) # -# # -# Permission is hereby granted, free of charge, to any person obtaining a # -# copy of this software and associated documentation files (the 'Software'), # -# to deal in the Software without restriction, including without limitation # -# the rights to use, copy, modify, merge, publish, distribute, sublicense, # -# and/or sell copies of the Software, and to permit persons to whom the # -# Software is furnished to do so, subject to the following conditions: # -# # -# The above copyright notice and this permission notice shall be included in # -# all copies or substantial portions of the Software. # -# # -# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # -# DEALINGS IN THE SOFTWARE. # -# # -############################################################################### - -""" -This script contains unit tests of the :mod:`arkane.isodesmic` module. -""" - -import unittest - -import numpy as np - -from rmgpy.molecule import Molecule -from rmgpy.species import Species - -from arkane.encorr.isodesmic import ErrorCancelingScheme, ErrorCancelingSpecies, ErrorCancelingReaction, \ - IsodesmicScheme, SpeciesConstraints -from arkane.modelchem import LevelOfTheory - -################################################################################ - - -class TestErrorCancelingReactionAndSpecies(unittest.TestCase): - """ - Tests that ErrorCancelingReaction objects and ErrorCancelingSpecies object are properly implemented - """ - - @classmethod - def setUpClass(cls): - """ - A method called before each unit test in this class. - """ - cls.molecule1 = Molecule(smiles='CC') - cls.molecule2 = Molecule(smiles='[CH3]') - cls.species = Species(smiles='CC') - - def test_error_canceling_species(self): - """ - Test that ErrorCancelingSpecies can be created properly - """ - lot = LevelOfTheory('test') - error_canceling_species = ErrorCancelingSpecies(self.molecule1, (123.4, 'kcal/mol'), lot, (100.0, 'kJ/mol')) - self.assertIsInstance(error_canceling_species, ErrorCancelingSpecies) - self.assertAlmostEqual(error_canceling_species.low_level_hf298.value_si, 123.4*4184) - - # For target species the high level data is not given - target_species = ErrorCancelingSpecies(self.molecule2, (10.1, 'J/mol'), lot) - self.assertIs(target_species.high_level_hf298, None) - - def test_molecule_input_in_error_canceling_species(self): - """ - Test that an exception is raised if an rmgpy Molecule object is not passed to an ErrorCancelingSpecies - """ - with self.assertRaises(ValueError): - ErrorCancelingSpecies(self.species, (100.0, 'J/mol'), LevelOfTheory('test')) - - def test_error_canceling_reactions(self): - """ - Test that ErrorCancelingReaction object can be created and that hf298 can be calculated for the target - """ - # Take ethane as the target - lot = LevelOfTheory('test') - ethane = ErrorCancelingSpecies(self.molecule1, (100.0, 'kJ/mol'), lot) - methyl = ErrorCancelingSpecies(self.molecule2, (20.0, 'kcal/mol'), lot, (21000.0, 'cal/mol')) - - # This reaction is not an isodesmic reaction, but that does not matter for the unit test - rxn = ErrorCancelingReaction(ethane, {methyl: 2}) - self.assertAlmostEqual(rxn.calculate_target_thermo().value_si, 2*21000.0*4.184-(2*20.0*4184-100.0*1000)) - - def test_level_of_theory_consistency(self): - """ - Test that ErrorCancelingReaction objects properly check that all species use the same level of theory - """ - # Take ethane as the target - ethane = ErrorCancelingSpecies(self.molecule1, (100.0, 'kJ/mol'), LevelOfTheory('test_A')) - methyl = ErrorCancelingSpecies(self.molecule2, (20.0, 'kcal/mol'), LevelOfTheory('test_B'), - (21000.0, 'cal/mol')) - - # This should throw an exception because the model chemistry is different - with self.assertRaises(ValueError): - ErrorCancelingReaction(ethane, {methyl: 2}) - - -class TestSpeciesConstraints(unittest.TestCase): - """ - A class for testing that the SpeciesConstraint class functions properly - """ - - @classmethod - def setUpClass(cls): - """ - A method called before each unit test in this class. - """ - # Give all species a low level Hf298 of 100 J/mol--this is not important for this test - hf = (100.0, 'J/mol') - - lot = LevelOfTheory('test') - cls.propene = ErrorCancelingSpecies(Molecule(smiles='CC=C'), hf, lot) - cls.butane = ErrorCancelingSpecies(Molecule(smiles='CCCC'), hf, lot) - cls.benzene = ErrorCancelingSpecies(Molecule(smiles='c1ccccc1'), hf, lot) - cls.caffeine = ErrorCancelingSpecies(Molecule(smiles='CN1C=NC2=C1C(=O)N(C(=O)N2C)C'), hf, lot) - cls.ethyne = ErrorCancelingSpecies(Molecule(smiles='C#C'), hf, lot) - - def test_initializing_constraint_map(self): - """ - Test that the constraint map is properly initialized when a SpeciesConstraints object is initialized - """ - caffeine_consts = SpeciesConstraints(self.caffeine, [self.butane, self.benzene]) - self.assertEqual(set(caffeine_consts.constraint_map.keys()), {'H', 'C', 'O', 'N', - 'C=O', 'C-N', 'C-H', 'C=C', 'C=N', 'C-C', - '5_ring', '6_ring'}) - - no_rings = SpeciesConstraints(self.caffeine, [self.butane, self.benzene], conserve_ring_size=False) - self.assertEqual(set(no_rings.constraint_map.keys()), {'H', 'C', 'O', 'N', - 'C=O', 'C-N', 'C-H', 'C=C', 'C=N', 'C-C'}) - - atoms_only = SpeciesConstraints(self.caffeine, [self.butane], conserve_ring_size=False, conserve_bonds=False) - self.assertEqual(set(atoms_only.constraint_map.keys()), {'H', 'C', 'O', 'N'}) - - def test_enumerating_constraints(self): - """ - Test that a SpeciesConstraints object can properly enumerate the constraints of a given ErrorCancelingSpecies - """ - spcs_consts = SpeciesConstraints(self.benzene, []) - self.assertEqual(set(spcs_consts.constraint_map.keys()), {'C', 'H', 'C=C', 'C-C', 'C-H', '6_ring'}) - - # Now that we have confirmed that the correct keys are present, overwrite the constraint map to set the order - spcs_consts.constraint_map = {'H': 0, 'C': 1, 'C=C': 2, 'C-C': 3, 'C-H': 4, '6_ring': 5} - - self.assertTrue(np.array_equal(spcs_consts._enumerate_constraints(self.propene), np.array([6, 3, 1, 1, 6, 0]))) - self.assertTrue(np.array_equal(spcs_consts._enumerate_constraints(self.butane), np.array([10, 4, 0, 3, 10, 0]))) - self.assertTrue(np.array_equal(spcs_consts._enumerate_constraints(self.benzene), np.array([6, 6, 3, 3, 6, 1]))) - - # Caffeine and ethyne should return None since they have features not found in benzene - self.assertIs(spcs_consts._enumerate_constraints(self.caffeine), None) - self.assertIs(spcs_consts._enumerate_constraints(self.ethyne), None) - - def test_calculating_constraints(self): - """ - Test that a SpeciesConstraints object can properly return the target constraint vector and the constraint matrix - """ - spcs_consts = SpeciesConstraints(self.caffeine, [self.propene, self.butane, self.benzene, self.ethyne]) - self.assertEqual(set(spcs_consts.constraint_map.keys()), {'H', 'C', 'O', 'N', 'C=O', 'C-N', 'C-H', 'C=C', 'C=N', - 'C-C', '5_ring', '6_ring'}) - - # Now that we have confirmed that the correct keys are present, overwrite the constraint map to set the order - spcs_consts.constraint_map = ({'H': 0, 'C': 1, 'O': 2, 'N': 3, - 'C=O': 4, 'C-N': 5, 'C-H': 6, 'C=C': 7, 'C=N': 8, 'C-C': 9, - '5_ring': 10, '6_ring': 11}) - - target_consts, consts_matrix = spcs_consts.calculate_constraints() - - # First, test that ethyne is not included in the reference set - self.assertEqual(spcs_consts.reference_species, [self.propene, self.butane, self.benzene]) - - # Then, test the output of the calculation - self.assertTrue(np.array_equal(target_consts, np.array([10, 8, 2, 4, 2, 10, 10, 1, 1, 1, 1, 1]))) - self.assertTrue(np.array_equal(consts_matrix, np.array([[6, 3, 0, 0, 0, 0, 6, 1, 0, 1, 0, 0], - [10, 4, 0, 0, 0, 0, 10, 0, 0, 3, 0, 0], - [6, 6, 0, 0, 0, 0, 6, 3, 0, 3, 0, 1]]))) - - -class TestErrorCancelingScheme(unittest.TestCase): - """ - A class for testing that the ErrorCancelingScheme class functions properly - """ - - @classmethod - def setUpClass(cls): - try: - import pyomo as pyo - except ImportError: - pyo = None - cls.pyo = pyo - - lot = LevelOfTheory('test') - cls.propene = ErrorCancelingSpecies(Molecule(smiles='CC=C'), (100, 'kJ/mol'), lot, (105, 'kJ/mol')) - cls.propane = ErrorCancelingSpecies(Molecule(smiles='CCC'), (75, 'kJ/mol'), lot, (80, 'kJ/mol')) - cls.butane = ErrorCancelingSpecies(Molecule(smiles='CCCC'), (150, 'kJ/mol'), lot, (145, 'kJ/mol')) - cls.butene = ErrorCancelingSpecies(Molecule(smiles='C=CCC'), (175, 'kJ/mol'), lot, (180, 'kJ/mol')) - cls.pentane = ErrorCancelingSpecies(Molecule(smiles='CCCCC'), (200, 'kJ/mol'), lot, (190, 'kJ/mol')) - cls.pentene = ErrorCancelingSpecies(Molecule(smiles='C=CCCC'), (225, 'kJ/mol'), lot, (220, 'kJ/mol')) - cls.hexane = ErrorCancelingSpecies(Molecule(smiles='CCCCCC'), (250, 'kJ/mol'), lot, (260, 'kJ/mol')) - cls.hexene = ErrorCancelingSpecies(Molecule(smiles='C=CCCCC'), (275, 'kJ/mol'), lot, (275, 'kJ/mol')) - cls.benzene = ErrorCancelingSpecies(Molecule(smiles='c1ccccc1'), (-50, 'kJ/mol'), lot, (-80, 'kJ/mol')) - cls.caffeine = ErrorCancelingSpecies(Molecule(smiles='CN1C=NC2=C1C(=O)N(C(=O)N2C)C'), (300, 'kJ/mol'), lot) - cls.ethyne = ErrorCancelingSpecies(Molecule(smiles='C#C'), (200, 'kJ/mol'), lot) - - def test_creating_error_canceling_schemes(self): - scheme = ErrorCancelingScheme(self.propene, [self.butane, self.benzene, self.caffeine, self.ethyne], True, True) - - self.assertEqual(scheme.reference_species, [self.butane]) - - isodesmic_scheme = IsodesmicScheme(self.propene, [self.butane, self.benzene, self.caffeine, self.ethyne]) - - self.assertEqual(isodesmic_scheme.reference_species, [self.butane, self.benzene]) - - def test_find_error_canceling_reaction(self): - """ - Test that the MILP problem can be solved to find a single isodesmic reaction - """ - scheme = IsodesmicScheme(self.propene, [self.propane, self.butane, self.butene, self.caffeine, self.ethyne]) - - # Note that caffeine and ethyne will not be allowed, so for the full set the indices are [0, 1, 2] - rxn, _ = scheme._find_error_canceling_reaction([0, 1, 2], milp_software=['lpsolve']) - self.assertEqual(rxn.species[self.butane], -1) - self.assertEqual(rxn.species[self.propane], 1) - self.assertEqual(rxn.species[self.butene], 1) - - if self.pyo is not None: - rxn, _ = scheme._find_error_canceling_reaction([0, 1, 2], milp_software=['pyomo']) - self.assertEqual(rxn.species[self.butane], -1) - self.assertEqual(rxn.species[self.propane], 1) - self.assertEqual(rxn.species[self.butene], 1) - - def test_multiple_error_canceling_reactions(self): - """ - Test that multiple error canceling reactions can be found - """ - scheme = IsodesmicScheme(self.propene, [self.propane, self.butane, self.butene, self.pentane, self.pentene, - self.hexane, self.hexene, self.benzene]) - - reaction_list = scheme.multiple_error_canceling_reaction_search(n_reactions_max=20) - self.assertEqual(len(reaction_list), 20) - reaction_string = reaction_list.__repr__() - # Consider both permutations of the products in the reaction string - rxn_str1 = ' 1*CCC + 1*C=CCC >' - rxn_str2 = ' 1*C=CCC + 1*CCC >' - self.assertTrue(any(rxn_string in reaction_string for rxn_string in [rxn_str1, rxn_str2])) - - if self.pyo is not None: - # pyomo is slower, so don't test as many - reaction_list = scheme.multiple_error_canceling_reaction_search(n_reactions_max=5, milp_software=['pyomo']) - self.assertEqual(len(reaction_list), 5) - reaction_string = reaction_list.__repr__() - self.assertTrue(any(rxn_string in reaction_string for rxn_string in [rxn_str1, rxn_str2])) - - def test_calculate_target_enthalpy(self): - """ - Test that ErrorCancelingScheme is able to calculate thermochemistry for the target species - """ - scheme = IsodesmicScheme(self.propene, [self.propane, self.butane, self.butene, self.pentane, self.pentene, - self.hexane, self.hexene, self.benzene]) - - target_thermo, rxn_list = scheme.calculate_target_enthalpy(n_reactions_max=3, milp_software=['lpsolve']) - self.assertEqual(target_thermo.value_si, 115000.0) - self.assertIsInstance(rxn_list[0], ErrorCancelingReaction) - - if self.pyo is not None: - target_thermo, _ = scheme.calculate_target_enthalpy(n_reactions_max=3, milp_software=['pyomo']) - self.assertEqual(target_thermo.value_si, 115000.0) - - -if __name__ == '__main__': - unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arkane/ess/gaussian.py b/arkane/ess/gaussian.py index 41e861733f..df432631bf 100644 --- a/arkane/ess/gaussian.py +++ b/arkane/ess/gaussian.py @@ -143,7 +143,7 @@ def load_force_constant_matrix(self): while line != '': # Read force constant matrix if 'Force constants in Cartesian coordinates:' in line: - force = np.zeros((n_rows, n_rows), np.float64) + force = np.zeros((n_rows, n_rows), float) for i in range(int(math.ceil(n_rows / 5.0))): # Header row line = f.readline() @@ -187,9 +187,9 @@ def load_geometry(self): for num in number: mass1, _ = get_element_mass(num) mass.append(mass1) - coord = np.array(coord, np.float64) - number = np.array(number, np.int) - mass = np.array(mass, np.float64) + coord = np.array(coord, float) + number = np.array(number, int) + mass = np.array(mass, float) if len(number) == 0 or len(coord) == 0 or len(mass) == 0: raise LogError('Unable to read atoms from Gaussian geometry output file {0}. ' 'Make sure the output file is not corrupt.\nNote: if your species has ' @@ -460,9 +460,9 @@ def load_scan_energies(self): print(f' Assuming {os.path.basename(self.path)} is the output from a rigid scan...') # For rigid scans, all of the angles are evenly spaced with a constant step size scan_res = math.pi / 180 * self._load_scan_angle() - angle = np.arange(0.0, scan_res * (len(vlist) - 1) + 0.00001, scan_res, np.float64) + angle = np.arange(0.0, scan_res * (len(vlist) - 1) + 0.00001, scan_res, float) else: - angle = np.array(angle, np.float64) + angle = np.array(angle, float) # Convert -180 ~ 180 degrees to 0 ~ 2pi rads angle = (angle - angle[0]) angle[angle < 0] += 360.0 @@ -470,7 +470,7 @@ def load_scan_energies(self): angle[-1] = angle[-1] if angle[-1] > 2 * self._load_scan_angle() else angle[-1] + 360.0 angle = angle * math.pi / 180 - vlist = np.array(vlist, np.float64) + vlist = np.array(vlist, float) # 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) diff --git a/arkane/ess/gaussianTest.py b/arkane/ess/gaussianTest.py deleted file mode 100644 index 1aa5c8f2e0..0000000000 --- a/arkane/ess/gaussianTest.py +++ /dev/null @@ -1,253 +0,0 @@ -#!/usr/bin/env python3 - -############################################################################### -# # -# RMG - Reaction Mechanism Generator # -# # -# Copyright (c) 2002-2023 Prof. William H. Green (whgreen@mit.edu), # -# Prof. Richard H. West (r.west@neu.edu) and the RMG Team (rmg_dev@mit.edu) # -# # -# Permission is hereby granted, free of charge, to any person obtaining a # -# copy of this software and associated documentation files (the 'Software'), # -# to deal in the Software without restriction, including without limitation # -# the rights to use, copy, modify, merge, publish, distribute, sublicense, # -# and/or sell copies of the Software, and to permit persons to whom the # -# Software is furnished to do so, subject to the following conditions: # -# # -# The above copyright notice and this permission notice shall be included in # -# all copies or substantial portions of the Software. # -# # -# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # -# DEALINGS IN THE SOFTWARE. # -# # -############################################################################### - -""" -This module contains unit tests of the :mod:`arkane.ess.gaussian` module. -""" - -import os -import unittest - -import numpy as np - -import rmgpy.constants as constants -from external.wip import work_in_progress -from rmgpy.statmech import IdealGasTranslation, LinearRotor, NonlinearRotor, HarmonicOscillator, HinderedRotor - -from arkane.ess.gaussian import GaussianLog -from arkane.exceptions import LogError - -################################################################################ - - -class GaussianLogTest(unittest.TestCase): - """ - Contains unit tests for the gaussian module, used for parsing Gaussian log files. - """ - @classmethod - def setUpClass(cls): - """ - A method that is run before all unit tests in this class. - """ - cls.data_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'data', 'gaussian') - - def test_check_for_errors(self): - """ - Uses Gaussian log files that had various errors - to test if errors are properly parsed. - """ - with self.assertRaises(LogError): - GaussianLog(os.path.join(self.data_path, 'l913.out')) - with self.assertRaises(LogError): - GaussianLog(os.path.join(self.data_path, 'l9999.out')) - with self.assertRaises(LogError): - GaussianLog(os.path.join(self.data_path, 'error_termination.out')) - - @work_in_progress - def test_load_ethylene_from_gaussian_log_cbsqb3(self): - """ - Uses a Gaussian03 log file for ethylene (C2H4) to test that its - molecular degrees of freedom can be properly read. - """ - - log = GaussianLog(os.path.join(self.data_path, 'ethylene.log')) - conformer, unscaled_frequencies = log.load_conformer() - e0 = log.load_energy() - - 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] - t_list = np.array([298.15], np.float64) - self.assertAlmostEqual(trans.get_partition_function(t_list), 5.83338e6, delta=1e1) - self.assertAlmostEqual(rot.get_partition_function(t_list), 2.59622e3, delta=1e-2) - self.assertAlmostEqual(vib.get_partition_function(t_list), 1.0481e0, delta=1e-4) - - self.assertAlmostEqual(e0 / constants.Na / constants.E_h, -78.467452, 4) - self.assertEqual(conformer.spin_multiplicity, 1) - self.assertEqual(conformer.optical_isomers, 1) - - def test_gaussian_energies(self): - """ - test parsing double hydride, MP2, CCSD, CCSD(T), cbs-qb3, cbs-4m, g4, g4mp2 form Gaussian log - """ - log_doublehybrid = GaussianLog(os.path.join(self.data_path, 'B2PLYP.LOG')) - log_mp2 = GaussianLog(os.path.join(self.data_path, 'UMP2_C_ATOM.LOG')) - log_ccsd = GaussianLog(os.path.join(self.data_path, 'UCCSD_C_ATOM.LOG')) - log_ccsdt = GaussianLog(os.path.join(self.data_path, 'UCCSDT_C_ATOM.LOG')) - log_qb3 = GaussianLog(os.path.join(os.path.dirname(os.path.dirname(__file__)), - '../examples/arkane/species/C2H5/', 'ethyl_cbsqb3.log')) - log_cbs4m = GaussianLog(os.path.join(self.data_path, 'cbs-4m_85_methanol.out')) - log_g4 = GaussianLog(os.path.join(self.data_path, 'g4_85_methanol.out')) - log_g4mp2 = GaussianLog(os.path.join(self.data_path, 'g4mp2_85_methanol.out')) - log_rocbsqb3 = GaussianLog(os.path.join(self.data_path, 'rocbs-qb3_85_methanol.out')) - - - self.assertAlmostEqual(log_doublehybrid.load_energy() / constants.Na / constants.E_h, -0.40217794572194e+02, - delta=1e-6) - self.assertAlmostEqual(log_mp2.load_energy() / constants.Na / constants.E_h, -0.37504683723025e+02, - delta=1e-6) - self.assertAlmostEqual(log_ccsd.load_energy() / constants.Na / constants.E_h, -37.517151426, - delta=1e-6) - self.assertAlmostEqual(log_ccsdt.load_energy() / constants.Na / constants.E_h, -0.37517454469e+02, - delta=1e-6) - self.assertAlmostEqual(log_qb3.load_energy() / constants.Na / constants.E_h, -79.029798, - delta=1e-6) - self.assertAlmostEqual(log_cbs4m.load_energy() / constants.Na / constants.E_h, -115.613180, - delta=1e-6) - self.assertAlmostEqual(log_g4.load_energy() / constants.Na / constants.E_h, -115.698896, - delta=1e-6) - self.assertAlmostEqual(log_g4mp2.load_energy() / constants.Na / constants.E_h, -115.617241, - delta=1e-6) - self.assertAlmostEqual(log_rocbsqb3.load_energy() / constants.Na / constants.E_h, -115.590540, - delta=1e-6) - - def test_load_oxygen_from_gaussian_log(self): - """ - Uses a Gaussian03 log file for oxygen (O2) to test that its - molecular degrees of freedom can be properly read. - """ - - log = GaussianLog(os.path.join(self.data_path, 'oxygen.log')) - conformer, unscaled_frequencies = log.load_conformer() - e0 = log.load_energy() - - 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] - t_list = np.array([298.15], np.float64) - self.assertAlmostEqual(trans.get_partition_function(t_list), 7.11169e6, delta=1e1) - self.assertAlmostEqual(rot.get_partition_function(t_list), 7.13316e1, delta=1e-4) - self.assertAlmostEqual(vib.get_partition_function(t_list), 1.00037e0, delta=1e-4) - - self.assertAlmostEqual(e0 / constants.Na / constants.E_h, -150.3784877, 4) - self.assertEqual(conformer.spin_multiplicity, 3) - self.assertEqual(conformer.optical_isomers, 1) - - @work_in_progress - def test_load_ethylene_from_gaussian_log_g3(self): - """ - Uses a Gaussian03 log file for ethylene (C2H4) to test that its - molecular degrees of freedom can be properly read. - """ - - log = GaussianLog(os.path.join(self.data_path, 'ethylene_G3.log')) - conformer, unscaled_frequencies = log.load_conformer() - e0 = log.load_energy() - - 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] - t_list = np.array([298.15], np.float64) - - self.assertAlmostEqual(trans.get_partition_function(t_list), 5.83338e6, delta=1e1) - self.assertAlmostEqual(rot.get_partition_function(t_list), 2.53410e3, delta=1e-2) - self.assertAlmostEqual(vib.get_partition_function(t_list), 1.0304e0, delta=1e-4) - - self.assertAlmostEqual(e0 / constants.Na / constants.E_h, -78.562189, 4) - self.assertEqual(conformer.spin_multiplicity, 1) - self.assertEqual(conformer.optical_isomers, 1) - - def test_load_symmetry_and_optics(self): - """ - Uses a Gaussian03 log file for oxygen (O2) to test that its - molecular degrees of freedom can be properly read. - """ - - log = GaussianLog(os.path.join(self.data_path, 'oxygen.log')) - optical, symmetry, _ = log.get_symmetry_properties() - self.assertEqual(optical, 1) - self.assertEqual(symmetry, 2) - - conf = log.load_conformer()[0] - self.assertEqual(conf.optical_isomers, 1) - found_rotor = False - for mode in conf.modes: - if isinstance(mode, LinearRotor): - self.assertEqual(mode.symmetry, 2) - found_rotor = True - self.assertTrue(found_rotor) - - def test_load_scan_angle(self): - """ - Ensures proper scan angle found in Gaussian scan job - """ - log = GaussianLog(os.path.join(self.data_path, 'isobutanolQOOH_scan.log')) - self.assertAlmostEqual(log._load_scan_angle(), 10.0) - - def test_load_number_scans(self): - """ - Ensures proper scan angle found in Gaussian scan job - """ - log = GaussianLog(os.path.join(self.data_path, 'isobutanolQOOH_scan.log')) - self.assertAlmostEqual(log._load_number_scans(), 36) - - def test_load_scan_with_freq(self): - """ - Ensures that the length of enegies with hr scans and freq calc is correct - """ - log = GaussianLog(os.path.join(self.data_path, 'hr_scan_with_freq.log')) - self.assertAlmostEqual(log._load_number_scans(), 36) - self.assertAlmostEqual(log._load_scan_angle(), 10.0) - vlist, _ = log.load_scan_energies() - self.assertEqual(len(vlist), 37) - - def test_load_negative_frequency(self): - """ - Load an imaginary frequency from a Gaussian output file. - """ - log = GaussianLog(os.path.join(self.data_path, 'hr_scan_with_freq.log')) - imaginary_freq = log.load_negative_frequency() - self.assertEqual(imaginary_freq, -556.0124) - - # verify that an error is raised if there are no negative frequencies - with self.assertRaises(LogError): - log = GaussianLog(os.path.join(self.data_path, 'rocbs-qb3_85_methanol.out')) - imaginary_freq = log.load_negative_frequency() - - -################################################################################ - - -if __name__ == '__main__': - unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arkane/ess/molpro.py b/arkane/ess/molpro.py index e27d3ccba3..35fcfbb00c 100644 --- a/arkane/ess/molpro.py +++ b/arkane/ess/molpro.py @@ -138,7 +138,7 @@ def load_force_constant_matrix(self): while line != '': # Read force constant matrix if 'Force Constants (Second Derivatives of the Energy) in [a.u.]' in line: - fc = np.zeros((n_rows, n_rows), np.float64) + fc = np.zeros((n_rows, n_rows), float) for i in range(int(math.ceil(n_rows / 5.0))): # Header row line = f.readline() @@ -202,9 +202,9 @@ def load_geometry(self): mass1, num1 = get_element_mass(atom1) mass.append(mass1) number.append(num1) - number = np.array(number, np.int) - mass = np.array(mass, np.float64) - coord = np.array(coord, np.float64) + number = np.array(number, int) + mass = np.array(mass, float) + coord = np.array(coord, float) if len(number) == 0 or len(coord) == 0 or len(mass) == 0: raise LogError('Unable to read atoms from Molpro geometry output file {0}'.format(self.path)) diff --git a/arkane/ess/orca.py b/arkane/ess/orca.py index 452c4a8448..e80d5ad180 100644 --- a/arkane/ess/orca.py +++ b/arkane/ess/orca.py @@ -134,7 +134,7 @@ def load_force_constant_matrix(self): while line != '': if '$hessian' in line: line = f.readline() - force = np.zeros((n_rows, n_rows), np.float64) + force = np.zeros((n_rows, n_rows), float) for i in range(int(math.ceil(n_rows / 5.0))): line = f.readline() for j in range(n_rows): @@ -180,9 +180,9 @@ def load_geometry(self): mass1, num1 = get_element_mass(atom1) mass.append(mass1) numbers.append(num1) - coord = np.array(coords, np.float64) - number = np.array(numbers, np.int) - mass = np.array(mass, np.float64) + coord = np.array(coords, float) + number = np.array(numbers, int) + mass = np.array(mass, float) if len(number) == 0 or len(coord) == 0 or len(mass) == 0: raise LogError(f'Unable to read atoms from orca geometry output file {self.path}.') diff --git a/arkane/ess/psi4.py b/arkane/ess/psi4.py index 9b0daa4bc0..2a995bad1e 100644 --- a/arkane/ess/psi4.py +++ b/arkane/ess/psi4.py @@ -159,9 +159,9 @@ def load_geometry(self): mass_, num_ = get_element_mass(atom) mass.append(mass_) number.append(num_) - coord = np.array(coord, np.float64) - number = np.array(number, np.int) - mass = np.array(mass, np.float64) + coord = np.array(coord, float) + number = np.array(number, int) + mass = np.array(mass, float) if any(len(param) == 0 for param in [number, coord, mass]): raise LogError(f'Unable to read atoms from Psi4 geometry output file {self.path}.') diff --git a/arkane/ess/psi4Test.py b/arkane/ess/psi4Test.py deleted file mode 100644 index 163cd0a23d..0000000000 --- a/arkane/ess/psi4Test.py +++ /dev/null @@ -1,222 +0,0 @@ -#!/usr/bin/env python3 - -############################################################################### -# # -# RMG - Reaction Mechanism Generator # -# # -# Copyright (c) 2002-2023 Prof. William H. Green (whgreen@mit.edu), # -# Prof. Richard H. West (r.west@neu.edu) and the RMG Team (rmg_dev@mit.edu) # -# # -# Permission is hereby granted, free of charge, to any person obtaining a # -# copy of this software and associated documentation files (the 'Software'), # -# to deal in the Software without restriction, including without limitation # -# the rights to use, copy, modify, merge, publish, distribute, sublicense, # -# and/or sell copies of the Software, and to permit persons to whom the # -# Software is furnished to do so, subject to the following conditions: # -# # -# The above copyright notice and this permission notice shall be included in # -# all copies or substantial portions of the Software. # -# # -# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # -# DEALINGS IN THE SOFTWARE. # -# # -############################################################################### - -""" -This module contains unit tests of the :mod:`arkane.ess.psi4` module. -""" - -import os -import unittest - -import numpy as np - -from rmgpy.statmech import IdealGasTranslation, NonlinearRotor, HarmonicOscillator, HinderedRotor - -from arkane.exceptions import LogError -from arkane.ess.psi4 import Psi4Log - -################################################################################ - - -class Psi4LogTest(unittest.TestCase): - """ - Contains unit tests for the Psi4Log module, used for parsing Psi4 log files. - """ - @classmethod - def setUpClass(cls): - """ - A method that is run before all unit tests in this class. - """ - cls.data_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'data', 'psi4') - - def test_check_for_errors(self): - """ - Uses Psi4 log files that had various errors to test if errors are properly parsed. - """ - with self.assertRaises(LogError): - Psi4Log(os.path.join(self.data_path, 'IO_error.out')) - - def test_number_of_atoms_from_psi4_log(self): - """ - Uses a Psi4 log files to test that - number of atoms can be properly read. - """ - log = Psi4Log(os.path.join(self.data_path, 'opt_freq.out')) - self.assertEqual(log.get_number_of_atoms(), 3) - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_ts.out')) - self.assertEqual(log.get_number_of_atoms(), 4) - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_dft.out')) - self.assertEqual(log.get_number_of_atoms(), 3) - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_dft_ts.out')) - self.assertEqual(log.get_number_of_atoms(), 4) - - def test_energy_from_psi4_log(self): - """ - Uses a Psi4 log files to test that - molecular energies can be properly read. - """ - log = Psi4Log(os.path.join(self.data_path, 'opt_freq.out')) - self.assertAlmostEqual(log.load_energy(), -199599899.9822719, delta=1e-2) - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_ts.out')) - self.assertAlmostEqual(log.load_energy(), -395828407.5987777, delta=1e-2) - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_dft.out')) - self.assertAlmostEqual(log.load_energy(), -200640009.37231186, delta=1e-2) - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_dft_ts.out')) - self.assertAlmostEqual(log.load_energy(), -397841662.56434655, delta=1e-2) - - def test_zero_point_energy_from_psi4_log(self): - """ - Uses Psi4 log files to test that zero-point energies can be properly read. - """ - log = Psi4Log(os.path.join(self.data_path, 'opt_freq.out')) - self.assertAlmostEqual(log.load_zero_point_energy(), 60868.832, delta=1e-3) - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_dft.out')) - self.assertAlmostEqual(log.load_zero_point_energy(), 56107.44, delta=1e-3) - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_dft_ts.out')) - self.assertAlmostEqual(log.load_zero_point_energy(), 67328.928, delta=1e-3) - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_ts.out')) - self.assertAlmostEqual(log.load_zero_point_energy(), 75136.272, delta=1e-3) - - def test_load_force_constant_matrix_from_psi4_log(self): - """ - Uses Psi4 log files to test that force constant matrices can be properly read. - """ - log = Psi4Log(os.path.join(self.data_path, 'opt_freq.out')) - expected_mat_1 = np.array([[79.60709821, 0., 0., -158.56969492, 0., -119.50250089, -158.56969492, 0., 119.50250089], - [0., 0., 0., 0., 0., 0., 0., 0., 0.], - [0., 0., 51.88196366, -92.52464457, 0., -103.3438893, 92.52464457, 0., -103.3438893], - [-158.56969492, 0., -92.52464457, 682.40616438, 0., 422.33771249, -50.69495535, 0., -53.73729893], - [0., 0., 0., 0., 0., 0., 0., 0., 0.], - [-119.50250089, 0., -103.3438893, 422.33771249, 0., 385.24274073, 53.73729893, 0., 26.45946547], - [-158.56969492, 0., 92.52464457, -50.69495535, 0., 53.73729893, 682.40616438, 0., -422.33771249], - [0., 0., 0., 0., 0., 0., 0., 0., 0.], - [119.50250089, 0., -103.3438893, -53.73729893, 0., 26.45946547, -422.33771249, 0., 385.24274073]], - np.float64) - self.assertTrue(np.allclose(log.load_force_constant_matrix(), expected_mat_1)) - - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_dft.out')) - expected_mat_2 = np.array([[65.29227021, 0., 0., -130.05593215, 0., -102.09767406, -130.05593215, 0., 102.09767406], - [0., 0., 0., 0., 0., 0., 0., 0., 0.], - [0., 0., 44.51008758, -77.12673693, 0., -88.65982001, 77.12673693, 0., -88.65982001], - [-130.05593215, 0., -77.12673693, 567.48290169, 0., 356.99781537, -49.36504715, 0., -49.73970876], - [0., 0., 0., 0., 0., 0., 0., 0., 0.], - [-102.09767406, 0., -88.65982001, 356.99781537, 0., 336.25221646, 49.73970876, 0., 16.95147799], - [-130.05593215, 0., 77.12673693, -49.36504715, 0., 49.73970876, 567.48290169, 0., -356.99781537], - [0., 0., 0., 0., 0., 0., 0., 0., 0.], - [102.09767406, 0., -88.65982001, -49.73970876, 0., 16.95147799, -356.99781537, 0., 336.25221646]], - np.float64) - self.assertTrue(np.allclose(log.load_force_constant_matrix(), expected_mat_2)) - - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_dft_ts.out')) - expected_mat_3 = np.array([[-1.13580195, 0., 0., 3.38451439, 0., 0., 1.13580195, 0., 0., -3.38451439, 0., 0.], - [0., 32.96704817, -7.81315371, 0., -24.52602914, 47.62525747, 0., -23.84113467, -5.93732553, 0., -11.82985738, 7.15401071], - [0., -7.81315371, 54.99575056, 0., 23.33047286, -191.28989554, 0., 5.93732553, -7.5316094, 0., -15.85753341, 2.20187269], - [3.38451439, 0., 0., -10.08532992, 0., 0., -3.38451439, 0., 0., 10.08532992, 0., 0.], - [0., -24.52602914, 23.33047286, 0., 143.78387645, -158.67358218, 0., -11.82985738, 15.85753341, 0., 1.05099332, 2.55609183], - [0., 47.62525747, -191.28989554, 0., -158.67358218, 742.27868659, 0., -7.15401071, 2.20187269, 0., -2.55609183, 11.01167933], - [1.13580195, 0., 0., -3.38451439, 0., 0., -1.13580195, 0., 0., 3.38451439, 0., 0.], - [0., -23.84113467, 5.93732553, 0., -11.82985738, -7.15401071, 0., 32.96704817, 7.81315371, 0., -24.52602914, -47.62525747], - [0., -5.93732553, -7.5316094, 0., 15.85753341, 2.20187269, 0., 7.81315371, 54.99575056, 0., -23.33047286, -191.28989554], - [-3.38451439, 0., 0., 10.08532992, 0., 0., 3.38451439, 0., 0., -10.08532992, 0., 0.], - [0., -11.82985738, -15.85753341, 0., 1.05099332, -2.55609183, 0., -24.52602914, -23.33047286, 0., 143.78387645, 158.67358218], - [0., 7.15401071, 2.20187269, 0., 2.55609183, 11.01167933, 0., -47.62525747, -191.28989554, 0., 158.67358218, 742.27868659]], - np.float64) - self.assertTrue(np.allclose(log.load_force_constant_matrix(), expected_mat_3)) - - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_ts.out')) - expected_mat_4 = np.array([[-1.36856086, 0., 0., 3.91653225, 0., 0., 1.36856086, 0., 0., -3.91653225, 0., 0.], - [0., 47.82294224, -11.20296807, 0., -35.81980174, 65.25989773, 0., -35.42652343, -7.19264812, 0., -13.56514966, 8.02470416], - [0., -11.20296807, 66.4797624, 0., 35.78782098, -229.4811002, 0., 7.19264812, -9.74548387, 0., -19.81147687, 3.46263087], - [3.91653225, 0., 0., -11.2082886, 0., 0., -3.91653225, 0., 0., 11.2082886, 0., 0.], - [0., -35.81980174, 35.78782098, 0., 194.95334567, -224.75547126, 0., -13.56514966, 19.81147687, 0., 1.78681563, 3.25854712], - [0., 65.25989773, -229.4811002, 0., -224.75547126, 889.16020169, 0., -8.02470416, 3.46263087, 0., -3.25854712, 11.25397079], - [1.36856086, 0., 0., -3.91653225, 0., 0., -1.36856086, 0., 0., 3.91653225, 0., 0.], - [0., -35.42652343, 7.19264812, 0., -13.56514966, -8.02470416, 0., 47.82294224, 11.20296807, 0., -35.81980174, -65.25989773], - [0., -7.19264812, -9.74548387, 0., 19.81147687, 3.46263087, 0., 11.20296807, 66.4797624, 0., -35.78782098, -229.4811002], - [-3.91653225, 0., 0., 11.2082886, 0., 0., 3.91653225, 0., 0., -11.2082886, 0., 0.], - [0., -13.56514966, -19.81147687, 0., 1.78681563, -3.25854712, 0., -35.81980174, -35.78782098, 0., 194.95334567, 224.75547126], - [0., 8.02470416, 3.46263087, 0., 3.25854712, 11.25397079, 0., -65.25989773, -229.4811002, 0., 224.75547126, 889.16020169]], - np.float64) - self.assertTrue(np.allclose(log.load_force_constant_matrix(), expected_mat_4)) - - def test_load_vibrations_from_psi4_log(self): - """ - Uses a Psi4 log files to test that - molecular energies can be properly read. - """ - log = Psi4Log(os.path.join(self.data_path, 'opt_freq.out')) - conformer, unscaled_frequencies = log.load_conformer() - self.assertEqual(len(conformer.modes[2]._frequencies.value), 3) - self.assertEqual(conformer.modes[2]._frequencies.value[2], 4261.7445) - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_dft_ts.out')) - conformer, unscaled_frequencies = log.load_conformer() - self.assertEqual(len(conformer.modes[2]._frequencies.value), 5) - self.assertEqual(conformer.modes[2]._frequencies.value[2], 1456.2449) - - def test_load_modes_from_psi4_log(self): - """ - Uses a Psi4 log file for opt_freq.out to test that its - molecular modes can be properly read. - """ - log = Psi4Log(os.path.join(self.data_path, 'opt_freq.out')) - conformer, unscaled_frequencies = log.load_conformer() - 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.assertEqual(len(unscaled_frequencies), 3) - - def test_load_negative_frequency(self): - """ - Test properly loading negative frequencies. - """ - log_1 = Psi4Log(os.path.join(self.data_path, 'opt_freq_dft_ts.out')) - neg_freq_1 = log_1.load_negative_frequency() - self.assertEqual(neg_freq_1, -617.1749) - log_2 = Psi4Log(os.path.join(self.data_path, 'opt_freq_ts.out')) - neg_freq_2 = log_2.load_negative_frequency() - self.assertEqual(neg_freq_2, -653.3950) - - def test_spin_multiplicity_from_psi4_log(self): - """ - Uses a Psi4 log file for opt_freq_dft_ts.out to test that its - molecular degrees of freedom can be properly read. - """ - log = Psi4Log(os.path.join(self.data_path, 'opt_freq.out')) - conformer, unscaled_frequencies = log.load_conformer() - self.assertEqual(conformer.spin_multiplicity, 1) - log = Psi4Log(os.path.join(self.data_path, 'opt_freq_dft_ts.out')) - conformer, unscaled_frequencies = log.load_conformer() - self.assertEqual(conformer.spin_multiplicity, 1) - - -################################################################################ - - -if __name__ == '__main__': - unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arkane/ess/qchem.py b/arkane/ess/qchem.py index d6835d47b9..0dec05a40c 100644 --- a/arkane/ess/qchem.py +++ b/arkane/ess/qchem.py @@ -149,7 +149,7 @@ def load_force_constant_matrix(self): while line != '': # Read force constant matrix if 'Final Hessian.' in line or 'Hessian of the SCF Energy' in line: - force = np.zeros((n_rows, n_rows), np.float64) + force = np.zeros((n_rows, n_rows), float) for i in range(int(math.ceil(n_rows / 6.0))): # Header row line = f.readline() @@ -199,9 +199,9 @@ def load_geometry(self): mass1, num1 = get_element_mass(atom1) mass.append(mass1) number.append(num1) - coord = np.array(coord, np.float64) - number = np.array(number, np.int) - mass = np.array(mass, np.float64) + coord = np.array(coord, float) + number = np.array(number, int) + mass = np.array(mass, float) if len(number) == 0 or len(coord) == 0 or len(mass) == 0: raise LogError('Unable to read atoms from QChem geometry output file {0}.'.format(self.path)) @@ -364,7 +364,7 @@ def load_scan_energies(self): read = True logging.info(' Assuming {0} is the output from a QChem PES scan...'.format(os.path.basename(self.path))) - v_list = np.array(v_list, np.float64) + v_list = np.array(v_list, float) # check to see if the scanlog indicates that one of your reacting species may not be the lowest energy conformer check_conformer_energy(v_list, self.path) @@ -372,7 +372,7 @@ def load_scan_energies(self): # Also convert units from Hartree/particle to J/mol v_list -= np.min(v_list) v_list *= constants.E_h * constants.Na - angle = np.arange(0.0, 2 * math.pi + 0.00001, 2 * math.pi / (len(v_list) - 1), np.float64) + angle = np.arange(0.0, 2 * math.pi + 0.00001, 2 * math.pi / (len(v_list) - 1), float) return v_list, angle def load_negative_frequency(self): diff --git a/arkane/ess/terachem.py b/arkane/ess/terachem.py index 2e680b0da6..cae46b4e68 100644 --- a/arkane/ess/terachem.py +++ b/arkane/ess/terachem.py @@ -118,7 +118,7 @@ def load_force_constant_matrix(self): while line != '': # Read force constant matrix if '*** Hessian Matrix (Hartree/Bohr^2) ***' in line: - force = np.zeros((n_rows, n_rows), np.float64) + force = np.zeros((n_rows, n_rows), float) for i in range(int(math.ceil(n_rows / 6.0))): # Matrix element rows for j in range(n_rows): @@ -190,9 +190,9 @@ def load_geometry(self): j += 1 break - coords = np.array(coords, np.float64) - numbers = np.array(numbers, np.int) - masses = np.array(masses, np.float64) + coords = np.array(coords, float) + numbers = np.array(numbers, int) + masses = np.array(masses, float) if len(coords) == 0 or len(numbers) == 0 or len(masses) == 0 \ or ((len(coords) != num_of_atoms or len(numbers) != num_of_atoms or len(masses) != num_of_atoms) and num_of_atoms is not None): @@ -319,7 +319,7 @@ def load_scan_energies(self): raise LogError(f'Could not parse scan energies from {self.path}') logging.info(' Assuming {0} is the output from a TeraChem PES scan...'.format(os.path.basename(self.path))) - v_list = np.array(v_list, np.float64) + v_list = np.array(v_list, float) # check to see if the scanlog indicates that one of the reacting species may not be the lowest energy conformer check_conformer_energy(v_list, self.path) @@ -328,7 +328,7 @@ def load_scan_energies(self): # Also convert units from Hartree/particle to J/mol v_list -= np.min(v_list) v_list *= constants.E_h * constants.Na - angles = np.arange(0.0, 2 * math.pi + 0.00001, 2 * math.pi / (len(v_list) - 1), np.float64) + angles = np.arange(0.0, 2 * math.pi + 0.00001, 2 * math.pi / (len(v_list) - 1), float) # remove None's: indices_to_pop = [v_list.index[entry] for entry in v_list if entry is None] diff --git a/arkane/ess/terachemTest.py b/arkane/ess/terachemTest.py deleted file mode 100644 index d8c252c1ab..0000000000 --- a/arkane/ess/terachemTest.py +++ /dev/null @@ -1,418 +0,0 @@ -#!/usr/bin/env python3 - -############################################################################### -# # -# RMG - Reaction Mechanism Generator # -# # -# Copyright (c) 2002-2023 Prof. William H. Green (whgreen@mit.edu), # -# Prof. Richard H. West (r.west@neu.edu) and the RMG Team (rmg_dev@mit.edu) # -# # -# Permission is hereby granted, free of charge, to any person obtaining a # -# copy of this software and associated documentation files (the 'Software'), # -# to deal in the Software without restriction, including without limitation # -# the rights to use, copy, modify, merge, publish, distribute, sublicense, # -# and/or sell copies of the Software, and to permit persons to whom the # -# Software is furnished to do so, subject to the following conditions: # -# # -# The above copyright notice and this permission notice shall be included in # -# all copies or substantial portions of the Software. # -# # -# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # -# DEALINGS IN THE SOFTWARE. # -# # -############################################################################### - -""" -This module contains unit tests of the :mod:`arkane.ess.terachem` module. -""" - -import os -import unittest - -import numpy as np - -from rmgpy.statmech.conformer import Conformer - -from arkane.exceptions import LogError -from arkane.ess.terachem import TeraChemLog - -################################################################################ - - -class TeraChemLogTest(unittest.TestCase): - """ - Contains unit tests for the terachem module, used for parsing TeraChem files. - """ - @classmethod - def setUpClass(cls): - """ - A method that is run before all unit tests in this class. - """ - cls.data_path = os.path.join(os.path.dirname(os.path.dirname(__file__)), 'data', 'terachem') - - def test_get_number_of_atoms(self): - """Uses various TeraChem log files to test that number of atoms can be properly read.""" - log_file = TeraChemLog(os.path.join(self.data_path, 'ethane_minimize_output.out')) - self.assertEqual(log_file.get_number_of_atoms(), 6) - log_file = TeraChemLog(os.path.join(self.data_path, 'ethane_coords.xyz')) - self.assertEqual(log_file.get_number_of_atoms(), 6) - log_file = TeraChemLog(os.path.join(self.data_path, 'formaldehyde_coords.xyz')) - self.assertEqual(log_file.get_number_of_atoms(), 4) - log_file = TeraChemLog(os.path.join(self.data_path, 'ethane_output.geometry')) - self.assertEqual(log_file.get_number_of_atoms(), 6) - log_file = TeraChemLog(os.path.join(self.data_path, 'formaldehyde_output.geometry')) - self.assertEqual(log_file.get_number_of_atoms(), 4) - - def test_load_force_constant_matrix(self): - """Test loading the Hessian""" - log_file = TeraChemLog(os.path.join(self.data_path, 'ethanol_freq_output.out')) - hessian = log_file.load_force_constant_matrix() - self.assertEqual(len(hessian), 27) # 9 atoms * 3 dof = 27 - self.assertEqual(len(hessian[0]), 27) - - log_file = TeraChemLog(os.path.join(self.data_path, 'ethylamine_freq_output.out')) - hessian = log_file.load_force_constant_matrix() - expected_hessian = [ - [914.9859609920952, -86.71893487707963, 25.53304366219221, -229.64170366910673, 9.65273601863364, - 122.37178242977485, -2.4910286499699716, 0.6227571624924929, 14.323414737327337, -42.347487049489516, - -13.389278993588597, 43.90437995572075, -0.7784464531156161, -3.7365429749549572, 1.8682714874774786, - -0.6227571624924929, -0.15568929062312323, -1.8682714874774786, 3.1137858124624644, -0.46706787186936966, - -0.15568929062312323, 2.802407231216218, 0.6227571624924929, -0.31137858124624646, -99.64114599879886, - 27.40131514966969, 10.742561052995502, -545.6909636340469, 67.10208425856611, -216.40811396614131], - [-86.71893487707963, 853.1773126147153, -244.12080769705722, -20.395297071629145, -150.7072333231833, - 73.7967237553604, 16.035996934181693, 13.389278993588597, -12.61083254047298, 9.808425309256764, - 4.982057299939943, -11.521007506111118, -41.5690405963739, -9.497046728010517, 43.74869066509763, - 0.7784464531156161, 3.1137858124624644, 0.6227571624924929, -0.6227571624924929, -0.6227571624924929, - 1.0898250343618625, -0.0, -0.46706787186936966, -6.227571624924929, 2.9580965218393414, -620.7332017143923, - 60.09606618052557, 119.72506448918175, -94.5033994082358, 95.28184586135141], - [25.53304366219221, -244.12080769705722, 432.81622793228263, 54.95831958996249, 23.820461465337853, - -210.49192092246258, 48.88643725566069, 14.167725446704214, -49.04212654628382, -1.5568929062312322, - -2.9580965218393414, 11.676696796734241, 16.81444338729731, 9.808425309256764, -15.724618352935446, - -0.6227571624924929, 0.9341357437387393, 4.82636800931682, 0.31137858124624646, 2.179650068723725, - 4.982057299939943, -0.7784464531156161, -6.850328787417422, -11.988075377980488, 11.365318215487996, - 143.23414737327337, -40.94628343388141, -155.06653346063072, 59.784687599279316, -126.88677185784543], - [-229.64170366910673, -20.395297071629145, 54.95831958996249, 880.2672491831387, -45.92834073382135, - 71.77276297725982, -131.55745057653914, -13.54496828421172, -26.311490115307823, -390.1573623015468, - 81.1141204146472, -143.3898366638965, -84.38359551773279, 16.50306480605106, -4.35930013744745, - -0.6227571624924929, 0.6227571624924929, 3.7365429749549572, -7.4730859499099145, -26.62286869655407, - -44.838515699459485, 4.35930013744745, 20.550986362252267, 34.563022518333355, 2.3353393593468486, - 0.6227571624924929, 4.514989428070574, -42.970244211982006, -12.14376466860361, 49.04212654628382], - [9.65273601863364, -150.7072333231833, 23.820461465337853, -45.92834073382135, 917.1656110608188, - -66.63501638669673, -16.191686224804815, -175.15045195101362, -61.80864837737992, 74.57517020847602, - -101.50941748627633, 38.455254783911435, 25.377354371569083, -464.4211539287766, 50.59901945251505, - -8.874289565518025, -26.1558008246847, -47.95230151192195, 0.46706787186936966, 6.383260915548052, - 10.275493181126134, 3.7365429749549572, 7.7844645311561615, 17.4372005497898, -48.73074796503757, - -17.125821968543555, 47.64092293067571, 5.449125171809313, 4.047921556201204, -11.521007506111118], - [122.37178242977485, 73.7967237553604, -210.49192092246258, 71.77276297725982, -66.63501638669673, - 700.1347399321851, -33.00612961210212, -67.41346283981235, -223.8811999160512, -132.95865419214724, - 37.209740458926454, -132.80296490152412, -7.317396659286792, 58.383483983671205, -85.1620419708484, - 2.179650068723725, 3.2694751030855875, 6.071882334301805, -2.802407231216218, -11.209628924864871, - -20.706675652875386, -3.8922322655780808, -11.521007506111118, -23.353393593468482, 7.628775240533038, - -6.850328787417422, -19.616850618513528, -22.73063643097599, -9.65273601863364, 9.808425309256764], - [-2.4910286499699716, 16.035996934181693, 48.88643725566069, -131.55745057653914, -16.191686224804815, - -33.00612961210212, 886.3391315174406, -7.4730859499099145, -21.796500687237252, -4.35930013744745, - -24.910286499699716, -42.03610846824327, 1.7125821968543555, 2.6467179405930947, 2.3353393593468486, - -78.62309176467723, 21.329432815367884, -2.179650068723725, -394.04959456712487, 80.49136325215471, - -137.00657574834844, -278.68383021539057, -74.57517020847602, 184.64749867902415, 0.15568929062312323, - 1.8682714874774786, -2.3353393593468486, 2.6467179405930947, 1.0898250343618625, 2.4910286499699716], - [0.6227571624924929, 13.389278993588597, 14.167725446704214, -13.54496828421172, -175.15045195101362, - -67.41346283981235, -7.4730859499099145, 850.219216092876, -70.37155936165169, 1.2455143249849858, - 5.916193043678683, 9.341357437387394, -8.7186002748949, -25.065975790322838, -46.86247647756009, - 22.1078792684835, -467.22356115999276, 54.17987313684688, 78.77878105530036, -95.9046030238439, - 38.76663336515768, -74.41948091785291, -107.42561052995504, 66.79070567731986, 0.46706787186936966, - 3.2694751030855875, 2.802407231216218, 0.6227571624924929, -1.2455143249849858, -0.9341357437387393], - [14.323414737327337, -12.61083254047298, -49.04212654628382, -26.311490115307823, -61.80864837737992, - -223.8811999160512, -21.796500687237252, -70.37155936165169, 750.2666915128308, -6.538950206171175, - -13.389278993588597, -20.083918490382896, -0.9341357437387393, 0.46706787186936966, 5.916193043678683, - -3.1137858124624644, 55.26969817120874, -86.09617771458714, -138.40777936395656, 37.98818691204207, - -132.33589702965475, 185.27025584151662, 66.32363780545049, -249.72562215948963, -0.46706787186936966, - -1.7125821968543555, 1.8682714874774786, -1.8682714874774786, 1.2455143249849858, 3.580853684331834], - [-42.347487049489516, 9.808425309256764, -1.5568929062312322, -390.1573623015468, 74.57517020847602, - -132.95865419214724, -4.35930013744745, 1.2455143249849858, -6.538950206171175, 437.17552806973, - -82.82670261150155, 139.34191510769529, 0.31137858124624646, 2.802407231216218, -1.0898250343618625, - 0.15568929062312323, -0.46706787186936966, 0.46706787186936966, 1.8682714874774786, -0.6227571624924929, - -0.7784464531156161, 0.46706787186936966, -0.15568929062312323, -0.9341357437387393, 0.15568929062312323, - -0.46706787186936966, -1.2455143249849858, -3.580853684331834, -4.514989428070574, 5.2934358811861895], - [-13.389278993588597, 4.982057299939943, -2.9580965218393414, 81.1141204146472, -101.50941748627633, - 37.209740458926454, -24.910286499699716, 5.916193043678683, -13.389278993588597, -82.82670261150155, - 97.46149593007515, -36.58698329643396, 46.239719315067596, -9.18566814676427, 18.83840416539791, - -0.46706787186936966, 1.401203615608109, 1.5568929062312322, -1.5568929062312322, -1.2455143249849858, - -5.449125171809313, 0.6227571624924929, 0.7784464531156161, 0.7784464531156161, -0.46706787186936966, - 0.6227571624924929, -1.401203615608109, -4.047921556201204, 0.9341357437387393, 1.0898250343618625], - [43.90437995572075, -11.521007506111118, 11.676696796734241, -143.3898366638965, 38.455254783911435, - -132.80296490152412, -42.03610846824327, 9.341357437387394, -20.083918490382896, 139.34191510769529, - -36.58698329643396, 150.39585474193703, -7.006018078040545, 1.7125821968543555, -2.6467179405930947, - 0.9341357437387393, 0.15568929062312323, 2.3353393593468486, -0.46706787186936966, -5.760503753055559, - -7.4730859499099145, 0.46706787186936966, 0.7784464531156161, 1.5568929062312322, -0.6227571624924929, - -0.0, 1.2455143249849858, 8.25153240302553, 3.2694751030855875, -4.047921556201204], - [-0.7784464531156161, -41.5690405963739, 16.81444338729731, -84.38359551773279, 25.377354371569083, - -7.317396659286792, 1.7125821968543555, -8.7186002748949, -0.9341357437387393, 0.31137858124624646, - 46.239719315067596, -7.006018078040545, 85.47342055209465, -14.323414737327337, -4.982057299939943, - 1.401203615608109, -1.5568929062312322, -0.9341357437387393, 0.31137858124624646, -0.46706787186936966, - 1.2455143249849858, 0.31137858124624646, 0.31137858124624646, -0.31137858124624646, -5.760503753055559, - -4.35930013744745, 5.2934358811861895, 1.2455143249849858, -1.0898250343618625, -1.8682714874774786], - [-3.7365429749549572, -9.497046728010517, 9.808425309256764, 16.50306480605106, -464.4211539287766, - 58.383483983671205, 2.6467179405930947, -25.065975790322838, 0.46706787186936966, 2.802407231216218, - -9.18566814676427, 1.7125821968543555, -14.323414737327337, 503.8105444564267, -65.54519135233488, - -0.7784464531156161, -0.15568929062312323, -5.137746590563067, -0.6227571624924929, 1.2455143249849858, - 0.46706787186936966, 0.31137858124624646, 0.7784464531156161, -0.15568929062312323, -2.4910286499699716, - 2.4910286499699716, 0.31137858124624646, -0.15568929062312323, 0.15568929062312323, -0.6227571624924929], - [1.8682714874774786, 43.74869066509763, -15.724618352935446, -4.35930013744745, 50.59901945251505, - -85.1620419708484, 2.3353393593468486, -46.86247647756009, 5.916193043678683, -1.0898250343618625, - 18.83840416539791, -2.6467179405930947, -4.982057299939943, -65.54519135233488, 103.84475684562318, - -1.5568929062312322, -5.2934358811861895, -8.25153240302553, 0.15568929062312323, 1.401203615608109, - 2.023960778100602, 0.15568929062312323, 1.5568929062312322, 2.3353393593468486, 7.7844645311561615, - 2.179650068723725, -3.580853684331834, -0.31137858124624646, -0.6227571624924929, 1.0898250343618625], - [-0.6227571624924929, 0.7784464531156161, -0.6227571624924929, -0.6227571624924929, -8.874289565518025, - 2.179650068723725, -78.62309176467723, 22.1078792684835, -3.1137858124624644, 0.15568929062312323, - -0.46706787186936966, 0.9341357437387393, 1.401203615608109, -0.7784464531156161, -1.5568929062312322, - 75.50930595221476, -22.73063643097599, 4.514989428070574, -0.9341357437387393, 47.018165768183216, - -6.071882334301805, 2.802407231216218, -37.67680833079582, 3.425164393708711, 0.6227571624924929, - 0.15568929062312323, 0.6227571624924929, 0.0, 0.31137858124624646, 0.0], - [-0.15568929062312323, 3.1137858124624644, 0.9341357437387393, 0.6227571624924929, -26.1558008246847, - 3.2694751030855875, 21.329432815367884, -467.22356115999276, 55.26969817120874, -0.46706787186936966, - 1.401203615608109, 0.15568929062312323, -1.5568929062312322, -0.15568929062312323, -5.2934358811861895, - -22.73063643097599, 508.4812231751205, -57.760726821178714, 1.2455143249849858, -9.18566814676427, - 2.023960778100602, 0.31137858124624646, -11.05393963424175, 2.179650068723725, 1.0898250343618625, - 0.6227571624924929, -1.0898250343618625, 0.31137858124624646, -0.0, 0.15568929062312323], - [-1.8682714874774786, 0.6227571624924929, 4.82636800931682, 3.7365429749549572, -47.95230151192195, - 6.071882334301805, -2.179650068723725, 54.17987313684688, -86.09617771458714, 0.46706787186936966, - 1.5568929062312322, 2.3353393593468486, -0.9341357437387393, -5.137746590563067, -8.25153240302553, - 4.514989428070574, -57.760726821178714, 89.8327206895421, 0.46706787186936966, 19.77253990913665, - -3.7365429749549572, -4.670678718693697, 33.31750819334837, -4.514989428070574, 0.31137858124624646, - 1.401203615608109, -0.31137858124624646, 0.31137858124624646, -0.15568929062312323, -0.15568929062312323], - [3.1137858124624644, -0.6227571624924929, 0.31137858124624646, -7.4730859499099145, 0.46706787186936966, - -2.802407231216218, -394.04959456712487, 78.77878105530036, -138.40777936395656, 1.8682714874774786, - -1.5568929062312322, -0.46706787186936966, 0.31137858124624646, -0.6227571624924929, 0.15568929062312323, - -0.9341357437387393, 1.2455143249849858, 0.46706787186936966, 426.4329670167345, -87.18600274894901, - 155.37791204187698, -30.670790252755275, 8.7186002748949, -14.167725446704214, 0.15568929062312323, - 0.31137858124624646, 0.15568929062312323, 0.7784464531156161, 0.31137858124624646, -0.6227571624924929], - [-0.46706787186936966, -0.6227571624924929, 2.179650068723725, -26.62286869655407, 6.383260915548052, - -11.209628924864871, 80.49136325215471, -95.9046030238439, 37.98818691204207, -0.6227571624924929, - -1.2455143249849858, -5.760503753055559, -0.46706787186936966, 1.2455143249849858, 1.401203615608109, - 47.018165768183216, -9.18566814676427, 19.77253990913665, -87.18600274894901, 96.06029231446702, - -37.67680833079582, -13.07790041234235, 2.179650068723725, -7.161707368663668, 0.31137858124624646, - 0.15568929062312323, -0.15568929062312323, 0.9341357437387393, 0.6227571624924929, 0.46706787186936966], - [-0.15568929062312323, 1.0898250343618625, 4.982057299939943, -44.838515699459485, 10.275493181126134, - -20.706675652875386, -137.00657574834844, 38.76663336515768, -132.33589702965475, -0.7784464531156161, - -5.449125171809313, -7.4730859499099145, 1.2455143249849858, 0.46706787186936966, 2.023960778100602, - -6.071882334301805, 2.023960778100602, -3.7365429749549572, 155.37791204187698, -37.67680833079582, - 143.23414737327337, 30.048033090262784, -9.497046728010517, 15.724618352935446, -0.15568929062312323, - 0.31137858124624646, -0.31137858124624646, 1.8682714874774786, -0.46706787186936966, -1.7125821968543555], - [2.802407231216218, -0.0, -0.7784464531156161, 4.35930013744745, 3.7365429749549572, -3.8922322655780808, - -278.68383021539057, -74.41948091785291, 185.27025584151662, 0.46706787186936966, 0.6227571624924929, - 0.46706787186936966, 0.31137858124624646, 0.31137858124624646, 0.15568929062312323, 2.802407231216218, - 0.31137858124624646, -4.670678718693697, -30.670790252755275, -13.07790041234235, 30.048033090262784, - 297.67792367141163, 82.98239190212468, -205.50986362252266, 0.0, -0.15568929062312323, - -0.15568929062312323, 0.7784464531156161, -0.6227571624924929, -0.9341357437387393], - [0.6227571624924929, -0.46706787186936966, -6.850328787417422, 20.550986362252267, 7.7844645311561615, - -11.521007506111118, -74.57517020847602, -107.42561052995504, 66.32363780545049, -0.15568929062312323, - 0.7784464531156161, 0.7784464531156161, 0.31137858124624646, 0.7784464531156161, 1.5568929062312322, - -37.67680833079582, -11.05393963424175, 33.31750819334837, 8.7186002748949, 2.179650068723725, - -9.497046728010517, 82.98239190212468, 107.58129982057814, -73.32965588349104, 0.0, -0.15568929062312323, - -1.0898250343618625, -0.7784464531156161, 0.0, 0.31137858124624646], - [-0.31137858124624646, -6.227571624924929, -11.988075377980488, 34.563022518333355, 17.4372005497898, - -23.353393593468482, 184.64749867902415, 66.79070567731986, -249.72562215948963, -0.9341357437387393, - 0.7784464531156161, 1.5568929062312322, -0.31137858124624646, -0.15568929062312323, 2.3353393593468486, - 3.425164393708711, 2.179650068723725, -4.514989428070574, -14.167725446704214, -7.161707368663668, - 15.724618352935446, -205.50986362252266, -73.32965588349104, 268.40833703426443, -0.6227571624924929, - -0.6227571624924929, 1.2455143249849858, -0.7784464531156161, 0.0, 0.31137858124624646], - [-99.64114599879886, 2.9580965218393414, 11.365318215487996, 2.3353393593468486, -48.73074796503757, - 7.628775240533038, 0.15568929062312323, 0.46706787186936966, -0.46706787186936966, 0.15568929062312323, - -0.46706787186936966, -0.6227571624924929, -5.760503753055559, -2.4910286499699716, 7.7844645311561615, - 0.6227571624924929, 1.0898250343618625, 0.31137858124624646, 0.15568929062312323, 0.31137858124624646, - -0.15568929062312323, 0.0, 0.0, -0.6227571624924929, 103.06631039250756, -18.83840416539791, - -13.389278993588597, -0.9341357437387393, 65.38950206171175, -11.676696796734241], - [27.40131514966969, -620.7332017143923, 143.23414737327337, 0.6227571624924929, -17.125821968543555, - -6.850328787417422, 1.8682714874774786, 3.2694751030855875, -1.7125821968543555, -0.46706787186936966, - 0.6227571624924929, -0.0, -4.35930013744745, 2.4910286499699716, 2.179650068723725, 0.15568929062312323, - 0.6227571624924929, 1.401203615608109, 0.31137858124624646, 0.15568929062312323, 0.31137858124624646, - -0.15568929062312323, -0.15568929062312323, -0.6227571624924929, -18.83840416539791, 647.5117597015695, - -131.86882915778537, -6.383260915548052, -14.946171899819829, -6.227571624924929], - [10.742561052995502, 60.09606618052557, -40.94628343388141, 4.514989428070574, 47.64092293067571, - -19.616850618513528, -2.3353393593468486, 2.802407231216218, 1.8682714874774786, -1.2455143249849858, - -1.401203615608109, 1.2455143249849858, 5.2934358811861895, 0.31137858124624646, -3.580853684331834, - 0.6227571624924929, -1.0898250343618625, -0.31137858124624646, 0.15568929062312323, -0.15568929062312323, - -0.31137858124624646, -0.15568929062312323, -1.0898250343618625, 1.2455143249849858, -13.389278993588597, - -131.86882915778537, 68.03622000230486, -4.047921556201204, 24.754597209076593, -7.628775240533038], - [-545.6909636340469, 119.72506448918175, -155.06653346063072, -42.970244211982006, 5.449125171809313, - -22.73063643097599, 2.6467179405930947, 0.6227571624924929, -1.8682714874774786, -3.580853684331834, - -4.047921556201204, 8.25153240302553, 1.2455143249849858, -0.15568929062312323, -0.31137858124624646, 0.0, - 0.31137858124624646, 0.31137858124624646, 0.7784464531156161, 0.9341357437387393, 1.8682714874774786, - 0.7784464531156161, -0.7784464531156161, -0.7784464531156161, -0.9341357437387393, -6.383260915548052, - -4.047921556201204, 587.8827613929133, -116.14421080484992, 174.68338407914425], - [67.10208425856611, -94.5033994082358, 59.784687599279316, -12.14376466860361, 4.047921556201204, - -9.65273601863364, 1.0898250343618625, -1.2455143249849858, 1.2455143249849858, -4.514989428070574, - 0.9341357437387393, 3.2694751030855875, -1.0898250343618625, 0.15568929062312323, -0.6227571624924929, - 0.31137858124624646, -0.0, -0.15568929062312323, 0.31137858124624646, 0.6227571624924929, - -0.46706787186936966, -0.6227571624924929, 0.0, 0.0, 65.38950206171175, -14.946171899819829, - 24.754597209076593, -116.14421080484992, 105.09027117060819, -78.15602389280787], - [-216.40811396614131, 95.28184586135141, -126.88677185784543, 49.04212654628382, -11.521007506111118, - 9.808425309256764, 2.4910286499699716, -0.9341357437387393, 3.580853684331834, 5.2934358811861895, - 1.0898250343618625, -4.047921556201204, -1.8682714874774786, -0.6227571624924929, 1.0898250343618625, 0.0, - 0.15568929062312323, -0.15568929062312323, -0.6227571624924929, 0.46706787186936966, -1.7125821968543555, - -0.9341357437387393, 0.31137858124624646, 0.31137858124624646, -11.676696796734241, -6.227571624924929, - -7.628775240533038, 174.68338407914425, -78.15602389280787, 125.95263611410668]] - np.testing.assert_almost_equal(hessian, np.array(expected_hessian, np.float64)) - - def test_load_geometry(self): - """Test loading the geometry from a TeraChem xyz output file""" - log_file = TeraChemLog(os.path.join(self.data_path, 'ethane_coords.xyz')) - coords, numbers, masses = log_file.load_geometry() - np.testing.assert_almost_equal( - coords, np.array([[0.66409651, 0.00395265, 0.07100793], - [-0.66409647, -0.00395253, -0.0710079], - [1.24675866, 0.88983869, -0.1613784], - [1.19483972, -0.8753068, 0.42244414], - [-1.19483975, 0.87530673, -0.42244421], - [-1.24675868, -0.88983873, 0.16137844]], np.float64)) - np.testing.assert_almost_equal(numbers, np.array([6, 6, 1, 1, 1, 1], np.float64)) - np.testing.assert_almost_equal(masses, np.array( - [12., 12., 1.00782503, 1.00782503, 1.00782503, 1.00782503], np.float64)) - - log_file = TeraChemLog(os.path.join(self.data_path, 'formaldehyde_coords.xyz')) - coords, numbers, masses = log_file.load_geometry() - np.testing.assert_almost_equal( - coords, np.array([[-4.23756410e-03, 4.24348000e-05, -5.28516700e-04], - [1.19165823e+00, -1.75471911e-02, 1.58030931e-01], - [-5.96146428e-01, 9.38505681e-01, 4.33255558e-02], - [-5.91274235e-01, -9.21000915e-01, -2.00827970e-01]], np.float64)) - np.testing.assert_almost_equal(numbers, np.array([6, 8, 1, 1], np.float64)) - np.testing.assert_almost_equal( - masses, np.array([12., 15.99491462, 1.00782503, 1.00782503], np.float64)) - - log_file = TeraChemLog(os.path.join(self.data_path, 'ethane_output.geometry')) - coords, numbers, masses = log_file.load_geometry() - np.testing.assert_almost_equal( - coords, np.array([[0.66409651, 0.00395265, 0.07100793], - [-0.66409647, -0.00395253, -0.0710079], - [1.24675866, 0.88983869, -0.1613784], - [1.19483972, -0.8753068, 0.42244414], - [-1.19483975, 0.87530673, -0.42244421], - [-1.24675868, -0.88983873, 0.16137844]], np.float64)) - np.testing.assert_almost_equal(numbers, np.array([6, 6, 1, 1, 1, 1], np.float64)) - np.testing.assert_almost_equal( - masses, np.array([12., 12., 1.00782504, 1.00782504, 1.00782504, 1.00782504], np.float64)) - - log_file = TeraChemLog(os.path.join(self.data_path, 'formaldehyde_output.geometry')) - coords, numbers, masses = log_file.load_geometry() - np.testing.assert_almost_equal( - coords, np.array([[-1.2224100e-02, 1.8041000e-04, -1.6211600e-03], - [1.2016482e+00, -1.7734170e-02, 1.5936241e-01], - [-5.9716440e-01, 9.3272817e-01, 4.2440100e-02], - [-5.9225970e-01, -9.1517440e-01, -2.0018135e-01]], np.float64)) - np.testing.assert_almost_equal(numbers, np.array([6, 8, 1, 1], np.float64)) - np.testing.assert_almost_equal( - masses, np.array([12., 15.99491464, 1.00782504, 1.00782504], np.float64)) - - log_file = TeraChemLog(os.path.join(self.data_path, 'ethylamine_freq_output.out')) - coords, numbers, masses = log_file.load_geometry() - np.testing.assert_almost_equal( - coords, np.array([[2.370236, 0.065481, -1.194536], - [0.512276, -0.516064, 0.779232], - [0.859257, 0.87292, 3.300986], - [-1.367578, -0.100279, 0.008089], - [0.56292, -2.564216, 1.100445], - [0.755566, 2.927958, 3.038153], - [2.705598, 0.43874, 4.141338], - [-0.600934, 0.336582, 4.672435], - [2.352825, 1.959707, -1.552162], - [4.141389, -0.322693, -0.540207]], np.float64)) - np.testing.assert_almost_equal(numbers, np.array([7, 6, 6, 1, 1, 1, 1, 1, 1, 1], np.float64)) - np.testing.assert_almost_equal( - masses, np.array([14.003074, 12., 12., 1.00782503, 1.00782503, 1.00782503, 1.00782503, - 1.00782503, 1.00782503, 1.00782503], np.float64)) - - log_file = TeraChemLog(os.path.join(self.data_path, 'formaldehyde_freq_output.out')) - coords, numbers, masses = log_file.load_geometry() - np.testing.assert_almost_equal( - coords, np.array([[2.261989e+00, -1.149050e-01, 1.783170e-01], - [-8.108000e-03, 2.710000e-04, -6.880000e-04], - [-1.038653e+00, 1.827038e+00, -6.398200e-02], - [-1.215229e+00, -1.712404e+00, -1.136470e-01]], np.float64)) - np.testing.assert_almost_equal(numbers, np.array([8, 6, 1, 1], np.float64)) - np.testing.assert_almost_equal( - masses, np.array([15.99491462, 12., 1.00782503, 1.00782503], np.float64)) - - def test_load_conformer(self): - """ - Test parsing frequencies and spin multiplicity from a TeraChem log file. - Translation and rotation modes are not read from the TeraCHem log, and are instead added in statmech. - """ - log_file = TeraChemLog(os.path.join(self.data_path, 'formaldehyde_freq_output.out')) - conformer, unscaled_freqs = log_file.load_conformer() - self.assertIsInstance(conformer, Conformer) - self.assertEqual(len(conformer.modes), 1) - np.testing.assert_almost_equal(conformer.modes[0].frequencies.value_si, unscaled_freqs) - expected_freqs = [1198.6352081, 1276.1991058, 1563.6275932, 1893.2440765, - 2916.3917533, 2965.8683956] - np.testing.assert_almost_equal(conformer.modes[0].frequencies.value_si, expected_freqs) - self.assertEqual(conformer.spin_multiplicity, 1) - - failed_log_file = TeraChemLog(os.path.join(self.data_path, 'failed_freq_job.out')) - with self.assertRaises(LogError): - failed_log_file.load_conformer() - - def test_load_energy(self): - """Test loading the energy in J/mol from a TeraChem output.out or results.dat file""" - output_file = TeraChemLog(os.path.join(self.data_path, 'formaldehyde_sp_terachem_output.out')) - results_file = TeraChemLog(os.path.join(self.data_path, 'formaldehyde_sp_terachem_results.dat')) - freq_file = TeraChemLog(os.path.join(self.data_path, 'formaldehyde_freq_output.out')) - opt_file = TeraChemLog(os.path.join(self.data_path, 'ethane_minimize_output.out')) - e_elect_1 = output_file.load_energy() - e_elect_2 = results_file.load_energy() - e_elect_3 = freq_file.load_energy() - e_elect_4 = opt_file.load_energy() - self.assertEqual(e_elect_1, e_elect_2) - self.assertEqual(e_elect_1, e_elect_3) - self.assertAlmostEqual(e_elect_1, -300621953.7863082) - self.assertAlmostEqual(e_elect_4, -206346606.4271929) - - def test_load_zero_point_energy(self): - """Test loading the ZPE from a TeraChem freq output file""" - log_file = TeraChemLog(os.path.join(self.data_path, 'ethylamine_freq_output.out')) - zpe = log_file.load_zero_point_energy() - self.assertAlmostEqual(zpe, 243113.46765236984) - - log_file = TeraChemLog(os.path.join(self.data_path, 'formaldehyde_freq_output.out')) - zpe = log_file.load_zero_point_energy() - self.assertAlmostEqual(zpe, 70663.2091453692) - - def test_load_scan_energies(self): - """Test loading a PES scan from a TeraCHem log file""" - log_file = TeraChemLog(os.path.join(self.data_path, 'ethanol_scan_terachem_output.out')) - v_list, angles = log_file.load_scan_energies() - print(angles) - expected_v_list = [3.31469351e+00, 5.61670297e+02, 2.28894412e+03, 5.02988537e+03, - 8.06230147e+03, 1.09146826e+04, 1.31616066e+04, 1.44091777e+04, - 1.42173813e+04, 1.28403610e+04, 1.07514495e+04, 7.96656078e+03, - 4.81040645e+03, 2.42069223e+03, 7.90256554e+02, 4.20132486e+00, - 4.54592173e+02, 2.06279144e+03, 4.67391931e+03, 7.62857835e+03, - 1.04970774e+04, 1.27455046e+04, 1.42866289e+04, 1.43930501e+04, - 1.31587081e+04, 1.10047441e+04, 8.24254519e+03, 5.10264086e+03, - 2.56880350e+03, 7.56736797e+02, 1.30067263e+00, 5.19872864e+02, - 2.30963595e+03, 5.02046166e+03, 7.97285489e+03, 1.06923710e+04, - 1.29244615e+04, 1.43422341e+04, 1.43905580e+04, 1.32047110e+04, - 1.12088126e+04, 8.31162367e+03, 5.06568695e+03, 2.54966151e+03, - 8.50076205e+02, 0.00000000e+00] - expected_angles = [0., 0.13962634, 0.27925268, 0.41887902, 0.55850536, 0.6981317, - 0.83775804, 0.97738438, 1.11701072, 1.25663706, 1.3962634, 1.53588974, - 1.67551608, 1.81514242, 1.95476876, 2.0943951, 2.23402144, 2.37364778, - 2.51327412, 2.65290046, 2.7925268, 2.93215314, 3.07177948, 3.21140582, - 3.35103216, 3.4906585, 3.63028484, 3.76991118, 3.90953752, 4.04916386, - 4.1887902, 4.32841654, 4.46804289, 4.60766923, 4.74729557, 4.88692191, - 5.02654825, 5.16617459, 5.30580093, 5.44542727, 5.58505361, 5.72467995, - 5.86430629, 6.00393263, 6.14355897, 6.28318531] # radians - np.testing.assert_almost_equal(v_list, expected_v_list, 4) - np.testing.assert_almost_equal(angles, expected_angles) - -################################################################################ - - -if __name__ == '__main__': - unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arkane/inputTest.py b/arkane/inputTest.py deleted file mode 100644 index c2e2671414..0000000000 --- a/arkane/inputTest.py +++ /dev/null @@ -1,268 +0,0 @@ -#!/usr/bin/env python3 - -############################################################################### -# # -# RMG - Reaction Mechanism Generator # -# # -# Copyright (c) 2002-2023 Prof. William H. Green (whgreen@mit.edu), # -# Prof. Richard H. West (r.west@neu.edu) and the RMG Team (rmg_dev@mit.edu) # -# # -# Permission is hereby granted, free of charge, to any person obtaining a # -# copy of this software and associated documentation files (the 'Software'), # -# to deal in the Software without restriction, including without limitation # -# the rights to use, copy, modify, merge, publish, distribute, sublicense, # -# and/or sell copies of the Software, and to permit persons to whom the # -# Software is furnished to do so, subject to the following conditions: # -# # -# The above copyright notice and this permission notice shall be included in # -# all copies or substantial portions of the Software. # -# # -# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # -# DEALINGS IN THE SOFTWARE. # -# # -############################################################################### - -""" -This module contains unit tests of the :mod:`arkane.input` module. -""" - -import os -import unittest - -import rmgpy -from rmgpy.exceptions import InputError -from rmgpy.kinetics.tunneling import Eckart -from rmgpy.pdep.collision import SingleExponentialDown -from rmgpy.statmech.rotation import NonlinearRotor -from rmgpy.statmech.translation import IdealGasTranslation -from rmgpy.statmech.vibration import HarmonicOscillator -from rmgpy.thermo.nasa import NASAPolynomial, NASA -from rmgpy.transport import TransportData - -from arkane.input import species, transitionState, reaction, SMILES, load_input_file, process_model_chemistry -from arkane.modelchem import LevelOfTheory, CompositeLevelOfTheory - -################################################################################ - - -class InputTest(unittest.TestCase): - """ - Contains unit tests for the Arkane input module - """ - - def test_species(self): - """ - Test loading a species from input file-like kew word arguments - """ - label0 = 'CH2O' - kwargs = {'E0': (28.69, 'kcal/mol'), - 'structure': SMILES('C=O'), - 'collisionModel': TransportData(sigma=(3.69e-10, 'm'), epsilon=(4.0, 'kJ/mol')), - 'energyTransferModel': SingleExponentialDown(alpha0=(0.956, 'kJ/mol'), T0=(300, 'K'), n=0.95), - 'spinMultiplicity': 1, - 'opticalIsomers': 1, - 'modes': [HarmonicOscillator(frequencies=([1180, 1261, 1529, 1764, 2931, 2999], 'cm^-1')), - NonlinearRotor(rotationalConstant=([1.15498821005263, 1.3156969584727, 9.45570474524524], - "cm^-1"), symmetry=2, quantum=False), - IdealGasTranslation(mass=(30.0106, "g/mol")), - ]} - - spc0 = species(label0, **kwargs) - self.assertEqual(spc0.label, 'CH2O') - self.assertEqual(spc0.smiles, 'C=O') - self.assertAlmostEqual(spc0.conformer.E0.value_si, 120038.96) - self.assertEqual(spc0.conformer.spin_multiplicity, 1) - self.assertEqual(spc0.conformer.optical_isomers, 1) - self.assertEqual(len(spc0.conformer.modes), 3) - self.assertIsInstance(spc0.transport_data, TransportData) - self.assertIsInstance(spc0.energy_transfer_model, SingleExponentialDown) - - def test_species_atomic_nasa_polynomial(self): - """ - Test loading a atom with NASA polynomials - """ - label0 = "H(1)" - kwargs = {"structure": SMILES('[H]'), - "thermo": NASA(polynomials=[ - NASAPolynomial(coeffs=[2.5, 0, 0, 0, 0, 25473.7, -0.446683], Tmin=(200, 'K'), Tmax=(1000, 'K')), - NASAPolynomial(coeffs=[2.5, 0, 0, 0, 0, 25473.7, -0.446683], Tmin=(1000, 'K'), Tmax=(6000, 'K'))], - Tmin=(200, 'K'), Tmax=(6000, 'K'), comment="""Thermo library: FFCM1(-)"""), - "energyTransferModel": SingleExponentialDown(alpha0=(3.5886, 'kJ/mol'), T0=(300, 'K'), n=0.85)} - spc0 = species(label0, **kwargs) - self.assertEqual(spc0.label, label0) - self.assertEqual(spc0.smiles, '[H]') - self.assertTrue(spc0.has_statmech()) - self.assertEqual(spc0.thermo, kwargs['thermo']) - - def test_species_polyatomic_nasa_polynomial(self): - """ - Test loading a species with NASA polynomials - """ - label0 = "benzyl" - kwargs = {"structure": SMILES('[c]1ccccc1'), - "thermo": NASA(polynomials=[NASAPolynomial( - coeffs=[2.78632, 0.00784632, 7.97887e-05, -1.11617e-07, 4.39429e-11, 39695, 11.5114], - Tmin=(100, 'K'), Tmax=(943.73, 'K')), - NASAPolynomial( - coeffs=[13.2455, 0.0115667, -2.49996e-06, 4.66496e-10, -4.12376e-14, - 35581.1, -49.6793], Tmin=(943.73, 'K'), Tmax=(5000, 'K'))], - Tmin=(100, 'K'), Tmax=(5000, 'K'), - comment="""Thermo library: Fulvene_H + radical(CbJ)"""), - "energyTransferModel": SingleExponentialDown(alpha0=(3.5886, 'kJ/mol'), T0=(300, 'K'), n=0.85)} - spc0 = species(label0, **kwargs) - self.assertEqual(spc0.label, label0) - self.assertTrue(spc0.has_statmech()) - self.assertEqual(spc0.thermo, kwargs['thermo']) - - def test_transition_state(self): - """ - Test loading a transition state from input file-like kew word arguments - """ - label0 = 'TS1' - kwargs = {'E0': (39.95, 'kcal/mol'), - 'spinMultiplicity': 2, - 'opticalIsomers': 1, - 'frequency': (-1934, 'cm^-1'), - 'modes': [HarmonicOscillator(frequencies=([792, 987, 1136, 1142, 1482, 2441, 3096, 3183], 'cm^-1')), - NonlinearRotor(rotationalConstant=([0.928, 0.962, 5.807], "cm^-1"), symmetry=1, - quantum=False), - IdealGasTranslation(mass=(31.01843, "g/mol"))]} - - ts0 = transitionState(label0, **kwargs) - self.assertEqual(ts0.label, 'TS1') - self.assertAlmostEqual(ts0.conformer.E0.value_si, 167150.8) - self.assertEqual(ts0.conformer.spin_multiplicity, 2) - self.assertEqual(ts0.conformer.optical_isomers, 1) - self.assertEqual(ts0.frequency.value_si, -1934.0) - self.assertEqual(len(ts0.conformer.modes), 3) - - def test_reaction(self): - """ - Test loading a reaction from input file-like kew word arguments - """ - - species( - label='methoxy', - structure=SMILES('C[O]'), - E0=(9.44, 'kcal/mol'), - modes=[ - HarmonicOscillator(frequencies=([758, 960, 1106, 1393, 1403, 1518, 2940, 3019, 3065], 'cm^-1')), - NonlinearRotor(rotationalConstant=([0.916, 0.921, 5.251], "cm^-1"), symmetry=3, quantum=False), - IdealGasTranslation(mass=(31.01843, "g/mol"))], - spinMultiplicity=2, - opticalIsomers=1, - molecularWeight=(31.01843, 'amu'), - collisionModel=TransportData(sigma=(3.69e-10, 'm'), epsilon=(4.0, 'kJ/mol')), - energyTransferModel=SingleExponentialDown(alpha0=(0.956, 'kJ/mol'), T0=(300, 'K'), n=0.95)) - - species( - label='formaldehyde', - E0=(28.69, 'kcal/mol'), - molecularWeight=(30.0106, "g/mol"), - collisionModel=TransportData(sigma=(3.69e-10, 'm'), epsilon=(4.0, 'kJ/mol')), - energyTransferModel=SingleExponentialDown(alpha0=(0.956, 'kJ/mol'), T0=(300, 'K'), n=0.95), - spinMultiplicity=1, - opticalIsomers=1, - modes=[HarmonicOscillator(frequencies=([1180, 1261, 1529, 1764, 2931, 2999], 'cm^-1')), - NonlinearRotor(rotationalConstant=([1.15498821005263, 1.3156969584727, 9.45570474524524], "cm^-1"), - symmetry=2, quantum=False), - IdealGasTranslation(mass=(30.0106, "g/mol"))]) - - species( - label='H', - E0=(0.000, 'kcal/mol'), - molecularWeight=(1.00783, "g/mol"), - collisionModel=TransportData(sigma=(3.69e-10, 'm'), epsilon=(4.0, 'kJ/mol')), - energyTransferModel=SingleExponentialDown(alpha0=(0.956, 'kJ/mol'), T0=(300, 'K'), n=0.95), - modes=[IdealGasTranslation(mass=(1.00783, "g/mol"))], - spinMultiplicity=2, - opticalIsomers=1) - - transitionState( - label='TS3', - E0=(34.1, 'kcal/mol'), - spinMultiplicity=2, - opticalIsomers=1, - frequency=(-967, 'cm^-1'), - modes=[HarmonicOscillator(frequencies=([466, 581, 1169, 1242, 1499, 1659, 2933, 3000], 'cm^-1')), - NonlinearRotor(rotationalConstant=([0.970, 1.029, 3.717], "cm^-1"), symmetry=1, quantum=False), - IdealGasTranslation(mass=(31.01843, "g/mol"))]) - - reactants = ['formaldehyde', 'H'] - products = ['methoxy'] - tunneling = 'Eckart' - - rxn = reaction('CH2O+H=Methoxy', reactants, products, 'TS3', tunneling=tunneling) - self.assertEqual(rxn.label, 'CH2O+H=Methoxy') - self.assertEqual(len(rxn.reactants), 2) - self.assertEqual(len(rxn.products), 1) - self.assertAlmostEqual(rxn.reactants[0].conformer.E0.value_si, 0) - self.assertAlmostEqual(rxn.reactants[1].conformer.E0.value_si, 120038.96) - self.assertAlmostEqual(rxn.products[0].conformer.E0.value_si, 39496.96) - self.assertAlmostEqual(rxn.transition_state.conformer.E0.value_si, 142674.4) - self.assertAlmostEqual(rxn.transition_state.frequency.value_si, -967.0) - self.assertIsInstance(rxn.transition_state.tunneling, Eckart) - - def test_load_input_file(self): - """Test loading an Arkane input file""" - path = os.path.join(os.path.dirname(os.path.dirname(rmgpy.__file__)), 'examples', 'arkane', 'networks', - 'acetyl+O2', 'input.py') - job_list, reaction_dict, species_dict, transition_state_dict, network_dict, model_chemistry \ - = load_input_file(path) - - self.assertEqual(len(job_list), 1) - - self.assertEqual(len(reaction_dict), 5) - self.assertTrue('entrance1' in reaction_dict) - self.assertTrue('exit2' in reaction_dict) - - self.assertEqual(len(species_dict), 9) - self.assertTrue('acetyl' in species_dict) - self.assertTrue('hydroperoxyl' in species_dict) - - self.assertEqual(len(transition_state_dict), 5) - self.assertTrue('entrance1' in transition_state_dict) - self.assertTrue('isom1' in transition_state_dict) - - self.assertEqual(len(network_dict), 1) - self.assertTrue('acetyl + O2' in network_dict) - - self.assertIsNone(model_chemistry) - - def test_process_model_chemistry(self): - """ - Test processing the model chemistry to derive the sp and freq levels - """ - mc = 'ccsd(t)-f12a/aug-cc-pvtz//b3lyp/6-311++g(3df,3pd)' - lot = process_model_chemistry(mc) - self.assertIsInstance(lot, CompositeLevelOfTheory) - self.assertEqual(lot.energy, LevelOfTheory('ccsd(t)-f12a', 'aug-cc-pvtz')) - self.assertEqual(lot.freq, LevelOfTheory('b3lyp', '6-311++g(3df,3pd)')) - - mc = 'b3lyp-d3/def2-tzvp' - lot = process_model_chemistry(mc) - self.assertIsInstance(lot, LevelOfTheory) - self.assertEqual(lot, LevelOfTheory('b3lyp-d3', 'def2-tzvp')) - - mc = 'cbs-qb3' - lot = process_model_chemistry(mc) - self.assertIsInstance(lot, LevelOfTheory) - self.assertEqual(lot, LevelOfTheory('cbs-qb3')) - - mc = LevelOfTheory('test') - lot = process_model_chemistry(mc) - self.assertIs(mc, lot) - - with self.assertRaises(InputError): - process_model_chemistry('CCSD(T)-F12a/aug-cc-pVTZ//CCSD(T)-F12a/aug-cc-pVTZ//B3LYP/6-311++G(3df,3pd)') - -################################################################################ - - -if __name__ == '__main__': - unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arkane/kinetics.py b/arkane/kinetics.py index 2153a0c6f2..6b2ffcdfff 100644 --- a/arkane/kinetics.py +++ b/arkane/kinetics.py @@ -602,7 +602,7 @@ def draw(self, reaction, file_format, path=None): break # Determine naive position of each well (one per column) - coordinates = np.zeros((len(self.wells), 2), np.float64) + coordinates = np.zeros((len(self.wells), 2), float) x = padding for i in range(len(self.wells)): well = self.wells[i] diff --git a/arkane/modelchemTest.py b/arkane/modelchemTest.py deleted file mode 100644 index d1163f41db..0000000000 --- a/arkane/modelchemTest.py +++ /dev/null @@ -1,308 +0,0 @@ -#!/usr/bin/env python3 - -############################################################################### -# # -# RMG - Reaction Mechanism Generator # -# # -# Copyright (c) 2002-2023 Prof. William H. Green (whgreen@mit.edu), # -# Prof. Richard H. West (r.west@neu.edu) and the RMG Team (rmg_dev@mit.edu) # -# # -# Permission is hereby granted, free of charge, to any person obtaining a # -# copy of this software and associated documentation files (the 'Software'), # -# to deal in the Software without restriction, including without limitation # -# the rights to use, copy, modify, merge, publish, distribute, sublicense, # -# and/or sell copies of the Software, and to permit persons to whom the # -# Software is furnished to do so, subject to the following conditions: # -# # -# The above copyright notice and this permission notice shall be included in # -# all copies or substantial portions of the Software. # -# # -# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # -# DEALINGS IN THE SOFTWARE. # -# # -############################################################################### - -""" -This script contains unit tests for the :mod:`arkane.modelchem` module. -""" - -import unittest -from dataclasses import FrozenInstanceError - -from arkane.modelchem import (LOT, LevelOfTheory, CompositeLevelOfTheory, - model_chem_to_lot, str_to_lot, get_software_id) - -# Instances for use in tests -FREQ = LevelOfTheory( - method='wB97X-D', - basis='def2-TZVP', - software='Gaussian 16', - args='very-tight' -) -ENERGY = LevelOfTheory( - method='DLPNO-CCSD(T)-F12', - basis='def2-TZVP', - software='Orca' -) -COMPOSITE = CompositeLevelOfTheory( - freq=FREQ, - energy=ENERGY -) - -# Representations corresponding to instances -FREQ_REPR = "LevelOfTheory(method='wb97xd',basis='def2tzvp',software='gaussian',args=('verytight',))" -ENERGY_REPR = "LevelOfTheory(method='dlpnoccsd(t)f12',basis='def2tzvp',software='orca')" -COMPOSITE_REPR = f"CompositeLevelOfTheory(freq={FREQ_REPR},energy={ENERGY_REPR})" - -# Dictionaries corresponding to instances -FREQ_DICT = { - 'class': 'LevelOfTheory', - 'method': 'wb97xd', - 'basis': 'def2tzvp', - 'software': 'gaussian', - 'args': ['verytight'] # This is a list instead of tuple because that's what YAML files expect -} -ENERGY_DICT = { - 'class': 'LevelOfTheory', - 'method': 'dlpnoccsd(t)f12', - 'basis': 'def2tzvp', - 'software': 'orca', -} -COMPOSITE_DICT = { - 'class': 'CompositeLevelOfTheory', - 'freq': FREQ_DICT, - 'energy': ENERGY_DICT -} - -# Model chemistries corresponding to instances -FREQ_MODELCHEM = 'wb97xd/def2tzvp' -ENERGY_MODELCHEM = 'dlpnoccsd(t)f12/def2tzvp' -COMPOSITE_MODELCHEM = f'{ENERGY_MODELCHEM}//{FREQ_MODELCHEM}' - - -class TestLevelOfTheory(unittest.TestCase): - """ - A class for testing that the LevelOfTheory class functions properly. - """ - - def test_attrs(self): - """ - Test that instance behaves correctly. - """ - self.assertEqual(FREQ.method, 'wb97xd') - self.assertEqual(FREQ.basis, 'def2tzvp') - self.assertEqual(FREQ.software, 'gaussian') - self.assertTupleEqual(FREQ.args, ('verytight',)) - with self.assertRaises(FrozenInstanceError): - FREQ.method = '' - - self.assertEqual(repr(FREQ), FREQ_REPR) - self.assertEqual(repr(ENERGY), ENERGY_REPR) - - with self.assertRaises(ValueError): - _ = LevelOfTheory(method=FREQ.method) - lot = LevelOfTheory(method=FREQ.method, software=FREQ.software) - self.assertIsNone(lot.basis) - self.assertIsNone(lot.auxiliary_basis) - self.assertIsNone(lot.cabs) - self.assertIsNone(lot.software_version) - self.assertIsNone(lot.solvent) - self.assertIsNone(lot.solvation_method) - self.assertIsNone(lot.args) - - self.assertIsInstance(FREQ, LOT) - - def test_comparison(self): - """ - Test comparisons between instances. - """ - self.assertIsInstance(hash(FREQ), int) - self.assertNotEqual(FREQ, ENERGY) - with self.assertRaises(TypeError): - _ = ENERGY > FREQ - - # Test args in different order - lot1 = LevelOfTheory('method', args=('arg1', 'arg2')) - lot2 = LevelOfTheory('method', args=('arg2', 'arg1')) - self.assertEqual(lot1, lot2) - - def test_simple(self): - """ - Test that simple level of theory can be obtained. - """ - lot = FREQ.simple() - self.assertIsNot(lot, FREQ) - self.assertEqual(lot.method, FREQ.method) - self.assertEqual(lot.basis, FREQ.basis) - self.assertEqual(lot.software, FREQ.software) - for attr, val in lot.__dict__.items(): - if attr not in {'method', 'basis', 'software'}: - self.assertIsNone(val) - - def test_to_model_chem(self): - """ - Test conversion to model chemistry. - """ - self.assertEqual(FREQ.to_model_chem(), FREQ_MODELCHEM) - self.assertEqual(ENERGY.to_model_chem(), ENERGY_MODELCHEM) - - lot = LevelOfTheory( - method='CBS-QB3', - software='g16' - ) - self.assertEqual(lot.to_model_chem(), 'cbsqb3') - - def test_update(self): - """ - Test updating attributes. - """ - lot = FREQ.update(software='Q-Chem') - self.assertIsNot(lot, FREQ) - self.assertEqual(lot.software, 'qchem') - with self.assertRaises(TypeError): - FREQ.update(test='test') - - def test_as_dict(self): - """ - Test conversion to dictionary. - """ - self.assertDictEqual(FREQ.as_dict(), FREQ_DICT) - self.assertDictEqual(ENERGY.as_dict(), ENERGY_DICT) - - -class TestCompositeLevelOfTheory(unittest.TestCase): - """ - A class for testing that the CompositeLevelOfTheory class functions properly. - """ - - def test_attrs(self): - """ - Test that instance behaves correctly. - """ - self.assertIs(COMPOSITE.freq, FREQ) - self.assertIs(COMPOSITE.energy, ENERGY) - self.assertEqual(repr(COMPOSITE), COMPOSITE_REPR) - with self.assertRaises(FrozenInstanceError): - COMPOSITE.energy = '' - - self.assertIsInstance(COMPOSITE, LOT) - - def test_comparison(self): - """ - Test comparisons between instances. - """ - other = CompositeLevelOfTheory(freq=ENERGY, energy=FREQ) - self.assertIsInstance(hash(COMPOSITE), int) - self.assertNotEqual(COMPOSITE, other) - with self.assertRaises(TypeError): - _ = COMPOSITE > other - - def test_simple(self): - """ - Test that simple level of theory can be obtained. - """ - lot = COMPOSITE.simple() - self.assertIsNot(lot, COMPOSITE) - self.assertEqual(lot.freq.method, COMPOSITE.freq.method) - self.assertEqual(lot.freq.basis, COMPOSITE.freq.basis) - self.assertEqual(lot.freq.software, COMPOSITE.freq.software) - self.assertEqual(lot.energy.method, COMPOSITE.energy.method) - self.assertEqual(lot.energy.basis, COMPOSITE.energy.basis) - for attr, val in lot.freq.__dict__.items(): - if attr not in {'method', 'basis', 'software'}: - self.assertIsNone(val) - for attr, val in lot.energy.__dict__.items(): - if attr not in {'method', 'basis'}: - self.assertIsNone(val) - - def test_to_model_chem(self): - """ - Test conversion to model chemistry. - """ - self.assertEqual(COMPOSITE.to_model_chem(), COMPOSITE_MODELCHEM) - - def test_as_dict(self): - """ - Test conversion to dictionary. - """ - self.assertDictEqual(COMPOSITE.as_dict(), COMPOSITE_DICT) - - -class TestFuncs(unittest.TestCase): - """ - A class for testing that the functions in the modelchem module work. - """ - - def test_model_chem_to_lot(self): - """ - Test model chemistry to quantum calculation settings conversion. - """ - self.assertEqual( - model_chem_to_lot(FREQ_MODELCHEM, software='gaussian', args='verytight'), - FREQ - ) - self.assertEqual( - model_chem_to_lot(FREQ_MODELCHEM, - freq_settings={'software': 'gaussian', 'args': 'verytight'}), - FREQ - ) - self.assertEqual( - model_chem_to_lot(FREQ_MODELCHEM, - freq_settings={'software': 'gaussian', 'args': 'verytight'}, - energy_settings={'unused setting': None}), - FREQ - ) - self.assertEqual( - model_chem_to_lot(ENERGY_MODELCHEM, energy_settings={'software': 'orca'}), - ENERGY - ) - self.assertEqual( - model_chem_to_lot(COMPOSITE_MODELCHEM, - freq_settings={'software': 'gaussian', 'args': 'verytight'}, - energy_settings={'software': 'orca'}), - COMPOSITE - ) - - def test_str_to_lot(self): - """ - Test key to quantum calculation settings conversion. - """ - self.assertEqual(str_to_lot(FREQ_REPR), FREQ) - self.assertEqual(str_to_lot(ENERGY_REPR), ENERGY) - self.assertEqual(str_to_lot(COMPOSITE_REPR), COMPOSITE) - - def test_get_software_id(self): - """ - Test standardized software identifiers. - """ - test_names = ['gaussian', 'Gaussian 09', 'g-16', 'Gau 03'] - for name in test_names: - self.assertEqual(get_software_id(name), 'gaussian') - - test_names = ['qchem', 'QChem', 'Q-Chem'] - for name in test_names: - self.assertEqual(get_software_id(name), 'qchem') - - test_names = ['molpro', 'Molpro', 'MOLPRO'] - for name in test_names: - self.assertEqual(get_software_id(name), 'molpro') - - test_names = ['orca', 'Orca', 'ORCA'] - for name in test_names: - self.assertEqual(get_software_id(name), 'orca') - - test_names = ['terachem', 'Terachem', 'TeraChem', 'Tera-Chem', 'Tera Chem'] - for name in test_names: - self.assertEqual(get_software_id(name), 'terachem') - - with self.assertRaises(ValueError): - get_software_id('g') - - -if __name__ == '__main__': - unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arkane/pdep.py b/arkane/pdep.py index e00be3cc99..60fb0fd05d 100644 --- a/arkane/pdep.py +++ b/arkane/pdep.py @@ -317,7 +317,7 @@ def generate_T_list(self): if self.Tlist is None: if self.interpolation_model[0].lower() == 'chebyshev': # Distribute temperatures on a Gauss-Chebyshev grid - Tlist = np.zeros(Tcount, np.float64) + Tlist = np.zeros(Tcount, float) 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) @@ -389,7 +389,7 @@ def generate_P_list(self): pass elif self.interpolation_model[0].lower() == 'chebyshev': # Distribute pressures on a Gauss-Chebyshev grid - Plist = np.zeros(Pcount, np.float64) + Plist = np.zeros(Pcount, float) 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))) diff --git a/arkane/statmech.py b/arkane/statmech.py index a63600f24b..4380bad121 100644 --- a/arkane/statmech.py +++ b/arkane/statmech.py @@ -252,9 +252,9 @@ def hinderedRotor2D(scandir, pivots1, top1, symmetry1, pivots2, top2, symmetry2, return [scandir, pivots1, top1, symmetry1, pivots2, top2, symmetry2, symmetry] -def hinderedRotorClassicalND(calcPath, pivots, tops, sigmas, semiclassical): +def hinderedRotorClassicalND(calc_path, pivots, tops, sigmas, semiclassical): """Read an N dimensional hindered rotor directive, and return the attributes in a list""" - return [calcPath, pivots, tops, sigmas, semiclassical] + return [calc_path, pivots, tops, sigmas, semiclassical] class StatMechJob(object): @@ -923,7 +923,7 @@ def create_hindered_rotor_figure(self, angle, v_list, cosine_rotor, fourier_roto Plot the potential for the rotor, along with its cosine and Fourier series potential fits, and save it in the `hindered_rotor_plots` attribute. """ - phi = np.arange(0, 6.3, 0.02, np.float64) + phi = np.arange(0, 6.3, 0.02, float) Vlist_cosine = np.zeros_like(phi) Vlist_fourier = np.zeros_like(phi) for i in range(phi.shape[0]): @@ -1050,7 +1050,7 @@ def project_rotors(conformer, hessian, rotors, linear, is_ts, get_projected_out_ if linear: external = 5 - d = np.zeros((n_atoms * 3, external), np.float64) + d = np.zeros((n_atoms * 3, external), float) # Transform the coordinates to the principal axes p = np.dot(coordinates, inertia_xyz) @@ -1076,9 +1076,9 @@ def project_rotors(conformer, hessian, rotors, linear, is_ts, get_projected_out_ # Make sure projection matrix is orthonormal - inertia = np.identity(n_atoms * 3, np.float64) + inertia = np.identity(n_atoms * 3, float) - p = np.zeros((n_atoms * 3, 3 * n_atoms + external), np.float64) + p = np.zeros((n_atoms * 3, 3 * n_atoms + external), float) p[:, 0:external] = d[:, 0:external] p[:, external:external + 3 * n_atoms] = inertia[:, 0:3 * n_atoms] @@ -1111,7 +1111,7 @@ def project_rotors(conformer, hessian, rotors, linear, is_ts, get_projected_out_ i += 1 # T is the transformation vector from cartesian to internal coordinates - T = np.zeros((n_atoms * 3, 3 * n_atoms - external), np.float64) + T = np.zeros((n_atoms * 3, 3 * n_atoms - external), float) T[:, 0:3 * n_atoms - external] = p[:, external:3 * n_atoms] @@ -1137,7 +1137,7 @@ def project_rotors(conformer, hessian, rotors, linear, is_ts, get_projected_out_ logging.debug(np.sqrt(eig[i]) / (2 * math.pi * constants.c * 100)) # Now we can start thinking about projecting out the internal rotations - d_int = np.zeros((3 * n_atoms, n_rotors), np.float64) + d_int = np.zeros((3 * n_atoms, n_rotors), float) counter = 0 for i, rotor in enumerate(rotors): @@ -1188,7 +1188,7 @@ def project_rotors(conformer, hessian, rotors, linear, is_ts, get_projected_out_ # Normal modes in mass weighted cartesian coordinates vmw = np.dot(T, v) - eigm = np.zeros((3 * n_atoms - external, 3 * n_atoms - external), np.float64) + eigm = np.zeros((3 * n_atoms - external, 3 * n_atoms - external), float) for i in range(3 * n_atoms - external): eigm[i, i] = eig[i] @@ -1231,7 +1231,7 @@ def project_rotors(conformer, hessian, rotors, linear, is_ts, get_projected_out_ # Do the projection d_int_proj = np.dot(vmw.T, d_int) proj = np.dot(d_int, d_int.T) - inertia = np.identity(n_atoms * 3, np.float64) + inertia = np.identity(n_atoms * 3, float) proj = inertia - proj fm = np.dot(proj, np.dot(fm, proj)) # Get eigenvalues of mass-weighted force constant matrix diff --git a/arkane/statmechTest.py b/arkane/statmechTest.py deleted file mode 100644 index 9846197505..0000000000 --- a/arkane/statmechTest.py +++ /dev/null @@ -1,385 +0,0 @@ -#!/usr/bin/env python3 - -############################################################################### -# # -# RMG - Reaction Mechanism Generator # -# # -# Copyright (c) 2002-2023 Prof. William H. Green (whgreen@mit.edu), # -# Prof. Richard H. West (r.west@neu.edu) and the RMG Team (rmg_dev@mit.edu) # -# # -# Permission is hereby granted, free of charge, to any person obtaining a # -# copy of this software and associated documentation files (the 'Software'), # -# to deal in the Software without restriction, including without limitation # -# the rights to use, copy, modify, merge, publish, distribute, sublicense, # -# and/or sell copies of the Software, and to permit persons to whom the # -# Software is furnished to do so, subject to the following conditions: # -# # -# The above copyright notice and this permission notice shall be included in # -# all copies or substantial portions of the Software. # -# # -# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # -# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER # -# DEALINGS IN THE SOFTWARE. # -# # -############################################################################### - -""" -This module contains unit tests of the :mod:`arkane.statmech` module. -""" - -import os -import unittest - -import numpy as np - -from rmgpy.species import Species -from rmgpy.exceptions import InputError - -from arkane import Arkane -from arkane.ess.qchem import QChemLog -from arkane.modelchem import LevelOfTheory -from arkane.statmech import ScanLog, StatMechJob, determine_rotor_symmetry, is_linear - -################################################################################ - - -class TestStatmech(unittest.TestCase): - """ - Contains unit tests of the StatmechJob class. - """ - - @classmethod - def setUp(cls): - """A method that is run before each unit test in this class""" - arkane = Arkane() - cls.job_list = arkane.load_input_file(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""" - job = self.job_list[-2] - self.assertTrue(isinstance(job, StatMechJob)) - with self.assertRaises(InputError): - job.load() - - def test_rotor_symmetry_determination(self): - """ - Test that the correct symmetry number is determined for rotor potential scans. - """ - path1 = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'NCC_NRotor.out') - path2 = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'data', 'NCC_CRotor.out') - scan_log1 = QChemLog(path1) - scan_log2 = QChemLog(path2) - v_list1, angle = scan_log1.load_scan_energies() - v_list2, angle = scan_log2.load_scan_energies() - symmetry1 = determine_rotor_symmetry(energies=v_list1, label='NCC', pivots=[]) - symmetry2 = determine_rotor_symmetry(energies=v_list2, label='NCC', pivots=[]) - self.assertEqual(symmetry1, 1) - self.assertEqual(symmetry2, 3) - - def test_is_linear(self): - """Test that we can determine the linearity of a molecule from it's coordinates""" - xyz1 = np.array([ - [0.000000, 0.000000, 0.000000], - [0.000000, 0.000000, 1.159076], - [0.000000, 0.000000, -1.159076]]) # a trivial case - xyz2 = np.array([ - [-0.06618943, -0.12360663, -0.07631983], - [-0.79539707, 0.86755487, 1.02675668], - [-0.68919931, 0.25421823, -1.34830853], - [0.01546439, -1.54297548, 0.44580391], - [1.94428095, 0.40772394, 1.03719428], - [2.20318015, -0.14715186, -0.64755729], - [1.59252246, 1.51178950, -0.33908352], - [-0.87856890, -2.02453514, 0.38494433], - [-1.34135876, 1.49608206, 0.53295071]]) # a non-linear multi-atom molecule - xyz3 = np.array([ - [0.0000000000, 0.0000000000, 0.3146069129], - [-1.0906813653, 0.0000000000, -0.1376405244], - [1.0906813653, 0.0000000000, -0.1376405244]]) # NO2, a non-linear 3-atom molecule - xyz4 = np.array([ - [0.0000000000, 0.0000000000, 0.1413439534], - [-0.8031792912, 0.0000000000, -0.4947038368], - [0.8031792912, 0.0000000000, -0.4947038368]]) # NH2, a non-linear 3-atom molecule - xyz5 = np.array([ - [-0.5417345330, 0.8208150346, 0.0000000000], - [0.9206183692, 1.6432038228, 0.0000000000], - [-1.2739176462, 1.9692549926, 0.0000000000]]) # HSO, a non-linear 3-atom molecule - xyz6 = np.array([ - [1.18784533, 0.98526702, 0.00000000], - [0.04124533, 0.98526702, 0.00000000], - [-1.02875467, 0.98526702, 0.00000000]]) # HCN, a linear 3-atom molecule - xyz7 = np.array([ - [-4.02394116, 0.56169428, 0.00000000], - [-5.09394116, 0.56169428, 0.00000000], - [-2.82274116, 0.56169428, 0.00000000], - [-1.75274116, 0.56169428, 0.00000000]]) # C2H2, a linear 4-atom molecule - xyz8 = np.array([ - [-1.02600933, 2.12845307, 0.00000000], - [-0.77966935, 0.95278385, 0.00000000], - [-1.23666197, 3.17751246, 0.00000000], - [-0.56023545, -0.09447399, 0.00000000]]) # C2H2, just 0.5 degree off from linearity, so NOT linear - xyz9 = np.array([ - [-1.1998, 0.1610, 0.0275], - [-1.4021, 0.6223, -0.8489], - [-1.48302, 0.80682, -1.19946]]) # just 3 points in space on a straight line (not a physical molecule) - xyz10 = np.array([ - [-1.1998, 0.1610, 0.0275]]) # mono-atomic species, non-linear - xyz11 = np.array([ - [1.06026500, -0.07706800, 0.03372800], - [3.37340700, -0.07706800, 0.03372800], - [2.21683600, -0.07706800, 0.03372800]]) # CO2 at wb97xd/6-311+g(d,p), linear - xyz12 = np.array([ - [1.05503600, -0.00335000, 0.09823600], - [2.42816800, -0.00335000, 0.09823600], - [-0.14726400, -0.00335000, 0.09823600], - [3.63046800, -0.00335000, 0.09823600], - [-1.21103500, -0.00335000, 0.09823600], - [4.69423900, -0.00335000, 0.09823600]]) # C#CC#C at wb97xd/6-311+g(d,p), linear - - self.assertTrue(is_linear(xyz1)) - self.assertTrue(is_linear(xyz6)) - self.assertTrue(is_linear(xyz7)) - self.assertTrue(is_linear(xyz9)) - self.assertTrue(is_linear(xyz11)) - self.assertTrue(is_linear(xyz12)) - self.assertFalse(is_linear(xyz2)) - self.assertFalse(is_linear(xyz3)) - self.assertFalse(is_linear(xyz4)) - self.assertFalse(is_linear(xyz5)) - self.assertFalse(is_linear(xyz8)) - self.assertFalse(is_linear(xyz10)) - - def test_specifying_absolute_file_paths(self): - """Test specifying absolute file paths of statmech files""" - h2o2_input = """#!/usr/bin/env python -# -*- coding: utf-8 -*- - -bonds = {{'H-O': 2, 'O-O': 1}} - -externalSymmetry = 2 - -spinMultiplicity = 1 - -opticalIsomers = 1 - -energy = {{'b3lyp/6-311+g(3df,2p)': Log('{energy}')}} - -geometry = Log('{freq}') - -frequencies = Log('{freq}') - -rotors = [HinderedRotor(scanLog=Log('{scan}'), pivots=[1, 2], top=[1, 3], symmetry=1, fit='fourier')] - -""" - abs_arkane_path = os.path.abspath(os.path.dirname(__file__)) # this is the absolute path to `.../RMG-Py/arkane` - energy_path = os.path.join('arkane', 'data', 'H2O2', 'sp_a19032.out') - freq_path = os.path.join('arkane', 'data', 'H2O2', 'freq_a19031.out') - scan_path = os.path.join('arkane', 'data', 'H2O2', 'scan_a19034.out') - h2o2_input = h2o2_input.format(energy=energy_path, freq=freq_path, scan=scan_path) - h2o2_path = os.path.join(abs_arkane_path, 'data', 'H2O2', 'H2O2.py') - if not os.path.exists(os.path.dirname(h2o2_path)): - os.makedirs(os.path.dirname(h2o2_path)) - with open(h2o2_path, 'w') as f: - f.write(h2o2_input) - h2o2 = Species(label='H2O2', smiles='OO') - self.assertIsNone(h2o2.conformer) - statmech_job = StatMechJob(species=h2o2, path=h2o2_path) - statmech_job.level_of_theory = LevelOfTheory('b3lyp', '6-311+g(3df,2p)') - statmech_job.load(pdep=False, plot=False) - self.assertAlmostEqual(h2o2.conformer.E0.value_si, -146031.49933673252) - os.remove(h2o2_path) - - def test_hinder_rotor_from_1d_array(self): - """Test assigning hindered rotor 1D PES profile directly to HinderedRotor1DArray""" - h2o2_input = """#!/usr/bin/env python -# -*- coding: utf-8 -*- - -bonds = {{'H-O': 2, 'O-O': 1}} - -externalSymmetry = 2 - -spinMultiplicity = 1 - -opticalIsomers = 1 - -energy = {{'b3lyp/6-311+g(3df,2p)': Log('{energy}')}} - -geometry = Log('{freq}') - -frequencies = Log('{freq}') - -rotors = [HinderedRotor1DArray( - angles=[0. , 0.17453293, 0.34906585, 0.52359878, 0.6981317 , - 0.87266463, 1.04719755, 1.22173048, 1.3962634 , 1.57079633, - 1.74532925, 1.91986218, 2.0943951 , 2.26892803, 2.44346095, - 2.61799388, 2.7925268 , 2.96705973, 3.14159265, 3.31612558, - 3.4906585 , 3.66519143, 3.83972435, 4.01425728, 4.1887902 , - 4.36332313, 4.53785606, 4.71238898, 4.88692191, 5.06145483, - 5.23598776, 5.41052068, 5.58505361, 5.75958653, 5.93411946, - 6.10865238, 6.28318531], - energies=[0.00000000e+00, 3.09449290e+02, 1.07459871e+03, 2.05925305e+03, - 3.02877926e+03, 3.79724994e+03, 4.23486826e+03, 4.26190303e+03, - 3.88196432e+03, 3.15173930e+03, 2.20016363e+03, 1.20431941e+03, - 3.94499732e+02, 7.23850312e+00, 2.77854025e+02, 1.40711827e+03, - 3.50375319e+03, 6.57899330e+03, 1.05208190e+04, 1.50847596e+04, - 1.99269611e+04, 2.46164740e+04, 2.86972097e+04, 3.17430074e+04, - 3.34148312e+04, 3.35267510e+04, 3.20643922e+04, 2.91936786e+04, - 2.52325029e+04, 2.06007483e+04, 1.57531541e+04, 1.11268684e+04, - 7.08120679e+03, 3.87554760e+03, 1.63995547e+03, 3.80256396e+02, - 6.14367036e-01], - pivots=[1, 2], top=[1, 3], symmetry=1, fit='fourier')] -""" - angles = np.array([0. , 0.17453293, 0.34906585, 0.52359878, 0.6981317 , - 0.87266463, 1.04719755, 1.22173048, 1.3962634 , 1.57079633, - 1.74532925, 1.91986218, 2.0943951 , 2.26892803, 2.44346095, - 2.61799388, 2.7925268 , 2.96705973, 3.14159265, 3.31612558, - 3.4906585 , 3.66519143, 3.83972435, 4.01425728, 4.1887902 , - 4.36332313, 4.53785606, 4.71238898, 4.88692191, 5.06145483, - 5.23598776, 5.41052068, 5.58505361, 5.75958653, 5.93411946, - 6.10865238, 6.28318531]) - energies = np.array([0.00000000e+00, 3.09449290e+02, 1.07459871e+03, 2.05925305e+03, - 3.02877926e+03, 3.79724994e+03, 4.23486826e+03, 4.26190303e+03, - 3.88196432e+03, 3.15173930e+03, 2.20016363e+03, 1.20431941e+03, - 3.94499732e+02, 7.23850312e+00, 2.77854025e+02, 1.40711827e+03, - 3.50375319e+03, 6.57899330e+03, 1.05208190e+04, 1.50847596e+04, - 1.99269611e+04, 2.46164740e+04, 2.86972097e+04, 3.17430074e+04, - 3.34148312e+04, 3.35267510e+04, 3.20643922e+04, 2.91936786e+04, - 2.52325029e+04, 2.06007483e+04, 1.57531541e+04, 1.11268684e+04, - 7.08120679e+03, 3.87554760e+03, 1.63995547e+03, 3.80256396e+02, - 6.14367036e-01]) - abs_arkane_path = os.path.abspath(os.path.dirname(__file__)) # this is the absolute path to `.../RMG-Py/arkane` - energy_path = os.path.join('arkane', 'data', 'H2O2', 'sp_a19032.out') - freq_path = os.path.join('arkane', 'data', 'H2O2', 'freq_a19031.out') - h2o2_input = h2o2_input.format(energy=energy_path, freq=freq_path, angles=angles, energies=energies) - h2o2_path = os.path.join(abs_arkane_path, 'data', 'H2O2', 'H2O2_PES.py') - os.makedirs(os.path.dirname(h2o2_path), exist_ok=True) - with open(h2o2_path, 'w') as f: - f.write(h2o2_input) - h2o2 = Species(label='H2O2', smiles='OO') - self.assertIsNone(h2o2.conformer) - statmech_job = StatMechJob(species=h2o2, path=h2o2_path) - statmech_job.level_of_theory = LevelOfTheory('b3lyp', '6-311+g(3df,2p)') - statmech_job.load(pdep=False, plot=False) - self.assertEqual(len(statmech_job.raw_hindered_rotor_data), 1) - self.assertEqual(statmech_job.raw_hindered_rotor_data[0][2], 1) - self.assertTrue(np.allclose(statmech_job.raw_hindered_rotor_data[0][3], angles, atol=1e-6)) - self.assertTrue(np.allclose(statmech_job.raw_hindered_rotor_data[0][4], energies, atol=1e-6)) - self.assertAlmostEqual(h2o2.conformer.E0.value_si, -146031.49933673252) - os.remove(h2o2_path) - - def test_scanlog_class(self): - """ - Test scanlog works for various input format and returns the correct PES profiles. - """ - angles = np.array([0. , 0.17453293, 0.34906585, 0.52359878, 0.6981317 , - 0.87266463, 1.04719755, 1.22173048, 1.3962634 , 1.57079633, - 1.74532925, 1.91986218, 2.0943951 , 2.26892803, 2.44346095, - 2.61799388, 2.7925268 , 2.96705973, 3.14159265, 3.31612558, - 3.4906585 , 3.66519143, 3.83972435, 4.01425728, 4.1887902 , - 4.36332313, 4.53785606, 4.71238898, 4.88692191, 5.06145483, - 5.23598776, 5.41052068, 5.58505361, 5.75958653, 5.93411946, - 6.10865238, 6.28318531]) - energies = np.array([0.00000000e+00, 3.09449290e+02, 1.07459871e+03, 2.05925305e+03, - 3.02877926e+03, 3.79724994e+03, 4.23486826e+03, 4.26190303e+03, - 3.88196432e+03, 3.15173930e+03, 2.20016363e+03, 1.20431941e+03, - 3.94499732e+02, 7.23850312e+00, 2.77854025e+02, 1.40711827e+03, - 3.50375319e+03, 6.57899330e+03, 1.05208190e+04, 1.50847596e+04, - 1.99269611e+04, 2.46164740e+04, 2.86972097e+04, 3.17430074e+04, - 3.34148312e+04, 3.35267510e+04, 3.20643922e+04, 2.91936786e+04, - 2.52325029e+04, 2.06007483e+04, 1.57531541e+04, 1.11268684e+04, - 7.08120679e+03, 3.87554760e+03, 1.63995547e+03, 3.80256396e+02, - 6.14367036e-01]) - abs_arkane_path = os.path.abspath(os.path.dirname(__file__)) - scanpath1 = os.path.join(abs_arkane_path, 'data', 'H2O2', 'scan.txt') - scanlog1 = ScanLog(scanpath1) - angles1, energies1 = scanlog1.load() - self.assertTrue(np.allclose(angles, angles1, atol=1e-6)) - self.assertTrue(np.allclose(energies, energies1, atol=1e-6)) - - scanpath2 = os.path.join(abs_arkane_path, 'data', 'H2O2', 'scan.yml') - scanlog2 = ScanLog(scanpath2) - angles2, energies2 = scanlog2.load() - self.assertTrue(np.allclose(angles, angles2, atol=1e-6)) - print(energies, energies2) - self.assertTrue(np.allclose(energies, energies2, atol=1e-6)) - - scanpath3 = os.path.join(abs_arkane_path, 'data', 'H2O2', 'scan.csv') - scanlog3 = ScanLog(scanpath3) - angles3, energies3 = scanlog3.load() - self.assertTrue(np.allclose(angles, angles3, atol=1e-6)) - self.assertTrue(np.allclose(energies, energies3, atol=1e-6)) - - def test_hindered_rotor_from_scan_logs(self): - """ - Test assigning hindered rotor 1D PES profile via ScanLog to HinderedRotor in statmech jobs. - """ - angles = np.array([0. , 0.17453293, 0.34906585, 0.52359878, 0.6981317 , - 0.87266463, 1.04719755, 1.22173048, 1.3962634 , 1.57079633, - 1.74532925, 1.91986218, 2.0943951 , 2.26892803, 2.44346095, - 2.61799388, 2.7925268 , 2.96705973, 3.14159265, 3.31612558, - 3.4906585 , 3.66519143, 3.83972435, 4.01425728, 4.1887902 , - 4.36332313, 4.53785606, 4.71238898, 4.88692191, 5.06145483, - 5.23598776, 5.41052068, 5.58505361, 5.75958653, 5.93411946, - 6.10865238, 6.28318531]) - energies = np.array([0.00000000e+00, 3.09449290e+02, 1.07459871e+03, 2.05925305e+03, - 3.02877926e+03, 3.79724994e+03, 4.23486826e+03, 4.26190303e+03, - 3.88196432e+03, 3.15173930e+03, 2.20016363e+03, 1.20431941e+03, - 3.94499732e+02, 7.23850312e+00, 2.77854025e+02, 1.40711827e+03, - 3.50375319e+03, 6.57899330e+03, 1.05208190e+04, 1.50847596e+04, - 1.99269611e+04, 2.46164740e+04, 2.86972097e+04, 3.17430074e+04, - 3.34148312e+04, 3.35267510e+04, 3.20643922e+04, 2.91936786e+04, - 2.52325029e+04, 2.06007483e+04, 1.57531541e+04, 1.11268684e+04, - 7.08120679e+03, 3.87554760e+03, 1.63995547e+03, 3.80256396e+02, - 6.14367036e-01]) - h2o2_input = """#!/usr/bin/env python -# -*- coding: utf-8 -*- - -bonds = {{'H-O': 2, 'O-O': 1}} - -externalSymmetry = 2 - -spinMultiplicity = 1 - -opticalIsomers = 1 - -energy = {{'b3lyp/6-311+g(3df,2p)': Log('{energy}')}} - -geometry = Log('{freq}') - -frequencies = Log('{freq}') - -rotors = [HinderedRotor(scanLog=ScanLog('{scan}'), pivots=[1, 2], top=[1, 3], symmetry=1, fit='fourier')] - -""" - abs_arkane_path = os.path.abspath(os.path.dirname(__file__)) # this is the absolute path to `.../RMG-Py/arkane` - energy_path = os.path.join(abs_arkane_path, 'data', 'H2O2', 'sp_a19032.out') - freq_path = os.path.join(abs_arkane_path, 'data', 'H2O2', 'freq_a19031.out') - h2o2_path = os.path.join(abs_arkane_path, 'data', 'H2O2', 'H2O2.py') - h2o2 = Species(label='H2O2', smiles='OO') - os.makedirs(os.path.dirname(h2o2_path), exist_ok=True) - - for file in ['scan.txt', 'scan.csv', 'scan.yml']: - scan_path = os.path.join(abs_arkane_path, 'data', 'H2O2', file) - h2o2_input_tmp = h2o2_input.format(energy=energy_path, freq=freq_path, scan=scan_path) - with open(h2o2_path, 'w') as f: - f.write(h2o2_input_tmp) - statmech_job = StatMechJob(species=h2o2, path=h2o2_path) - statmech_job.level_of_theory = LevelOfTheory('b3lyp', '6-311+g(3df,2p)') - statmech_job.load(pdep=False, plot=False) - self.assertEqual(len(statmech_job.raw_hindered_rotor_data), 1) - self.assertTrue(np.allclose(statmech_job.raw_hindered_rotor_data[0][3], angles, atol=1e-6)) - self.assertTrue(np.allclose(statmech_job.raw_hindered_rotor_data[0][4], energies, atol=1e-6)) - os.remove(h2o2_path) - - - -################################################################################ - - -if __name__ == '__main__': - unittest.main(testRunner=unittest.TextTestRunner(verbosity=2)) diff --git a/arkane/thermo.py b/arkane/thermo.py index 557aeeaa9c..a5fe0b4e6a 100644 --- a/arkane/thermo.py +++ b/arkane/thermo.py @@ -116,7 +116,7 @@ def generate_thermo(self): 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) + Tlist = np.arange(10.0, 3001.0, 10.0, float) Cplist = np.zeros_like(Tlist) H298 = 0.0 S298 = 0.0 diff --git a/documentation/make.bat b/documentation/make.bat deleted file mode 100644 index 91ef85e170..0000000000 --- a/documentation/make.bat +++ /dev/null @@ -1,170 +0,0 @@ -@ECHO OFF - -REM Command file for Sphinx documentation - -if "%SPHINXBUILD%" == "" ( - set SPHINXBUILD=sphinx-build -) -set BUILDDIR=build -set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source -if NOT "%PAPER%" == "" ( - set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% -) - -if "%1" == "" goto help - -if "%1" == "help" ( - :help - echo.Please use `make ^` where ^ is one of - echo. html to make standalone HTML files - echo. dirhtml to make HTML files named index.html in directories - echo. singlehtml to make a single large HTML file - echo. pickle to make pickle files - echo. json to make JSON files - echo. htmlhelp to make HTML files and a HTML help project - echo. qthelp to make HTML files and a qthelp project - echo. devhelp to make HTML files and a Devhelp project - echo. epub to make an epub - echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter - echo. text to make text files - echo. man to make manual pages - echo. changes to make an overview over all changed/added/deprecated items - echo. linkcheck to check all external links for integrity - echo. doctest to run all doctests embedded in the documentation if enabled - goto end -) - -if "%1" == "clean" ( - for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i - del /q /s %BUILDDIR%\* - goto end -) - -if "%1" == "html" ( - %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/html. - goto end -) - -if "%1" == "dirhtml" ( - %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. - goto end -) - -if "%1" == "singlehtml" ( - %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. - goto end -) - -if "%1" == "pickle" ( - %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the pickle files. - goto end -) - -if "%1" == "json" ( - %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can process the JSON files. - goto end -) - -if "%1" == "htmlhelp" ( - %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run HTML Help Workshop with the ^ -.hhp project file in %BUILDDIR%/htmlhelp. - goto end -) - -if "%1" == "qthelp" ( - %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; now you can run "qcollectiongenerator" with the ^ -.qhcp project file in %BUILDDIR%/qthelp, like this: - echo.^> qcollectiongenerator %BUILDDIR%\qthelp\RMGPy.qhcp - echo.To view the help file: - echo.^> assistant -collectionFile %BUILDDIR%\qthelp\RMGPy.ghc - goto end -) - -if "%1" == "devhelp" ( - %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. - goto end -) - -if "%1" == "epub" ( - %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The epub file is in %BUILDDIR%/epub. - goto end -) - -if "%1" == "latex" ( - %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex - if errorlevel 1 exit /b 1 - echo. - echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. - goto end -) - -if "%1" == "text" ( - %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The text files are in %BUILDDIR%/text. - goto end -) - -if "%1" == "man" ( - %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man - if errorlevel 1 exit /b 1 - echo. - echo.Build finished. The manual pages are in %BUILDDIR%/man. - goto end -) - -if "%1" == "changes" ( - %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes - if errorlevel 1 exit /b 1 - echo. - echo.The overview file is in %BUILDDIR%/changes. - goto end -) - -if "%1" == "linkcheck" ( - %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck - if errorlevel 1 exit /b 1 - echo. - echo.Link check complete; look for any errors in the above output ^ -or in %BUILDDIR%/linkcheck/output.txt. - goto end -) - -if "%1" == "doctest" ( - %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest - if errorlevel 1 exit /b 1 - echo. - echo.Testing of doctests in the sources finished, look at the ^ -results in %BUILDDIR%/doctest/output.txt. - goto end -) - -:end diff --git a/documentation/source/reference/chemkin/index.rst b/documentation/source/reference/chemkin/index.rst index 555b603bb9..5ed52f572c 100644 --- a/documentation/source/reference/chemkin/index.rst +++ b/documentation/source/reference/chemkin/index.rst @@ -41,8 +41,6 @@ Function Description :func:`save_chemkin_file` Save a reaction mechanism to a Chemkin file :func:`save_species_dictionary` Save a species dictionary to a file :func:`save_transport_file` Save a Chemkin transport properties file -:func:`save_html_file` Save an HTML file representing a Chemkin mechanism -:func:`save_java_kinetics_library` Save a mechanism to a (Chemkin-like) kinetics library for RMG-Java ---------------------------------- ------------------------------------------------ :func:`get_species_identifier` Return the Chemkin-valid identifier for a given species :func:`mark_duplicate_reactions` Find and mark all duplicate reactions in a mechanism diff --git a/documentation/source/reference/chemkin/writer.rst b/documentation/source/reference/chemkin/writer.rst index b09f105ce8..bfb287e2a8 100644 --- a/documentation/source/reference/chemkin/writer.rst +++ b/documentation/source/reference/chemkin/writer.rst @@ -13,10 +13,6 @@ Main functions .. autofunction:: rmgpy.chemkin.save_transport_file -.. autofunction:: rmgpy.chemkin.save_html_file - -.. autofunction:: rmgpy.chemkin.save_java_kinetics_library - Helper functions ================ diff --git a/documentation/source/users/arkane/installation.rst b/documentation/source/users/arkane/installation.rst index df4930184c..2eebc128ed 100644 --- a/documentation/source/users/arkane/installation.rst +++ b/documentation/source/users/arkane/installation.rst @@ -21,7 +21,8 @@ Installing Q2DTor Q2DTor is a software for calculating the partition functions and themodynamic properties of molecular systems with two or more torsional modes developed by David Ferro Costas (david.ferro@usc.es) and Antonio Fernandez Ramos (qf.ramos@usc.es) at the Universidade de Santiago de Compostela. Arkane can integrate Q2DTor to compute the quantum mechanical partition function -of 2D rotors. +of 2D rotors. +Learn more at https://github.com/cathedralpkg/Q2DTor For use of Q2DTor and HinderedRotor2D within Arkane please cite: D. Ferro-Costas, M. N. D. S. Cordeiro, D. G. Truhlar, A. Fernández-Ramos, Comput. Phys. Commun. 232, 190-205, 2018. diff --git a/documentation/source/users/rmg/database/modification.rst b/documentation/source/users/rmg/database/modification.rst index 1fa567022f..dce49a25bf 100644 --- a/documentation/source/users/rmg/database/modification.rst +++ b/documentation/source/users/rmg/database/modification.rst @@ -61,7 +61,6 @@ There are several places in the RMG-database and RMG-Py source code where reacti * ``getReactionPairs``: figuring out which species becomes which for flux analyses * ``__generateReactions``: correcting degeneracy eg. dividing by 2 for radical recombination * rmgpy.data.kinetics.rules - * ``processOldLibraryEntry``: determining units when importing RMG-Java database * ``getAllRules``: for radical recombination add reverse templates * rmgpy.data.kinetics.groups * ``getReactionTemplate``: for radical recombination duplicate the template diff --git a/documentation/source/users/rmg/installation/anacondaDeveloper.rst b/documentation/source/users/rmg/installation/anacondaDeveloper.rst index eedc86ae1c..3fba6303b8 100644 --- a/documentation/source/users/rmg/installation/anacondaDeveloper.rst +++ b/documentation/source/users/rmg/installation/anacondaDeveloper.rst @@ -136,7 +136,7 @@ Installation by Source Using Anaconda Environment for Unix-based Systems: Linux #. Install and Link Julia dependencies: :: - julia -e 'using Pkg; Pkg.add("PyCall");Pkg.build("PyCall");Pkg.add(PackageSpec(name="ReactionMechanismSimulator",rev="main")); using ReactionMechanismSimulator;' + julia -e 'using Pkg; Pkg.add("PyCall");Pkg.build("PyCall");Pkg.add(PackageSpec(name="ReactionMechanismSimulator",rev="for_rmg")); using ReactionMechanismSimulator;' python -c "import julia; julia.install(); import diffeqpy; diffeqpy.install()" @@ -152,8 +152,8 @@ Debugging ========= If you wish to debug using the (very helpful) debugger in `VSCode `_, -here is an example launch configuration to put in your launch.json file, -which can be found in the .vscode folder. +here is an example launch configuration to put in your ``launch.json`` file, +which can be found in the ``.vscode`` folder. You might have to edit them slightly to match your exact paths. Specifically, you will need ``/opt/miniconda3/envs/rmg_env`` to point to where your conda environment is located. @@ -178,16 +178,16 @@ python-jl. :: }, This configuration will allow you to debug a subset of the unit tests. -Open one of the many test files named `*Test.py` before you launch it:: +Open one of the many test files named ``*Test.py`` in ``test/rmgpy`` before you launch it:: - { - "name": "Python: nosetest Current File", + { + "name": "Python: pytest Current File", "type": "python", "request": "launch", - "program": "/opt/miniconda3/envs/rmg_env/bin/nosetests", + "program": "/opt/miniconda3/envs/rmg_env/bin/pytest", + "python": "/opt/miniconda3/envs/rmg_env/bin/python-jl", "args": [ - "--nologcapture", - "--nocapture", + "--capture=no", "--verbose", "${file}" ], @@ -204,13 +204,12 @@ This configuration will allow you to debug running all the database tests.:: "name": "Test RMG-database", "type": "python", "request": "launch", - "program": "/opt/miniconda3/envs/rmg_env/bin/nosetests", + "program": "/opt/miniconda3/envs/rmg_env/bin/pytest", + "python": "/opt/miniconda3/envs/rmg_env/bin/python-jl", "args": [ - "--nologcapture", - "--nocapture", + "--capture=no", "--verbose", - "--detailed-errors", - "${workspaceFolder}/testing/databaseTest.py" + "${workspaceFolder}/test/database/databaseTest.py" ], "console": "integratedTerminal", "env": { @@ -219,6 +218,22 @@ This configuration will allow you to debug running all the database tests.:: }, }, +This configuration will allow you to use the debugger breakpoints inside unit tests being run by the pytest framework:: + + { + "name": "Python: Debug Tests", + "type": "python", + "request": "launch", + "program": "${file}", + "purpose": ["debug-test"], + "python": "/opt/miniconda3/envs/rmg_env/bin/python-jl", + "console": "integratedTerminal", + "justMyCode": false, + "env": {"PYTEST_ADDOPTS": "--no-cov",} // without disabling coverage VS Code doesn't stop at breakpoints while debugging because pytest-cov is using the same technique to access the source code being run + } + +See more about testing in VSCode in the :ref:`Testing in VSCode ` section below. + Test Suite ========== @@ -242,6 +257,44 @@ Make sure that the environment is active before running the tests: ``conda activ make test-database +.. _vscode_testing: + +Testing in VSCode +================= + +Once you have the Python extension installed and a Python file open within the editor, +a test beaker icon will be displayed on the VS Code Activity bar. +The beaker icon is for the Test Explorer view. When opening the Test Explorer, +you will see a Configure Tests button if you don't have a test framework enabled. +Once you select Configure Tests, you will be prompted to select a test framework +(**select `pytest`**) +and a folder containing the tests +(**select `test`**). +To configure the rest of the settings, find the ``settings.json`` file in your ``.vscode`` folder. +You can use the following settings to configure the pytest framework:: + + "python.testing.pytestEnabled": true, + "python.testing.pytestPath": "python-jl -m pytest", + "python.testing.pytestArgs": [ + "-p", "julia.pytestplugin", + "--julia-compiled-modules=no", + "--ignore", "test/regression", + "-m", "not functional", + // "-n", "auto", // number of parallel processes, if you install pytest-xdist + "test" + ], + +To run the tests, you can click the Run All Tests button in the Test Explorer view. +Learn more at the `Python testing in Visual Studio Code `_ documentation. + +Given the time taken for Julia to compile things every time it launches, +you might find this to be painfully slow even for a simple test. +It may be possible to use ``--julia-sysimage=JULIA_SYSIMAGE`` instead of ``--julia-compiled-modules=no``, +or disable PyJulia entirely. +If you find a better way to do this, or clearer instructions, +please `update this section `_. + + Running Examples ================ diff --git a/documentation/source/users/rmg/installation/dependencies.rst b/documentation/source/users/rmg/installation/dependencies.rst index 1e257148f9..ba8a3ad66c 100644 --- a/documentation/source/users/rmg/installation/dependencies.rst +++ b/documentation/source/users/rmg/installation/dependencies.rst @@ -32,7 +32,7 @@ Briefly, RMG depends on the following packages, almost all of which can be found * **mpmath:** for arbitrary-precision arithmetic used in Arkane * **muq:** (optional) MIT Uncertainty Quantification library, used for global uncertainty analysis * **networkx:** (optional) network analysis for reaction-path analysis IPython notebook -* **nose:** advanced unit test controls +* **pytest:** advanced unit test controls * **numpy:** fast matrix operations * **openbabel:** chemical toolbox for speaking the many languages of chemical data * **psutil:** system utilization diagnostic tool @@ -58,7 +58,7 @@ License Restrictions on Dependencies All of RMG's dependencies except the ones listed below are freely available and compatible with RMG's open source MIT license (though the specific nature of their licenses vary). -* **pydas**: The DAE solvers used in the simulations come from `Linda Petzold’s research group `_ at UCSB. For running sensitivity analysis in RMG, the DASPK 3.1 solver is required, which "is subject to copyright restrictions” for non-academic use. Please visit their website for more details. To run RMG without this restriction, one may switch to compiling with the DASSL solver instead in RMG, which is "available in the public domain.” +* **pydas**: The DAE solvers used in the simulations come from `Linda Petzold's research group `_ at UCSB. For running sensitivity analysis in RMG, the DASPK 3.1 solver is required, which "is subject to copyright restrictions” for non-academic use. Please visit their website for more details. To run RMG without this restriction, one may switch to compiling with the DASSL solver instead in RMG, which is "available in the public domain.” If you wish to do on-the-fly quantum chemistry calculations of thermochemistry (advisable for fused cyclic species in particular, where the ring corrections to group additive estimates are lacking), the then you will need the third-party software for the QM calculations: diff --git a/documentation/source/users/rmg/modules/convertFAME.rst b/documentation/source/users/rmg/modules/convertFAME.rst deleted file mode 100644 index f709206826..0000000000 --- a/documentation/source/users/rmg/modules/convertFAME.rst +++ /dev/null @@ -1,29 +0,0 @@ -.. _convertFAME: - -*********************************** -Convert FAME to Arkane Input File -*********************************** - -This module is utilized to convert FAME file types (used in RMG-Java) to Arkane (formerly called CanTherm) objects -(used in RMG-Py) for pressure dependent calculations. - -FAME is an early version of the pdep code in Arkane, and it is written in Fortran and used by RMG-Java. -This script enables importing FAME input files into Arkane. Note that it is mostly designed to load the FAME input files -generated automatically by RMG-Java, and may not load hand-crafted FAME input files. If you specify a `moleculeDict`, -then this script will use it to associate the species with their structures. :: - - python convertFAME.py fame_object - -where ``fame_object`` is the FAME file used to be converted into the Arkane object. - -Some additional options involve adding an RMG dictionary to process with the file. The syntax for this is :: - - python convertFAME.py -d RMG_dictionary.txt fame_object - -where ``RMG_dictionary.txt`` is the dictionary to process with the file. - -A max energy cuttoff is also possible when converting the file formats. :: - - python convertFAME.py -d RMG_dictionary.txt -x value units value units fame_object - -where ``value`` represents the max energy amount and ``units`` represents its units diff --git a/documentation/source/users/rmg/modules/generateFluxDiagram.rst b/documentation/source/users/rmg/modules/generateFluxDiagram.rst index d4d7c1bc07..4fc19f0428 100644 --- a/documentation/source/users/rmg/modules/generateFluxDiagram.rst +++ b/documentation/source/users/rmg/modules/generateFluxDiagram.rst @@ -10,7 +10,7 @@ that shows interconnected arrows between species that represent fluxes. To use this method, you just need a Chemkin input file and an RMG species dictionary. The syntax is as follows:: - python generateFluxDiagram.py [-h] [--java] [--no-dlim] [-s SPECIES] [-f] + python generateFluxDiagram.py [-h] [--no-dlim] [-s SPECIES] [-f] [-n N] [-e N] [-c TOL] [-r TOL] [-t S] INPUT CHEMKIN DICTIONARY [CHEMKIN_OUTPUT] @@ -24,7 +24,6 @@ Positional arguments:: Optional arguments:: -h, --help show this help message and exit - --java process RMG-Java model --no-dlim Turn off diffusion-limited rates -s DIR, --species DIR Path to folder containing species images -f, --foreign Not an RMG generated Chemkin file (will be checked for duplicates) diff --git a/documentation/source/users/rmg/modules/index.rst b/documentation/source/users/rmg/modules/index.rst index 5db2c622c3..3bb8d7c200 100644 --- a/documentation/source/users/rmg/modules/index.rst +++ b/documentation/source/users/rmg/modules/index.rst @@ -18,7 +18,6 @@ otherwise. simulate generateFluxDiagram thermoEstimation - convertFAME databaseScripts standardizeModelSpeciesNames isotopes diff --git a/environment.yml b/environment.yml index f1c805a979..e9c5e8c071 100644 --- a/environment.yml +++ b/environment.yml @@ -63,7 +63,15 @@ dependencies: - pyparsing - pyyaml - networkx - - nose + - pytest + - pytest-cov + # we use a the pytest-check plugin, which is on Conda and PyPI, but the + # version compatible with Python 3.7 is only on PyPI + # switch to the conda version after upgrading to 3.11 + # - conda-forge::pytest-check + - pip + - pip: + - pytest-check - matplotlib >=1.5 - mpmath - pandas diff --git a/examples/arkane/species/Toulene_Free_Rotor/TolueneEnergy.log b/examples/arkane/species/Toluene_Free_Rotor/TolueneEnergy.log similarity index 100% rename from examples/arkane/species/Toulene_Free_Rotor/TolueneEnergy.log rename to examples/arkane/species/Toluene_Free_Rotor/TolueneEnergy.log diff --git a/examples/arkane/species/Toulene_Free_Rotor/TolueneFreq.log b/examples/arkane/species/Toluene_Free_Rotor/TolueneFreq.log similarity index 100% rename from examples/arkane/species/Toulene_Free_Rotor/TolueneFreq.log rename to examples/arkane/species/Toluene_Free_Rotor/TolueneFreq.log diff --git a/examples/arkane/species/Toulene_Free_Rotor/input.py b/examples/arkane/species/Toluene_Free_Rotor/input.py similarity index 100% rename from examples/arkane/species/Toulene_Free_Rotor/input.py rename to examples/arkane/species/Toluene_Free_Rotor/input.py diff --git a/examples/arkane/species/Toulene_Free_Rotor/toluene_FreeRotor.py b/examples/arkane/species/Toluene_Free_Rotor/toluene_FreeRotor.py similarity index 100% rename from examples/arkane/species/Toulene_Free_Rotor/toluene_FreeRotor.py rename to examples/arkane/species/Toluene_Free_Rotor/toluene_FreeRotor.py diff --git a/examples/arkane/species/Toulene_Hindered_Rotor/TolueneEnergy.log b/examples/arkane/species/Toluene_Hindered_Rotor/TolueneEnergy.log similarity index 100% rename from examples/arkane/species/Toulene_Hindered_Rotor/TolueneEnergy.log rename to examples/arkane/species/Toluene_Hindered_Rotor/TolueneEnergy.log diff --git a/examples/arkane/species/Toulene_Hindered_Rotor/TolueneFreq.log b/examples/arkane/species/Toluene_Hindered_Rotor/TolueneFreq.log similarity index 100% rename from examples/arkane/species/Toulene_Hindered_Rotor/TolueneFreq.log rename to examples/arkane/species/Toluene_Hindered_Rotor/TolueneFreq.log diff --git a/examples/arkane/species/Toulene_Hindered_Rotor/TolueneRot1.log b/examples/arkane/species/Toluene_Hindered_Rotor/TolueneRot1.log similarity index 100% rename from examples/arkane/species/Toulene_Hindered_Rotor/TolueneRot1.log rename to examples/arkane/species/Toluene_Hindered_Rotor/TolueneRot1.log diff --git a/examples/arkane/species/Toulene_Hindered_Rotor/input.py b/examples/arkane/species/Toluene_Hindered_Rotor/input.py similarity index 100% rename from examples/arkane/species/Toulene_Hindered_Rotor/input.py rename to examples/arkane/species/Toluene_Hindered_Rotor/input.py diff --git a/examples/arkane/species/Toulene_Hindered_Rotor/toluene_HinderedRotor.py b/examples/arkane/species/Toluene_Hindered_Rotor/toluene_HinderedRotor.py similarity index 100% rename from examples/arkane/species/Toulene_Hindered_Rotor/toluene_HinderedRotor.py rename to examples/arkane/species/Toluene_Hindered_Rotor/toluene_HinderedRotor.py diff --git a/examples/arkane/species/Toulene_Hindered_Rotor_SemiClassicalND/TolueneEnergy.log b/examples/arkane/species/Toluene_Hindered_Rotor_SemiClassicalND/TolueneEnergy.log similarity index 100% rename from examples/arkane/species/Toulene_Hindered_Rotor_SemiClassicalND/TolueneEnergy.log rename to examples/arkane/species/Toluene_Hindered_Rotor_SemiClassicalND/TolueneEnergy.log diff --git a/examples/arkane/species/Toulene_Hindered_Rotor_SemiClassicalND/TolueneFreq.log b/examples/arkane/species/Toluene_Hindered_Rotor_SemiClassicalND/TolueneFreq.log similarity index 100% rename from examples/arkane/species/Toulene_Hindered_Rotor_SemiClassicalND/TolueneFreq.log rename to examples/arkane/species/Toluene_Hindered_Rotor_SemiClassicalND/TolueneFreq.log diff --git a/examples/arkane/species/Toulene_Hindered_Rotor_SemiClassicalND/TolueneRot1.log b/examples/arkane/species/Toluene_Hindered_Rotor_SemiClassicalND/TolueneRot1.log similarity index 100% rename from examples/arkane/species/Toulene_Hindered_Rotor_SemiClassicalND/TolueneRot1.log rename to examples/arkane/species/Toluene_Hindered_Rotor_SemiClassicalND/TolueneRot1.log diff --git a/examples/arkane/species/Toulene_Hindered_Rotor_SemiClassicalND/input.py b/examples/arkane/species/Toluene_Hindered_Rotor_SemiClassicalND/input.py similarity index 100% rename from examples/arkane/species/Toulene_Hindered_Rotor_SemiClassicalND/input.py rename to examples/arkane/species/Toluene_Hindered_Rotor_SemiClassicalND/input.py diff --git a/examples/arkane/species/Toluene_Hindered_Rotor_SemiClassicalND/toluene_HinderedRotor.py b/examples/arkane/species/Toluene_Hindered_Rotor_SemiClassicalND/toluene_HinderedRotor.py new file mode 100644 index 0000000000..78d0c3cad8 --- /dev/null +++ b/examples/arkane/species/Toluene_Hindered_Rotor_SemiClassicalND/toluene_HinderedRotor.py @@ -0,0 +1,21 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +bonds = { + "C-C": 4, + "C-H": 8, + "C=C": 3, +} + +externalSymmetry = 1 + +spinMultiplicity = 1 + +opticalIsomers = 1 + +energy = {"CBS-QB3": Log("TolueneEnergy.log")} + +geometry = Log("TolueneFreq.log") + +frequencies = Log("TolueneFreq.log") + +rotors = [HinderedRotorClassicalND(calc_path="TolueneRot1.log", pivots=[[3, 12]], tops=[[12, 13, 14, 15]], sigmas=[6], semiclassical=True)] diff --git a/examples/arkane/species/Toulene_Hindered_Rotor_SemiClassicalND/toluene_HinderedRotor.py b/examples/arkane/species/Toulene_Hindered_Rotor_SemiClassicalND/toluene_HinderedRotor.py deleted file mode 100755 index fe8f299ac8..0000000000 --- a/examples/arkane/species/Toulene_Hindered_Rotor_SemiClassicalND/toluene_HinderedRotor.py +++ /dev/null @@ -1,23 +0,0 @@ -#!/usr/bin/env python -# -*- coding: utf-8 -*- -bonds = { - 'C-C': 4, - 'C-H': 8, - 'C=C': 3, -} - -externalSymmetry = 1 - -spinMultiplicity = 1 - -opticalIsomers = 1 - -energy = { - 'CBS-QB3': Log('TolueneEnergy.log') -} - -geometry = Log('TolueneFreq.log') - -frequencies = Log('TolueneFreq.log') - -rotors = [HinderedRotorClassicalND(calcPath='TolueneRot1.log', pivots=[[3,12]], tops=[[12,13,14,15]], sigmas=[6], semiclassical=True)] diff --git a/examples/arkane/species/thermo_demo/input.py b/examples/arkane/species/thermo_demo/input.py index 6e46762ac8..7afab82532 100644 --- a/examples/arkane/species/thermo_demo/input.py +++ b/examples/arkane/species/thermo_demo/input.py @@ -2,31 +2,33 @@ # encoding: utf-8 # Define the level of theory ("model chemistry"): -modelChemistry = LevelOfTheory(method='CCSD(T)-F12', basis='cc-pVTZ-F12', software='molpro') +modelChemistry = LevelOfTheory(method="CCSD(T)-F12", basis="cc-pVTZ-F12", software="molpro") useHinderedRotors = True useBondCorrections = True +# FIXME: While switching to pytest, the commented-out examples stopped working. I suspect they have not +# been run in some time and fell vitim to tech. debt. + # Define the species: -species('methoxy', 'data/methoxy.py', structure=SMILES('C[O]')) -species('1,2-butadiene', 'data/1,2-butadiene.py', structure=SMILES('C=C=CC')) -species('aziridine', 'data/aziridine.py', structure=SMILES('C1NC1')) -species('hydrazino', 'data/hydrazino.py', structure=SMILES('N[NH]')) -species('1-propene-12-diol', 'data/1-propene-12-diol.py', structure=SMILES('CC(O)=CO')) -species('hydroxyiminomethyl', 'data/hydroxyiminomethyl.py', structure=SMILES('[CH]=NO')) -species('2-methyl-2-propanamine', 'data/2-methyl-2-propanamine.py', structure=SMILES('CC(C)(C)N')) -species('nitrosodioxaziridine', 'data/nitrosodioxaziridine.py', structure=SMILES('O=NN1OO1')) -species('ethynol', 'data/ethynol.py', structure=SMILES('C#CO')) -species('2-iminoethyl', 'data/2-iminoethyl.py', structure=SMILES('[CH2]C=N')) +species("methoxy", "data/methoxy.py", structure=SMILES("C[O]")) +# species("1,2-butadiene", "data/1,2-butadiene.py", structure=SMILES("C=C=CC")) +species("aziridine", "data/aziridine.py", structure=SMILES("C1NC1")) +species("hydrazino", "data/hydrazino.py", structure=SMILES("N[NH]")) +species("1-propene-12-diol", "data/1-propene-12-diol.py", structure=SMILES("CC(O)=CO")) +species("hydroxyiminomethyl", "data/hydroxyiminomethyl.py", structure=SMILES("[CH]=NO")) +species("2-methyl-2-propanamine", "data/2-methyl-2-propanamine.py", structure=SMILES("CC(C)(C)N")) +# species("nitrosodioxaziridine", "data/nitrosodioxaziridine.py", structure=SMILES("O=NN1OO1")) +species("ethynol", "data/ethynol.py", structure=SMILES("C#CO")) +species("2-iminoethyl", "data/2-iminoethyl.py", structure=SMILES("[CH2]C=N")) # Request thermodynamic property calculation with a NASA polynomial output: -thermo('methoxy', 'NASA') -thermo('1,2-butadiene', 'NASA') -thermo('aziridine', 'NASA') -thermo('hydrazino', 'NASA') -thermo('1-propene-12-diol', 'NASA') -thermo('hydroxyiminomethyl', 'NASA') -thermo('2-methyl-2-propanamine', 'NASA') -thermo('nitrosodioxaziridine', 'NASA') -thermo('ethynol', 'NASA') -thermo('2-iminoethyl', 'NASA') - +thermo("methoxy", "NASA") +# thermo("1,2-butadiene", "NASA") +thermo("aziridine", "NASA") +thermo("hydrazino", "NASA") +thermo("1-propene-12-diol", "NASA") +thermo("hydroxyiminomethyl", "NASA") +thermo("2-methyl-2-propanamine", "NASA") +# thermo("nitrosodioxaziridine", "NASA") +thermo("ethynol", "NASA") +thermo("2-iminoethyl", "NASA") diff --git a/examples/rmg/1,3-hexadiene/RMG.bat b/examples/rmg/1,3-hexadiene/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/1,3-hexadiene/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/TEOS/RMG.bat b/examples/rmg/TEOS/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/TEOS/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/c3h4/RMG.bat b/examples/rmg/c3h4/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/c3h4/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/ch3no2/RMG.bat b/examples/rmg/ch3no2/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/ch3no2/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/diesel/RMG.bat b/examples/rmg/diesel/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/diesel/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/e85/RMG.bat b/examples/rmg/e85/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/e85/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/gri_mech_rxn_lib/RMG.bat b/examples/rmg/gri_mech_rxn_lib/RMG.bat deleted file mode 100644 index ac88ed3cd4..0000000000 --- a/examples/rmg/gri_mech_rxn_lib/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/liquid_phase/RMG.bat b/examples/rmg/liquid_phase/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/liquid_phase/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/liquid_phase_constSPC/RMG.bat b/examples/rmg/liquid_phase_constSPC/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/liquid_phase_constSPC/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/methylformate/RMG.bat b/examples/rmg/methylformate/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/methylformate/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/minimal/RMG.bat b/examples/rmg/minimal/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/minimal/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/minimal_sensitivity/RMG.bat b/examples/rmg/minimal_sensitivity/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/minimal_sensitivity/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/examples/rmg/minimal_surface/RMG.bat b/examples/rmg/minimal_surface/RMG.bat deleted file mode 100644 index 61fc6b8960..0000000000 --- a/examples/rmg/minimal_surface/RMG.bat +++ /dev/null @@ -1,13 +0,0 @@ -@echo off - -REM RMG-Py Windows batch script for RMG execution -REM Put me in the directory containing the input file and double-click to run RMG. -REM This assumes that the condition file is called input.py. -REM Output from RMG will be logged to the file RMG.log. - -echo Running RMG... -python "..\..\..\rmg.py" input.py -echo RMG job completed. - -:end -pause diff --git a/external/README b/external/README deleted file mode 100644 index 00c7aba3fb..0000000000 --- a/external/README +++ /dev/null @@ -1,48 +0,0 @@ -This folder ('external') is for external programs that RMG depends on but are -not part of the RMG code itself. In most cases you can get them elsewhere. -Nevertheless, they are stored here because - (1) they may be hard to find elsewhere - (2) we know that that these versions work (but ones from elsewhere may not) - -ctml_writer.py -comes from Cantera 1.7 (https://sourceforge.net/projects/cantera/) -which we think uses the New BSD License -http://www.opensource.org/licenses/bsd-license.php - -pydot.py -comes from Pydot (http://www.dkbza.org/pydot.html) -which uses the MIT license -http://opensource.org/licenses/mit-license.html -the version here is based on 1.0.2 but contains a bug fix patch - - -cinfony/webel.py -from http://cinfony.googlecode.com/svn/trunk/cinfony/webel.py - -jquery.min.js -from http://ajax.googleapis.com/ajax/libs/jquery/1.4.1/jquery.min.js -Used by the HTML output of RMG. Useful to have it locally if you do not have -internet access when you want to look at your results. - - -symmetry -Brute force symmetry determination program and the associated test set. -(C) 1996, 2003 S. Patchkovskii, Serguei.Patchkovskii@sympatico.ca -Published under GNU General Public License -http://www.cobalt.chem.ucalgary.ca/ps/symmetry/ -(now mirrored at https://github.com/nquesada/symmetry) -This is based on Revision 1.16 2003/04/04 -This program is no longer stored in the external programs folder but is instead found on the anaconda platform. - - -cclib -An open source library, written in Python, for parsing and interpreting -the results of computational chemistry packages. -N. M. O'Boyle, A. L. Tenderholt, K. M. Langner, -"cclib: a library for package-independent computational chemistry algorithms", -J. Comp. Chem. 29 (5), pp. 839-845, 2008 -cclib is licensed under the LGPL -http://cclib.sourceforge.net -This is based on version 1.0 but with some modifications, -probably made in the RMG-Java project. -We should endeavor to get the modifications merged upstream and use the main cclib. \ No newline at end of file diff --git a/external/__init__.py b/external/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/external/jquery.min.js b/external/jquery.min.js deleted file mode 100644 index 0c7294c90a..0000000000 --- a/external/jquery.min.js +++ /dev/null @@ -1,152 +0,0 @@ -/*! - * jQuery JavaScript Library v1.4.1 - * http://jquery.com/ - * - * Copyright 2010, John Resig - * Dual licensed under the MIT or GPL Version 2 licenses. - * http://jquery.org/license - * - * Includes Sizzle.js - * http://sizzlejs.com/ - * Copyright 2010, The Dojo Foundation - * Released under the MIT, BSD, and GPL Licenses. - * - * Date: Mon Jan 25 19:43:33 2010 -0500 - */ -(function(z,v){function la(){if(!c.isReady){try{r.documentElement.doScroll("left")}catch(a){setTimeout(la,1);return}c.ready()}}function Ma(a,b){b.src?c.ajax({url:b.src,async:false,dataType:"script"}):c.globalEval(b.text||b.textContent||b.innerHTML||"");b.parentNode&&b.parentNode.removeChild(b)}function X(a,b,d,f,e,i){var j=a.length;if(typeof b==="object"){for(var n in b)X(a,n,b[n],f,e,d);return a}if(d!==v){f=!i&&f&&c.isFunction(d);for(n=0;n-1){i=j.data;i.beforeFilter&&i.beforeFilter[a.type]&&!i.beforeFilter[a.type](a)||f.push(j.selector)}else delete x[o]}i=c(a.target).closest(f, -a.currentTarget);m=0;for(s=i.length;m)[^>]*$|^#([\w-]+)$/,Qa=/^.[^:#\[\.,]*$/,Ra=/\S/,Sa=/^(\s|\u00A0)+|(\s|\u00A0)+$/g,Ta=/^<(\w+)\s*\/?>(?:<\/\1>)?$/,O=navigator.userAgent, -va=false,P=[],L,$=Object.prototype.toString,aa=Object.prototype.hasOwnProperty,ba=Array.prototype.push,Q=Array.prototype.slice,wa=Array.prototype.indexOf;c.fn=c.prototype={init:function(a,b){var d,f;if(!a)return this;if(a.nodeType){this.context=this[0]=a;this.length=1;return this}if(typeof a==="string")if((d=Pa.exec(a))&&(d[1]||!b))if(d[1]){f=b?b.ownerDocument||b:r;if(a=Ta.exec(a))if(c.isPlainObject(b)){a=[r.createElement(a[1])];c.fn.attr.call(a,b,true)}else a=[f.createElement(a[1])];else{a=ra([d[1]], -[f]);a=(a.cacheable?a.fragment.cloneNode(true):a.fragment).childNodes}}else{if(b=r.getElementById(d[2])){if(b.id!==d[2])return S.find(a);this.length=1;this[0]=b}this.context=r;this.selector=a;return this}else if(!b&&/^\w+$/.test(a)){this.selector=a;this.context=r;a=r.getElementsByTagName(a)}else return!b||b.jquery?(b||S).find(a):c(b).find(a);else if(c.isFunction(a))return S.ready(a);if(a.selector!==v){this.selector=a.selector;this.context=a.context}return c.isArray(a)?this.setArray(a):c.makeArray(a, -this)},selector:"",jquery:"1.4.1",length:0,size:function(){return this.length},toArray:function(){return Q.call(this,0)},get:function(a){return a==null?this.toArray():a<0?this.slice(a)[0]:this[a]},pushStack:function(a,b,d){a=c(a||null);a.prevObject=this;a.context=this.context;if(b==="find")a.selector=this.selector+(this.selector?" ":"")+d;else if(b)a.selector=this.selector+"."+b+"("+d+")";return a},setArray:function(a){this.length=0;ba.apply(this,a);return this},each:function(a,b){return c.each(this, -a,b)},ready:function(a){c.bindReady();if(c.isReady)a.call(r,c);else P&&P.push(a);return this},eq:function(a){return a===-1?this.slice(a):this.slice(a,+a+1)},first:function(){return this.eq(0)},last:function(){return this.eq(-1)},slice:function(){return this.pushStack(Q.apply(this,arguments),"slice",Q.call(arguments).join(","))},map:function(a){return this.pushStack(c.map(this,function(b,d){return a.call(b,d,b)}))},end:function(){return this.prevObject||c(null)},push:ba,sort:[].sort,splice:[].splice}; -c.fn.init.prototype=c.fn;c.extend=c.fn.extend=function(){var a=arguments[0]||{},b=1,d=arguments.length,f=false,e,i,j,n;if(typeof a==="boolean"){f=a;a=arguments[1]||{};b=2}if(typeof a!=="object"&&!c.isFunction(a))a={};if(d===b){a=this;--b}for(;b
a";var e=d.getElementsByTagName("*"),i=d.getElementsByTagName("a")[0];if(!(!e||!e.length||!i)){c.support= -{leadingWhitespace:d.firstChild.nodeType===3,tbody:!d.getElementsByTagName("tbody").length,htmlSerialize:!!d.getElementsByTagName("link").length,style:/red/.test(i.getAttribute("style")),hrefNormalized:i.getAttribute("href")==="/a",opacity:/^0.55$/.test(i.style.opacity),cssFloat:!!i.style.cssFloat,checkOn:d.getElementsByTagName("input")[0].value==="on",optSelected:r.createElement("select").appendChild(r.createElement("option")).selected,checkClone:false,scriptEval:false,noCloneEvent:true,boxModel:null}; -b.type="text/javascript";try{b.appendChild(r.createTextNode("window."+f+"=1;"))}catch(j){}a.insertBefore(b,a.firstChild);if(z[f]){c.support.scriptEval=true;delete z[f]}a.removeChild(b);if(d.attachEvent&&d.fireEvent){d.attachEvent("onclick",function n(){c.support.noCloneEvent=false;d.detachEvent("onclick",n)});d.cloneNode(true).fireEvent("onclick")}d=r.createElement("div");d.innerHTML="";a=r.createDocumentFragment();a.appendChild(d.firstChild); -c.support.checkClone=a.cloneNode(true).cloneNode(true).lastChild.checked;c(function(){var n=r.createElement("div");n.style.width=n.style.paddingLeft="1px";r.body.appendChild(n);c.boxModel=c.support.boxModel=n.offsetWidth===2;r.body.removeChild(n).style.display="none"});a=function(n){var o=r.createElement("div");n="on"+n;var m=n in o;if(!m){o.setAttribute(n,"return;");m=typeof o[n]==="function"}return m};c.support.submitBubbles=a("submit");c.support.changeBubbles=a("change");a=b=d=e=i=null}})();c.props= -{"for":"htmlFor","class":"className",readonly:"readOnly",maxlength:"maxLength",cellspacing:"cellSpacing",rowspan:"rowSpan",colspan:"colSpan",tabindex:"tabIndex",usemap:"useMap",frameborder:"frameBorder"};var G="jQuery"+J(),Ua=0,xa={},Va={};c.extend({cache:{},expando:G,noData:{embed:true,object:true,applet:true},data:function(a,b,d){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==z?xa:a;var f=a[G],e=c.cache;if(!b&&!f)return null;f||(f=++Ua);if(typeof b==="object"){a[G]=f;e=e[f]=c.extend(true, -{},b)}else e=e[f]?e[f]:typeof d==="undefined"?Va:(e[f]={});if(d!==v){a[G]=f;e[b]=d}return typeof b==="string"?e[b]:e}},removeData:function(a,b){if(!(a.nodeName&&c.noData[a.nodeName.toLowerCase()])){a=a==z?xa:a;var d=a[G],f=c.cache,e=f[d];if(b){if(e){delete e[b];c.isEmptyObject(e)&&c.removeData(a)}}else{try{delete a[G]}catch(i){a.removeAttribute&&a.removeAttribute(G)}delete f[d]}}}});c.fn.extend({data:function(a,b){if(typeof a==="undefined"&&this.length)return c.data(this[0]);else if(typeof a==="object")return this.each(function(){c.data(this, -a)});var d=a.split(".");d[1]=d[1]?"."+d[1]:"";if(b===v){var f=this.triggerHandler("getData"+d[1]+"!",[d[0]]);if(f===v&&this.length)f=c.data(this[0],a);return f===v&&d[1]?this.data(d[0]):f}else return this.trigger("setData"+d[1]+"!",[d[0],b]).each(function(){c.data(this,a,b)})},removeData:function(a){return this.each(function(){c.removeData(this,a)})}});c.extend({queue:function(a,b,d){if(a){b=(b||"fx")+"queue";var f=c.data(a,b);if(!d)return f||[];if(!f||c.isArray(d))f=c.data(a,b,c.makeArray(d));else f.push(d); -return f}},dequeue:function(a,b){b=b||"fx";var d=c.queue(a,b),f=d.shift();if(f==="inprogress")f=d.shift();if(f){b==="fx"&&d.unshift("inprogress");f.call(a,function(){c.dequeue(a,b)})}}});c.fn.extend({queue:function(a,b){if(typeof a!=="string"){b=a;a="fx"}if(b===v)return c.queue(this[0],a);return this.each(function(){var d=c.queue(this,a,b);a==="fx"&&d[0]!=="inprogress"&&c.dequeue(this,a)})},dequeue:function(a){return this.each(function(){c.dequeue(this,a)})},delay:function(a,b){a=c.fx?c.fx.speeds[a]|| -a:a;b=b||"fx";return this.queue(b,function(){var d=this;setTimeout(function(){c.dequeue(d,b)},a)})},clearQueue:function(a){return this.queue(a||"fx",[])}});var ya=/[\n\t]/g,ca=/\s+/,Wa=/\r/g,Xa=/href|src|style/,Ya=/(button|input)/i,Za=/(button|input|object|select|textarea)/i,$a=/^(a|area)$/i,za=/radio|checkbox/;c.fn.extend({attr:function(a,b){return X(this,a,b,true,c.attr)},removeAttr:function(a){return this.each(function(){c.attr(this,a,"");this.nodeType===1&&this.removeAttribute(a)})},addClass:function(a){if(c.isFunction(a))return this.each(function(o){var m= -c(this);m.addClass(a.call(this,o,m.attr("class")))});if(a&&typeof a==="string")for(var b=(a||"").split(ca),d=0,f=this.length;d-1)return true;return false},val:function(a){if(a===v){var b=this[0];if(b){if(c.nodeName(b,"option"))return(b.attributes.value|| -{}).specified?b.value:b.text;if(c.nodeName(b,"select")){var d=b.selectedIndex,f=[],e=b.options;b=b.type==="select-one";if(d<0)return null;var i=b?d:0;for(d=b?d+1:e.length;i=0;else if(c.nodeName(this,"select")){var x=c.makeArray(s);c("option",this).each(function(){this.selected=c.inArray(c(this).val(),x)>=0});if(!x.length)this.selectedIndex=-1}else this.value=s}})}});c.extend({attrFn:{val:true,css:true,html:true,text:true,data:true,width:true,height:true,offset:true},attr:function(a,b,d,f){if(!a||a.nodeType===3||a.nodeType===8)return v;if(f&&b in c.attrFn)return c(a)[b](d); -f=a.nodeType!==1||!c.isXMLDoc(a);var e=d!==v;b=f&&c.props[b]||b;if(a.nodeType===1){var i=Xa.test(b);if(b in a&&f&&!i){if(e){b==="type"&&Ya.test(a.nodeName)&&a.parentNode&&c.error("type property can't be changed");a[b]=d}if(c.nodeName(a,"form")&&a.getAttributeNode(b))return a.getAttributeNode(b).nodeValue;if(b==="tabIndex")return(b=a.getAttributeNode("tabIndex"))&&b.specified?b.value:Za.test(a.nodeName)||$a.test(a.nodeName)&&a.href?0:v;return a[b]}if(!c.support.style&&f&&b==="style"){if(e)a.style.cssText= -""+d;return a.style.cssText}e&&a.setAttribute(b,""+d);a=!c.support.hrefNormalized&&f&&i?a.getAttribute(b,2):a.getAttribute(b);return a===null?v:a}return c.style(a,b,d)}});var ab=function(a){return a.replace(/[^\w\s\.\|`]/g,function(b){return"\\"+b})};c.event={add:function(a,b,d,f){if(!(a.nodeType===3||a.nodeType===8)){if(a.setInterval&&a!==z&&!a.frameElement)a=z;if(!d.guid)d.guid=c.guid++;if(f!==v){d=c.proxy(d);d.data=f}var e=c.data(a,"events")||c.data(a,"events",{}),i=c.data(a,"handle"),j;if(!i){j= -function(){return typeof c!=="undefined"&&!c.event.triggered?c.event.handle.apply(j.elem,arguments):v};i=c.data(a,"handle",j)}if(i){i.elem=a;b=b.split(/\s+/);for(var n,o=0;n=b[o++];){var m=n.split(".");n=m.shift();if(o>1){d=c.proxy(d);if(f!==v)d.data=f}d.type=m.slice(0).sort().join(".");var s=e[n],x=this.special[n]||{};if(!s){s=e[n]={};if(!x.setup||x.setup.call(a,f,m,d)===false)if(a.addEventListener)a.addEventListener(n,i,false);else a.attachEvent&&a.attachEvent("on"+n,i)}if(x.add)if((m=x.add.call(a, -d,f,m,s))&&c.isFunction(m)){m.guid=m.guid||d.guid;m.data=m.data||d.data;m.type=m.type||d.type;d=m}s[d.guid]=d;this.global[n]=true}a=null}}},global:{},remove:function(a,b,d){if(!(a.nodeType===3||a.nodeType===8)){var f=c.data(a,"events"),e,i,j;if(f){if(b===v||typeof b==="string"&&b.charAt(0)===".")for(i in f)this.remove(a,i+(b||""));else{if(b.type){d=b.handler;b=b.type}b=b.split(/\s+/);for(var n=0;i=b[n++];){var o=i.split(".");i=o.shift();var m=!o.length,s=c.map(o.slice(0).sort(),ab);s=new RegExp("(^|\\.)"+ -s.join("\\.(?:.*\\.)?")+"(\\.|$)");var x=this.special[i]||{};if(f[i]){if(d){j=f[i][d.guid];delete f[i][d.guid]}else for(var A in f[i])if(m||s.test(f[i][A].type))delete f[i][A];x.remove&&x.remove.call(a,o,j);for(e in f[i])break;if(!e){if(!x.teardown||x.teardown.call(a,o)===false)if(a.removeEventListener)a.removeEventListener(i,c.data(a,"handle"),false);else a.detachEvent&&a.detachEvent("on"+i,c.data(a,"handle"));e=null;delete f[i]}}}}for(e in f)break;if(!e){if(A=c.data(a,"handle"))A.elem=null;c.removeData(a, -"events");c.removeData(a,"handle")}}}},trigger:function(a,b,d,f){var e=a.type||a;if(!f){a=typeof a==="object"?a[G]?a:c.extend(c.Event(e),a):c.Event(e);if(e.indexOf("!")>=0){a.type=e=e.slice(0,-1);a.exclusive=true}if(!d){a.stopPropagation();this.global[e]&&c.each(c.cache,function(){this.events&&this.events[e]&&c.event.trigger(a,b,this.handle.elem)})}if(!d||d.nodeType===3||d.nodeType===8)return v;a.result=v;a.target=d;b=c.makeArray(b);b.unshift(a)}a.currentTarget=d;(f=c.data(d,"handle"))&&f.apply(d, -b);f=d.parentNode||d.ownerDocument;try{if(!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()]))if(d["on"+e]&&d["on"+e].apply(d,b)===false)a.result=false}catch(i){}if(!a.isPropagationStopped()&&f)c.event.trigger(a,b,f,true);else if(!a.isDefaultPrevented()){d=a.target;var j;if(!(c.nodeName(d,"a")&&e==="click")&&!(d&&d.nodeName&&c.noData[d.nodeName.toLowerCase()])){try{if(d[e]){if(j=d["on"+e])d["on"+e]=null;this.triggered=true;d[e]()}}catch(n){}if(j)d["on"+e]=j;this.triggered=false}}},handle:function(a){var b, -d;a=arguments[0]=c.event.fix(a||z.event);a.currentTarget=this;d=a.type.split(".");a.type=d.shift();b=!d.length&&!a.exclusive;var f=new RegExp("(^|\\.)"+d.slice(0).sort().join("\\.(?:.*\\.)?")+"(\\.|$)");d=(c.data(this,"events")||{})[a.type];for(var e in d){var i=d[e];if(b||f.test(i.type)){a.handler=i;a.data=i.data;i=i.apply(this,arguments);if(i!==v){a.result=i;if(i===false){a.preventDefault();a.stopPropagation()}}if(a.isImmediatePropagationStopped())break}}return a.result},props:"altKey attrChange attrName bubbles button cancelable charCode clientX clientY ctrlKey currentTarget data detail eventPhase fromElement handler keyCode layerX layerY metaKey newValue offsetX offsetY originalTarget pageX pageY prevValue relatedNode relatedTarget screenX screenY shiftKey srcElement target toElement view wheelDelta which".split(" "), -fix:function(a){if(a[G])return a;var b=a;a=c.Event(b);for(var d=this.props.length,f;d;){f=this.props[--d];a[f]=b[f]}if(!a.target)a.target=a.srcElement||r;if(a.target.nodeType===3)a.target=a.target.parentNode;if(!a.relatedTarget&&a.fromElement)a.relatedTarget=a.fromElement===a.target?a.toElement:a.fromElement;if(a.pageX==null&&a.clientX!=null){b=r.documentElement;d=r.body;a.pageX=a.clientX+(b&&b.scrollLeft||d&&d.scrollLeft||0)-(b&&b.clientLeft||d&&d.clientLeft||0);a.pageY=a.clientY+(b&&b.scrollTop|| -d&&d.scrollTop||0)-(b&&b.clientTop||d&&d.clientTop||0)}if(!a.which&&(a.charCode||a.charCode===0?a.charCode:a.keyCode))a.which=a.charCode||a.keyCode;if(!a.metaKey&&a.ctrlKey)a.metaKey=a.ctrlKey;if(!a.which&&a.button!==v)a.which=a.button&1?1:a.button&2?3:a.button&4?2:0;return a},guid:1E8,proxy:c.proxy,special:{ready:{setup:c.bindReady,teardown:c.noop},live:{add:function(a,b){c.extend(a,b||{});a.guid+=b.selector+b.live;b.liveProxy=a;c.event.add(this,b.live,na,b)},remove:function(a){if(a.length){var b= -0,d=new RegExp("(^|\\.)"+a[0]+"(\\.|$)");c.each(c.data(this,"events").live||{},function(){d.test(this.type)&&b++});b<1&&c.event.remove(this,a[0],na)}},special:{}},beforeunload:{setup:function(a,b,d){if(this.setInterval)this.onbeforeunload=d;return false},teardown:function(a,b){if(this.onbeforeunload===b)this.onbeforeunload=null}}}};c.Event=function(a){if(!this.preventDefault)return new c.Event(a);if(a&&a.type){this.originalEvent=a;this.type=a.type}else this.type=a;this.timeStamp=J();this[G]=true}; -c.Event.prototype={preventDefault:function(){this.isDefaultPrevented=Z;var a=this.originalEvent;if(a){a.preventDefault&&a.preventDefault();a.returnValue=false}},stopPropagation:function(){this.isPropagationStopped=Z;var a=this.originalEvent;if(a){a.stopPropagation&&a.stopPropagation();a.cancelBubble=true}},stopImmediatePropagation:function(){this.isImmediatePropagationStopped=Z;this.stopPropagation()},isDefaultPrevented:Y,isPropagationStopped:Y,isImmediatePropagationStopped:Y};var Aa=function(a){for(var b= -a.relatedTarget;b&&b!==this;)try{b=b.parentNode}catch(d){break}if(b!==this){a.type=a.data;c.event.handle.apply(this,arguments)}},Ba=function(a){a.type=a.data;c.event.handle.apply(this,arguments)};c.each({mouseenter:"mouseover",mouseleave:"mouseout"},function(a,b){c.event.special[a]={setup:function(d){c.event.add(this,b,d&&d.selector?Ba:Aa,a)},teardown:function(d){c.event.remove(this,b,d&&d.selector?Ba:Aa)}}});if(!c.support.submitBubbles)c.event.special.submit={setup:function(a,b,d){if(this.nodeName.toLowerCase()!== -"form"){c.event.add(this,"click.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="submit"||i==="image")&&c(e).closest("form").length)return ma("submit",this,arguments)});c.event.add(this,"keypress.specialSubmit."+d.guid,function(f){var e=f.target,i=e.type;if((i==="text"||i==="password")&&c(e).closest("form").length&&f.keyCode===13)return ma("submit",this,arguments)})}else return false},remove:function(a,b){c.event.remove(this,"click.specialSubmit"+(b?"."+b.guid:""));c.event.remove(this, -"keypress.specialSubmit"+(b?"."+b.guid:""))}};if(!c.support.changeBubbles){var da=/textarea|input|select/i;function Ca(a){var b=a.type,d=a.value;if(b==="radio"||b==="checkbox")d=a.checked;else if(b==="select-multiple")d=a.selectedIndex>-1?c.map(a.options,function(f){return f.selected}).join("-"):"";else if(a.nodeName.toLowerCase()==="select")d=a.selectedIndex;return d}function ea(a,b){var d=a.target,f,e;if(!(!da.test(d.nodeName)||d.readOnly)){f=c.data(d,"_change_data");e=Ca(d);if(a.type!=="focusout"|| -d.type!=="radio")c.data(d,"_change_data",e);if(!(f===v||e===f))if(f!=null||e){a.type="change";return c.event.trigger(a,b,d)}}}c.event.special.change={filters:{focusout:ea,click:function(a){var b=a.target,d=b.type;if(d==="radio"||d==="checkbox"||b.nodeName.toLowerCase()==="select")return ea.call(this,a)},keydown:function(a){var b=a.target,d=b.type;if(a.keyCode===13&&b.nodeName.toLowerCase()!=="textarea"||a.keyCode===32&&(d==="checkbox"||d==="radio")||d==="select-multiple")return ea.call(this,a)},beforeactivate:function(a){a= -a.target;a.nodeName.toLowerCase()==="input"&&a.type==="radio"&&c.data(a,"_change_data",Ca(a))}},setup:function(a,b,d){for(var f in T)c.event.add(this,f+".specialChange."+d.guid,T[f]);return da.test(this.nodeName)},remove:function(a,b){for(var d in T)c.event.remove(this,d+".specialChange"+(b?"."+b.guid:""),T[d]);return da.test(this.nodeName)}};var T=c.event.special.change.filters}r.addEventListener&&c.each({focus:"focusin",blur:"focusout"},function(a,b){function d(f){f=c.event.fix(f);f.type=b;return c.event.handle.call(this, -f)}c.event.special[b]={setup:function(){this.addEventListener(a,d,true)},teardown:function(){this.removeEventListener(a,d,true)}}});c.each(["bind","one"],function(a,b){c.fn[b]=function(d,f,e){if(typeof d==="object"){for(var i in d)this[b](i,f,d[i],e);return this}if(c.isFunction(f)){e=f;f=v}var j=b==="one"?c.proxy(e,function(n){c(this).unbind(n,j);return e.apply(this,arguments)}):e;return d==="unload"&&b!=="one"?this.one(d,f,e):this.each(function(){c.event.add(this,d,j,f)})}});c.fn.extend({unbind:function(a, -b){if(typeof a==="object"&&!a.preventDefault){for(var d in a)this.unbind(d,a[d]);return this}return this.each(function(){c.event.remove(this,a,b)})},trigger:function(a,b){return this.each(function(){c.event.trigger(a,b,this)})},triggerHandler:function(a,b){if(this[0]){a=c.Event(a);a.preventDefault();a.stopPropagation();c.event.trigger(a,b,this[0]);return a.result}},toggle:function(a){for(var b=arguments,d=1;d0){y=t;break}}t=t[g]}l[q]=y}}}var f=/((?:\((?:\([^()]+\)|[^()]+)+\)|\[(?:\[[^[\]]*\]|['"][^'"]*['"]|[^[\]'"]+)+\]|\\.|[^ >+~,(\[\\]+)+|[>+~])(\s*,\s*)?((?:.|\r|\n)*)/g,e=0,i=Object.prototype.toString,j=false,n=true;[0,0].sort(function(){n=false;return 0});var o=function(g,h,k,l){k=k||[];var q=h=h||r;if(h.nodeType!==1&&h.nodeType!==9)return[];if(!g|| -typeof g!=="string")return k;for(var p=[],u,t,y,R,H=true,M=w(h),I=g;(f.exec(""),u=f.exec(I))!==null;){I=u[3];p.push(u[1]);if(u[2]){R=u[3];break}}if(p.length>1&&s.exec(g))if(p.length===2&&m.relative[p[0]])t=fa(p[0]+p[1],h);else for(t=m.relative[p[0]]?[h]:o(p.shift(),h);p.length;){g=p.shift();if(m.relative[g])g+=p.shift();t=fa(g,t)}else{if(!l&&p.length>1&&h.nodeType===9&&!M&&m.match.ID.test(p[0])&&!m.match.ID.test(p[p.length-1])){u=o.find(p.shift(),h,M);h=u.expr?o.filter(u.expr,u.set)[0]:u.set[0]}if(h){u= -l?{expr:p.pop(),set:A(l)}:o.find(p.pop(),p.length===1&&(p[0]==="~"||p[0]==="+")&&h.parentNode?h.parentNode:h,M);t=u.expr?o.filter(u.expr,u.set):u.set;if(p.length>0)y=A(t);else H=false;for(;p.length;){var D=p.pop();u=D;if(m.relative[D])u=p.pop();else D="";if(u==null)u=h;m.relative[D](y,u,M)}}else y=[]}y||(y=t);y||o.error(D||g);if(i.call(y)==="[object Array]")if(H)if(h&&h.nodeType===1)for(g=0;y[g]!=null;g++){if(y[g]&&(y[g]===true||y[g].nodeType===1&&E(h,y[g])))k.push(t[g])}else for(g=0;y[g]!=null;g++)y[g]&& -y[g].nodeType===1&&k.push(t[g]);else k.push.apply(k,y);else A(y,k);if(R){o(R,q,k,l);o.uniqueSort(k)}return k};o.uniqueSort=function(g){if(C){j=n;g.sort(C);if(j)for(var h=1;h":function(g,h){var k=typeof h==="string";if(k&&!/\W/.test(h)){h=h.toLowerCase();for(var l=0,q=g.length;l=0))k||l.push(u);else if(k)h[p]=false;return false},ID:function(g){return g[1].replace(/\\/g,"")},TAG:function(g){return g[1].toLowerCase()},CHILD:function(g){if(g[1]==="nth"){var h=/(-?)(\d*)n((?:\+|-)?\d*)/.exec(g[2]==="even"&&"2n"||g[2]==="odd"&& -"2n+1"||!/\D/.test(g[2])&&"0n+"+g[2]||g[2]);g[2]=h[1]+(h[2]||1)-0;g[3]=h[3]-0}g[0]=e++;return g},ATTR:function(g,h,k,l,q,p){h=g[1].replace(/\\/g,"");if(!p&&m.attrMap[h])g[1]=m.attrMap[h];if(g[2]==="~=")g[4]=" "+g[4]+" ";return g},PSEUDO:function(g,h,k,l,q){if(g[1]==="not")if((f.exec(g[3])||"").length>1||/^\w/.test(g[3]))g[3]=o(g[3],null,null,h);else{g=o.filter(g[3],h,k,true^q);k||l.push.apply(l,g);return false}else if(m.match.POS.test(g[0])||m.match.CHILD.test(g[0]))return true;return g},POS:function(g){g.unshift(true); -return g}},filters:{enabled:function(g){return g.disabled===false&&g.type!=="hidden"},disabled:function(g){return g.disabled===true},checked:function(g){return g.checked===true},selected:function(g){return g.selected===true},parent:function(g){return!!g.firstChild},empty:function(g){return!g.firstChild},has:function(g,h,k){return!!o(k[3],g).length},header:function(g){return/h\d/i.test(g.nodeName)},text:function(g){return"text"===g.type},radio:function(g){return"radio"===g.type},checkbox:function(g){return"checkbox"=== -g.type},file:function(g){return"file"===g.type},password:function(g){return"password"===g.type},submit:function(g){return"submit"===g.type},image:function(g){return"image"===g.type},reset:function(g){return"reset"===g.type},button:function(g){return"button"===g.type||g.nodeName.toLowerCase()==="button"},input:function(g){return/input|select|textarea|button/i.test(g.nodeName)}},setFilters:{first:function(g,h){return h===0},last:function(g,h,k,l){return h===l.length-1},even:function(g,h){return h%2=== -0},odd:function(g,h){return h%2===1},lt:function(g,h,k){return hk[3]-0},nth:function(g,h,k){return k[3]-0===h},eq:function(g,h,k){return k[3]-0===h}},filter:{PSEUDO:function(g,h,k,l){var q=h[1],p=m.filters[q];if(p)return p(g,k,h,l);else if(q==="contains")return(g.textContent||g.innerText||a([g])||"").indexOf(h[3])>=0;else if(q==="not"){h=h[3];k=0;for(l=h.length;k= -0}},ID:function(g,h){return g.nodeType===1&&g.getAttribute("id")===h},TAG:function(g,h){return h==="*"&&g.nodeType===1||g.nodeName.toLowerCase()===h},CLASS:function(g,h){return(" "+(g.className||g.getAttribute("class"))+" ").indexOf(h)>-1},ATTR:function(g,h){var k=h[1];g=m.attrHandle[k]?m.attrHandle[k](g):g[k]!=null?g[k]:g.getAttribute(k);k=g+"";var l=h[2];h=h[4];return g==null?l==="!=":l==="="?k===h:l==="*="?k.indexOf(h)>=0:l==="~="?(" "+k+" ").indexOf(h)>=0:!h?k&&g!==false:l==="!="?k!==h:l==="^="? -k.indexOf(h)===0:l==="$="?k.substr(k.length-h.length)===h:l==="|="?k===h||k.substr(0,h.length+1)===h+"-":false},POS:function(g,h,k,l){var q=m.setFilters[h[2]];if(q)return q(g,k,h,l)}}},s=m.match.POS;for(var x in m.match){m.match[x]=new RegExp(m.match[x].source+/(?![^\[]*\])(?![^\(]*\))/.source);m.leftMatch[x]=new RegExp(/(^(?:.|\r|\n)*?)/.source+m.match[x].source.replace(/\\(\d+)/g,function(g,h){return"\\"+(h-0+1)}))}var A=function(g,h){g=Array.prototype.slice.call(g,0);if(h){h.push.apply(h,g);return h}return g}; -try{Array.prototype.slice.call(r.documentElement.childNodes,0)}catch(B){A=function(g,h){h=h||[];if(i.call(g)==="[object Array]")Array.prototype.push.apply(h,g);else if(typeof g.length==="number")for(var k=0,l=g.length;k";var k=r.documentElement;k.insertBefore(g,k.firstChild);if(r.getElementById(h)){m.find.ID=function(l,q,p){if(typeof q.getElementById!=="undefined"&&!p)return(q=q.getElementById(l[1]))?q.id===l[1]||typeof q.getAttributeNode!=="undefined"&&q.getAttributeNode("id").nodeValue===l[1]?[q]:v:[]};m.filter.ID=function(l,q){var p=typeof l.getAttributeNode!=="undefined"&&l.getAttributeNode("id"); -return l.nodeType===1&&p&&p.nodeValue===q}}k.removeChild(g);k=g=null})();(function(){var g=r.createElement("div");g.appendChild(r.createComment(""));if(g.getElementsByTagName("*").length>0)m.find.TAG=function(h,k){k=k.getElementsByTagName(h[1]);if(h[1]==="*"){h=[];for(var l=0;k[l];l++)k[l].nodeType===1&&h.push(k[l]);k=h}return k};g.innerHTML="";if(g.firstChild&&typeof g.firstChild.getAttribute!=="undefined"&&g.firstChild.getAttribute("href")!=="#")m.attrHandle.href=function(h){return h.getAttribute("href", -2)};g=null})();r.querySelectorAll&&function(){var g=o,h=r.createElement("div");h.innerHTML="

";if(!(h.querySelectorAll&&h.querySelectorAll(".TEST").length===0)){o=function(l,q,p,u){q=q||r;if(!u&&q.nodeType===9&&!w(q))try{return A(q.querySelectorAll(l),p)}catch(t){}return g(l,q,p,u)};for(var k in g)o[k]=g[k];h=null}}();(function(){var g=r.createElement("div");g.innerHTML="
";if(!(!g.getElementsByClassName||g.getElementsByClassName("e").length=== -0)){g.lastChild.className="e";if(g.getElementsByClassName("e").length!==1){m.order.splice(1,0,"CLASS");m.find.CLASS=function(h,k,l){if(typeof k.getElementsByClassName!=="undefined"&&!l)return k.getElementsByClassName(h[1])};g=null}}})();var E=r.compareDocumentPosition?function(g,h){return g.compareDocumentPosition(h)&16}:function(g,h){return g!==h&&(g.contains?g.contains(h):true)},w=function(g){return(g=(g?g.ownerDocument||g:0).documentElement)?g.nodeName!=="HTML":false},fa=function(g,h){var k=[], -l="",q;for(h=h.nodeType?[h]:h;q=m.match.PSEUDO.exec(g);){l+=q[0];g=g.replace(m.match.PSEUDO,"")}g=m.relative[g]?g+"*":g;q=0;for(var p=h.length;q=0===d})};c.fn.extend({find:function(a){for(var b=this.pushStack("","find",a),d=0,f=0,e=this.length;f0)for(var i=d;i0},closest:function(a,b){if(c.isArray(a)){var d=[],f=this[0],e,i={},j;if(f&&a.length){e=0;for(var n=a.length;e --1:c(f).is(e)){d.push({selector:j,elem:f});delete i[j]}}f=f.parentNode}}return d}var o=c.expr.match.POS.test(a)?c(a,b||this.context):null;return this.map(function(m,s){for(;s&&s.ownerDocument&&s!==b;){if(o?o.index(s)>-1:c(s).is(a))return s;s=s.parentNode}return null})},index:function(a){if(!a||typeof a==="string")return c.inArray(this[0],a?c(a):this.parent().children());return c.inArray(a.jquery?a[0]:a,this)},add:function(a,b){a=typeof a==="string"?c(a,b||this.context):c.makeArray(a);b=c.merge(this.get(), -a);return this.pushStack(pa(a[0])||pa(b[0])?b:c.unique(b))},andSelf:function(){return this.add(this.prevObject)}});c.each({parent:function(a){return(a=a.parentNode)&&a.nodeType!==11?a:null},parents:function(a){return c.dir(a,"parentNode")},parentsUntil:function(a,b,d){return c.dir(a,"parentNode",d)},next:function(a){return c.nth(a,2,"nextSibling")},prev:function(a){return c.nth(a,2,"previousSibling")},nextAll:function(a){return c.dir(a,"nextSibling")},prevAll:function(a){return c.dir(a,"previousSibling")}, -nextUntil:function(a,b,d){return c.dir(a,"nextSibling",d)},prevUntil:function(a,b,d){return c.dir(a,"previousSibling",d)},siblings:function(a){return c.sibling(a.parentNode.firstChild,a)},children:function(a){return c.sibling(a.firstChild)},contents:function(a){return c.nodeName(a,"iframe")?a.contentDocument||a.contentWindow.document:c.makeArray(a.childNodes)}},function(a,b){c.fn[a]=function(d,f){var e=c.map(this,b,d);bb.test(a)||(f=d);if(f&&typeof f==="string")e=c.filter(f,e);e=this.length>1?c.unique(e): -e;if((this.length>1||db.test(f))&&cb.test(a))e=e.reverse();return this.pushStack(e,a,Q.call(arguments).join(","))}});c.extend({filter:function(a,b,d){if(d)a=":not("+a+")";return c.find.matches(a,b)},dir:function(a,b,d){var f=[];for(a=a[b];a&&a.nodeType!==9&&(d===v||a.nodeType!==1||!c(a).is(d));){a.nodeType===1&&f.push(a);a=a[b]}return f},nth:function(a,b,d){b=b||1;for(var f=0;a;a=a[d])if(a.nodeType===1&&++f===b)break;return a},sibling:function(a,b){for(var d=[];a;a=a.nextSibling)a.nodeType===1&&a!== -b&&d.push(a);return d}});var Fa=/ jQuery\d+="(?:\d+|null)"/g,V=/^\s+/,Ga=/(<([\w:]+)[^>]*?)\/>/g,eb=/^(?:area|br|col|embed|hr|img|input|link|meta|param)$/i,Ha=/<([\w:]+)/,fb=/"},F={option:[1,""],legend:[1,"
","
"],thead:[1,"","
"],tr:[2,"","
"],td:[3,"","
"], -col:[2,"","
"],area:[1,"",""],_default:[0,"",""]};F.optgroup=F.option;F.tbody=F.tfoot=F.colgroup=F.caption=F.thead;F.th=F.td;if(!c.support.htmlSerialize)F._default=[1,"div
","
"];c.fn.extend({text:function(a){if(c.isFunction(a))return this.each(function(b){var d=c(this);d.text(a.call(this,b,d.text()))});if(typeof a!=="object"&&a!==v)return this.empty().append((this[0]&&this[0].ownerDocument||r).createTextNode(a));return c.getText(this)}, -wrapAll:function(a){if(c.isFunction(a))return this.each(function(d){c(this).wrapAll(a.call(this,d))});if(this[0]){var b=c(a,this[0].ownerDocument).eq(0).clone(true);this[0].parentNode&&b.insertBefore(this[0]);b.map(function(){for(var d=this;d.firstChild&&d.firstChild.nodeType===1;)d=d.firstChild;return d}).append(this)}return this},wrapInner:function(a){if(c.isFunction(a))return this.each(function(b){c(this).wrapInner(a.call(this,b))});return this.each(function(){var b=c(this),d=b.contents();d.length? -d.wrapAll(a):b.append(a)})},wrap:function(a){return this.each(function(){c(this).wrapAll(a)})},unwrap:function(){return this.parent().each(function(){c.nodeName(this,"body")||c(this).replaceWith(this.childNodes)}).end()},append:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.appendChild(a)})},prepend:function(){return this.domManip(arguments,true,function(a){this.nodeType===1&&this.insertBefore(a,this.firstChild)})},before:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments, -false,function(b){this.parentNode.insertBefore(b,this)});else if(arguments.length){var a=c(arguments[0]);a.push.apply(a,this.toArray());return this.pushStack(a,"before",arguments)}},after:function(){if(this[0]&&this[0].parentNode)return this.domManip(arguments,false,function(b){this.parentNode.insertBefore(b,this.nextSibling)});else if(arguments.length){var a=this.pushStack(this,"after",arguments);a.push.apply(a,c(arguments[0]).toArray());return a}},clone:function(a){var b=this.map(function(){if(!c.support.noCloneEvent&& -!c.isXMLDoc(this)){var d=this.outerHTML,f=this.ownerDocument;if(!d){d=f.createElement("div");d.appendChild(this.cloneNode(true));d=d.innerHTML}return c.clean([d.replace(Fa,"").replace(V,"")],f)[0]}else return this.cloneNode(true)});if(a===true){qa(this,b);qa(this.find("*"),b.find("*"))}return b},html:function(a){if(a===v)return this[0]&&this[0].nodeType===1?this[0].innerHTML.replace(Fa,""):null;else if(typeof a==="string"&&!/