diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 8362d52..9ac5ced 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -26,7 +26,7 @@ jobs: - name: Install dependencies run: | pip3 install pip-tools - make init + make install-dev - name: Lint run: | make lint diff --git a/Makefile b/Makefile index fc3a6a9..57414dc 100644 --- a/Makefile +++ b/Makefile @@ -10,9 +10,9 @@ help: @echo " help to get this help" init: - pip-sync && pip3 install -e . + pip3 install -e . -sync: +install-dev: pip-sync lint: diff --git a/docs/install.rst b/docs/install.rst index ab99378..2c3f89a 100644 --- a/docs/install.rst +++ b/docs/install.rst @@ -42,7 +42,7 @@ To contribute to the project, + Go in it: ``cd nachos`` + Install pip-tools: ``pip3 install pip-tools`` + Install virtualenv ``python3 -m venv venv; source venv/bin/activate`` -+ Install dependencies: ``make init``. ++ Install dependencies: ``make install-dev``. + Add upstream: ``git remote add upstream https://github.com/pierre-24/nachos.git`` + Don't forget to create a separate branch to implement your changes: ``git checkout -b my_branch upstream/dev``. diff --git a/docs/use.rst b/docs/use.rst index 76da071..1dbe90f 100644 --- a/docs/use.rst +++ b/docs/use.rst @@ -521,6 +521,12 @@ By using ``-d``, you can decide where the input files should be generated, but k The ``-V 1`` option allows you to know how much files where generated. + +.. warning:: + + When using electric fields, Gaussian compute the fields in an opposite direction to what is expected by Nachos. + So, e.g., if the title card say that the field is computed in the +x direction it is the **normal behavior** that the x component of the electric field has a negative sign. + .. note:: To helps the dalton program, a file called ``inputs_matching.txt`` is created for this *flavor*, where each lines contains the combination of dal and mol file to launch (because there may be different dal files). diff --git a/nachos/__init__.py b/nachos/__init__.py index 39d9ad2..fa90d81 100644 --- a/nachos/__init__.py +++ b/nachos/__init__.py @@ -11,34 +11,6 @@ __email__ = 'pierre.beaujean@unamur.be' __status__ = 'Development' -# List of the scripts that are installed, without the .py extension. The name is used to give the command name. -provide_scripts = [ - 'make', - 'prepare', - 'cook', - 'bake', - 'shake', - 'analyze', - 'peek' -] - - -def make_console_scripts(package_name='nachos'): - """Function used to generate the ``console_scripts`` list for ``setup.py`` - - :rtype: list - """ - - console_scripts = [] - for script in provide_scripts: - path = os.path.join(package_name, script + '.py') - if not os.path.isfile(path): - raise FileNotFoundError(path) - - console_scripts.append('{0} = {1}.{2}:main'.format('nachos_' + script, package_name, script)) - - return console_scripts - def is_dir(dirname): """Checks if a path is an actual directory""" diff --git a/nachos/core/__init__.py b/nachos/core/__init__.py index 91869b0..72ec56b 100644 --- a/nachos/core/__init__.py +++ b/nachos/core/__init__.py @@ -86,6 +86,13 @@ } } +GAUSSIAN_DOUBLE_HYBRIDS = [ + 'B2PLYP', 'B2PLYPD', 'B2PLYPD3', + 'mPW2PLYP', 'mPW2PLYPD', + 'DSDPBEP86', + 'PBE0DH', 'PBEQIDH' +] + def compute_numerical_derivative_of_tensor( recipe, basis, derivative_repr, tensor_func, frequency=None, dry_run=False, force_choice=None, **kwargs): diff --git a/nachos/core/baking.py b/nachos/core/baking.py index 97e0b29..0d3835b 100644 --- a/nachos/core/baking.py +++ b/nachos/core/baking.py @@ -261,10 +261,10 @@ def output_information( basis_name)) out.write('\n------------------------------------------------------\n') - out.write(' F V(F) V(F)-V(0)\n') + out.write(' F V(F) V(F)-V(0)\n') out.write('------------------------------------------------------\n') zero_field_val = tensor_access( - [0] * len(field), 0, initial_derivative, False, b_coo, final_result.frequency, recipe) + [0] * len(field), 0, initial_derivative, b_coo, final_result.frequency, recipe) for i, c in enumerate(all_fields): k = i - recipe['k_max'] @@ -274,7 +274,7 @@ def output_information( field_val = recipe['min_field'] * recipe['ratio'] ** (abs(k) - 1) * (-1 if k < 0 else 1) val = tensor_access( - c, 0, initial_derivative, False, b_coo, final_result.frequency, recipe) + c, 0, initial_derivative, b_coo, final_result.frequency, recipe) dV = val - zero_field_val out.write( '{: .7f} {: .14e} {: .14e}\n'.format( diff --git a/nachos/core/cooking.py b/nachos/core/cooking.py index ba7c148..76ccd63 100644 --- a/nachos/core/cooking.py +++ b/nachos/core/cooking.py @@ -7,7 +7,7 @@ from qcip_tools import quantities, derivatives, derivatives_e from qcip_tools.chemistry_files import helpers, PropertyNotPresent, PropertyNotDefined -from nachos.core import files, preparing +from nachos.core import files, preparing, GAUSSIAN_DOUBLE_HYBRIDS from nachos.qcip_tools_ext import gaussian, qchem # noqa @@ -110,6 +110,11 @@ def almost_the_same(a, b, threshold=1e-3): if self.recipe['type'] == 'F': try: real_fields = f.property('n:input_electric_field')[1:4] + + if f.file_type in ['GAUSSIAN_FCHK', 'GAUSSIAN_LOG']: + # Gaussian computes actually for the opposite field! + real_fields = list(-x for x in real_fields) + except PropertyNotPresent: raise BadCooking('F derivative but not electric field for {}'.format(name)) else: @@ -143,6 +148,8 @@ def almost_the_same(a, b, threshold=1e-3): key = self.recipe['method'] if key == 'DFT': key = 'SCF/DFT' + if self.recipe['flavor_extra']['XC'] in GAUSSIAN_DOUBLE_HYBRIDS: + key = 'MP2' # Gaussian puts the result in the MP2 field instead of SCF/DFT. energy = energies[key] # tries to catch the energy for the correct method obtained.append('energy:' + self.recipe['method']) else: # ?!? diff --git a/nachos/core/files.py b/nachos/core/files.py index 2406e49..3a3ab0a 100644 --- a/nachos/core/files.py +++ b/nachos/core/files.py @@ -376,7 +376,7 @@ def read(self, path): self.results[t_fields] = chemistry_datafile.ChemistryDataFile.read_derivatives_from_group( fields_group[i], dof) - def tensor_element_access(self, fields, min_field, basis, inverse, component, frequency, recipe): + def tensor_element_access(self, fields, min_field, basis, component, frequency, recipe): t_fields = tuple(fields) if t_fields not in self.results: raise BadResult('fields {} is not available'.format(fields)) @@ -398,7 +398,7 @@ def tensor_element_access(self, fields, min_field, basis, inverse, component, fr if len(component) != results.representation.order(): raise BadResult('shape does not match for {}'.format(b_repr)) - return (-1. if inverse else 1.) * results.components[component] + return results.components[component] @staticmethod def get_recipe_check_data(recipe): diff --git a/nachos/core/preparing.py b/nachos/core/preparing.py index d263d24..94dd1be 100644 --- a/nachos/core/preparing.py +++ b/nachos/core/preparing.py @@ -240,6 +240,9 @@ def prepare_gaussian_inputs(self, dry_run=False): fi.title = 'field({})='.format(level) + \ ','.join(Preparer.nonzero_fields(fields, self.recipe.geometry, self.recipe['type'])) + if self.recipe['type'] == 'F': + fi.title += '\nNote: E-field in the opposite direction is used.' + fi.options['nprocshared'] = self.recipe['flavor_extra']['procs'] fi.options['mem'] = self.recipe['flavor_extra']['memory'] fi.options['chk'] = 'xxx' @@ -281,7 +284,7 @@ def prepare_gaussian_inputs(self, dry_run=False): fi.other_blocks.extend(extra_sections_before) if self.recipe['type'] == 'F': - fi.other_blocks.append(['\t'.join(['{: .10f}'.format(a) for a in real_fields])]) + fi.other_blocks.append(['\t'.join(['{: .10f}'.format(-a) for a in real_fields])]) if extra_sections: fi.other_blocks.extend(extra_sections) diff --git a/nachos/qcip_tools_ext/gaussian.py b/nachos/qcip_tools_ext/gaussian.py index 25e355c..cdb6258 100644 --- a/nachos/qcip_tools_ext/gaussian.py +++ b/nachos/qcip_tools_ext/gaussian.py @@ -46,81 +46,6 @@ def _find_in_links(obj, q, links): return -1 -@gaussian.Output.define_property('computed_energies') -def gaussian__Output__get_computed_energies(obj, *args, **kwargs): - """Get the energies... Actually, "only" - + HF and DFT energy (in link 502/503/506/508) - + MP2 energy (in link 804/903/905/906) - + MP3, CCSD and CCSD(T) energy (in link 913) - - :param obj: object - :type obj: qcip_tools.chemistry_files.gaussian.Output - :rtype: dict - """ - energies = {} - modified_gaussian = False # pristine Gaussian 16 - - # fetch HF or DFT energy - n = _find_in_links(obj, 'SCF Done:', [502, 503, 506, 508]) - if n > 0: - chunks = obj.lines[n][12:].split() - e = float(chunks[2]) - if (len(chunks[2]) - chunks[2].find('.')) != 9: - modified_gaussian = True - else: # try to fetch more decimals above: "E = xxx" contains eleven of them - for line in reversed(obj.lines[:n]): - if 'Delta-E=' in line: - e = float(line.split()[1]) - break - elif 'Cycle' in line: - break - - if 'HF' in chunks[0]: - energies['HF'] = e - else: - energies['SCF/DFT'] = e - - energies['total'] = e - - # fetch MP2 energies - n = _find_in_links(obj, 'EUMP2 =', [804, 903, 905, 906]) - if n > 0: - chunk = obj.lines[n].split()[-1] - if not modified_gaussian: - chunk = chunk.replace('D', 'E') - - energies['MP2'] = float(chunk) - energies['total'] = energies['MP2'] - - # fetch MP3 energies - n = _find_in_links(obj, 'EUMP3=', [913]) - if n > 0: - chunk = obj.lines[n].split()[-1] - if not modified_gaussian: - chunk = chunk.replace('D', 'E') - energies['MP3'] = float(chunk) - - # fetch CCSD energies - n = obj.search('Wavefunction amplitudes converged.', into=913) - if n > 0: - chunk = obj.lines[n - 3][:-16].split()[-1] - if not modified_gaussian: - chunk = chunk.replace('D', 'E') - energies['CCSD'] = float(chunk) - energies['total'] = energies['CCSD'] - - # fetch CCSD(T) energies - n = obj.search('CCSD(T)=', into=913) - if n > 0: - chunk = obj.lines[n].split()[-1] - if not modified_gaussian: - chunk = chunk.replace('D', 'E') - energies['CCSD(T)'] = float(chunk) - energies['total'] = energies['CCSD(T)'] - - return energies - - @gaussian.Output.define_property('n:spin_components_e2') def gaussian__Output__get_spin_component_e2(obj, *args, **kwargs): """Get the spin components of E(2) (link 906) diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..3c75a54 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,51 @@ +[project] +name = "nachos" +dynamic = ["version"] +authors = [ + {name = "Pierre Beaujean", email = "pierre.beaujean@unamur.be"}, +] +description = "NACHOS: numerical differentiation code" +readme = "README.md" +requires-python = ">=3.7" +classifiers = [ + "Development Status :: 3 - Alpha", + "License :: OSI Approved :: MIT License", + "Natural Language :: English", + "Operating System :: OS Independent", + "Programming Language :: Python", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", +] +dependencies = [ + 'pyyaml>=5.0', + 'h5py', + 'qcip-tools @ git+https://github.com/pierre-24/qcip_tools.git@v0.7.1', + 'prompt_toolkit==1.0.15', + 'pandas>=1.2', + 'scipy>=1.7', + 'numpy>=1.20' +] + + +[project.urls] +documentation = "https://pierre-24.github.io/nachos/" +repository = "https://github.com/pierre-24/nachos.git" + +[project.scripts] + +# keep that alphabetical +nachos_make = 'nachos.make:main' +nachos_prepare = 'nachos.prepare:main' +nachos_cook = 'nachos.cook:main' +nachos_bake = 'nachos.bake:main' +nachos_shake = 'nachos.shake:main' +nachos_analyze = 'nachos.analyze:main' +nachos_peek = 'nachos.peek:main' + +[tool.setuptools] +packages = ['nachos', 'nachos.core', 'nachos.qcip_tools_ext'] + +[tool.setuptools.dynamic] +version = {attr = "nachos.__version__"} \ No newline at end of file diff --git a/requirements/requirements.in b/requirements.in similarity index 71% rename from requirements/requirements.in rename to requirements.in index a55d8e2..fa71b65 100644 --- a/requirements/requirements.in +++ b/requirements.in @@ -1,5 +1,5 @@ --r requirements-base.in -flake8 +-e file:. #egg=nachos +flake8<6.0 flake8-quotes autopep8 sphinxcontrib-autoprogram diff --git a/requirements.txt b/requirements.txt index 10c2418..fcfb251 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,107 +1,103 @@ # -# This file is autogenerated by pip-compile with python 3.9 -# To update, run: +# This file is autogenerated by pip-compile with Python 3.11 +# by the following command: # -# pip-compile --output-file=requirements.txt requirements/requirements.in +# pip-compile requirements.in # +-e file:. + # via -r requirements.in alabaster==0.7.12 # via sphinx -autopep8==1.6.0 - # via -r requirements/requirements.in -babel==2.9.1 +autopep8==2.0.0 + # via -r requirements.in +babel==2.11.0 # via sphinx -beautifulsoup4==4.10.0 +beautifulsoup4==4.11.1 # via qcip-tools bump2version==1.0.1 - # via -r requirements/requirements.in -certifi==2021.10.8 + # via -r requirements.in +certifi==2022.12.7 # via requests -charset-normalizer==2.0.10 +charset-normalizer==2.1.1 # via requests -colorama==0.4.4 +colorama==0.4.6 # via mendeleev docutils==0.17.1 # via # sphinx # sphinx-rtd-theme -flake8==4.0.1 +flake8==5.0.4 # via - # -r requirements/requirements.in + # -r requirements.in # flake8-quotes flake8-quotes==3.3.1 - # via -r requirements/requirements.in -greenlet==1.1.2 + # via -r requirements.in +greenlet==2.0.1 # via sqlalchemy -h5py==3.6.0 +h5py==3.7.0 # via - # -r requirements/requirements-base.in + # nachos # qcip-tools -idna==3.3 +idna==3.4 # via requests -imagesize==1.3.0 +imagesize==1.4.1 # via sphinx -importlib-metadata==4.11.3 - # via sphinx -jinja2==3.1.1 +jinja2==3.1.2 # via sphinx markupsafe==2.1.1 # via jinja2 -mccabe==0.6.1 +mccabe==0.7.0 # via flake8 -mendeleev==0.9.0 +mendeleev==0.12.1 # via qcip-tools -numpy==1.22.1 +numpy==1.23.5 # via - # -r requirements/requirements-base.in # h5py # mendeleev + # nachos # pandas # qcip-tools # scipy -packaging==21.3 - # via - # pint - # sphinx -pandas==1.4.0 +packaging==22.0 + # via sphinx +pandas==1.5.2 # via - # -r requirements/requirements-base.in # mendeleev + # nachos # qcip-tools -pint==0.18 +pint==0.20.1 # via qcip-tools -prompt_toolkit==1.0.15 - # via -r requirements/requirements-base.in -pycodestyle==2.8.0 +prompt-toolkit==1.0.15 + # via nachos +pycodestyle==2.9.1 # via # autopep8 # flake8 pyfiglet==0.8.post1 # via mendeleev -pyflakes==2.4.0 +pyflakes==2.5.0 # via flake8 -pygments==2.11.2 +pygments==2.13.0 # via # mendeleev # sphinx -pyparsing==3.0.7 - # via packaging python-dateutil==2.8.2 # via pandas -pytz==2021.3 +pytz==2022.6 # via # babel # pandas pyyaml==6.0 - # via -r requirements/requirements-base.in -git+https://github.com/pierre-24/qcip_tools.git@v0.6.9 - # via -r requirements/requirements-base.in -requests==2.27.1 + # via nachos +qcip-tools @ git+https://github.com/pierre-24/qcip_tools.git@v0.7.1 + # via nachos +requests==2.28.1 # via # qcip-tools # sphinx -scipy==1.7.3 +scipy==1.9.3 # via - # -r requirements/requirements-base.in + # nachos # qcip-tools six==1.16.0 # via @@ -111,19 +107,19 @@ six==1.16.0 # sphinxcontrib-autoprogram snowballstemmer==2.2.0 # via sphinx -soupsieve==2.3.1 +soupsieve==2.3.2.post1 # via beautifulsoup4 -sphinx==4.5.0 +sphinx==5.3.0 # via - # -r requirements/requirements.in + # -r requirements.in # sphinx-rtd-theme # sphinxcontrib-autoprogram -sphinx-rtd-theme==1.0.0 - # via -r requirements/requirements.in +sphinx-rtd-theme==1.1.1 + # via -r requirements.in sphinxcontrib-applehelp==1.0.2 # via sphinx sphinxcontrib-autoprogram==0.1.7 - # via -r requirements/requirements.in + # via -r requirements.in sphinxcontrib-devhelp==1.0.2 # via sphinx sphinxcontrib-htmlhelp==2.0.0 @@ -134,15 +130,13 @@ sphinxcontrib-qthelp==1.0.3 # via sphinx sphinxcontrib-serializinghtml==1.1.5 # via sphinx -sqlalchemy==1.4.31 +sqlalchemy==1.4.45 # via mendeleev -toml==0.10.2 +tomli==2.0.1 # via autopep8 -transforms3d==0.3.1 +transforms3d==0.4.1 # via qcip-tools -urllib3==1.26.8 +urllib3==1.26.13 # via requests wcwidth==0.2.5 # via prompt-toolkit -zipp==3.7.0 - # via importlib-metadata diff --git a/requirements/requirements-base.in b/requirements/requirements-base.in deleted file mode 100644 index f52ea74..0000000 --- a/requirements/requirements-base.in +++ /dev/null @@ -1,7 +0,0 @@ -pyyaml>=5.0 -h5py -qcip-tools @ git+https://github.com/pierre-24/qcip_tools.git@v0.6.10 -prompt_toolkit==1.0.15 -pandas>=1.2 -scipy>=1.7 -numpy>=1.20 \ No newline at end of file diff --git a/setup.py b/setup.py deleted file mode 100644 index 300a5f0..0000000 --- a/setup.py +++ /dev/null @@ -1,60 +0,0 @@ -from setuptools import setup, find_packages -from os import path - -import nachos - -here = path.abspath(path.dirname(__file__)) - -# Get the long description from the README file -with open(path.join(here, 'README.md')) as f: - long_description = f.read() - -with open(path.join(here, 'requirements/requirements-base.in')) as f: - requirements = f.readlines() - -with open(path.join(here, 'requirements/requirements.in')) as f: - requirements_dev = f.readlines()[1:] - -setup( - name='nachos', - version=nachos.__version__, - - # Description - description=nachos.__doc__, - long_description=long_description, - long_description_content_type='text/markdown', - keywords='website', - - project_urls={ - 'Bug Reports': 'https://github.com/pierre-24/nachos/issues', - 'Source': 'https://github.com/pierre-24/nachos', - }, - - url='https://github.com/pierre-24/nachos', - author=nachos.__author__, - - # Classifiers - classifiers=[ - 'Environment :: Scientific', - 'Operating System :: OS Independent', - - # Specify the Python versions: - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.8', - 'Programming Language :: Python :: 3.9' - ], - - packages=find_packages(), - python_requires='>=3.8', - test_suite='tests', - entry_points={ - 'console_scripts': nachos.make_console_scripts() - }, - - # requirements - install_requires=requirements, - - extras_require={ # Optional - 'dev': requirements_dev, - }, -) diff --git a/tests/__init__.py b/tests/__init__.py index 217b525..2070a7b 100644 --- a/tests/__init__.py +++ b/tests/__init__.py @@ -5,6 +5,7 @@ import tempfile import shutil import zipfile +import pathlib from qcip_tools import derivatives @@ -109,7 +110,6 @@ def run_python_script( self, path, args=None, - cwd='.', in_pipe=subprocess.DEVNULL, out_pipe=subprocess.DEVNULL, err_pipe=subprocess.DEVNULL): @@ -128,8 +128,10 @@ def run_python_script( :rtype: subprocess.Popen """ - real_path = os.path.join(cwd, path) - if not os.path.isfile(real_path): + cwd = pathlib.Path(__file__).parent.parent + + real_path = cwd / path + if not real_path.is_file(): raise FileNotFoundError(real_path) cmd = ['python', path] diff --git a/tests/tests_files/numdiff_F.zip b/tests/tests_files/numdiff_F.zip index 5da2511..60fd6c2 100644 Binary files a/tests/tests_files/numdiff_F.zip and b/tests/tests_files/numdiff_F.zip differ diff --git a/tests/tests_files/numdiff_F_b2plyp.zip b/tests/tests_files/numdiff_F_b2plyp.zip new file mode 100644 index 0000000..50cae3e Binary files /dev/null and b/tests/tests_files/numdiff_F_b2plyp.zip differ diff --git a/tests/tests_files/numdiff_G.zip b/tests/tests_files/numdiff_G.zip index f66ad7e..51a147d 100644 Binary files a/tests/tests_files/numdiff_G.zip and b/tests/tests_files/numdiff_G.zip differ diff --git a/tests/tests_nachos_bake.py b/tests/tests_nachos_bake.py index 94ec672..f91f4ea 100644 --- a/tests/tests_nachos_bake.py +++ b/tests/tests_nachos_bake.py @@ -88,6 +88,17 @@ def test_bake_gaussian_F(self): electrical_derivatives['FFF']['static'], cf_with_alpha.derivatives['FFF']['static']) + # dynamic + cf_with_alpha = baker.bake(only=[(derivatives.Derivative('dD'), 1)]) + + self.assertIn('dDF', cf_with_alpha.derivatives) + self.assertEqual(len(cf_with_alpha.derivatives), 1) + + self.assertTensorsAlmostEqual( + electrical_derivatives['dDF'][0.0428226997], + cf_with_alpha.derivatives['dDF']['1064nm'], + skip_frequency_test=True) + # fire some errors: with self.assertRaises(baking.BadBaking): baker.bake(only=[(derivatives.Derivative(), 4)]) diff --git a/tests/tests_nachos_cook.py b/tests/tests_nachos_cook.py index 0b4e480..f8aa825 100644 --- a/tests/tests_nachos_cook.py +++ b/tests/tests_nachos_cook.py @@ -16,13 +16,13 @@ def setUp(self): self.zip_F = 'numdiff_F.zip' self.zip_F_qchem = 'numdiff_F_qchem.zip' self.zip_F_scs_mp2 = 'numdiff_F_SCS-MP2.zip' + self.zip_F_b2plyp = 'numdiff_F_b2plyp.zip' self.zip_G = 'numdiff_G.zip' self.zip_G_dalton = 'numdiff_G_dalton.zip' self.working_directory = self.setup_temporary_directory() def tearDown(self): super().tearDown() - pass def test_fields_from_deformed_geometry(self): """Test that the code is able to get back the fields from a deformed geometry""" @@ -97,11 +97,49 @@ def test_cook_F_gaussian(self): if level <= 1: self.assertTensorsAlmostEqual( electrical_derivatives['FF']['static'], results['FF']['static']) + self.assertTensorsAlmostEqual( - electrical_derivatives['dD'][0.0428227067], + electrical_derivatives['dD'][0.0428226997], results['dD']['1064nm'], skip_frequency_test=True) + def test_cook_F_gaussian_b2plyp(self): + """Check if B2PLYP data are similar to MP2 ones""" + + self.unzip_it(self.zip_F_b2plyp, self.working_directory) + directory = os.path.join(self.working_directory, 'numdiff_F_b2plyp') + path = os.path.join(directory, 'nachos_recipe.yml') + + r = files.Recipe(directory=directory) + + with open(path) as f: + r.read(f) + + fields = preparing.fields_needed_by_recipe(r) + + c = cooking.Cooker(r, directory) + storage = c.cook([directory]) + + # write and read + self.assertEqual(storage.check(), ([], [])) + + # check data + for _ in range(10): + n = random.randrange(1, len(fields) + 1) + fields_n, level = fields[n - 1] + t_fields = tuple(fields_n) + path = os.path.join(directory, r['name'] + '_{:04d}.fchk').format(n) + self.assertTrue(os.path.exists(path), msg=path) + with open(path) as f: + fx = gaussian.FCHK() + fx.read(f) + results = storage.results[t_fields] + + energies = fx.property('computed_energies') + + self.assertNotAlmostEqual(energies['SCF/DFT'], energies['MP2']) + self.assertAlmostEqual(energies['MP2'], results[''].components[0]) + def test_cook_G_gaussian(self): self.unzip_it(self.zip_G, self.working_directory) directory = os.path.join(self.working_directory, 'numdiff_G') @@ -254,6 +292,9 @@ def test_cook_F_qchem(self): def test_cook_F_scs_mp2(self): """Check that using SCS-MP2 is ok""" + + # TODO: relaunch calculation with the inverse E-fields + self.unzip_it(self.zip_F_scs_mp2, self.working_directory) directory = os.path.join(self.working_directory, 'numdiff_F_SCS-MP2') path = os.path.join(directory, 'nachos_recipe.yml') @@ -273,7 +314,7 @@ def test_cook_F_scs_mp2(self): for _ in range(10): n = random.randrange(1, len(fields) + 1) fields_n, level = fields[n - 1] - t_fields = tuple(fields_n) + t_fields = tuple(-x for x in fields_n) path = os.path.join(directory, r['name'] + '_{:04d}.log').format(n) self.assertTrue(os.path.exists(path), msg=path) with open(path) as f: @@ -297,37 +338,6 @@ def test_cook_F_scs_mp2(self): places=10 ) - def test_log_and_FCHK_energies_almost_equals(self): - self.unzip_it(self.zip_F_scs_mp2, self.working_directory) - directory = os.path.join(self.working_directory, 'numdiff_F_SCS-MP2') - path = os.path.join(directory, 'nachos_recipe.yml') - - r = files.Recipe(directory=directory) - - with open(path) as f: - r.read(f) - - fields = preparing.fields_needed_by_recipe(r) - - for m in ['HF', 'MP2', 'MP3', 'CCSD', 'CCSD(T)']: - r['method'] = m - - c = cooking.Cooker(r, directory) - - storage_from_fchk = c.cook([directory]) - storage_from_log = c.cook([directory], use_gaussian_logs=True) - - # check data randomly - for _ in range(5): - n = random.randrange(1, len(fields) + 1) - t_fields = tuple(fields[n - 1][0]) - - self.assertAlmostEqual( - storage_from_log.results[t_fields][''].components[0], - storage_from_fchk.results[t_fields][''].components[0], - places=10 - ) - def test_nachos_cook(self): """Test the cooker program""" diff --git a/tests/tests_nachos_prepare.py b/tests/tests_nachos_prepare.py index 8bdd7d8..19f0fcb 100644 --- a/tests/tests_nachos_prepare.py +++ b/tests/tests_nachos_prepare.py @@ -183,7 +183,7 @@ def test_preparer_for_F(self): self.assertEqual(fi.other_blocks[-2][0], 'O 0') self.assertEqual( - [float(a) for a in fi.other_blocks[-1][0].split()], + [-float(a) for a in fi.other_blocks[-1][0].split()], # Gaussian compute reverse field!! numerical_differentiation.real_fields(fields_n, min_field, 2.)) def test_preparer_for_G(self):