diff --git a/.git_archival.txt b/.git_archival.txt new file mode 100644 index 00000000..8fb235d7 --- /dev/null +++ b/.git_archival.txt @@ -0,0 +1,4 @@ +node: $Format:%H$ +node-date: $Format:%cI$ +describe-name: $Format:%(describe:tags=true,match=*[0-9]*)$ +ref-names: $Format:%D$ diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..00a7b00c --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +.git_archival.txt export-subst diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 00000000..650ff59e --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,23 @@ +name: Python package + +on: + - push + - pull_request + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: 3.12 + - run: curl -LsSf https://astral.sh/uv/install.sh | sh + - name: Install dependencies + run: uv pip install --system .[amber,ase,pymatgen,benchmark] rdkit openbabel-wheel + - name: Run benchmarks + uses: CodSpeedHQ/action@v2 + with: + token: ${{ secrets.CODSPEED_TOKEN }} + run: pytest benchmark/ --codspeed diff --git a/.github/workflows/pyright.yml b/.github/workflows/pyright.yml new file mode 100644 index 00000000..73dc81f1 --- /dev/null +++ b/.github/workflows/pyright.yml @@ -0,0 +1,19 @@ +on: + - push + - pull_request + +name: Type checker +jobs: + pyright: + name: pyright + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - uses: actions/setup-python@v5 + with: + python-version: '3.12' + - run: pip install uv + - run: uv pip install --system -e .[amber,ase,pymatgen] rdkit openbabel-wheel + - uses: jakebailey/pyright-action@v2 + with: + version: 1.1.363 diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e4d9a91f..4a17fcde 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -18,11 +18,9 @@ jobs: uses: actions/setup-python@v5 with: python-version: ${{ matrix.python-version }} - # install rdkit and openbabel - - name: Install rdkit - run: python -m pip install rdkit openbabel-wheel + - run: curl -LsSf https://astral.sh/uv/install.sh | sh - name: Install dependencies - run: python -m pip install .[amber,ase,pymatgen] coverage ./tests/plugin + run: uv pip install --system .[amber,ase,pymatgen] coverage ./tests/plugin rdkit openbabel-wheel - name: Test run: cd tests && coverage run --source=../dpdata -m unittest && cd .. && coverage combine tests/.coverage && coverage report - name: Run codecov diff --git a/.github/workflows/test_import.yml b/.github/workflows/test_import.yml index 6ab0dbe2..de2e53f5 100644 --- a/.github/workflows/test_import.yml +++ b/.github/workflows/test_import.yml @@ -1,17 +1,18 @@ -name: test Python import - -on: - - push - - pull_request - -jobs: - build: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - uses: actions/setup-python@v5 - with: - python-version: '3.9' - architecture: 'x64' - - run: python -m pip install . - - run: python -c 'import dpdata' +name: test Python import + +on: + - push + - pull_request + +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-python@v5 + with: + python-version: '3.9' + architecture: 'x64' + - run: python -m pip install uv + - run: python -m uv pip install --system . + - run: python -c 'import dpdata' diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a7a2afa8..d6baf8d0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: # there are many log files in tests # TODO: seperate py files and log files @@ -16,10 +16,12 @@ repos: - id: check-merge-conflict - id: check-symlinks - id: check-toml + - id: mixed-line-ending + args: ["--fix=lf"] # Python - repo: https://github.com/astral-sh/ruff-pre-commit # Ruff version. - rev: v0.3.5 + rev: v0.4.4 hooks: - id: ruff args: ["--fix"] diff --git a/benchmark/__init__.py b/benchmark/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/benchmark/test_import.py b/benchmark/test_import.py new file mode 100644 index 00000000..846d72b2 --- /dev/null +++ b/benchmark/test_import.py @@ -0,0 +1,20 @@ +from __future__ import annotations + +import subprocess +import sys + +import pytest + + +@pytest.mark.benchmark +def test_import(): + """Test import dpdata.""" + subprocess.check_output( + [sys.executable, "-c", "'from dpdata import LabeledSystem'"] + ).decode("ascii") + + +@pytest.mark.benchmark +def test_cli(): + """Test dpdata command.""" + subprocess.check_output([sys.executable, "-m", "dpdata", "-h"]).decode("ascii") diff --git a/docs/conf.py b/docs/conf.py index 0f9ff097..e3c0b3d4 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -11,6 +11,8 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # +from __future__ import annotations + import os import subprocess as sp import sys @@ -207,3 +209,4 @@ def setup(app): # jupyterlite jupyterlite_contents = "./nb" jupyterlite_bind_ipynb_suffix = False +jupyterlite_silence = False diff --git a/docs/credits.rst b/docs/credits.rst index 54fd9884..f8cfc843 100644 --- a/docs/credits.rst +++ b/docs/credits.rst @@ -1,4 +1,4 @@ -Authors -======= - +Authors +======= + .. git-shortlog-authors:: diff --git a/docs/environment.yml b/docs/environment.yml index b0a80ffa..89d2e5ca 100644 --- a/docs/environment.yml +++ b/docs/environment.yml @@ -1,8 +1,9 @@ name: dpdata channels: - https://repo.mamba.pm/emscripten-forge - - https://repo.mamba.pm/conda-forge + - conda-forge dependencies: + - xeus-python - numpy - scipy - monty diff --git a/docs/make_format.py b/docs/make_format.py index 4e78ce53..2b3c03c6 100644 --- a/docs/make_format.py +++ b/docs/make_format.py @@ -1,8 +1,15 @@ +from __future__ import annotations + import csv import os +import sys from collections import defaultdict from inspect import Parameter, Signature, cleandoc, signature -from typing import Literal + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal from numpydoc.docscrape import Parameter as numpydoc_Parameter from numpydoc.docscrape_sphinx import SphinxDocString @@ -134,13 +141,13 @@ def generate_sub_format_pages(formats: dict): for format, alias in formats.items(): # format: Format, alias: list[str] buff = [] - buff.append(".. _%s:" % format.__name__) + buff.append(f".. _{format.__name__}:") buff.append("") for aa in alias: - buff.append("%s format" % aa) + buff.append(f"{aa} format") buff.append("=" * len(buff[-1])) buff.append("") - buff.append("Class: %s" % get_cls_link(format)) + buff.append(f"Class: {get_cls_link(format)}") buff.append("") docstring = format.__doc__ @@ -158,10 +165,10 @@ def generate_sub_format_pages(formats: dict): buff.append(f".. _{format.__name__}_{method}:") buff.append("") if method.startswith("from_"): - buff.append("Convert from this format to %s" % method_classes[method]) + buff.append(f"Convert from this format to {method_classes[method]}") buff.append("`" * len(buff[-1])) elif method.startswith("to_"): - buff.append("Convert from %s to this format" % method_classes[method]) + buff.append(f"Convert from {method_classes[method]} to this format") buff.append("`" * len(buff[-1])) buff.append("") method_obj = getattr(format, method) @@ -224,10 +231,7 @@ def generate_sub_format_pages(formats: dict): buff.append(""" :noindex:""") buff.append("") if docstring is None or method not in format.__dict__: - docstring = ( - """ Convert this format to :class:`%s`.""" - % (method_classes[method]) - ) + docstring = f""" Convert this format to :class:`{method_classes[method]}`.""" doc_obj = SphinxDocString(docstring) if len(doc_obj["Parameters"]) > 0: doc_obj["Parameters"] = [ @@ -295,7 +299,7 @@ def generate_sub_format_pages(formats: dict): ) ): docstring = ( - "Convert :class:`%s` to this format." % (method_classes[method]) + f"Convert :class:`{method_classes[method]}` to this format." ) doc_obj = SphinxDocString(docstring) if len(doc_obj["Parameters"]) > 0: @@ -324,7 +328,7 @@ def generate_sub_format_pages(formats: dict): buff.append("") buff.append("") - with open("formats/%s.rst" % format.__name__, "w") as rstfile: + with open(f"formats/{format.__name__}.rst", "w") as rstfile: rstfile.write("\n".join(buff)) @@ -342,8 +346,8 @@ def generate_sub_format_pages(formats: dict): for kk, vv in formats.items(): writer.writerow( { - "Format": ":ref:`%s`" % kk.__name__, - "Alias": "\n".join("``%s``" % vvv for vvv in vv), + "Format": f":ref:`{kk.__name__}`", + "Alias": "\n".join(f"``{vvv}``" for vvv in vv), "Supported Conversions": "\n".join( method_links[mtd].format(kk.__name__, mtd) for mtd in check_supported(kk) @@ -364,7 +368,7 @@ def generate_sub_format_pages(formats: dict): writer.writerow( { "Class": get_cls_link(kk), - "Alias": "\n".join("``%s``" % vvv for vvv in vv), + "Alias": "\n".join(f"``{vvv}``" for vvv in vv), } ) @@ -381,7 +385,7 @@ def generate_sub_format_pages(formats: dict): writer.writerow( { "Class": get_cls_link(kk), - "Alias": "\n".join("``%s``" % vvv for vvv in vv), + "Alias": "\n".join(f"``{vvv}``" for vvv in vv), } ) generate_sub_format_pages(formats) diff --git a/docs/nb/try_dpdata.ipynb b/docs/nb/try_dpdata.ipynb index 7dc225b4..1a0a7328 100644 --- a/docs/nb/try_dpdata.ipynb +++ b/docs/nb/try_dpdata.ipynb @@ -13,6 +13,8 @@ "metadata": {}, "outputs": [], "source": [ + "from __future__ import annotations\n", + "\n", "import dpdata" ] }, diff --git a/docs/rtd_environment.yml b/docs/rtd_environment.yml index 2752fc1c..7eae4aad 100644 --- a/docs/rtd_environment.yml +++ b/docs/rtd_environment.yml @@ -1,6 +1,7 @@ name: dpdata channels: - - https://repo.mamba.pm/conda-forge + - conda-forge dependencies: + - mamba - pip: - ..[docs] diff --git a/dpdata/__about__.py b/dpdata/__about__.py index d5cfca64..3ee47d3c 100644 --- a/dpdata/__about__.py +++ b/dpdata/__about__.py @@ -1 +1,3 @@ +from __future__ import annotations + __version__ = "unknown" diff --git a/dpdata/__init__.py b/dpdata/__init__.py index dd853697..f2cd233f 100644 --- a/dpdata/__init__.py +++ b/dpdata/__init__.py @@ -1,17 +1,7 @@ -# monty needs lzma -# See https://github.com/pandas-dev/pandas/pull/27882 -try: - import lzma # noqa: F401 -except ImportError: - - class fakemodule: - pass - - import sys - - sys.modules["lzma"] = fakemodule +from __future__ import annotations from . import lammps, md, vasp +from .bond_order_system import BondOrderSystem from .system import LabeledSystem, MultiSystems, System try: @@ -19,18 +9,6 @@ class fakemodule: except ImportError: from .__about__ import __version__ -# BondOrder System has dependency on rdkit -try: - # prevent conflict with dpdata.rdkit - import rdkit as _ # noqa: F401 - - USE_RDKIT = True -except ModuleNotFoundError: - USE_RDKIT = False - -if USE_RDKIT: - from .bond_order_system import BondOrderSystem - __all__ = [ "__version__", "lammps", diff --git a/dpdata/__main__.py b/dpdata/__main__.py new file mode 100644 index 00000000..4c60f3f2 --- /dev/null +++ b/dpdata/__main__.py @@ -0,0 +1,6 @@ +from __future__ import annotations + +from dpdata.cli import dpdata_cli + +if __name__ == "__main__": + dpdata_cli() diff --git a/dpdata/abacus/md.py b/dpdata/abacus/md.py index 4b8ec038..fa184177 100644 --- a/dpdata/abacus/md.py +++ b/dpdata/abacus/md.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import warnings @@ -28,7 +30,7 @@ def get_path_out(fname, inlines): for line in inlines: if len(line) > 0 and "suffix" in line and "suffix" == line.split()[0]: suffix = line.split()[1] - path_out = os.path.join(fname, "OUT.%s/" % suffix) + path_out = os.path.join(fname, f"OUT.{suffix}/") break return path_out @@ -189,7 +191,7 @@ def get_frame(fname): unconv_stru += "%d " % i ndump = len(energy) if unconv_stru != "": - warnings.warn("Structure %s are unconverged and not collected!" % unconv_stru) + warnings.warn(f"Structure {unconv_stru} are unconverged and not collected!") for iframe in range(ndump): stress[iframe] *= np.linalg.det(cells[iframe, :, :].reshape([3, 3])) diff --git a/dpdata/abacus/relax.py b/dpdata/abacus/relax.py index 346120c4..976243b8 100644 --- a/dpdata/abacus/relax.py +++ b/dpdata/abacus/relax.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import numpy as np @@ -183,7 +185,7 @@ def get_frame(fname): ) logf = get_log_file(fname, inlines) - assert os.path.isfile(logf), "Error: can not find %s" % logf + assert os.path.isfile(logf), f"Error: can not find {logf}" with open(logf) as f1: lines = f1.readlines() diff --git a/dpdata/abacus/scf.py b/dpdata/abacus/scf.py index 975ef539..193e4d4b 100644 --- a/dpdata/abacus/scf.py +++ b/dpdata/abacus/scf.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import re import warnings @@ -23,7 +25,7 @@ def CheckFile(ifile): if not os.path.isfile(ifile): - print("Can not find file %s" % ifile) + print(f"Can not find file {ifile}") return False return True @@ -38,10 +40,10 @@ def get_block(lines, keyword, skip=0, nlines=None): found = True blk_idx = idx + 1 + skip line_idx = 0 - while len(re.split("\s+", lines[blk_idx])) == 0: + while len(re.split(r"\s+", lines[blk_idx])) == 0: blk_idx += 1 while line_idx < nlines and blk_idx != len(lines): - if len(re.split("\s+", lines[blk_idx])) == 0 or lines[blk_idx] == "": + if len(re.split(r"\s+", lines[blk_idx])) == 0 or lines[blk_idx] == "": blk_idx += 1 continue ret.append(lines[blk_idx]) @@ -91,7 +93,7 @@ def get_path_out(fname, inlines): for line in inlines: if "suffix" in line and "suffix" == line.split()[0]: suffix = line.split()[1] - path_out = os.path.join(fname, "OUT.%s/running_scf.log" % suffix) + path_out = os.path.join(fname, f"OUT.{suffix}/running_scf.log") break return path_out @@ -131,7 +133,7 @@ def get_coords(celldm, cell, geometry_inlines, inlines=None): tmp = np.matmul(xyz, cell) xyz = tmp else: - print("coord_type = %s" % coord_type) + print(f"coord_type = {coord_type}") raise RuntimeError( "Input coordination type is invalid.\n Only direct and cartesian are accepted." ) @@ -329,7 +331,7 @@ def get_nele_from_stru(geometry_inlines): for iline in range( keyword_line_index[idx] + 1, keyword_line_index[idx + 1] ): - if len(re.split("\s+", geometry_inlines[iline])) >= 3: + if len(re.split(r"\s+", geometry_inlines[iline])) >= 3: nele += 1 return nele @@ -367,11 +369,11 @@ def make_unlabeled_stru( for iele in range(len(data["atom_names"])): out += data["atom_names"][iele] + " " if mass is not None: - out += "%.3f " % mass[iele] + out += f"{mass[iele]:.3f} " else: out += "1 " if pp_file is not None: - out += "%s\n" % pp_file[iele] + out += f"{pp_file[iele]}\n" else: out += "\n" out += "\n" @@ -380,12 +382,12 @@ def make_unlabeled_stru( assert len(numerical_orbital) == len(data["atom_names"]) out += "NUMERICAL_ORBITAL\n" for iele in range(len(numerical_orbital)): - out += "%s\n" % numerical_orbital[iele] + out += f"{numerical_orbital[iele]}\n" out += "\n" if numerical_descriptor is not None: assert isinstance(numerical_descriptor, str) - out += "NUMERICAL_DESCRIPTOR\n%s\n" % numerical_descriptor + out += f"NUMERICAL_DESCRIPTOR\n{numerical_descriptor}\n" out += "\n" out += "LATTICE_CONSTANT\n" diff --git a/dpdata/amber/mask.py b/dpdata/amber/mask.py index e3ae1e8d..155e2a7b 100644 --- a/dpdata/amber/mask.py +++ b/dpdata/amber/mask.py @@ -1,5 +1,7 @@ """Amber mask.""" +from __future__ import annotations + try: import parmed except ImportError: diff --git a/dpdata/amber/md.py b/dpdata/amber/md.py index 279ce55e..f3217fbd 100644 --- a/dpdata/amber/md.py +++ b/dpdata/amber/md.py @@ -1,8 +1,9 @@ +from __future__ import annotations + import os import re import numpy as np -from scipy.io import netcdf_file from dpdata.amber.mask import pick_by_amber_mask from dpdata.unit import EnergyConversion @@ -44,6 +45,8 @@ def read_amber_traj( labeled : bool Whether to return labeled data """ + from scipy.io import netcdf_file + flag_atom_type = False flag_atom_numb = False amber_types = [] diff --git a/dpdata/amber/sqm.py b/dpdata/amber/sqm.py index 5dcbf995..1be3802a 100644 --- a/dpdata/amber/sqm.py +++ b/dpdata/amber/sqm.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np from dpdata.periodic_table import ELEMENTS diff --git a/dpdata/ase_calculator.py b/dpdata/ase_calculator.py index 65a462a5..1de760a5 100644 --- a/dpdata/ase_calculator.py +++ b/dpdata/ase_calculator.py @@ -1,6 +1,8 @@ -from typing import TYPE_CHECKING, List, Optional +from __future__ import annotations -from ase.calculators.calculator import ( +from typing import TYPE_CHECKING + +from ase.calculators.calculator import ( # noqa: TID253 Calculator, PropertyNotImplementedError, all_changes, @@ -23,7 +25,10 @@ class DPDataCalculator(Calculator): dpdata driver """ - name = "dpdata" + @property + def name(self) -> str: + return "dpdata" + implemented_properties = ["energy", "free_energy", "forces", "virial", "stress"] def __init__(self, driver: Driver, **kwargs) -> None: @@ -32,9 +37,9 @@ def __init__(self, driver: Driver, **kwargs) -> None: def calculate( self, - atoms: Optional["Atoms"] = None, - properties: List[str] = ["energy", "forces"], - system_changes: List[str] = all_changes, + atoms: Atoms | None = None, + properties: list[str] = ["energy", "forces"], + system_changes: list[str] = all_changes, ): """Run calculation with a driver. @@ -48,10 +53,10 @@ def calculate( system_changes : List[str], optional unused, only for function signature compatibility, by default all_changes """ - if atoms is not None: - self.atoms = atoms.copy() + assert atoms is not None + atoms = atoms.copy() - system = dpdata.System(self.atoms, fmt="ase/structure") + system = dpdata.System(atoms, fmt="ase/structure") data = system.predict(driver=self.driver).data self.results["energy"] = data["energies"][0] diff --git a/dpdata/bond_order_system.py b/dpdata/bond_order_system.py index e2449ee6..7a23acca 100644 --- a/dpdata/bond_order_system.py +++ b/dpdata/bond_order_system.py @@ -1,9 +1,10 @@ # %% # Bond Order System +from __future__ import annotations + from copy import deepcopy import numpy as np -from rdkit.Chem import Conformer import dpdata.rdkit.utils from dpdata.rdkit.sanitize import Sanitizer @@ -97,11 +98,14 @@ def from_fmt_obj(self, fmtobj, file_name, **kwargs): mol = fmtobj.from_bond_order_system(file_name, **kwargs) self.from_rdkit_mol(mol) if hasattr(fmtobj.from_bond_order_system, "post_func"): - for post_f in fmtobj.from_bond_order_system.post_func: + for post_f in fmtobj.from_bond_order_system.post_func: # type: ignore self.post_funcs.get_plugin(post_f)(self) return self def to_fmt_obj(self, fmtobj, *args, **kwargs): + from rdkit.Chem import Conformer + + assert self.rdkit_mol is not None self.rdkit_mol.RemoveAllConformers() for ii in range(self.get_nframes()): conf = Conformer() @@ -144,9 +148,9 @@ def get_formal_charges(self): """Return the formal charges on each atom.""" return self.data["formal_charges"] - def copy(self): + def copy(self): # type: ignore new_mol = deepcopy(self.rdkit_mol) - self.__class__(data=deepcopy(self.data), rdkit_mol=new_mol) + return self.__class__(data=deepcopy(self.data), rdkit_mol=new_mol) def __add__(self, other): raise NotImplementedError( diff --git a/dpdata/cli.py b/dpdata/cli.py index 07e7b4b5..aadff1a8 100644 --- a/dpdata/cli.py +++ b/dpdata/cli.py @@ -1,7 +1,8 @@ """Command line interface for dpdata.""" +from __future__ import annotations + import argparse -from typing import Optional from . import __version__ from .system import LabeledSystem, MultiSystems, System @@ -37,9 +38,7 @@ def dpdata_parser() -> argparse.ArgumentParser: ) parser.add_argument("--type-map", "-t", type=str, nargs="+", help="type map") - parser.add_argument( - "--version", action="version", version="dpdata v%s" % __version__ - ) + parser.add_argument("--version", action="version", version=f"dpdata v{__version__}") return parser @@ -61,11 +60,11 @@ def convert( *, from_file: str, from_format: str = "auto", - to_file: Optional[str] = None, - to_format: Optional[str] = None, + to_file: str | None = None, + to_format: str | None = None, no_labeled: bool = False, multi: bool = False, - type_map: Optional[list] = None, + type_map: list | None = None, **kwargs, ): """Convert files from one format to another one. diff --git a/dpdata/cp2k/cell.py b/dpdata/cp2k/cell.py index 7af73353..a3021b81 100644 --- a/dpdata/cp2k/cell.py +++ b/dpdata/cp2k/cell.py @@ -1,4 +1,5 @@ # %% +from __future__ import annotations import numpy as np diff --git a/dpdata/cp2k/output.py b/dpdata/cp2k/output.py index c84355c4..bd827595 100644 --- a/dpdata/cp2k/output.py +++ b/dpdata/cp2k/output.py @@ -1,4 +1,6 @@ # %% +from __future__ import annotations + import math import re from collections import OrderedDict diff --git a/dpdata/data_type.py b/dpdata/data_type.py index b5141a4e..bbc7401d 100644 --- a/dpdata/data_type.py +++ b/dpdata/data_type.py @@ -1,5 +1,7 @@ +from __future__ import annotations + from enum import Enum, unique -from typing import TYPE_CHECKING, Tuple +from typing import TYPE_CHECKING import numpy as np @@ -50,7 +52,7 @@ def __init__( self, name: str, dtype: type, - shape: Tuple[int, Axis] = None, + shape: tuple[int | Axis, ...] | None = None, required: bool = True, ) -> None: self.name = name @@ -58,8 +60,9 @@ def __init__( self.shape = shape self.required = required - def real_shape(self, system: "System") -> Tuple[int]: + def real_shape(self, system: System) -> tuple[int]: """Returns expected real shape of a system.""" + assert self.shape is not None shape = [] for ii in self.shape: if ii is Axis.NFRAMES: @@ -70,7 +73,7 @@ def real_shape(self, system: "System") -> Tuple[int]: shape.append(system.get_natoms()) elif ii is Axis.NBONDS: # BondOrderSystem - shape.append(system.get_nbonds()) + shape.append(system.get_nbonds()) # type: ignore elif ii == -1: shape.append(AnyInt(-1)) elif isinstance(ii, int): @@ -79,7 +82,7 @@ def real_shape(self, system: "System") -> Tuple[int]: raise RuntimeError("Shape is not an int!") return tuple(shape) - def check(self, system: "System"): + def check(self, system: System): """Check if a system has correct data of this type. Parameters @@ -121,7 +124,7 @@ def check(self, system: "System"): else: raise RuntimeError("Unsupported type to check shape") elif self.required: - raise DataError("%s not found in data" % self.name) + raise DataError(f"{self.name} not found in data") __system_data_type_plugin = Plugin() diff --git a/dpdata/deepmd/comp.py b/dpdata/deepmd/comp.py index 7b909b16..ab004447 100644 --- a/dpdata/deepmd/comp.py +++ b/dpdata/deepmd/comp.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import glob import os import shutil diff --git a/dpdata/deepmd/hdf5.py b/dpdata/deepmd/hdf5.py index ef54d862..34ae9dbe 100644 --- a/dpdata/deepmd/hdf5.py +++ b/dpdata/deepmd/hdf5.py @@ -3,16 +3,15 @@ from __future__ import annotations import warnings +from typing import TYPE_CHECKING -try: - import h5py -except ImportError: - pass import numpy as np -from wcmatch.glob import globfilter import dpdata +if TYPE_CHECKING: + import h5py + __all__ = ["to_system_data", "dump"] @@ -35,6 +34,8 @@ def to_system_data( labels : bool labels """ + from wcmatch.glob import globfilter + g = f[folder] if folder else f data = {} @@ -139,7 +140,7 @@ def to_system_data( for ii in sets: set = g[ii] - fn = "%s.npy" % prop["fn"] + fn = "{}.npy".format(prop["fn"]) if fn in set.keys(): dd = set[fn][:] nframes = dd.shape[0] @@ -257,7 +258,7 @@ def dump( for dt, prop in data_types.items(): if dt in reshaped_data: set_folder.create_dataset( - "%s.npy" % prop["fn"], data=reshaped_data[dt][set_stt:set_end] + "{}.npy".format(prop["fn"]), data=reshaped_data[dt][set_stt:set_end] ) if nopbc: diff --git a/dpdata/deepmd/mixed.py b/dpdata/deepmd/mixed.py index 0d0ad89d..b25107db 100644 --- a/dpdata/deepmd/mixed.py +++ b/dpdata/deepmd/mixed.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import glob import os import shutil diff --git a/dpdata/deepmd/raw.py b/dpdata/deepmd/raw.py index c7a64ec4..e772714a 100644 --- a/dpdata/deepmd/raw.py +++ b/dpdata/deepmd/raw.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import warnings diff --git a/dpdata/dftbplus/output.py b/dpdata/dftbplus/output.py index ba8f6c84..0f10c3ac 100644 --- a/dpdata/dftbplus/output.py +++ b/dpdata/dftbplus/output.py @@ -1,9 +1,9 @@ -from typing import Tuple +from __future__ import annotations import numpy as np -def read_dftb_plus(fn_1: str, fn_2: str) -> Tuple[str, np.ndarray, float, np.ndarray]: +def read_dftb_plus(fn_1: str, fn_2: str) -> tuple[str, np.ndarray, float, np.ndarray]: """Read from DFTB+ input and output. Parameters diff --git a/dpdata/driver.py b/dpdata/driver.py index 81d9a9ed..b5ff5340 100644 --- a/dpdata/driver.py +++ b/dpdata/driver.py @@ -1,12 +1,14 @@ """Driver plugin system.""" +from __future__ import annotations + from abc import ABC, abstractmethod -from typing import TYPE_CHECKING, Callable, List, Union +from typing import TYPE_CHECKING, Callable from .plugin import Plugin if TYPE_CHECKING: - import ase + import ase.calculators.calculator class Driver(ABC): @@ -43,7 +45,7 @@ def register(key: str) -> Callable: return Driver.__DriverPlugin.register(key) @staticmethod - def get_driver(key: str) -> "Driver": + def get_driver(key: str) -> type[Driver]: """Get a driver plugin. Parameters @@ -97,7 +99,7 @@ def label(self, data: dict) -> dict: return NotImplemented @property - def ase_calculator(self) -> "ase.calculators.calculator.Calculator": + def ase_calculator(self) -> ase.calculators.calculator.Calculator: """Returns an ase calculator based on this driver.""" from .ase_calculator import DPDataCalculator @@ -130,7 +132,7 @@ class HybridDriver(Driver): This driver is the hybrid of SQM and DP. """ - def __init__(self, drivers: List[Union[dict, Driver]]) -> None: + def __init__(self, drivers: list[dict | Driver]) -> None: self.drivers = [] for driver in drivers: if isinstance(driver, Driver): @@ -157,6 +159,7 @@ def label(self, data: dict) -> dict: dict labeled data with energies and forces """ + labeled_data = {} for ii, driver in enumerate(self.drivers): lb_data = driver.label(data.copy()) if ii == 0: @@ -199,7 +202,7 @@ def register(key: str) -> Callable: return Minimizer.__MinimizerPlugin.register(key) @staticmethod - def get_minimizer(key: str) -> "Minimizer": + def get_minimizer(key: str) -> type[Minimizer]: """Get a minimizer plugin. Parameters diff --git a/dpdata/fhi_aims/output.py b/dpdata/fhi_aims/output.py index c4cd9257..762e8bf4 100755 --- a/dpdata/fhi_aims/output.py +++ b/dpdata/fhi_aims/output.py @@ -1,14 +1,16 @@ +from __future__ import annotations + import re import warnings import numpy as np -latt_patt = "\|\s+([0-9]{1,}[.][0-9]*)\s+([0-9]{1,}[.][0-9]*)\s+([0-9]{1,}[.][0-9]*)" -pos_patt_first = "\|\s+[0-9]{1,}[:]\s\w+\s(\w+)(\s.*[-]?[0-9]{1,}[.][0-9]*)(\s+[-]?[0-9]{1,}[.][0-9]*)(\s+[-]?[0-9]{1,}[.][0-9]*)" -pos_patt_other = "\s+[a][t][o][m]\s+([-]?[0-9]{1,}[.][0-9]*)\s+([-]?[0-9]{1,}[.][0-9]*)\s+([-]?[0-9]{1,}[.][0-9]*)\s+(\w{1,2})" -force_patt = "\|\s+[0-9]{1,}\s+([-]?[0-9]{1,}[.][0-9]*[E][+-][0-9]{1,})\s+([-]?[0-9]{1,}[.][0-9]*[E][+-][0-9]{1,})\s+([-]?[0-9]{1,}[.][0-9]*[E][+-][0-9]{1,})" -eng_patt = "Total energy uncorrected.*([-]?[0-9]{1,}[.][0-9]*[E][+-][0-9]{1,})\s+eV" -# atom_numb_patt="Number of atoms.*([0-9]{1,})" +latt_patt = r"\|\s+([0-9]{1,}[.][0-9]*)\s+([0-9]{1,}[.][0-9]*)\s+([0-9]{1,}[.][0-9]*)" +pos_patt_first = r"\|\s+[0-9]{1,}[:]\s\w+\s(\w+)(\s.*[-]?[0-9]{1,}[.][0-9]*)(\s+[-]?[0-9]{1,}[.][0-9]*)(\s+[-]?[0-9]{1,}[.][0-9]*)" +pos_patt_other = r"\s+[a][t][o][m]\s+([-]?[0-9]{1,}[.][0-9]*)\s+([-]?[0-9]{1,}[.][0-9]*)\s+([-]?[0-9]{1,}[.][0-9]*)\s+(\w{1,2})" +force_patt = r"\|\s+[0-9]{1,}\s+([-]?[0-9]{1,}[.][0-9]*[E][+-][0-9]{1,})\s+([-]?[0-9]{1,}[.][0-9]*[E][+-][0-9]{1,})\s+([-]?[0-9]{1,}[.][0-9]*[E][+-][0-9]{1,})" +eng_patt = r"Total energy uncorrected.*([-]?[0-9]{1,}[.][0-9]*[E][+-][0-9]{1,})\s+eV" +# atom_numb_patt=r"Number of atoms.*([0-9]{1,})" debug = False diff --git a/dpdata/format.py b/dpdata/format.py index c231ef72..ade83c21 100644 --- a/dpdata/format.py +++ b/dpdata/format.py @@ -1,5 +1,7 @@ """Implement the format plugin system.""" +from __future__ import annotations + import os from abc import ABC @@ -163,7 +165,7 @@ def decorator(object): if not isinstance(func_name, (list, tuple, set)): object.post_func = (func_name,) else: - object.post_func = func_name + object.post_func = tuple(func_name) return object return decorator @@ -184,7 +186,7 @@ def from_system(self, file_name, **kwargs): system data, whose keys are defined in System.DTYPES """ raise NotImplementedError( - "%s doesn't support System.from" % (self.__class__.__name__) + f"{self.__class__.__name__} doesn't support System.from" ) def to_system(self, data, *args, **kwargs): @@ -200,7 +202,7 @@ def to_system(self, data, *args, **kwargs): keyword arguments that will be passed from the method """ raise NotImplementedError( - "%s doesn't support System.to" % (self.__class__.__name__) + f"{self.__class__.__name__} doesn't support System.to" ) def from_labeled_system(self, file_name, **kwargs): @@ -219,7 +221,7 @@ def from_labeled_system(self, file_name, **kwargs): system data, whose keys are defined in LabeledSystem.DTYPES """ raise NotImplementedError( - "%s doesn't support LabeledSystem.from" % (self.__class__.__name__) + f"{self.__class__.__name__} doesn't support LabeledSystem.from" ) def to_labeled_system(self, data, *args, **kwargs): @@ -254,7 +256,7 @@ def from_bond_order_system(self, file_name, **kwargs): system data """ raise NotImplementedError( - "%s doesn't support BondOrderSystem.from" % (self.__class__.__name__) + f"{self.__class__.__name__} doesn't support BondOrderSystem.from" ) def to_bond_order_system(self, data, rdkit_mol, *args, **kwargs): @@ -313,7 +315,7 @@ def from_multi_systems(self, directory, **kwargs): if os.path.isdir(os.path.join(directory, name)) ] raise NotImplementedError( - "%s doesn't support MultiSystems.from" % (self.__class__.__name__) + f"{self.__class__.__name__} doesn't support MultiSystems.from" ) def to_multi_systems(self, formulas, directory, **kwargs): @@ -333,7 +335,7 @@ def to_multi_systems(self, formulas, directory, **kwargs): if self.MultiMode == self.MultiModes.Directory: return [os.path.join(directory, ff) for ff in formulas] raise NotImplementedError( - "%s doesn't support MultiSystems.to" % (self.__class__.__name__) + f"{self.__class__.__name__} doesn't support MultiSystems.to" ) def mix_system(self, *system, type_map, **kwargs): @@ -354,5 +356,5 @@ def mix_system(self, *system, type_map, **kwargs): dict of mixed system with key 'atom_numbs' """ raise NotImplementedError( - "%s doesn't support System.from" % (self.__class__.__name__) + f"{self.__class__.__name__} doesn't support System.from" ) diff --git a/dpdata/gaussian/gjf.py b/dpdata/gaussian/gjf.py index 21300a60..b83dad1c 100644 --- a/dpdata/gaussian/gjf.py +++ b/dpdata/gaussian/gjf.py @@ -3,27 +3,19 @@ # under LGPL 3.0 license """Generate Gaussian input file.""" +from __future__ import annotations + import itertools import re import uuid import warnings -from typing import List, Optional, Tuple, Union import numpy as np -from scipy.sparse import csr_matrix -from scipy.sparse.csgraph import connected_components -try: - from openbabel import openbabel -except ImportError: - try: - import openbabel - except ImportError: - openbabel = None from dpdata.periodic_table import Element -def _crd2frag(symbols: List[str], crds: np.ndarray) -> Tuple[int, List[int]]: +def _crd2frag(symbols: list[str], crds: np.ndarray) -> tuple[int, list[int]]: """Detect fragments from coordinates. Parameters @@ -53,10 +45,13 @@ def _crd2frag(symbols: List[str], crds: np.ndarray) -> Tuple[int, List[int]]: ImportError if Open Babel is not installed """ - if openbabel is None: - raise ImportError( - "Open Babel (Python interface) should be installed to detect fragmentation!" - ) + from scipy.sparse import csr_matrix + from scipy.sparse.csgraph import connected_components + + try: + from openbabel import openbabel + except ImportError: + import openbabel atomnumber = len(symbols) # Use openbabel to connect atoms mol = openbabel.OBMol() @@ -108,12 +103,12 @@ def detect_multiplicity(symbols: np.ndarray) -> int: def make_gaussian_input( sys_data: dict, - keywords: Union[str, List[str]], - multiplicity: Union[str, int] = "auto", + keywords: str | list[str], + multiplicity: str | int = "auto", charge: int = 0, fragment_guesses: bool = False, - basis_set: Optional[str] = None, - keywords_high_multiplicity: Optional[str] = None, + basis_set: str | None = None, + keywords_high_multiplicity: str | None = None, nproc: int = 1, ) -> str: """Make gaussian input file. diff --git a/dpdata/gaussian/log.py b/dpdata/gaussian/log.py index 66881dc1..204cf464 100644 --- a/dpdata/gaussian/log.py +++ b/dpdata/gaussian/log.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np from ..periodic_table import ELEMENTS diff --git a/dpdata/gromacs/gro.py b/dpdata/gromacs/gro.py index b643eea8..aca2443b 100644 --- a/dpdata/gromacs/gro.py +++ b/dpdata/gromacs/gro.py @@ -1,4 +1,6 @@ #!/usr/bin/env python3 +from __future__ import annotations + import re import numpy as np diff --git a/dpdata/lammps/dump.py b/dpdata/lammps/dump.py index 906fed9e..f0ade2b0 100644 --- a/dpdata/lammps/dump.py +++ b/dpdata/lammps/dump.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +from __future__ import annotations import os import sys diff --git a/dpdata/lammps/lmp.py b/dpdata/lammps/lmp.py index 317b30ed..604b18d1 100644 --- a/dpdata/lammps/lmp.py +++ b/dpdata/lammps/lmp.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +from __future__ import annotations import numpy as np diff --git a/dpdata/md/msd.py b/dpdata/md/msd.py index cfb446dd..dfad9550 100644 --- a/dpdata/md/msd.py +++ b/dpdata/md/msd.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np from .pbc import system_pbc_shift diff --git a/dpdata/md/pbc.py b/dpdata/md/pbc.py index 4eee7c65..e5757661 100644 --- a/dpdata/md/pbc.py +++ b/dpdata/md/pbc.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np diff --git a/dpdata/md/rdf.py b/dpdata/md/rdf.py index de8f1c74..b41be525 100644 --- a/dpdata/md/rdf.py +++ b/dpdata/md/rdf.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np diff --git a/dpdata/md/water.py b/dpdata/md/water.py index 0cb82cc9..cda4ad48 100644 --- a/dpdata/md/water.py +++ b/dpdata/md/water.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np from .pbc import posi_diff, posi_shift diff --git a/dpdata/openmx/omx.py b/dpdata/openmx/omx.py index bd4b7031..d3afff00 100644 --- a/dpdata/openmx/omx.py +++ b/dpdata/openmx/omx.py @@ -1,4 +1,6 @@ #!/usr/bin/python3 +from __future__ import annotations + import numpy as np from ..unit import ( diff --git a/dpdata/orca/output.py b/dpdata/orca/output.py index 13f072f3..a23013fd 100644 --- a/dpdata/orca/output.py +++ b/dpdata/orca/output.py @@ -1,64 +1,64 @@ -from typing import Tuple - -import numpy as np - - -def read_orca_sp_output(fn: str) -> Tuple[np.ndarray, np.ndarray, float, np.ndarray]: - """Read from ORCA output. - - Note that both the energy and the gradient should be printed. - - Parameters - ---------- - fn : str - file name - - Returns - ------- - np.ndarray - atomic symbols - np.ndarray - atomic coordinates - float - total potential energy - np.ndarray - atomic forces - """ - coord = None - symbols = None - forces = None - energy = None - with open(fn) as f: - flag = 0 - for line in f: - if flag in (1, 3, 4): - flag += 1 - elif flag == 2: - s = line.split() - if not len(s): - flag = 0 - else: - symbols.append(s[0].capitalize()) - coord.append([float(s[1]), float(s[2]), float(s[3])]) - elif flag == 5: - s = line.split() - if not len(s): - flag = 0 - else: - forces.append([float(s[3]), float(s[4]), float(s[5])]) - elif line.startswith("CARTESIAN COORDINATES (ANGSTROEM)"): - # coord - flag = 1 - coord = [] - symbols = [] - elif line.startswith("CARTESIAN GRADIENT"): - flag = 3 - forces = [] - elif line.startswith("FINAL SINGLE POINT ENERGY"): - energy = float(line.split()[-1]) - symbols = np.array(symbols) - forces = -np.array(forces) - coord = np.array(coord) - assert coord.shape == forces.shape - - return symbols, coord, energy, forces +from __future__ import annotations + +import numpy as np + + +def read_orca_sp_output(fn: str) -> tuple[np.ndarray, np.ndarray, float, np.ndarray]: + """Read from ORCA output. + + Note that both the energy and the gradient should be printed. + + Parameters + ---------- + fn : str + file name + + Returns + ------- + np.ndarray + atomic symbols + np.ndarray + atomic coordinates + float + total potential energy + np.ndarray + atomic forces + """ + coord = None + symbols = None + forces = None + energy = None + with open(fn) as f: + flag = 0 + for line in f: + if flag in (1, 3, 4): + flag += 1 + elif flag == 2: + s = line.split() + if not len(s): + flag = 0 + else: + symbols.append(s[0].capitalize()) + coord.append([float(s[1]), float(s[2]), float(s[3])]) + elif flag == 5: + s = line.split() + if not len(s): + flag = 0 + else: + forces.append([float(s[3]), float(s[4]), float(s[5])]) + elif line.startswith("CARTESIAN COORDINATES (ANGSTROEM)"): + # coord + flag = 1 + coord = [] + symbols = [] + elif line.startswith("CARTESIAN GRADIENT"): + flag = 3 + forces = [] + elif line.startswith("FINAL SINGLE POINT ENERGY"): + energy = float(line.split()[-1]) + symbols = np.array(symbols) + forces = -np.array(forces) + coord = np.array(coord) + assert coord.shape == forces.shape + + return symbols, coord, energy, forces diff --git a/dpdata/periodic_table.py b/dpdata/periodic_table.py index e6f16bc9..e6b56cb0 100644 --- a/dpdata/periodic_table.py +++ b/dpdata/periodic_table.py @@ -1,9 +1,11 @@ -from pathlib import Path +from __future__ import annotations -from monty.serialization import loadfn +import json +from pathlib import Path -fpdt = str(Path(__file__).absolute().parent / "periodic_table.json") -_pdt = loadfn(fpdt) +fpdt = Path(__file__).absolute().parent / "periodic_table.json" +with fpdt.open("r") as fpdt: + _pdt = json.load(fpdt) ELEMENTS = [ "H", "He", @@ -108,13 +110,28 @@ "Md", "No", "Lr", + "Rf", + "Db", + "Sg", + "Bh", + "Hs", + "Mt", + "Ds", + "Rg", + "Cn", + "Nh", + "Fl", + "Mc", + "Lv", + "Ts", + "Og", ] class Element: def __init__(self, symbol: str): assert symbol in ELEMENTS - self.symbol = "%s" % symbol + self.symbol = f"{symbol}" d = _pdt[symbol] self._Z = d["atomic_no"] self._name = d["name"] @@ -127,7 +144,7 @@ def __str__(self): return self.symbol def __repr__(self): - return "Element : %s" % self.symbol + return f"Element : {self.symbol}" @classmethod def from_Z(cls, Z): diff --git a/dpdata/plugin.py b/dpdata/plugin.py index 20e51eb2..9e18e212 100644 --- a/dpdata/plugin.py +++ b/dpdata/plugin.py @@ -1,5 +1,7 @@ """Base of plugin systems.""" +from __future__ import annotations + class Plugin: """A class to register plugins. diff --git a/dpdata/plugins/3dmol.py b/dpdata/plugins/3dmol.py index ec994dd9..56ec2516 100644 --- a/dpdata/plugins/3dmol.py +++ b/dpdata/plugins/3dmol.py @@ -1,4 +1,4 @@ -from typing import Tuple +from __future__ import annotations import numpy as np @@ -17,7 +17,7 @@ def to_system( self, data: dict, f_idx: int = 0, - size: Tuple[int] = (300, 300), + size: tuple[int] = (300, 300), style: dict = {"stick": {}, "sphere": {"radius": 0.4}}, **kwargs, ): diff --git a/dpdata/plugins/__init__.py b/dpdata/plugins/__init__.py index 66364aa2..15634bc0 100644 --- a/dpdata/plugins/__init__.py +++ b/dpdata/plugins/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import importlib from pathlib import Path diff --git a/dpdata/plugins/abacus.py b/dpdata/plugins/abacus.py index 754221be..eb2d7786 100644 --- a/dpdata/plugins/abacus.py +++ b/dpdata/plugins/abacus.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import dpdata.abacus.md import dpdata.abacus.relax import dpdata.abacus.scf diff --git a/dpdata/plugins/amber.py b/dpdata/plugins/amber.py index cdc92a30..42fce552 100644 --- a/dpdata/plugins/amber.py +++ b/dpdata/plugins/amber.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import subprocess as sp import tempfile @@ -124,7 +126,7 @@ class SQMDriver(Driver): -15.41111246 """ - def __init__(self, sqm_exec: str = "sqm", **kwargs: dict) -> None: + def __init__(self, sqm_exec: str = "sqm", **kwargs) -> None: self.sqm_exec = sqm_exec self.kwargs = kwargs diff --git a/dpdata/plugins/ase.py b/dpdata/plugins/ase.py index 9fd27772..683f80f2 100644 --- a/dpdata/plugins/ase.py +++ b/dpdata/plugins/ase.py @@ -1,4 +1,6 @@ -from typing import TYPE_CHECKING, Generator, List, Optional, Type +from __future__ import annotations + +from typing import TYPE_CHECKING, Generator, List import numpy as np @@ -6,16 +8,11 @@ from dpdata.driver import Driver, Minimizer from dpdata.format import Format -try: - import ase.io - from ase.calculators.calculator import PropertyNotImplementedError +if TYPE_CHECKING: + import ase + from ase.optimize.optimize import Optimizer from ase.io import Trajectory - if TYPE_CHECKING: - from ase.optimize.optimize import Optimizer -except ImportError: - pass - @Format.register("ase/structure") class ASEStructureFormat(Format): @@ -28,7 +25,7 @@ class ASEStructureFormat(Format): automatic detection fails. """ - def from_system(self, atoms: "ase.Atoms", **kwargs) -> dict: + def from_system(self, atoms: ase.Atoms, **kwargs) -> dict: """Convert ase.Atoms to a System. Parameters @@ -62,7 +59,7 @@ def from_system(self, atoms: "ase.Atoms", **kwargs) -> dict: } return info_dict - def from_labeled_system(self, atoms: "ase.Atoms", **kwargs) -> dict: + def from_labeled_system(self, atoms: ase.Atoms, **kwargs) -> dict: """Convert ase.Atoms to a LabeledSystem. Energies and forces are calculated by the calculator. @@ -84,6 +81,8 @@ def from_labeled_system(self, atoms: "ase.Atoms", **kwargs) -> dict: ASE will raise RuntimeError if the atoms does not have a calculator """ + from ase.calculators.calculator import PropertyNotImplementedError + info_dict = self.from_system(atoms) try: energies = atoms.get_potential_energy(force_consistent=True) @@ -107,10 +106,10 @@ def from_labeled_system(self, atoms: "ase.Atoms", **kwargs) -> dict: def from_multi_systems( self, file_name: str, - begin: Optional[int] = None, - end: Optional[int] = None, - step: Optional[int] = None, - ase_fmt: Optional[str] = None, + begin: int | None = None, + end: int | None = None, + step: int | None = None, + ase_fmt: str | None = None, **kwargs, ) -> Generator["ase.Atoms", None, None]: """Convert a ASE supported file to ASE Atoms. @@ -137,6 +136,8 @@ def from_multi_systems( ase.Atoms ASE atoms in the file """ + import ase.io + frames = ase.io.read(file_name, format=ase_fmt, index=slice(begin, end, step)) yield from frames @@ -197,9 +198,9 @@ class ASETrajFormat(Format): def from_system( self, file_name: str, - begin: Optional[int] = 0, - end: Optional[int] = None, - step: Optional[int] = 1, + begin: int | None = 0, + end: int | None = None, + step: int | None = 1, **kwargs, ) -> dict: """Read ASE's trajectory file to `System` of multiple frames. @@ -222,6 +223,8 @@ def from_system( dict_frames: dict a dictionary containing data of multiple frames """ + from ase.io import Trajectory + traj = Trajectory(file_name) sub_traj = traj[begin:end:step] dict_frames = ASEStructureFormat().from_system(sub_traj[0]) @@ -239,9 +242,9 @@ def from_system( def from_labeled_system( self, file_name: str, - begin: Optional[int] = 0, - end: Optional[int] = None, - step: Optional[int] = 1, + begin: int | None = 0, + end: int | None = None, + step: int | None = 1, **kwargs, ) -> dict: """Read ASE's trajectory file to `System` of multiple frames. @@ -264,6 +267,8 @@ def from_labeled_system( dict_frames: dict a dictionary containing data of multiple frames """ + from ase.io import Trajectory + traj = Trajectory(file_name) sub_traj = traj[begin:end:step] @@ -337,7 +342,7 @@ class ASEDriver(Driver): ASE calculator """ - def __init__(self, calculator: "ase.calculators.calculator.Calculator") -> None: + def __init__(self, calculator: ase.calculators.calculator.Calculator) -> None: """Setup the driver.""" self.calculator = calculator @@ -389,9 +394,9 @@ class ASEMinimizer(Minimizer): def __init__( self, driver: Driver, - optimizer: Optional[Type["Optimizer"]] = None, + optimizer: type[Optimizer] | None = None, fmax: float = 5e-3, - max_steps: Optional[int] = None, + max_steps: int | None = None, optimizer_kwargs: dict = {}, ) -> None: self.calculator = driver.ase_calculator diff --git a/dpdata/plugins/cp2k.py b/dpdata/plugins/cp2k.py index 162098f7..f5c1b539 100644 --- a/dpdata/plugins/cp2k.py +++ b/dpdata/plugins/cp2k.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import glob import dpdata.cp2k.output diff --git a/dpdata/plugins/deepmd.py b/dpdata/plugins/deepmd.py index 9daadcf3..1ed79f72 100644 --- a/dpdata/plugins/deepmd.py +++ b/dpdata/plugins/deepmd.py @@ -1,11 +1,8 @@ from __future__ import annotations import os +from typing import TYPE_CHECKING -try: - import h5py -except ImportError: - pass import numpy as np import dpdata @@ -16,6 +13,9 @@ from dpdata.driver import Driver from dpdata.format import Format +if TYPE_CHECKING: + import h5py + @Format.register("deepmd") @Format.register("deepmd/raw") @@ -202,6 +202,8 @@ def _from_system( TypeError file_name is not str or h5py.Group or h5py.File """ + import h5py + if isinstance(file_name, (h5py.Group, h5py.File)): return dpdata.deepmd.hdf5.to_system_data( file_name, "", type_map=type_map, labels=labels @@ -300,6 +302,8 @@ def to_system( **kwargs : dict other parameters """ + import h5py + if isinstance(file_name, (h5py.Group, h5py.File)): dpdata.deepmd.hdf5.dump( file_name, "", data, set_size=set_size, comp_prec=comp_prec @@ -330,6 +334,8 @@ def from_multi_systems(self, directory: str, **kwargs) -> h5py.Group: h5py.Group a HDF5 group in the HDF5 file """ + import h5py + with h5py.File(directory, "r") as f: for ff in f.keys(): yield f[ff] @@ -353,6 +359,8 @@ def to_multi_systems( h5py.Group a HDF5 group with the name of formula """ + import h5py + with h5py.File(directory, "w") as f: for ff in formulas: yield f.create_group(ff) diff --git a/dpdata/plugins/dftbplus.py b/dpdata/plugins/dftbplus.py index 5c8b4682..247fedc9 100644 --- a/dpdata/plugins/dftbplus.py +++ b/dpdata/plugins/dftbplus.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np from dpdata.dftbplus.output import read_dftb_plus diff --git a/dpdata/plugins/fhi_aims.py b/dpdata/plugins/fhi_aims.py index 45b181fc..3c198aff 100644 --- a/dpdata/plugins/fhi_aims.py +++ b/dpdata/plugins/fhi_aims.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import dpdata.fhi_aims.output from dpdata.format import Format diff --git a/dpdata/plugins/gaussian.py b/dpdata/plugins/gaussian.py index a22ce863..b55447b9 100644 --- a/dpdata/plugins/gaussian.py +++ b/dpdata/plugins/gaussian.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import subprocess as sp import tempfile @@ -81,7 +83,7 @@ class GaussianDriver(Driver): -1102.714590995794 """ - def __init__(self, gaussian_exec: str = "g16", **kwargs: dict) -> None: + def __init__(self, gaussian_exec: str = "g16", **kwargs) -> None: self.gaussian_exec = gaussian_exec self.kwargs = kwargs diff --git a/dpdata/plugins/gromacs.py b/dpdata/plugins/gromacs.py index 20e50835..12dece71 100644 --- a/dpdata/plugins/gromacs.py +++ b/dpdata/plugins/gromacs.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import dpdata.gromacs.gro from dpdata.format import Format diff --git a/dpdata/plugins/lammps.py b/dpdata/plugins/lammps.py index be89be9d..65e7f570 100644 --- a/dpdata/plugins/lammps.py +++ b/dpdata/plugins/lammps.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import dpdata.lammps.dump import dpdata.lammps.lmp from dpdata.format import Format diff --git a/dpdata/plugins/list.py b/dpdata/plugins/list.py index 68a14074..f7036883 100644 --- a/dpdata/plugins/list.py +++ b/dpdata/plugins/list.py @@ -1,3 +1,5 @@ +from __future__ import annotations + from dpdata.format import Format diff --git a/dpdata/plugins/n2p2.py b/dpdata/plugins/n2p2.py index 7162f09f..b70d6e6f 100644 --- a/dpdata/plugins/n2p2.py +++ b/dpdata/plugins/n2p2.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np from dpdata.format import Format diff --git a/dpdata/plugins/openmx.py b/dpdata/plugins/openmx.py index 675d1d2c..4e16566d 100644 --- a/dpdata/plugins/openmx.py +++ b/dpdata/plugins/openmx.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import dpdata.md.pbc import dpdata.openmx.omx from dpdata.format import Format diff --git a/dpdata/plugins/orca.py b/dpdata/plugins/orca.py index 2585743e..9dc32c32 100644 --- a/dpdata/plugins/orca.py +++ b/dpdata/plugins/orca.py @@ -1,51 +1,53 @@ -import numpy as np - -from dpdata.format import Format -from dpdata.orca.output import read_orca_sp_output -from dpdata.unit import EnergyConversion, ForceConversion - -energy_convert = EnergyConversion("hartree", "eV").value() -force_convert = ForceConversion("hartree/bohr", "eV/angstrom").value() - - -@Format.register("orca/spout") -class ORCASPOutFormat(Format): - """ORCA single point energy output. - - Note that both the energy and the gradient should be - printed into the output file. - """ - - def from_labeled_system(self, file_name: str, **kwargs) -> dict: - """Read from ORCA single point energy output. - - Parameters - ---------- - file_name : str - file name - **kwargs - keyword arguments - - Returns - ------- - dict - system data - """ - symbols, coord, energy, forces = read_orca_sp_output(file_name) - - atom_names, atom_types, atom_numbs = np.unique( - symbols, return_inverse=True, return_counts=True - ) - natoms = coord.shape[0] - - return { - "atom_types": atom_types, - "atom_names": list(atom_names), - "atom_numbs": list(atom_numbs), - "coords": coord.reshape((1, natoms, 3)), - "energies": np.array([energy * energy_convert]), - "forces": (forces * force_convert).reshape((1, natoms, 3)), - "cells": np.zeros((1, 3, 3)), - "orig": np.zeros(3), - "nopbc": True, - } +from __future__ import annotations + +import numpy as np + +from dpdata.format import Format +from dpdata.orca.output import read_orca_sp_output +from dpdata.unit import EnergyConversion, ForceConversion + +energy_convert = EnergyConversion("hartree", "eV").value() +force_convert = ForceConversion("hartree/bohr", "eV/angstrom").value() + + +@Format.register("orca/spout") +class ORCASPOutFormat(Format): + """ORCA single point energy output. + + Note that both the energy and the gradient should be + printed into the output file. + """ + + def from_labeled_system(self, file_name: str, **kwargs) -> dict: + """Read from ORCA single point energy output. + + Parameters + ---------- + file_name : str + file name + **kwargs + keyword arguments + + Returns + ------- + dict + system data + """ + symbols, coord, energy, forces = read_orca_sp_output(file_name) + + atom_names, atom_types, atom_numbs = np.unique( + symbols, return_inverse=True, return_counts=True + ) + natoms = coord.shape[0] + + return { + "atom_types": atom_types, + "atom_names": list(atom_names), + "atom_numbs": list(atom_numbs), + "coords": coord.reshape((1, natoms, 3)), + "energies": np.array([energy * energy_convert]), + "forces": (forces * force_convert).reshape((1, natoms, 3)), + "cells": np.zeros((1, 3, 3)), + "orig": np.zeros(3), + "nopbc": True, + } diff --git a/dpdata/plugins/psi4.py b/dpdata/plugins/psi4.py index ec7d9df1..a0cf00e4 100644 --- a/dpdata/plugins/psi4.py +++ b/dpdata/plugins/psi4.py @@ -1,102 +1,104 @@ -import numpy as np - -from dpdata.format import Format -from dpdata.psi4.input import write_psi4_input -from dpdata.psi4.output import read_psi4_output -from dpdata.unit import EnergyConversion, ForceConversion - -energy_convert = EnergyConversion("hartree", "eV").value() -force_convert = ForceConversion("hartree/bohr", "eV/angstrom").value() - - -@Format.register("psi4/out") -class PSI4OutFormat(Format): - """Psi4 output. - - Note that both the energy and the gradient should be - printed into the output file. - """ - - def from_labeled_system(self, file_name: str, **kwargs) -> dict: - """Read from Psi4 output. - - Parameters - ---------- - file_name : str - file name - **kwargs - keyword arguments - - Returns - ------- - dict - system data - """ - symbols, coord, energy, forces = read_psi4_output(file_name) - - atom_names, atom_types, atom_numbs = np.unique( - symbols, return_inverse=True, return_counts=True - ) - natoms = coord.shape[0] - - return { - "atom_types": atom_types, - "atom_names": list(atom_names), - "atom_numbs": list(atom_numbs), - "coords": (coord).reshape((1, natoms, 3)), - "energies": np.array([energy * energy_convert]), - "forces": (forces * force_convert).reshape((1, natoms, 3)), - "cells": np.zeros((1, 3, 3)), - "orig": np.zeros(3), - "nopbc": True, - } - - -@Format.register("psi4/inp") -class PSI4InputFormat(Format): - """Psi4 input file.""" - - def to_system( - self, - data: dict, - file_name: str, - method: str, - basis: str, - charge: int = 0, - multiplicity: int = 1, - frame_idx=0, - **kwargs, - ): - """Write PSI4 input. - - Parameters - ---------- - data : dict - system data - file_name : str - file name - method : str - computational method - basis : str - basis set; see https://psicode.org/psi4manual/master/basissets_tables.html - charge : int, default=0 - charge of system - multiplicity : int, default=1 - multiplicity of system - frame_idx : int, default=0 - The index of the frame to dump - **kwargs - keyword arguments - """ - types = np.array(data["atom_names"])[data["atom_types"]] - with open(file_name, "w") as fout: - fout.write( - write_psi4_input( - types=types, - coords=data["coords"][frame_idx], - method=method, - basis=basis, - charge=charge, - multiplicity=multiplicity, - ) - ) +from __future__ import annotations + +import numpy as np + +from dpdata.format import Format +from dpdata.psi4.input import write_psi4_input +from dpdata.psi4.output import read_psi4_output +from dpdata.unit import EnergyConversion, ForceConversion + +energy_convert = EnergyConversion("hartree", "eV").value() +force_convert = ForceConversion("hartree/bohr", "eV/angstrom").value() + + +@Format.register("psi4/out") +class PSI4OutFormat(Format): + """Psi4 output. + + Note that both the energy and the gradient should be + printed into the output file. + """ + + def from_labeled_system(self, file_name: str, **kwargs) -> dict: + """Read from Psi4 output. + + Parameters + ---------- + file_name : str + file name + **kwargs + keyword arguments + + Returns + ------- + dict + system data + """ + symbols, coord, energy, forces = read_psi4_output(file_name) + + atom_names, atom_types, atom_numbs = np.unique( + symbols, return_inverse=True, return_counts=True + ) + natoms = coord.shape[0] + + return { + "atom_types": atom_types, + "atom_names": list(atom_names), + "atom_numbs": list(atom_numbs), + "coords": (coord).reshape((1, natoms, 3)), + "energies": np.array([energy * energy_convert]), + "forces": (forces * force_convert).reshape((1, natoms, 3)), + "cells": np.zeros((1, 3, 3)), + "orig": np.zeros(3), + "nopbc": True, + } + + +@Format.register("psi4/inp") +class PSI4InputFormat(Format): + """Psi4 input file.""" + + def to_system( + self, + data: dict, + file_name: str, + method: str, + basis: str, + charge: int = 0, + multiplicity: int = 1, + frame_idx=0, + **kwargs, + ): + """Write PSI4 input. + + Parameters + ---------- + data : dict + system data + file_name : str + file name + method : str + computational method + basis : str + basis set; see https://psicode.org/psi4manual/master/basissets_tables.html + charge : int, default=0 + charge of system + multiplicity : int, default=1 + multiplicity of system + frame_idx : int, default=0 + The index of the frame to dump + **kwargs + keyword arguments + """ + types = np.array(data["atom_names"])[data["atom_types"]] + with open(file_name, "w") as fout: + fout.write( + write_psi4_input( + types=types, + coords=data["coords"][frame_idx], + method=method, + basis=basis, + charge=charge, + multiplicity=multiplicity, + ) + ) diff --git a/dpdata/plugins/pwmat.py b/dpdata/plugins/pwmat.py index 11257c4d..80f219b6 100644 --- a/dpdata/plugins/pwmat.py +++ b/dpdata/plugins/pwmat.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np import dpdata.pwmat.atomconfig diff --git a/dpdata/plugins/pymatgen.py b/dpdata/plugins/pymatgen.py index 82b64e71..322298c3 100644 --- a/dpdata/plugins/pymatgen.py +++ b/dpdata/plugins/pymatgen.py @@ -1,11 +1,31 @@ +from __future__ import annotations + import numpy as np import dpdata.pymatgen.molecule +import dpdata.pymatgen.structure from dpdata.format import Format @Format.register("pymatgen/structure") class PyMatgenStructureFormat(Format): + def from_system(self, structure, **kwargs) -> dict: + """Convert pymatgen.core.Structure to System. + + Parameters + ---------- + structure : pymatgen.core.Structure + a Pymatgen Structure, containing a structure + **kwargs : dict + other parameters + + Returns + ------- + dict + data dict + """ + return dpdata.pymatgen.structure.from_system_data(structure) + def to_system(self, data, **kwargs): """Convert System to Pymatgen Structure obj.""" structures = [] diff --git a/dpdata/plugins/qe.py b/dpdata/plugins/qe.py index 6a98eedd..682bb202 100644 --- a/dpdata/plugins/qe.py +++ b/dpdata/plugins/qe.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import dpdata.md.pbc import dpdata.qe.scf import dpdata.qe.traj diff --git a/dpdata/plugins/rdkit.py b/dpdata/plugins/rdkit.py index ff7638cb..f01b277d 100644 --- a/dpdata/plugins/rdkit.py +++ b/dpdata/plugins/rdkit.py @@ -1,20 +1,20 @@ -from dpdata.format import Format - -try: - import rdkit.Chem +from __future__ import annotations - import dpdata.rdkit.utils -except ModuleNotFoundError: - pass +import dpdata.rdkit.utils +from dpdata.format import Format @Format.register("mol") @Format.register("mol_file") class MolFormat(Format): def from_bond_order_system(self, file_name, **kwargs): + import rdkit.Chem + return rdkit.Chem.MolFromMolFile(file_name, sanitize=False, removeHs=False) def to_bond_order_system(self, data, mol, file_name, frame_idx=0, **kwargs): + import rdkit.Chem + assert frame_idx < mol.GetNumConformers() rdkit.Chem.MolToMolFile(mol, file_name, confId=frame_idx) @@ -24,6 +24,8 @@ def to_bond_order_system(self, data, mol, file_name, frame_idx=0, **kwargs): class SdfFormat(Format): def from_bond_order_system(self, file_name, **kwargs): """Note that it requires all molecules in .sdf file must be of the same topology.""" + import rdkit.Chem + mols = [ m for m in rdkit.Chem.SDMolSupplier(file_name, sanitize=False, removeHs=False) @@ -35,6 +37,8 @@ def from_bond_order_system(self, file_name, **kwargs): return mol def to_bond_order_system(self, data, mol, file_name, frame_idx=-1, **kwargs): + import rdkit.Chem + sdf_writer = rdkit.Chem.SDWriter(file_name) if frame_idx == -1: for ii in range(mol.GetNumConformers()): diff --git a/dpdata/plugins/siesta.py b/dpdata/plugins/siesta.py index 662b5c0e..906eeb51 100644 --- a/dpdata/plugins/siesta.py +++ b/dpdata/plugins/siesta.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import dpdata.siesta.aiMD_output import dpdata.siesta.output from dpdata.format import Format diff --git a/dpdata/plugins/vasp.py b/dpdata/plugins/vasp.py index c182bb95..d0681ceb 100644 --- a/dpdata/plugins/vasp.py +++ b/dpdata/plugins/vasp.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np import dpdata.vasp.outcar diff --git a/dpdata/plugins/xyz.py b/dpdata/plugins/xyz.py index fdb5bf3b..322bf77c 100644 --- a/dpdata/plugins/xyz.py +++ b/dpdata/plugins/xyz.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np from dpdata.format import Format diff --git a/dpdata/psi4/input.py b/dpdata/psi4/input.py index ad053281..3959cb75 100644 --- a/dpdata/psi4/input.py +++ b/dpdata/psi4/input.py @@ -1,4 +1,9 @@ -import numpy as np +from __future__ import annotations + +from typing import TYPE_CHECKING + +if TYPE_CHECKING: + import numpy as np # Angston is used in Psi4 by default template = """molecule {{ diff --git a/dpdata/psi4/output.py b/dpdata/psi4/output.py index e93858de..c06eb182 100644 --- a/dpdata/psi4/output.py +++ b/dpdata/psi4/output.py @@ -1,74 +1,74 @@ -from typing import Tuple - -import numpy as np - -from dpdata.unit import LengthConversion - - -def read_psi4_output(fn: str) -> Tuple[str, np.ndarray, float, np.ndarray]: - """Read from Psi4 output. - - Note that both the energy and the gradient should be printed. - - Parameters - ---------- - fn : str - file name - - Returns - ------- - str - atomic symbols - np.ndarray - atomic coordinates - float - total potential energy - np.ndarray - atomic forces - """ - coord = None - symbols = None - forces = None - energy = None - length_unit = None - with open(fn) as f: - flag = 0 - for line in f: - if flag in (1, 3, 4, 5, 6): - flag += 1 - elif flag == 2: - s = line.split() - if not len(s): - flag = 0 - else: - symbols.append(s[0].capitalize()) - coord.append([float(s[1]), float(s[2]), float(s[3])]) - elif flag == 7: - s = line.split() - if not len(s): - flag = 0 - else: - forces.append([float(s[1]), float(s[2]), float(s[3])]) - elif line.startswith( - " Center X Y Z Mass" - ): - # coord - flag = 1 - coord = [] - symbols = [] - elif line.startswith(" Geometry (in "): - # remove ), - length_unit = line.split()[2][:-2].lower() - elif line.startswith(" ## Total Gradient"): - flag = 3 - forces = [] - elif line.startswith(" Total Energy ="): - energy = float(line.split()[-1]) - assert length_unit is not None - length_convert = LengthConversion(length_unit, "angstrom").value() - symbols = np.array(symbols) - forces = -np.array(forces) - coord = np.array(coord) * length_convert - assert coord.shape == forces.shape - - return symbols, coord, energy, forces +from __future__ import annotations + +import numpy as np + +from dpdata.unit import LengthConversion + + +def read_psi4_output(fn: str) -> tuple[str, np.ndarray, float, np.ndarray]: + """Read from Psi4 output. + + Note that both the energy and the gradient should be printed. + + Parameters + ---------- + fn : str + file name + + Returns + ------- + str + atomic symbols + np.ndarray + atomic coordinates + float + total potential energy + np.ndarray + atomic forces + """ + coord = None + symbols = None + forces = None + energy = None + length_unit = None + with open(fn) as f: + flag = 0 + for line in f: + if flag in (1, 3, 4, 5, 6): + flag += 1 + elif flag == 2: + s = line.split() + if not len(s): + flag = 0 + else: + symbols.append(s[0].capitalize()) + coord.append([float(s[1]), float(s[2]), float(s[3])]) + elif flag == 7: + s = line.split() + if not len(s): + flag = 0 + else: + forces.append([float(s[1]), float(s[2]), float(s[3])]) + elif line.startswith( + " Center X Y Z Mass" + ): + # coord + flag = 1 + coord = [] + symbols = [] + elif line.startswith(" Geometry (in "): + # remove ), + length_unit = line.split()[2][:-2].lower() + elif line.startswith(" ## Total Gradient"): + flag = 3 + forces = [] + elif line.startswith(" Total Energy ="): + energy = float(line.split()[-1]) + assert length_unit is not None + length_convert = LengthConversion(length_unit, "angstrom").value() + symbols = np.array(symbols) + forces = -np.array(forces) + coord = np.array(coord) * length_convert + assert coord.shape == forces.shape + + return symbols, coord, energy, forces diff --git a/dpdata/pwmat/atomconfig.py b/dpdata/pwmat/atomconfig.py index 28cfaebc..62eff77c 100644 --- a/dpdata/pwmat/atomconfig.py +++ b/dpdata/pwmat/atomconfig.py @@ -1,4 +1,6 @@ #!/usr/bin/python3 +from __future__ import annotations + import numpy as np from ..periodic_table import ELEMENTS @@ -58,7 +60,7 @@ def from_system_data(system, f_idx=0, skip_zeros=True): ret += "\n" for ii in system["cells"][f_idx]: for jj in ii: - ret += "%.16e " % jj + ret += f"{jj:.16e} " ret += "\n" ret += "POSITION" ret += "\n" diff --git a/dpdata/pwmat/movement.py b/dpdata/pwmat/movement.py index 748744d6..ccfd819d 100644 --- a/dpdata/pwmat/movement.py +++ b/dpdata/pwmat/movement.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import warnings import numpy as np diff --git a/dpdata/py.typed b/dpdata/py.typed new file mode 100644 index 00000000..e69de29b diff --git a/dpdata/pymatgen/molecule.py b/dpdata/pymatgen/molecule.py index 13d4046c..8d397984 100644 --- a/dpdata/pymatgen/molecule.py +++ b/dpdata/pymatgen/molecule.py @@ -1,13 +1,13 @@ -import numpy as np +from __future__ import annotations -try: - from pymatgen.core import Molecule -except ImportError: - pass from collections import Counter +import numpy as np + def to_system_data(file_name, protect_layer=9): + from pymatgen.core import Molecule + mol = Molecule.from_file(file_name) elem_mol = list(str(site.species.elements[0]) for site in mol.sites) elem_counter = Counter(elem_mol) diff --git a/dpdata/pymatgen/structure.py b/dpdata/pymatgen/structure.py new file mode 100644 index 00000000..36e411c0 --- /dev/null +++ b/dpdata/pymatgen/structure.py @@ -0,0 +1,21 @@ +from __future__ import annotations + +import numpy as np + + +def from_system_data(structure) -> dict: + symbols = [site.species_string for site in structure] + atom_names = list(structure.symbol_set) + atom_numbs = [symbols.count(symbol) for symbol in atom_names] + atom_types = np.array([atom_names.index(symbol) for symbol in symbols]).astype(int) + coords = structure.cart_coords + cells = structure.lattice.matrix + + info_dict = { + "atom_names": atom_names, + "atom_numbs": atom_numbs, + "atom_types": atom_types, + "coords": np.array([coords]), + "cells": np.array([cells]), + } + return info_dict diff --git a/dpdata/qe/scf.py b/dpdata/qe/scf.py index cd9c6f28..37e5fbab 100755 --- a/dpdata/qe/scf.py +++ b/dpdata/qe/scf.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +from __future__ import annotations import os diff --git a/dpdata/qe/traj.py b/dpdata/qe/traj.py index e27990cb..1fbf0f71 100644 --- a/dpdata/qe/traj.py +++ b/dpdata/qe/traj.py @@ -1,4 +1,6 @@ #!/usr/bin/python3 +from __future__ import annotations + import warnings import numpy as np diff --git a/dpdata/rdkit/sanitize.py b/dpdata/rdkit/sanitize.py index 061de3d9..2b0d7663 100644 --- a/dpdata/rdkit/sanitize.py +++ b/dpdata/rdkit/sanitize.py @@ -1,18 +1,9 @@ +from __future__ import annotations + import os import time from copy import deepcopy -from rdkit import Chem -from rdkit.Chem.rdchem import BondType - -# openbabel -try: - from openbabel import openbabel - - USE_OBABEL = True -except ModuleNotFoundError as e: - USE_OBABEL = False - def get_explicit_valence(atom, verbose=False): exp_val_calculated_from_bonds = int( @@ -32,6 +23,8 @@ def get_explicit_valence(atom, verbose=False): def regularize_formal_charges(mol, sanitize=True, verbose=False): """Regularize formal charges of atoms.""" + from rdkit import Chem + assert isinstance(mol, Chem.rdchem.Mol) for atom in mol.GetAtoms(): assign_formal_charge_for_atom(atom, verbose) @@ -47,6 +40,8 @@ def regularize_formal_charges(mol, sanitize=True, verbose=False): def assign_formal_charge_for_atom(atom, verbose=False): """Assigen formal charge according to 8-electron rule for element B,C,N,O,S,P,As.""" + from rdkit import Chem + assert isinstance(atom, Chem.rdchem.Atom) valence = get_explicit_valence(atom, verbose) if atom.GetSymbol() == "B": @@ -135,6 +130,8 @@ def get_terminal_NR2s(atom): def sanitize_phosphate_Patom(P_atom, verbose=True): + from rdkit import Chem + if P_atom.GetSymbol() == "P": terminal_oxygens = get_terminal_oxygens(P_atom) mol = P_atom.GetOwningMol() @@ -161,6 +158,8 @@ def sanitize_phosphate(mol): def sanitize_sulfate_Satom(S_atom, verbose=True): + from rdkit import Chem + if S_atom.GetSymbol() == "S": terminal_oxygens = get_terminal_oxygens(S_atom) mol = S_atom.GetOwningMol() @@ -187,6 +186,8 @@ def sanitize_sulfate(mol): def sanitize_carboxyl_Catom(C_atom, verbose=True): + from rdkit import Chem + if C_atom.GetSymbol() == "C": terminal_oxygens = get_terminal_oxygens(C_atom) mol = C_atom.GetOwningMol() @@ -214,6 +215,8 @@ def sanitize_carboxyl(mol): def sanitize_guanidine_Catom(C_atom, verbose=True): + from rdkit import Chem + if C_atom.GetSymbol() == "C": terminal_NR2s = get_terminal_NR2s(C_atom) mol = C_atom.GetOwningMol() @@ -241,6 +244,8 @@ def sanitize_guanidine(mol): def sanitize_nitro_Natom(N_atom, verbose=True): + from rdkit import Chem + if N_atom.GetSymbol() == "N": terminal_oxygens = get_terminal_oxygens(N_atom) mol = N_atom.GetOwningMol() @@ -275,6 +280,8 @@ def is_terminal_nitrogen(N_atom): def sanitize_nitrine_Natom(atom, verbose=True): + from rdkit import Chem + if atom.GetSymbol() == "N" and len(atom.GetNeighbors()) == 2: mol = atom.GetOwningMol() nei1, nei2 = atom.GetNeighbors()[0], atom.GetNeighbors()[1] @@ -312,6 +319,8 @@ def contain_hetero_aromatic(mol): # for carbon with explicit valence > 4 def regularize_carbon_bond_order(atom, verbose=True): + from rdkit import Chem + if atom.GetSymbol() == "C" and get_explicit_valence(atom) > 4: if verbose: print("Detecting carbon with explicit valence > 4, fixing it...") @@ -330,6 +339,8 @@ def regularize_carbon_bond_order(atom, verbose=True): # for nitrogen with explicit valence > 4 def regularize_nitrogen_bond_order(atom, verbose=True): + from rdkit import Chem + mol = atom.GetOwningMol() if atom.GetSymbol() == "N" and get_explicit_valence(atom) > 4: O_atoms = get_terminal_oxygens(atom) @@ -363,6 +374,9 @@ def mol_edit_log(mol, i, j): def kekulize_aromatic_heterocycles(mol_in, assign_formal_charge=True, sanitize=True): + from rdkit import Chem + from rdkit.Chem.rdchem import BondType + mol = Chem.RWMol(mol_in) rings = Chem.rdmolops.GetSymmSSSR(mol) rings = [list(i) for i in list(rings)] @@ -566,6 +580,9 @@ def hetero_priority(idx, mol): def convert_by_obabel( mol, cache_dir=os.path.join(os.getcwd(), ".cache"), obabel_path="obabel" ): + from openbabel import openbabel + from rdkit import Chem + if not os.path.exists(cache_dir): os.mkdir(cache_dir) if mol.HasProp("_Name"): @@ -585,6 +602,8 @@ def convert_by_obabel( def super_sanitize_mol(mol, name=None, verbose=True): + from rdkit import Chem + if name is None: if mol.HasProp("_Name"): name = mol.GetProp("_Name") @@ -655,11 +674,6 @@ def _check_level(self, level): raise ValueError( f"Invalid level '{level}', please set to 'low', 'medium' or 'high'" ) - else: - if level == "high" and not USE_OBABEL: - raise ModuleNotFoundError( - "obabel not installed, high level sanitizer cannot work" - ) def _handle_exception(self, error_info): if self.raise_errors: @@ -669,6 +683,8 @@ def _handle_exception(self, error_info): def sanitize(self, mol): """Sanitize mol according to `self.level`. If failed, return None.""" + from rdkit import Chem + if self.level == "low": try: Chem.SanitizeMol(mol) diff --git a/dpdata/rdkit/utils.py b/dpdata/rdkit/utils.py index 25cf97cd..efeef607 100644 --- a/dpdata/rdkit/utils.py +++ b/dpdata/rdkit/utils.py @@ -1,11 +1,11 @@ -try: - from rdkit import Chem -except ModuleNotFoundError: - pass +from __future__ import annotations + import numpy as np def mol_to_system_data(mol): + from rdkit import Chem + if not isinstance(mol, Chem.rdchem.Mol): raise TypeError(f"rdkit.Chem.Mol required, not {type(mol)}") @@ -52,6 +52,8 @@ def mol_to_system_data(mol): def system_data_to_mol(data): + from rdkit import Chem + mol_ed = Chem.RWMol() atom_symbols = [data["atom_names"][i] for i in data["atom_types"]] # add atoms diff --git a/dpdata/siesta/aiMD_output.py b/dpdata/siesta/aiMD_output.py index 4e1890ec..daa4f6a2 100644 --- a/dpdata/siesta/aiMD_output.py +++ b/dpdata/siesta/aiMD_output.py @@ -1,4 +1,5 @@ # !/usr/bin/python3 +from __future__ import annotations import numpy as np diff --git a/dpdata/siesta/output.py b/dpdata/siesta/output.py index 7418d543..0c944d5b 100644 --- a/dpdata/siesta/output.py +++ b/dpdata/siesta/output.py @@ -1,4 +1,5 @@ #!/usr/bin/python3 +from __future__ import annotations import numpy as np diff --git a/dpdata/stat.py b/dpdata/stat.py index 1f6193af..5ec39570 100644 --- a/dpdata/stat.py +++ b/dpdata/stat.py @@ -1,4 +1,6 @@ -from abc import ABCMeta, abstractproperty +from __future__ import annotations + +from abc import ABCMeta, abstractmethod from functools import lru_cache import numpy as np @@ -52,20 +54,22 @@ class ErrorsBase(metaclass=ABCMeta): SYSTEM_TYPE = object def __init__(self, system_1: SYSTEM_TYPE, system_2: SYSTEM_TYPE) -> None: - assert isinstance(system_1, self.SYSTEM_TYPE), ( - "system_1 should be %s" % self.SYSTEM_TYPE.__name__ - ) - assert isinstance(system_2, self.SYSTEM_TYPE), ( - "system_2 should be %s" % self.SYSTEM_TYPE.__name__ - ) + assert isinstance( + system_1, self.SYSTEM_TYPE + ), f"system_1 should be {self.SYSTEM_TYPE.__name__}" + assert isinstance( + system_2, self.SYSTEM_TYPE + ), f"system_2 should be {self.SYSTEM_TYPE.__name__}" self.system_1 = system_1 self.system_2 = system_2 - @abstractproperty + @property + @abstractmethod def e_errors(self) -> np.ndarray: """Energy errors.""" - @abstractproperty + @property + @abstractmethod def f_errors(self) -> np.ndarray: """Force errors.""" @@ -114,12 +118,16 @@ class Errors(ErrorsBase): @lru_cache() def e_errors(self) -> np.ndarray: """Energy errors.""" + assert isinstance(self.system_1, self.SYSTEM_TYPE) + assert isinstance(self.system_2, self.SYSTEM_TYPE) return self.system_1["energies"] - self.system_2["energies"] @property @lru_cache() def f_errors(self) -> np.ndarray: """Force errors.""" + assert isinstance(self.system_1, self.SYSTEM_TYPE) + assert isinstance(self.system_2, self.SYSTEM_TYPE) return (self.system_1["forces"] - self.system_2["forces"]).ravel() @@ -147,6 +155,8 @@ class MultiErrors(ErrorsBase): @lru_cache() def e_errors(self) -> np.ndarray: """Energy errors.""" + assert isinstance(self.system_1, self.SYSTEM_TYPE) + assert isinstance(self.system_2, self.SYSTEM_TYPE) errors = [] for nn in self.system_1.systems.keys(): ss1 = self.system_1[nn] @@ -158,6 +168,8 @@ def e_errors(self) -> np.ndarray: @lru_cache() def f_errors(self) -> np.ndarray: """Force errors.""" + assert isinstance(self.system_1, self.SYSTEM_TYPE) + assert isinstance(self.system_2, self.SYSTEM_TYPE) errors = [] for nn in self.system_1.systems.keys(): ss1 = self.system_1[nn] diff --git a/dpdata/system.py b/dpdata/system.py index 3be86ef4..2614bc23 100644 --- a/dpdata/system.py +++ b/dpdata/system.py @@ -1,20 +1,33 @@ # %% +from __future__ import annotations + import glob import hashlib +import numbers import os +import sys import warnings from copy import deepcopy -from typing import Any, Dict, Optional, Tuple, Union +from typing import ( + TYPE_CHECKING, + Any, + Iterable, + overload, +) + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal import numpy as np -from monty.json import MSONable -from monty.serialization import dumpfn, loadfn import dpdata import dpdata.md.pbc # ensure all plugins are loaded! import dpdata.plugins +import dpdata.plugins.deepmd from dpdata.amber.mask import load_param_file, pick_by_amber_mask from dpdata.data_type import Axis, DataError, DataType, get_data_types from dpdata.driver import Driver, Minimizer @@ -28,6 +41,9 @@ utf8len, ) +if TYPE_CHECKING: + import parmed + def load_format(fmt): fmt = fmt.lower() @@ -41,7 +57,7 @@ def load_format(fmt): ) -class System(MSONable): +class System: """The data System. A data System (a concept used by `deepmd-kit `_) @@ -66,11 +82,11 @@ class System(MSONable): Attributes ---------- - DTYPES : tuple[DataType] + DTYPES : tuple[DataType, ...] data types of this class """ - DTYPES = ( + DTYPES: tuple[DataType, ...] = ( DataType("atom_numbs", list, (Axis.NTYPES,)), DataType("atom_names", list, (Axis.NTYPES,)), DataType("atom_types", np.ndarray, (Axis.NATOMS,)), @@ -86,13 +102,14 @@ class System(MSONable): def __init__( self, - file_name=None, - fmt="auto", - type_map=None, - begin=0, - step=1, - data=None, - convergence_check=True, + # some formats do not use string as input + file_name: Any = None, + fmt: str = "auto", + type_map: list[str] | None = None, + begin: int = 0, + step: int = 1, + data: dict[str, Any] | None = None, + convergence_check: bool = True, **kwargs, ): """Constructor. @@ -213,13 +230,13 @@ def check_data(self): post_funcs = Plugin() - def from_fmt(self, file_name, fmt="auto", **kwargs): + def from_fmt(self, file_name: Any, fmt: str = "auto", **kwargs: Any): fmt = fmt.lower() if fmt == "auto": fmt = os.path.basename(file_name).split(".")[-1].lower() return self.from_fmt_obj(load_format(fmt), file_name, **kwargs) - def from_fmt_obj(self, fmtobj, file_name, **kwargs): + def from_fmt_obj(self, fmtobj: Format, file_name: Any, **kwargs: Any): data = fmtobj.from_system(file_name, **kwargs) if data: if isinstance(data, (list, tuple)): @@ -229,11 +246,11 @@ def from_fmt_obj(self, fmtobj, file_name, **kwargs): self.data = {**self.data, **data} self.check_data() if hasattr(fmtobj.from_system, "post_func"): - for post_f in fmtobj.from_system.post_func: + for post_f in fmtobj.from_system.post_func: # type: ignore self.post_funcs.get_plugin(post_f)(self) return self - def to(self, fmt: str, *args, **kwargs) -> "System": + def to(self, fmt: str, *args: Any, **kwargs: Any) -> System: """Dump systems to the specific format. Parameters @@ -252,7 +269,7 @@ def to(self, fmt: str, *args, **kwargs) -> "System": """ return self.to_fmt_obj(load_format(fmt), *args, **kwargs) - def to_fmt_obj(self, fmtobj, *args, **kwargs): + def to_fmt_obj(self, fmtobj: Format, *args: Any, **kwargs: Any): return fmtobj.to_system(self.data, *args, **kwargs) def __repr__(self): @@ -270,13 +287,32 @@ def __str__(self): ret += "\n" + " ".join(map(str, self.get_atom_numbs())) return ret + @overload + def __getitem__(self, key: int | slice | list | np.ndarray) -> System: ... + @overload + def __getitem__( + self, key: Literal["atom_names", "real_atom_names"] + ) -> list[str]: ... + @overload + def __getitem__(self, key: Literal["atom_numbs"]) -> list[int]: ... + @overload + def __getitem__(self, key: Literal["nopbc"]) -> bool: ... + @overload + def __getitem__( + self, key: Literal["orig", "coords", "energies", "forces", "virials"] + ) -> np.ndarray: ... + @overload + def __getitem__(self, key: str) -> Any: + # other cases, for example customized data + ... + def __getitem__(self, key): """Returns proerty stored in System by key or by idx.""" if isinstance(key, (int, slice, list, np.ndarray)): return self.sub_system(key) return self.data[key] - def __len__(self): + def __len__(self) -> int: """Returns number of frames in the system.""" return self.get_nframes() @@ -295,11 +331,15 @@ def __add__(self, others): raise RuntimeError("Unspported data structure") return self.__class__.from_dict({"data": self_copy.data}) - def dump(self, filename, indent=4): + def dump(self, filename: str, indent: int = 4): """Dump .json or .yaml file.""" + from monty.serialization import dumpfn + dumpfn(self.as_dict(), filename, indent=indent) - def map_atom_types(self, type_map=None) -> np.ndarray: + def map_atom_types( + self, type_map: dict[str, int] | list[str] | None = None + ) -> np.ndarray: """Map the atom types of the system. Parameters @@ -338,11 +378,25 @@ def map_atom_types(self, type_map=None) -> np.ndarray: return new_atom_types @staticmethod - def load(filename): + def load(filename: str): """Rebuild System obj. from .json or .yaml file.""" + from monty.serialization import loadfn + return loadfn(filename) - def as_dict(self): + @classmethod + def from_dict(cls, data: dict): + """Construct a System instance from a data dict.""" + from monty.serialization import MontyDecoder # type: ignore + + decoded = { + k: MontyDecoder().process_decoded(v) + for k, v in data.items() + if not k.startswith("@") + } + return cls(**decoded) + + def as_dict(self) -> dict: """Returns data dict of System instance.""" d = { "@module": self.__class__.__module__, @@ -351,23 +405,23 @@ def as_dict(self): } return d - def get_atom_names(self): + def get_atom_names(self) -> list[str]: """Returns name of atoms.""" return self.data["atom_names"] - def get_atom_types(self): + def get_atom_types(self) -> np.ndarray: """Returns type of atoms.""" return self.data["atom_types"] - def get_atom_numbs(self): + def get_atom_numbs(self) -> list[int]: """Returns number of atoms.""" return self.data["atom_numbs"] - def get_nframes(self): + def get_nframes(self) -> int: """Returns number of frames in the system.""" return len(self.data["cells"]) - def get_natoms(self): + def get_natoms(self) -> int: """Returns total number of atoms in the system.""" return len(self.data["atom_types"]) @@ -379,7 +433,7 @@ def copy(self): """Returns a copy of the system.""" return self.__class__.from_dict({"data": deepcopy(self.data)}) - def sub_system(self, f_idx): + def sub_system(self, f_idx: int | slice | list | np.ndarray): """Construct a subsystem from the system. Parameters @@ -394,15 +448,18 @@ def sub_system(self, f_idx): """ tmp = self.__class__() # convert int to array_like - if isinstance(f_idx, (int, np.int64)): + if isinstance(f_idx, numbers.Integral): f_idx = np.array([f_idx]) + assert not isinstance(f_idx, int) for tt in self.DTYPES: if tt.name not in self.data: # skip optional data continue if tt.shape is not None and Axis.NFRAMES in tt.shape: axis_nframes = tt.shape.index(Axis.NFRAMES) - new_shape = [slice(None) for _ in self.data[tt.name].shape] + new_shape: list[slice | np.ndarray | list] = [ + slice(None) for _ in self.data[tt.name].shape + ] new_shape[axis_nframes] = f_idx tmp.data[tt.name] = self.data[tt.name][tuple(new_shape)] else: @@ -410,7 +467,7 @@ def sub_system(self, f_idx): tmp.data[tt.name] = self.data[tt.name] return tmp - def append(self, system): + def append(self, system: System) -> bool: """Append a system to this system. Parameters @@ -450,9 +507,9 @@ def append(self, system): # check if the first shape is nframes if tt.shape is not None and Axis.NFRAMES in tt.shape: if tt.name not in self.data and tt.name in system.data: - raise RuntimeError("system has %s, but this does not" % tt.name) + raise RuntimeError(f"system has {tt.name}, but this does not") elif tt.name in self.data and tt.name not in system.data: - raise RuntimeError("this has %s, but system does not" % tt.name) + raise RuntimeError(f"this has {tt.name}, but system does not") elif tt.name not in self.data and tt.name not in system.data: # skip if both not exist continue @@ -466,7 +523,7 @@ def append(self, system): self.data["nopbc"] = False return True - def convert_to_mixed_type(self, type_map=None): + def convert_to_mixed_type(self, type_map: list[str] | None = None): """Convert the data dict to mixed type format structure, in order to append systems with different formula but the same number of atoms. Change the 'atom_names' to one placeholder type 'MIXED_TOKEN' and add 'real_atom_types' to store the real type @@ -492,7 +549,7 @@ def convert_to_mixed_type(self, type_map=None): self.data["atom_numbs"] = [natoms] self.data["atom_names"] = ["MIXED_TOKEN"] - def sort_atom_names(self, type_map=None): + def sort_atom_names(self, type_map: list[str] | None = None): """Sort atom_names of the system and reorder atom_numbs and atom_types accoarding to atom_names. If type_map is not given, atom_names will be sorted by alphabetical order. If type_map is given, atom_names will be type_map. @@ -504,7 +561,7 @@ def sort_atom_names(self, type_map=None): """ self.data = sort_atom_names(self.data, type_map=type_map) - def check_type_map(self, type_map): + def check_type_map(self, type_map: list[str] | None): """Assign atom_names to type_map if type_map is given and different from atom_names. @@ -516,7 +573,16 @@ def check_type_map(self, type_map): if type_map is not None and type_map != self.data["atom_names"]: self.sort_atom_names(type_map=type_map) - def apply_type_map(self, type_map): + def apply_type_map(self, type_map: list[str]): + """Customize the element symbol order and it should maintain order + consistency in dpgen or deepmd-kit. It is especially recommended + for multiple complexsystems with multiple elements. + + Parameters + ---------- + type_map : list + type_map + """ if type_map is not None and isinstance(type_map, list): self.check_type_map(type_map) else: @@ -537,13 +603,15 @@ def sort_atom_types(self) -> np.ndarray: continue if tt.shape is not None and Axis.NATOMS in tt.shape: axis_natoms = tt.shape.index(Axis.NATOMS) - new_shape = [slice(None) for _ in self.data[tt.name].shape] + new_shape: list[slice | np.ndarray] = [ + slice(None) for _ in self.data[tt.name].shape + ] new_shape[axis_natoms] = idx self.data[tt.name] = self.data[tt.name][tuple(new_shape)] return idx @property - def formula(self): + def formula(self) -> str: """Return the formula of this system, like C3H5O2.""" return "".join( [ @@ -555,7 +623,7 @@ def formula(self): ) @property - def uniq_formula(self): + def uniq_formula(self) -> str: """Return the uniq_formula of this system. The uniq_formula sort the elements in formula by names. Systems with the same uniq_formula can be append together. @@ -605,7 +673,7 @@ def short_name(self) -> str: return short_formula return self.formula_hash - def extend(self, systems): + def extend(self, systems: Iterable[System]): """Extend a system list to this system. Parameters @@ -623,7 +691,7 @@ def apply_pbc(self): self.data["coords"] = np.matmul(ncoord, self.data["cells"]) @post_funcs.register("remove_pbc") - def remove_pbc(self, protect_layer=9): + def remove_pbc(self, protect_layer: int = 9): """This method does NOT delete the definition of the cells, it (1) revises the cell to a cubic cell and ensures that the cell boundary to any atom in the system is no less than `protect_layer` @@ -638,7 +706,7 @@ def remove_pbc(self, protect_layer=9): assert protect_layer >= 0, "the protect_layer should be no less than 0" remove_pbc(self.data, protect_layer) - def affine_map(self, trans, f_idx=0): + def affine_map(self, trans, f_idx: int | numbers.Integral = 0): assert np.linalg.det(trans) != 0 self.data["cells"][f_idx] = np.matmul(self.data["cells"][f_idx], trans) self.data["coords"][f_idx] = np.matmul(self.data["coords"][f_idx], trans) @@ -656,7 +724,7 @@ def rot_lower_triangular(self): for ii in range(self.get_nframes()): self.rot_frame_lower_triangular(ii) - def rot_frame_lower_triangular(self, f_idx=0): + def rot_frame_lower_triangular(self, f_idx: int | numbers.Integral = 0): qq, rr = np.linalg.qr(self.data["cells"][f_idx].T) if np.linalg.det(qq) < 0: qq = -qq @@ -673,11 +741,11 @@ def rot_frame_lower_triangular(self, f_idx=0): self.affine_map(rot, f_idx=f_idx) return np.matmul(qq, rot) - def add_atom_names(self, atom_names): + def add_atom_names(self, atom_names: list[str]): """Add atom_names that do not exist.""" self.data = add_atom_names(self.data, atom_names) - def replicate(self, ncopy): + def replicate(self, ncopy: list[int] | tuple[int, int, int]): """Replicate the each frame in the system in 3 dimensions. Each frame in the system will become a supercell. @@ -709,7 +777,7 @@ def replicate(self, ncopy): np.array(np.copy(data["atom_numbs"])) * np.prod(ncopy) ) tmp.data["atom_types"] = np.sort( - np.tile(np.copy(data["atom_types"]), np.prod(ncopy)), kind="stable" + np.tile(np.copy(data["atom_types"]), np.prod(ncopy).item()), kind="stable" ) tmp.data["cells"] = np.copy(data["cells"]) for ii in range(3): @@ -729,7 +797,7 @@ def replicate(self, ncopy): ) return tmp - def replace(self, initial_atom_type, end_atom_type, replace_num): + def replace(self, initial_atom_type: str, end_atom_type: str, replace_num: int): if type(self) is not dpdata.System: raise RuntimeError( "Must use method replace() of the instance of class dpdata.System" @@ -774,7 +842,11 @@ def replace(self, initial_atom_type, end_atom_type, replace_num): self.sort_atom_types() def perturb( - self, pert_num, cell_pert_fraction, atom_pert_distance, atom_pert_style="normal" + self, + pert_num: int, + cell_pert_fraction: float, + atom_pert_distance: float, + atom_pert_style: str = "normal", ): """Perturb each frame in the system randomly. The cell will be deformed randomly, and atoms will be displaced by a random distance in random direction. @@ -842,7 +914,7 @@ def nopbc(self): return False @nopbc.setter - def nopbc(self, value): + def nopbc(self, value: bool): self.data["nopbc"] = value def shuffle(self): @@ -851,7 +923,9 @@ def shuffle(self): self.data = self.sub_system(idx).data return idx - def predict(self, *args: Any, driver: str = "dp", **kwargs: Any) -> "LabeledSystem": + def predict( + self, *args: Any, driver: str | Driver = "dp", **kwargs: Any + ) -> LabeledSystem: """Predict energies and forces by a driver. Parameters @@ -880,8 +954,8 @@ def predict(self, *args: Any, driver: str = "dp", **kwargs: Any) -> "LabeledSyst return LabeledSystem(data=data) def minimize( - self, *args: Any, minimizer: Union[str, Minimizer], **kwargs: Any - ) -> "LabeledSystem": + self, *args: Any, minimizer: str | Minimizer, **kwargs: Any + ) -> LabeledSystem: """Minimize the geometry. Parameters @@ -903,7 +977,11 @@ def minimize( data = minimizer.minimize(self.data.copy()) return LabeledSystem(data=data) - def pick_atom_idx(self, idx, nopbc=None): + def pick_atom_idx( + self, + idx: int | numbers.Integral | list[int] | slice | np.ndarray, + nopbc: bool | None = None, + ): """Pick atom index. Parameters @@ -919,15 +997,18 @@ def pick_atom_idx(self, idx, nopbc=None): new system """ new_sys = self.copy() - if isinstance(idx, (int, np.int64)): + if isinstance(idx, numbers.Integral): idx = np.array([idx]) + assert not isinstance(idx, int) for tt in self.DTYPES: if tt.name not in self.data: # skip optional data continue if tt.shape is not None and Axis.NATOMS in tt.shape: axis_natoms = tt.shape.index(Axis.NATOMS) - new_shape = [slice(None) for _ in self.data[tt.name].shape] + new_shape: list[slice | np.ndarray | list[int]] = [ + slice(None) for _ in self.data[tt.name].shape + ] new_shape[axis_natoms] = idx new_sys.data[tt.name] = self.data[tt.name][tuple(new_shape)] # recalculate atom_numbs according to atom_types @@ -939,7 +1020,7 @@ def pick_atom_idx(self, idx, nopbc=None): new_sys.nopbc = nopbc return new_sys - def remove_atom_names(self, atom_names): + def remove_atom_names(self, atom_names: str | list[str]): """Remove atom names and all such atoms. For example, you may not remove EP atoms in TIP4P/Ew water, which is not a real atom. @@ -965,7 +1046,13 @@ def remove_atom_names(self, atom_names): new_sys.data["atom_numbs"] = new_sys.data["atom_numbs"][: len(new_atom_names)] return new_sys - def pick_by_amber_mask(self, param, maskstr, pass_coords=False, nopbc=None): + def pick_by_amber_mask( + self, + param: str | parmed.Structure, + maskstr: str, + pass_coords: bool = False, + nopbc: bool | None = None, + ): """Pick atoms by amber mask. Parameters @@ -995,7 +1082,7 @@ def pick_by_amber_mask(self, param, maskstr, pass_coords=False, nopbc=None): return self.pick_atom_idx(idx, nopbc=nopbc) @classmethod - def register_data_type(cls, *data_type: Tuple[DataType]): + def register_data_type(cls, *data_type: DataType): """Register data type. Parameters @@ -1015,7 +1102,7 @@ def register_data_type(cls, *data_type: Tuple[DataType]): cls.DTYPES = tuple(dtypes_dict.values()) -def get_cell_perturb_matrix(cell_pert_fraction): +def get_cell_perturb_matrix(cell_pert_fraction: float): if cell_pert_fraction < 0: raise RuntimeError("cell_pert_fraction can not be negative") e0 = np.random.rand(6) @@ -1030,7 +1117,10 @@ def get_cell_perturb_matrix(cell_pert_fraction): return cell_pert_matrix -def get_atom_perturb_vector(atom_pert_distance, atom_pert_style="normal"): +def get_atom_perturb_vector( + atom_pert_distance: float, + atom_pert_style: str = "normal", +): random_vector = None if atom_pert_distance < 0: raise RuntimeError("atom_pert_distance can not be negative") @@ -1100,7 +1190,7 @@ class LabeledSystem(System): The number of skipped frames when loading MD trajectory. """ - DTYPES = System.DTYPES + ( + DTYPES: tuple[DataType, ...] = System.DTYPES + ( DataType("energies", np.ndarray, (Axis.NFRAMES,)), DataType("forces", np.ndarray, (Axis.NFRAMES, Axis.NATOMS, 3)), DataType("virials", np.ndarray, (Axis.NFRAMES, 3, 3), required=False), @@ -1119,7 +1209,7 @@ def from_fmt_obj(self, fmtobj, file_name, **kwargs): self.data = {**self.data, **data} self.check_data() if hasattr(fmtobj.from_labeled_system, "post_func"): - for post_f in fmtobj.from_labeled_system.post_func: + for post_f in fmtobj.from_labeled_system.post_func: # type: ignore self.post_funcs.get_plugin(post_f)(self) return self @@ -1133,7 +1223,7 @@ def __str__(self): ret += "\nFrame Numbers : %d" % self.get_nframes() ret += "\nAtom Numbers : %d" % self.get_natoms() status = "Yes" if self.has_virial() else "No" - ret += "\nIncluding Virials : %s" % status + ret += f"\nIncluding Virials : {status}" ret += "\nElement List :" ret += "\n-------------------" ret += "\n" + " ".join(map(str, self.get_atom_names())) @@ -1155,11 +1245,11 @@ def __add__(self, others): raise RuntimeError("Unspported data structure") return self.__class__.from_dict({"data": self_copy.data}) - def has_virial(self): + def has_virial(self) -> bool: # return ('virials' in self.data) and (len(self.data['virials']) > 0) return "virials" in self.data - def affine_map_fv(self, trans, f_idx): + def affine_map_fv(self, trans, f_idx: int | numbers.Integral): assert np.linalg.det(trans) != 0 self.data["forces"][f_idx] = np.matmul(self.data["forces"][f_idx], trans) if self.has_virial(): @@ -1167,12 +1257,12 @@ def affine_map_fv(self, trans, f_idx): trans.T, np.matmul(self.data["virials"][f_idx], trans) ) - def rot_frame_lower_triangular(self, f_idx=0): + def rot_frame_lower_triangular(self, f_idx: int | numbers.Integral = 0): trans = System.rot_frame_lower_triangular(self, f_idx=f_idx) self.affine_map_fv(trans, f_idx=f_idx) return trans - def correction(self, hl_sys): + def correction(self, hl_sys: LabeledSystem) -> LabeledSystem: """Get energy and force correction between self and a high-level LabeledSystem. The self's coordinates will be kept, but energy and forces will be replaced by the correction between these two systems. @@ -1201,7 +1291,7 @@ def correction(self, hl_sys): ) return corrected_sys - def remove_outlier(self, threshold: float = 8.0) -> "LabeledSystem": + def remove_outlier(self, threshold: float = 8.0) -> LabeledSystem: r"""Remove outlier frames from the system. Remove the frames whose energies satisfy the condition @@ -1252,14 +1342,16 @@ def __init__(self, *systems, type_map=None): type_map : list of str Maps atom type to name """ - self.systems = {} + self.systems: dict[str, System] = {} if type_map is not None: - self.atom_names = type_map + self.atom_names: list[str] = type_map else: - self.atom_names = [] + self.atom_names: list[str] = [] self.append(*systems) - def from_fmt_obj(self, fmtobj, directory, labeled=True, **kwargs): + def from_fmt_obj( + self, fmtobj: Format, directory, labeled: bool = True, **kwargs: Any + ): if not isinstance(fmtobj, dpdata.plugins.deepmd.DeePMDMixedFormat): for dd in fmtobj.from_multi_systems(directory, **kwargs): if labeled: @@ -1283,7 +1375,7 @@ def from_fmt_obj(self, fmtobj, directory, labeled=True, **kwargs): self.append(*system_list) return self - def to_fmt_obj(self, fmtobj, directory, *args, **kwargs): + def to_fmt_obj(self, fmtobj: Format, directory, *args: Any, **kwargs: Any): if not isinstance(fmtobj, dpdata.plugins.deepmd.DeePMDMixedFormat): for fn, ss in zip( fmtobj.to_multi_systems( @@ -1302,7 +1394,7 @@ def to_fmt_obj(self, fmtobj, directory, *args, **kwargs): ) return self - def to(self, fmt: str, *args, **kwargs) -> "MultiSystems": + def to(self, fmt: str, *args: Any, **kwargs: Any) -> MultiSystems: """Dump systems to the specific format. Parameters @@ -1346,13 +1438,19 @@ def __add__(self, others): raise RuntimeError("Unspported data structure") @classmethod - def from_file(cls, file_name, fmt, **kwargs): + def from_file(cls, file_name, fmt: str, **kwargs: Any): multi_systems = cls() multi_systems.load_systems_from_file(file_name=file_name, fmt=fmt, **kwargs) return multi_systems @classmethod - def from_dir(cls, dir_name, file_name, fmt="auto", type_map=None): + def from_dir( + cls, + dir_name: str, + file_name: str, + fmt: str = "auto", + type_map: list[str] | None = None, + ): multi_systems = cls() target_file_list = sorted( glob.glob(f"./{dir_name}/**/{file_name}", recursive=True) @@ -1363,15 +1461,16 @@ def from_dir(cls, dir_name, file_name, fmt="auto", type_map=None): ) return multi_systems - def load_systems_from_file(self, file_name=None, fmt=None, **kwargs): + def load_systems_from_file(self, file_name=None, fmt: str | None = None, **kwargs): + assert fmt is not None fmt = fmt.lower() return self.from_fmt_obj(load_format(fmt), file_name, **kwargs) - def get_nframes(self): + def get_nframes(self) -> int: """Returns number of frames in all systems.""" return sum(len(system) for system in self.systems.values()) - def append(self, *systems): + def append(self, *systems: System | MultiSystems): """Append systems or MultiSystems to systems. Parameters @@ -1388,7 +1487,7 @@ def append(self, *systems): else: raise RuntimeError("Object must be System or MultiSystems!") - def __append(self, system): + def __append(self, system: System): if not system.formula: return # prevent changing the original system @@ -1400,7 +1499,7 @@ def __append(self, system): else: self.systems[formula] = system.copy() - def check_atom_names(self, system): + def check_atom_names(self, system: System): """Make atom_names in all systems equal, prevent inconsistent atom_types.""" # new_in_system = set(system["atom_names"]) - set(self.atom_names) # new_in_self = set(self.atom_names) - set(system["atom_names"]) @@ -1421,7 +1520,9 @@ def check_atom_names(self, system): system.add_atom_names(new_in_self) system.sort_atom_names(type_map=self.atom_names) - def predict(self, *args: Any, driver="dp", **kwargs: Any) -> "MultiSystems": + def predict( + self, *args: Any, driver: str | Driver = "dp", **kwargs: Any + ) -> MultiSystems: """Predict energies and forces by a driver. Parameters @@ -1446,8 +1547,8 @@ def predict(self, *args: Any, driver="dp", **kwargs: Any) -> "MultiSystems": return new_multisystems def minimize( - self, *args: Any, minimizer: Union[str, Minimizer], **kwargs: Any - ) -> "MultiSystems": + self, *args: Any, minimizer: str | Minimizer, **kwargs: Any + ) -> MultiSystems: """Minimize geometry by a minimizer. Parameters @@ -1480,7 +1581,11 @@ def minimize( new_multisystems.append(ss.minimize(*args, minimizer=minimizer, **kwargs)) return new_multisystems - def pick_atom_idx(self, idx, nopbc=None): + def pick_atom_idx( + self, + idx: int | numbers.Integral | list[int] | slice | np.ndarray, + nopbc: bool | None = None, + ): """Pick atom index. Parameters @@ -1500,7 +1605,7 @@ def pick_atom_idx(self, idx, nopbc=None): new_sys.append(ss.pick_atom_idx(idx, nopbc=nopbc)) return new_sys - def correction(self, hl_sys: "MultiSystems"): + def correction(self, hl_sys: MultiSystems) -> MultiSystems: """Get energy and force correction between self (assumed low-level) and a high-level MultiSystems. The self's coordinates will be kept, but energy and forces will be replaced by the correction between these two systems. @@ -1535,12 +1640,14 @@ def correction(self, hl_sys: "MultiSystems"): for nn in self.systems.keys(): ll_ss = self[nn] hl_ss = hl_sys[nn] + assert isinstance(ll_ss, LabeledSystem) + assert isinstance(hl_ss, LabeledSystem) corrected_sys.append(ll_ss.correction(hl_ss)) return corrected_sys def train_test_split( - self, test_size: Union[float, int], seed: Optional[int] = None - ) -> Tuple["MultiSystems", "MultiSystems", Dict[str, np.ndarray]]: + self, test_size: float | int, seed: int | None = None + ) -> tuple[MultiSystems, MultiSystems, dict[str, np.ndarray]]: """Split systems into random train and test subsets. Parameters @@ -1596,7 +1703,7 @@ def train_test_split( return train_systems, test_systems, test_system_idx -def get_cls_name(cls: object) -> str: +def get_cls_name(cls: type[Any]) -> str: """Returns the fully qualified name of a class, such as `np.ndarray`. Parameters @@ -1631,32 +1738,30 @@ def add_format_methods(): for method, formatcls in Format.get_from_methods().items(): - def get_func(ff): + def get_func_from(ff): # ff is not initized when defining from_format so cannot be polluted def from_format(self, file_name, **kwargs): return self.from_fmt_obj(ff(), file_name, **kwargs) - from_format.__doc__ = "Read data from :class:`%s` format." % ( - get_cls_name(ff) - ) + from_format.__doc__ = f"Read data from :class:`{get_cls_name(ff)}` format." return from_format - setattr(System, method, get_func(formatcls)) - setattr(LabeledSystem, method, get_func(formatcls)) - setattr(MultiSystems, method, get_func(formatcls)) + setattr(System, method, get_func_from(formatcls)) + setattr(LabeledSystem, method, get_func_from(formatcls)) + setattr(MultiSystems, method, get_func_from(formatcls)) for method, formatcls in Format.get_to_methods().items(): - def get_func(ff): + def get_func_to(ff): def to_format(self, *args, **kwargs): return self.to_fmt_obj(ff(), *args, **kwargs) - to_format.__doc__ = "Dump data to :class:`%s` format." % (get_cls_name(ff)) + to_format.__doc__ = f"Dump data to :class:`{get_cls_name(ff)}` format." return to_format - setattr(System, method, get_func(formatcls)) - setattr(LabeledSystem, method, get_func(formatcls)) - setattr(MultiSystems, method, get_func(formatcls)) + setattr(System, method, get_func_to(formatcls)) + setattr(LabeledSystem, method, get_func_to(formatcls)) + setattr(MultiSystems, method, get_func_to(formatcls)) # at this point, System.DTYPES and LabeledSystem.DTYPES has been initialized System.register_data_type(*get_data_types(labeled=False)) diff --git a/dpdata/unit.py b/dpdata/unit.py index eba07b41..09981b96 100644 --- a/dpdata/unit.py +++ b/dpdata/unit.py @@ -1,6 +1,8 @@ +from __future__ import annotations + from abc import ABC -from scipy import constants +from scipy import constants # noqa: TID253 AVOGADRO = constants.Avogadro # Avagadro constant ELE_CHG = constants.elementary_charge # Elementary Charge, in C diff --git a/dpdata/utils.py b/dpdata/utils.py index cf4a109e..e008120e 100644 --- a/dpdata/utils.py +++ b/dpdata/utils.py @@ -1,9 +1,34 @@ +from __future__ import annotations + +import sys +from typing import overload + +if sys.version_info >= (3, 8): + from typing import Literal +else: + from typing_extensions import Literal import numpy as np from dpdata.periodic_table import Element -def elements_index_map(elements, standard=False, inverse=False): +@overload +def elements_index_map( + elements: list[str], standard: bool, inverse: Literal[True] +) -> dict[int, str]: ... +@overload +def elements_index_map( + elements: list[str], standard: bool, inverse: Literal[False] = ... +) -> dict[str, int]: ... +@overload +def elements_index_map( + elements: list[str], standard: bool, inverse: bool = False +) -> dict[str, int] | dict[int, str]: ... + + +def elements_index_map( + elements: list[str], standard: bool = False, inverse: bool = False +) -> dict: if standard: elements.sort(key=lambda x: Element(x).Z) if inverse: diff --git a/dpdata/vasp/outcar.py b/dpdata/vasp/outcar.py index 0eddac91..0fa4cb68 100644 --- a/dpdata/vasp/outcar.py +++ b/dpdata/vasp/outcar.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import re import warnings diff --git a/dpdata/vasp/poscar.py b/dpdata/vasp/poscar.py index 95f9c15e..102e7904 100644 --- a/dpdata/vasp/poscar.py +++ b/dpdata/vasp/poscar.py @@ -1,4 +1,5 @@ #!/usr/bin/python3 +from __future__ import annotations import numpy as np @@ -59,12 +60,12 @@ def from_system_data(system, f_idx=0, skip_zeros=True): ret += "1.0\n" for ii in system["cells"][f_idx]: for jj in ii: - ret += "%.16e " % jj + ret += f"{jj:.16e} " ret += "\n" for idx, ii in enumerate(system["atom_names"]): if system["atom_numbs"][idx] == 0: continue - ret += "%s " % ii + ret += f"{ii} " ret += "\n" for ii in system["atom_numbs"]: if ii == 0: diff --git a/dpdata/vasp/xml.py b/dpdata/vasp/xml.py index a534fd0c..352b107e 100755 --- a/dpdata/vasp/xml.py +++ b/dpdata/vasp/xml.py @@ -1,4 +1,5 @@ #!/usr/bin/env python3 +from __future__ import annotations import xml.etree.ElementTree as ET diff --git a/dpdata/xyz/quip_gap_xyz.py b/dpdata/xyz/quip_gap_xyz.py index 068bec1f..b23b27e0 100644 --- a/dpdata/xyz/quip_gap_xyz.py +++ b/dpdata/xyz/quip_gap_xyz.py @@ -1,5 +1,7 @@ #!/usr/bin/env python3 # %% +from __future__ import annotations + import re from collections import OrderedDict diff --git a/dpdata/xyz/xyz.py b/dpdata/xyz/xyz.py index 745a97b1..0c36ac32 100644 --- a/dpdata/xyz/xyz.py +++ b/dpdata/xyz/xyz.py @@ -1,4 +1,4 @@ -from typing import Tuple +from __future__ import annotations import numpy as np @@ -31,7 +31,7 @@ def coord_to_xyz(coord: np.ndarray, types: list) -> str: return "\n".join(buff) -def xyz_to_coord(xyz: str) -> Tuple[np.ndarray, list]: +def xyz_to_coord(xyz: str) -> tuple[np.ndarray, list]: """Convert xyz format to coordinates and types. Parameters diff --git a/plugin_example/dpdata_random/__init__.py b/plugin_example/dpdata_random/__init__.py index 22820e0f..cc14faca 100644 --- a/plugin_example/dpdata_random/__init__.py +++ b/plugin_example/dpdata_random/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np from dpdata.format import Format diff --git a/pyproject.toml b/pyproject.toml index 8fe408eb..6efe0818 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=61", "setuptools_scm[toml]>=6.2"] +requires = ["setuptools>=61", "setuptools_scm[toml]>=7"] build-backend = "setuptools.build_meta" [project] @@ -26,6 +26,7 @@ dependencies = [ 'h5py', 'wcmatch', 'importlib_metadata>=1.4; python_version < "3.8"', + 'typing_extensions; python_version < "3.8"', ] requires-python = ">=3.7" readme = "README.md" @@ -56,7 +57,11 @@ docs = [ 'sphinx-argparse', 'rdkit', 'jupyterlite-sphinx', - 'jupyterlite-xeus-python', + 'jupyterlite-xeus', +] +benchmark = [ + 'pytest', + 'pytest-codspeed', ] [tool.setuptools.packages.find] @@ -78,6 +83,8 @@ select = [ "D", # pydocstyle "UP", # pyupgrade "I", # isort + "TID253", # banned-module-level-imports + "TCH", # flake8-type-checking ] ignore = [ "E501", # line too long @@ -103,3 +110,25 @@ ignore-init-module-imports = true [tool.ruff.lint.pydocstyle] convention = "numpy" + +[tool.ruff.lint.flake8-tidy-imports] +banned-module-level-imports = [ + "pymatgen", + "ase", + "openbabel", + "rdkit", + "parmed", + "deepmd", + "h5py", + "wcmatch", + "monty", + "scipy", +] + +[tool.ruff.lint.isort] +required-imports = ["from __future__ import annotations"] + +[tool.pyright] +include = [ + "dpdata/*.py", +] diff --git a/tests/comp_sys.py b/tests/comp_sys.py index f4663780..99879af6 100644 --- a/tests/comp_sys.py +++ b/tests/comp_sys.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np diff --git a/tests/context.py b/tests/context.py index 77a7557d..3214e28e 100644 --- a/tests/context.py +++ b/tests/context.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import sys diff --git a/tests/plugin/dpdata_plugin_test/__init__.py b/tests/plugin/dpdata_plugin_test/__init__.py index b3821cb3..ef26e7c1 100644 --- a/tests/plugin/dpdata_plugin_test/__init__.py +++ b/tests/plugin/dpdata_plugin_test/__init__.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np from dpdata.data_type import Axis, DataType, register_data_type diff --git a/tests/poscars/poscar_ref_oh.py b/tests/poscars/poscar_ref_oh.py index f120183e..2d29aeeb 100644 --- a/tests/poscars/poscar_ref_oh.py +++ b/tests/poscars/poscar_ref_oh.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np diff --git a/tests/poscars/test_lammps_dump_s_su.py b/tests/poscars/test_lammps_dump_s_su.py index 28673dfc..967c767a 100644 --- a/tests/poscars/test_lammps_dump_s_su.py +++ b/tests/poscars/test_lammps_dump_s_su.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/psi4/psi4.out b/tests/psi4/psi4.out index d0d9f8bb..bafdcd4a 100644 --- a/tests/psi4/psi4.out +++ b/tests/psi4/psi4.out @@ -1,549 +1,549 @@ - - ----------------------------------------------------------------------- - Psi4: An Open-Source Ab Initio Electronic Structure Package - Psi4 1.6.1 release - - Git: Rev {HEAD} 5b9f6e3 - - - D. G. A. Smith, L. A. Burns, A. C. Simmonett, R. M. Parrish, - M. C. Schieber, R. Galvelis, P. Kraus, H. Kruse, R. Di Remigio, - A. Alenaizan, A. M. James, S. Lehtola, J. P. Misiewicz, M. Scheurer, - R. A. Shaw, J. B. Schriber, Y. Xie, Z. L. Glick, D. A. Sirianni, - J. S. O'Brien, J. M. Waldrop, A. Kumar, E. G. Hohenstein, - B. P. Pritchard, B. R. Brooks, H. F. Schaefer III, A. Yu. Sokolov, - K. Patkowski, A. E. DePrince III, U. Bozkaya, R. A. King, - F. A. Evangelista, J. M. Turney, T. D. Crawford, C. D. Sherrill, - J. Chem. Phys. 152(18) 184108 (2020). https://doi.org/10.1063/5.0006002 - - Additional Code Authors - E. T. Seidl, C. L. Janssen, E. F. Valeev, M. L. Leininger, - J. F. Gonthier, R. M. Richard, H. R. McAlexander, M. Saitow, X. Wang, - P. Verma, M. H. Lechner, and A. Jiang - - Previous Authors, Complete List of Code Contributors, - and Citations for Specific Modules - https://github.com/psi4/psi4/blob/master/codemeta.json - https://github.com/psi4/psi4/graphs/contributors - http://psicode.org/psi4manual/master/introduction.html#citing-psifour - - ----------------------------------------------------------------------- - - - Psi4 started on: Saturday, 10 December 2022 09:13AM - - Process ID: 4075549 - Host: exp-2-41 - PSIDATADIR: /home/njzjz/anaconda3/envs/p4env/share/psi4 - Memory: 500.0 MiB - Threads: 1 - - ==> Input File <== - --------------------------------------------------------------------------- -molecule { -C -2.048123 8.737055 18.514156 -C -4.662446 9.798136 17.933256 -H -1.010928 7.930652 16.895966 -H -2.425558 7.214861 19.887138 -H -0.843649 10.172359 19.427254 -H -6.115021 8.325339 17.677330 -H -4.535513 10.918460 16.180138 -H -5.257615 11.056429 19.484720 -0 1 -unit bohr -} -set basis def2-TZVPPD -set gradient_write on -G, wfn = gradient("WB97M-D3BJ", return_wfn=True) -wfn.energy() -wfn.gradient().print_out()-------------------------------------------------------------------------- - -Scratch directory: /scratch/njzjz/job_17958150/ -gradient() will perform analytic gradient computation. - -*** tstart() called on exp-2-41 -*** at Sat Dec 10 09:13:42 2022 - - => Loading Basis Set <= - - Name: DEF2-TZVPPD - Role: ORBITAL - Keyword: BASIS - atoms 1-2 entry C line 144 file /home/njzjz/anaconda3/envs/p4env/share/psi4/basis/def2-tzvppd.gbs - atoms 3-8 entry H line 14 file /home/njzjz/anaconda3/envs/p4env/share/psi4/basis/def2-tzvppd.gbs - - => WB97M-D3BJ: Empirical Dispersion <= - - Grimme's -D3 (BJ-damping) Dispersion Correction - Grimme S.; Ehrlich S.; Goerigk L. (2011), J. Comput. Chem., 32: 1456 - Parametrisation from: A. Najib, L. Goerigk, J. Comput. Theory Chem.,14, 5725, 2018 - - s6 = 1.000000 - s8 = 0.390800 - a1 = 0.566000 - a2 = 3.128000 - - - --------------------------------------------------------- - SCF - by Justin Turney, Rob Parrish, Andy Simmonett - and Daniel G. A. Smith - RKS Reference - 1 Threads, 500 MiB Core - --------------------------------------------------------- - - ==> Geometry <== - - Molecular point group: c1 - Full point group: C1 - - Geometry (in Bohr), charge = 0, multiplicity = 1: - - Center X Y Z Mass - ------------ ----------------- ----------------- ----------------- ----------------- - C 1.309059187335 -0.530960676560 0.283395850372 12.000000000000 - C -1.305263812665 0.530120323440 -0.297504149628 12.000000000000 - H 2.346254187335 -1.337363676560 -1.334794149628 1.007825032230 - H 0.931624187335 -2.053154676560 1.656377850372 1.007825032230 - H 2.513533187335 0.904343323440 1.196493850372 1.007825032230 - H -2.757838812665 -0.942676676560 -0.553430149628 1.007825032230 - H -1.178330812665 1.650444323440 -2.050622149628 1.007825032230 - H -1.900432812665 1.788413323440 1.253959850372 1.007825032230 - - Running in c1 symmetry. - - Rotational constants: A = 2.61492 B = 0.67176 C = 0.67128 [cm^-1] - Rotational constants: A = 78393.23592 B = 20138.72637 C = 20124.39598 [MHz] - Nuclear repulsion = 42.114432251814023 - - Charge = 0 - Multiplicity = 1 - Electrons = 18 - Nalpha = 9 - Nbeta = 9 - - ==> Algorithm <== - - SCF Algorithm Type is DF. - DIIS enabled. - MOM disabled. - Fractional occupation disabled. - Guess Type is SAD. - Energy threshold = 1.00e-08 - Density threshold = 1.00e-08 - Integral threshold = 1.00e-12 - - ==> Primary Basis <== - - Basis Set: DEF2-TZVPPD - Blend: DEF2-TZVPPD - Number of shells: 68 - Number of basis functions: 176 - Number of Cartesian functions: 194 - Spherical Harmonics?: true - Max angular momentum: 3 - - ==> DFT Potential <== - - => LibXC <= - - Version 5.1.5 - S. Lehtola, C. Steigemann, M. J. Oliveira, and M. A. Marques, SoftwareX 7, 1 (2018) (10.1016/j.softx.2017.11.002) - - => Composite Functional: WB97M-D3BJ <= - - wB97M-V with D3(BJ) instead of VV10 dispersion - - A. Najib, L. Goerigk, J. Comput. Theory Chem.,14, 5725, 2018 - N. Mardirossian, M. Head-Gordon, J. Chem. Phys. 144, 214110, 2016 - - - Deriv = 1 - GGA = TRUE - Meta = TRUE - - Exchange Hybrid = TRUE - MP2 Hybrid = FALSE - - => Exchange-Correlation Functionals <= - - 1.0000 wB97M-V exchange-correlation functional - - => Exact (HF) Exchange <= - - 0.8500 HF,LR [omega = 0.3000] - 0.1500 HF - - => LibXC Density Thresholds <== - - XC_HYB_MGGA_XC_WB97M_V: 1.00E-13 - - => Molecular Quadrature <= - - Radial Scheme = TREUTLER - Pruning Scheme = NONE - Nuclear Scheme = TREUTLER - - Blocking Scheme = OCTREE - BS radius alpha = 1 - Pruning alpha = 1 - Radial Points = 75 - Spherical Points = 302 - Total Points = 174231 - Total Blocks = 1336 - Max Points = 256 - Max Functions = 176 - Weights Tolerance = 1.00E-15 - - => Loading Basis Set <= - - Name: (DEF2-TZVPPD AUX) - Role: JKFIT - Keyword: DF_BASIS_SCF - atoms 1-2 entry C line 198 file /home/njzjz/anaconda3/envs/p4env/share/psi4/basis/def2-universal-jkfit.gbs - atoms 3-8 entry H line 18 file /home/njzjz/anaconda3/envs/p4env/share/psi4/basis/def2-universal-jkfit.gbs - - ==> Integral Setup <== - - DFHelper Memory: AOs need 0.186 GiB; user supplied 0.186 GiB. Using in-core AOs. - - ==> MemDFJK: Density-Fitted J/K Matrices <== - - J tasked: Yes - K tasked: Yes - wK tasked: Yes - Omega: 3.000E-01 - OpenMP threads: 1 - Memory [MiB]: 190 - Algorithm: Core - Schwarz Cutoff: 1E-12 - Mask sparsity (%): 0.0065 - Fitting Condition: 1E-10 - - => Auxiliary Basis Set <= - - Basis Set: (DEF2-TZVPPD AUX) - Blend: DEF2-UNIVERSAL-JKFIT - Number of shells: 86 - Number of basis functions: 258 - Number of Cartesian functions: 298 - Spherical Harmonics?: true - Max angular momentum: 4 - - Cached 8.4% of DFT collocation blocks in 0.165 [GiB]. - - Minimum eigenvalue in the overlap matrix is 1.6743889872E-05. - Reciprocal condition number of the overlap matrix is 1.3935089665E-06. - Using symmetric orthogonalization. - - ==> Pre-Iterations <== - - SCF Guess: Superposition of Atomic Densities via on-the-fly atomic UHF (no occupation information). - - ------------------------- - Irrep Nso Nmo - ------------------------- - A 176 176 - ------------------------- - Total 176 176 - ------------------------- - - ==> Iterations <== - - Total Energy Delta E RMS |[F,P]| - - @DF-RKS iter SAD: -79.28992761806539 -7.92899e+01 0.00000e+00 - @DF-RKS iter 1: -79.67766568691725 -3.87738e-01 3.47782e-03 DIIS/ADIIS - @DF-RKS iter 2: -79.75816627738935 -8.05006e-02 2.66336e-03 DIIS/ADIIS - @DF-RKS iter 3: -79.86799006059530 -1.09824e-01 1.31950e-04 DIIS/ADIIS - @DF-RKS iter 4: -79.86851631941872 -5.26259e-04 3.15890e-05 DIIS - @DF-RKS iter 5: -79.86854815436648 -3.18349e-05 5.34471e-06 DIIS - @DF-RKS iter 6: -79.86854928519799 -1.13083e-06 7.04641e-07 DIIS - @DF-RKS iter 7: -79.86854931592435 -3.07264e-08 1.22071e-07 DIIS - @DF-RKS iter 8: -79.86854931651604 -5.91683e-10 4.97847e-08 DIIS - @DF-RKS iter 9: -79.86854931656264 -4.65974e-11 1.14257e-08 DIIS - @DF-RKS iter 10: -79.86854931656606 -3.42482e-12 1.80398e-09 DIIS - Energy and wave function converged. - - - ==> Post-Iterations <== - - Electrons on quadrature grid: - Ntotal = 18.0000127756 ; deviation = 1.278e-05 - - Orbital Energies [Eh] - --------------------- - - Doubly Occupied: - - 1A -10.334126 2A -10.333729 3A -0.875736 - 4A -0.726393 5A -0.543563 6A -0.542017 - 7A -0.469628 8A -0.441635 9A -0.432885 - - Virtual: - - 10A 0.045316 11A 0.065512 12A 0.109548 - 13A 0.110094 14A 0.133878 15A 0.135749 - 16A 0.153144 17A 0.168647 18A 0.170387 - 19A 0.200953 20A 0.215127 21A 0.217926 - 22A 0.244649 23A 0.250721 24A 0.263767 - 25A 0.282711 26A 0.286959 27A 0.305733 - 28A 0.317522 29A 0.324458 30A 0.335664 - 31A 0.352086 32A 0.354271 33A 0.370013 - 34A 0.372250 35A 0.374795 36A 0.385099 - 37A 0.410674 38A 0.413507 39A 0.415273 - 40A 0.440023 41A 0.444402 42A 0.462684 - 43A 0.466197 44A 0.474520 45A 0.495234 - 46A 0.496664 47A 0.513014 48A 0.619717 - 49A 0.627507 50A 0.655424 51A 0.689718 - 52A 0.706969 53A 0.721094 54A 0.742198 - 55A 0.748018 56A 0.749627 57A 0.752230 - 58A 0.786391 59A 0.789003 60A 0.821353 - 61A 0.918116 62A 0.925919 63A 0.967642 - 64A 0.991853 65A 1.087734 66A 1.114006 - 67A 1.167096 68A 1.170033 69A 1.183356 - 70A 1.195247 71A 1.214751 72A 1.237566 - 73A 1.302182 74A 1.333099 75A 1.363925 - 76A 1.393038 77A 1.406261 78A 1.436580 - 79A 1.556664 80A 1.558475 81A 1.583158 - 82A 1.619032 83A 1.627605 84A 1.634514 - 85A 1.663730 86A 1.679034 87A 1.693637 - 88A 1.704871 89A 1.885641 90A 1.917077 - 91A 2.023709 92A 2.053746 93A 2.136997 - 94A 2.301575 95A 2.355002 96A 2.613456 - 97A 2.677037 98A 2.694888 99A 2.755999 - 100A 2.773010 101A 2.788802 102A 2.836255 - 103A 2.840682 104A 2.916091 105A 2.963365 - 106A 2.979641 107A 2.991705 108A 3.039915 - 109A 3.052744 110A 3.129687 111A 3.137876 - 112A 3.147850 113A 3.155208 114A 3.244080 - 115A 3.259555 116A 3.294333 117A 3.314367 - 118A 3.342167 119A 3.422823 120A 3.431515 - 121A 3.533123 122A 3.564563 123A 3.588110 - 124A 3.627788 125A 3.640406 126A 3.679402 - 127A 3.713545 128A 3.739019 129A 3.864460 - 130A 3.875511 131A 3.937208 132A 3.974559 - 133A 3.998605 134A 4.017810 135A 4.093466 - 136A 4.111754 137A 4.123870 138A 4.160962 - 139A 4.181011 140A 4.207929 141A 4.216245 - 142A 4.244307 143A 4.248379 144A 4.336607 - 145A 4.362675 146A 4.386331 147A 4.416730 - 148A 4.535234 149A 4.558945 150A 4.609936 - 151A 4.655039 152A 4.693997 153A 4.717652 - 154A 4.892855 155A 4.913920 156A 4.939741 - 157A 4.952953 158A 5.012049 159A 5.070396 - 160A 5.246373 161A 5.293864 162A 5.347947 - 163A 5.357896 164A 5.364785 165A 5.373530 - 166A 5.390169 167A 5.418753 168A 5.480380 - 169A 5.558268 170A 5.620145 171A 5.692490 - 172A 5.711134 173A 5.756651 174A 5.791996 - 175A 23.799935 176A 23.927837 - - Final Occupation by Irrep: - A - DOCC [ 9 ] - - @DF-RKS Final Energy: -79.86854931656606 - - => Energetics <= - - Nuclear Repulsion Energy = 42.1144322518140228 - One-Electron Energy = -189.0217292834274190 - Two-Electron Energy = 75.8975285315186738 - DFT Exchange-Correlation Energy = -8.8527898464713530 - Empirical Dispersion Energy = -0.0059909700000000 - VV10 Nonlocal Energy = 0.0000000000000000 - Total Energy = -79.8685493165660603 - -Computation Completed - - -Properties will be evaluated at 0.000000, 0.000000, 0.000000 [a0] - -Properties computed using the SCF density matrix - - - Multipole Moments: - - ------------------------------------------------------------------------------------ - Multipole Electronic (a.u.) Nuclear (a.u.) Total (a.u.) - ------------------------------------------------------------------------------------ - - L = 1. Multiply by 2.5417464519 to convert [e a0] to [Debye] - Dipole X : 0.0200295 -0.0224186 -0.0023891 - Dipole Y : -0.0036566 0.0049638 0.0013072 - Dipole Z : -0.0746146 0.0833353 0.0087207 - Magnitude : 0.0091361 - - ------------------------------------------------------------------------------------ - -*** tstop() called on exp-2-41 at Sat Dec 10 09:14:39 2022 -Module time: - user time = 55.28 seconds = 0.92 minutes - system time = 0.33 seconds = 0.01 minutes - total time = 57 seconds = 0.95 minutes -Total time: - user time = 55.28 seconds = 0.92 minutes - system time = 0.33 seconds = 0.01 minutes - total time = 57 seconds = 0.95 minutes - -*** tstart() called on exp-2-41 -*** at Sat Dec 10 09:14:39 2022 - - - ------------------------------------------------------------ - SCF GRAD - Rob Parrish, Justin Turney, - Andy Simmonett, and Alex Sokolov - ------------------------------------------------------------ - - ==> Geometry <== - - Molecular point group: c1 - Full point group: C1 - - Geometry (in Bohr), charge = 0, multiplicity = 1: - - Center X Y Z Mass - ------------ ----------------- ----------------- ----------------- ----------------- - C 1.309059187335 -0.530960676560 0.283395850372 12.000000000000 - C -1.305263812665 0.530120323440 -0.297504149628 12.000000000000 - H 2.346254187335 -1.337363676560 -1.334794149628 1.007825032230 - H 0.931624187335 -2.053154676560 1.656377850372 1.007825032230 - H 2.513533187335 0.904343323440 1.196493850372 1.007825032230 - H -2.757838812665 -0.942676676560 -0.553430149628 1.007825032230 - H -1.178330812665 1.650444323440 -2.050622149628 1.007825032230 - H -1.900432812665 1.788413323440 1.253959850372 1.007825032230 - - Nuclear repulsion = 42.114432251814023 - - ==> Basis Set <== - - Basis Set: DEF2-TZVPPD - Blend: DEF2-TZVPPD - Number of shells: 68 - Number of basis functions: 176 - Number of Cartesian functions: 194 - Spherical Harmonics?: true - Max angular momentum: 3 - - ==> DFJKGrad: Density-Fitted SCF Gradients <== - - Gradient: 1 - J tasked: Yes - K tasked: Yes - wK tasked: Yes - Omega: 3.000E-01 - OpenMP threads: 1 - Integrals threads: 1 - Memory [MiB]: 375 - Schwarz Cutoff: 1E-12 - Fitting Condition: 1E-10 - - => Auxiliary Basis Set <= - - Basis Set: (DEF2-TZVPPD AUX) - Blend: DEF2-UNIVERSAL-JKFIT - Number of shells: 86 - Number of basis functions: 258 - Number of Cartesian functions: 298 - Spherical Harmonics?: true - Max angular momentum: 4 - - ==> DFT Potential <== - - => LibXC <= - - Version 5.1.5 - S. Lehtola, C. Steigemann, M. J. Oliveira, and M. A. Marques, SoftwareX 7, 1 (2018) (10.1016/j.softx.2017.11.002) - - => Composite Functional: WB97M-D3BJ <= - - wB97M-V with D3(BJ) instead of VV10 dispersion - - A. Najib, L. Goerigk, J. Comput. Theory Chem.,14, 5725, 2018 - N. Mardirossian, M. Head-Gordon, J. Chem. Phys. 144, 214110, 2016 - - - Deriv = 1 - GGA = TRUE - Meta = TRUE - - Exchange Hybrid = TRUE - MP2 Hybrid = FALSE - - => Exchange-Correlation Functionals <= - - 1.0000 wB97M-V exchange-correlation functional - - => Exact (HF) Exchange <= - - 0.8500 HF,LR [omega = 0.3000] - 0.1500 HF - - => LibXC Density Thresholds <== - - XC_HYB_MGGA_XC_WB97M_V: 1.00E-13 - - => Molecular Quadrature <= - - Radial Scheme = TREUTLER - Pruning Scheme = NONE - Nuclear Scheme = TREUTLER - - Blocking Scheme = OCTREE - BS radius alpha = 1 - Pruning alpha = 1 - Radial Points = 75 - Spherical Points = 302 - Total Points = 174231 - Total Blocks = 1336 - Max Points = 256 - Max Functions = 176 - Weights Tolerance = 1.00E-15 - - - -Total Gradient: - Atom X Y Z - ------ ----------------- ----------------- ----------------- - 1 0.001895773784 0.011781866898 -0.015170522698 - 2 -0.000546756434 -0.012395177679 0.012855204444 - 3 0.008623824979 -0.004386034056 -0.005762912894 - 4 -0.013730630020 -0.003687033163 0.003133079806 - 5 0.004399576588 0.007252138017 0.005168262011 - 6 -0.008316925113 -0.006142832108 -0.000486968302 - 7 0.007554932585 0.001672379716 -0.007775590500 - 8 0.000118796203 0.005904507716 0.008042064203 - - -*** tstop() called on exp-2-41 at Sat Dec 10 09:14:47 2022 -Module time: - user time = 8.05 seconds = 0.13 minutes - system time = 0.04 seconds = 0.00 minutes - total time = 8 seconds = 0.13 minutes -Total time: - user time = 63.34 seconds = 1.06 minutes - system time = 0.37 seconds = 0.01 minutes - total time = 65 seconds = 1.08 minutes - ## Total Gradient (Symmetry 0) ## - Irrep: 1 Size: 8 x 3 - - 1 2 3 - - 1 0.00189577378438 0.01178186689846 -0.01517052269765 - 2 -0.00054675643432 -0.01239517767892 0.01285520444405 - 3 0.00862382497882 -0.00438603405641 -0.00576291289370 - 4 -0.01373063001962 -0.00368703316336 0.00313307980576 - 5 0.00439957658795 0.00725213801722 0.00516826201141 - 6 -0.00831692511314 -0.00614283210761 -0.00048696830158 - 7 0.00755493258543 0.00167237971637 -0.00777559049988 - 8 0.00011879620295 0.00590450771644 0.00804206420271 - - - - - Psi4 stopped on: Saturday, 10 December 2022 09:14AM - Psi4 wall time for execution: 0:01:04.42 - -*** Psi4 exiting successfully. Buy a developer a beer! \ No newline at end of file + + ----------------------------------------------------------------------- + Psi4: An Open-Source Ab Initio Electronic Structure Package + Psi4 1.6.1 release + + Git: Rev {HEAD} 5b9f6e3 + + + D. G. A. Smith, L. A. Burns, A. C. Simmonett, R. M. Parrish, + M. C. Schieber, R. Galvelis, P. Kraus, H. Kruse, R. Di Remigio, + A. Alenaizan, A. M. James, S. Lehtola, J. P. Misiewicz, M. Scheurer, + R. A. Shaw, J. B. Schriber, Y. Xie, Z. L. Glick, D. A. Sirianni, + J. S. O'Brien, J. M. Waldrop, A. Kumar, E. G. Hohenstein, + B. P. Pritchard, B. R. Brooks, H. F. Schaefer III, A. Yu. Sokolov, + K. Patkowski, A. E. DePrince III, U. Bozkaya, R. A. King, + F. A. Evangelista, J. M. Turney, T. D. Crawford, C. D. Sherrill, + J. Chem. Phys. 152(18) 184108 (2020). https://doi.org/10.1063/5.0006002 + + Additional Code Authors + E. T. Seidl, C. L. Janssen, E. F. Valeev, M. L. Leininger, + J. F. Gonthier, R. M. Richard, H. R. McAlexander, M. Saitow, X. Wang, + P. Verma, M. H. Lechner, and A. Jiang + + Previous Authors, Complete List of Code Contributors, + and Citations for Specific Modules + https://github.com/psi4/psi4/blob/master/codemeta.json + https://github.com/psi4/psi4/graphs/contributors + http://psicode.org/psi4manual/master/introduction.html#citing-psifour + + ----------------------------------------------------------------------- + + + Psi4 started on: Saturday, 10 December 2022 09:13AM + + Process ID: 4075549 + Host: exp-2-41 + PSIDATADIR: /home/njzjz/anaconda3/envs/p4env/share/psi4 + Memory: 500.0 MiB + Threads: 1 + + ==> Input File <== + +-------------------------------------------------------------------------- +molecule { +C -2.048123 8.737055 18.514156 +C -4.662446 9.798136 17.933256 +H -1.010928 7.930652 16.895966 +H -2.425558 7.214861 19.887138 +H -0.843649 10.172359 19.427254 +H -6.115021 8.325339 17.677330 +H -4.535513 10.918460 16.180138 +H -5.257615 11.056429 19.484720 +0 1 +unit bohr +} +set basis def2-TZVPPD +set gradient_write on +G, wfn = gradient("WB97M-D3BJ", return_wfn=True) +wfn.energy() +wfn.gradient().print_out()-------------------------------------------------------------------------- + +Scratch directory: /scratch/njzjz/job_17958150/ +gradient() will perform analytic gradient computation. + +*** tstart() called on exp-2-41 +*** at Sat Dec 10 09:13:42 2022 + + => Loading Basis Set <= + + Name: DEF2-TZVPPD + Role: ORBITAL + Keyword: BASIS + atoms 1-2 entry C line 144 file /home/njzjz/anaconda3/envs/p4env/share/psi4/basis/def2-tzvppd.gbs + atoms 3-8 entry H line 14 file /home/njzjz/anaconda3/envs/p4env/share/psi4/basis/def2-tzvppd.gbs + + => WB97M-D3BJ: Empirical Dispersion <= + + Grimme's -D3 (BJ-damping) Dispersion Correction + Grimme S.; Ehrlich S.; Goerigk L. (2011), J. Comput. Chem., 32: 1456 + Parametrisation from: A. Najib, L. Goerigk, J. Comput. Theory Chem.,14, 5725, 2018 + + s6 = 1.000000 + s8 = 0.390800 + a1 = 0.566000 + a2 = 3.128000 + + + --------------------------------------------------------- + SCF + by Justin Turney, Rob Parrish, Andy Simmonett + and Daniel G. A. Smith + RKS Reference + 1 Threads, 500 MiB Core + --------------------------------------------------------- + + ==> Geometry <== + + Molecular point group: c1 + Full point group: C1 + + Geometry (in Bohr), charge = 0, multiplicity = 1: + + Center X Y Z Mass + ------------ ----------------- ----------------- ----------------- ----------------- + C 1.309059187335 -0.530960676560 0.283395850372 12.000000000000 + C -1.305263812665 0.530120323440 -0.297504149628 12.000000000000 + H 2.346254187335 -1.337363676560 -1.334794149628 1.007825032230 + H 0.931624187335 -2.053154676560 1.656377850372 1.007825032230 + H 2.513533187335 0.904343323440 1.196493850372 1.007825032230 + H -2.757838812665 -0.942676676560 -0.553430149628 1.007825032230 + H -1.178330812665 1.650444323440 -2.050622149628 1.007825032230 + H -1.900432812665 1.788413323440 1.253959850372 1.007825032230 + + Running in c1 symmetry. + + Rotational constants: A = 2.61492 B = 0.67176 C = 0.67128 [cm^-1] + Rotational constants: A = 78393.23592 B = 20138.72637 C = 20124.39598 [MHz] + Nuclear repulsion = 42.114432251814023 + + Charge = 0 + Multiplicity = 1 + Electrons = 18 + Nalpha = 9 + Nbeta = 9 + + ==> Algorithm <== + + SCF Algorithm Type is DF. + DIIS enabled. + MOM disabled. + Fractional occupation disabled. + Guess Type is SAD. + Energy threshold = 1.00e-08 + Density threshold = 1.00e-08 + Integral threshold = 1.00e-12 + + ==> Primary Basis <== + + Basis Set: DEF2-TZVPPD + Blend: DEF2-TZVPPD + Number of shells: 68 + Number of basis functions: 176 + Number of Cartesian functions: 194 + Spherical Harmonics?: true + Max angular momentum: 3 + + ==> DFT Potential <== + + => LibXC <= + + Version 5.1.5 + S. Lehtola, C. Steigemann, M. J. Oliveira, and M. A. Marques, SoftwareX 7, 1 (2018) (10.1016/j.softx.2017.11.002) + + => Composite Functional: WB97M-D3BJ <= + + wB97M-V with D3(BJ) instead of VV10 dispersion + + A. Najib, L. Goerigk, J. Comput. Theory Chem.,14, 5725, 2018 + N. Mardirossian, M. Head-Gordon, J. Chem. Phys. 144, 214110, 2016 + + + Deriv = 1 + GGA = TRUE + Meta = TRUE + + Exchange Hybrid = TRUE + MP2 Hybrid = FALSE + + => Exchange-Correlation Functionals <= + + 1.0000 wB97M-V exchange-correlation functional + + => Exact (HF) Exchange <= + + 0.8500 HF,LR [omega = 0.3000] + 0.1500 HF + + => LibXC Density Thresholds <== + + XC_HYB_MGGA_XC_WB97M_V: 1.00E-13 + + => Molecular Quadrature <= + + Radial Scheme = TREUTLER + Pruning Scheme = NONE + Nuclear Scheme = TREUTLER + + Blocking Scheme = OCTREE + BS radius alpha = 1 + Pruning alpha = 1 + Radial Points = 75 + Spherical Points = 302 + Total Points = 174231 + Total Blocks = 1336 + Max Points = 256 + Max Functions = 176 + Weights Tolerance = 1.00E-15 + + => Loading Basis Set <= + + Name: (DEF2-TZVPPD AUX) + Role: JKFIT + Keyword: DF_BASIS_SCF + atoms 1-2 entry C line 198 file /home/njzjz/anaconda3/envs/p4env/share/psi4/basis/def2-universal-jkfit.gbs + atoms 3-8 entry H line 18 file /home/njzjz/anaconda3/envs/p4env/share/psi4/basis/def2-universal-jkfit.gbs + + ==> Integral Setup <== + + DFHelper Memory: AOs need 0.186 GiB; user supplied 0.186 GiB. Using in-core AOs. + + ==> MemDFJK: Density-Fitted J/K Matrices <== + + J tasked: Yes + K tasked: Yes + wK tasked: Yes + Omega: 3.000E-01 + OpenMP threads: 1 + Memory [MiB]: 190 + Algorithm: Core + Schwarz Cutoff: 1E-12 + Mask sparsity (%): 0.0065 + Fitting Condition: 1E-10 + + => Auxiliary Basis Set <= + + Basis Set: (DEF2-TZVPPD AUX) + Blend: DEF2-UNIVERSAL-JKFIT + Number of shells: 86 + Number of basis functions: 258 + Number of Cartesian functions: 298 + Spherical Harmonics?: true + Max angular momentum: 4 + + Cached 8.4% of DFT collocation blocks in 0.165 [GiB]. + + Minimum eigenvalue in the overlap matrix is 1.6743889872E-05. + Reciprocal condition number of the overlap matrix is 1.3935089665E-06. + Using symmetric orthogonalization. + + ==> Pre-Iterations <== + + SCF Guess: Superposition of Atomic Densities via on-the-fly atomic UHF (no occupation information). + + ------------------------- + Irrep Nso Nmo + ------------------------- + A 176 176 + ------------------------- + Total 176 176 + ------------------------- + + ==> Iterations <== + + Total Energy Delta E RMS |[F,P]| + + @DF-RKS iter SAD: -79.28992761806539 -7.92899e+01 0.00000e+00 + @DF-RKS iter 1: -79.67766568691725 -3.87738e-01 3.47782e-03 DIIS/ADIIS + @DF-RKS iter 2: -79.75816627738935 -8.05006e-02 2.66336e-03 DIIS/ADIIS + @DF-RKS iter 3: -79.86799006059530 -1.09824e-01 1.31950e-04 DIIS/ADIIS + @DF-RKS iter 4: -79.86851631941872 -5.26259e-04 3.15890e-05 DIIS + @DF-RKS iter 5: -79.86854815436648 -3.18349e-05 5.34471e-06 DIIS + @DF-RKS iter 6: -79.86854928519799 -1.13083e-06 7.04641e-07 DIIS + @DF-RKS iter 7: -79.86854931592435 -3.07264e-08 1.22071e-07 DIIS + @DF-RKS iter 8: -79.86854931651604 -5.91683e-10 4.97847e-08 DIIS + @DF-RKS iter 9: -79.86854931656264 -4.65974e-11 1.14257e-08 DIIS + @DF-RKS iter 10: -79.86854931656606 -3.42482e-12 1.80398e-09 DIIS + Energy and wave function converged. + + + ==> Post-Iterations <== + + Electrons on quadrature grid: + Ntotal = 18.0000127756 ; deviation = 1.278e-05 + + Orbital Energies [Eh] + --------------------- + + Doubly Occupied: + + 1A -10.334126 2A -10.333729 3A -0.875736 + 4A -0.726393 5A -0.543563 6A -0.542017 + 7A -0.469628 8A -0.441635 9A -0.432885 + + Virtual: + + 10A 0.045316 11A 0.065512 12A 0.109548 + 13A 0.110094 14A 0.133878 15A 0.135749 + 16A 0.153144 17A 0.168647 18A 0.170387 + 19A 0.200953 20A 0.215127 21A 0.217926 + 22A 0.244649 23A 0.250721 24A 0.263767 + 25A 0.282711 26A 0.286959 27A 0.305733 + 28A 0.317522 29A 0.324458 30A 0.335664 + 31A 0.352086 32A 0.354271 33A 0.370013 + 34A 0.372250 35A 0.374795 36A 0.385099 + 37A 0.410674 38A 0.413507 39A 0.415273 + 40A 0.440023 41A 0.444402 42A 0.462684 + 43A 0.466197 44A 0.474520 45A 0.495234 + 46A 0.496664 47A 0.513014 48A 0.619717 + 49A 0.627507 50A 0.655424 51A 0.689718 + 52A 0.706969 53A 0.721094 54A 0.742198 + 55A 0.748018 56A 0.749627 57A 0.752230 + 58A 0.786391 59A 0.789003 60A 0.821353 + 61A 0.918116 62A 0.925919 63A 0.967642 + 64A 0.991853 65A 1.087734 66A 1.114006 + 67A 1.167096 68A 1.170033 69A 1.183356 + 70A 1.195247 71A 1.214751 72A 1.237566 + 73A 1.302182 74A 1.333099 75A 1.363925 + 76A 1.393038 77A 1.406261 78A 1.436580 + 79A 1.556664 80A 1.558475 81A 1.583158 + 82A 1.619032 83A 1.627605 84A 1.634514 + 85A 1.663730 86A 1.679034 87A 1.693637 + 88A 1.704871 89A 1.885641 90A 1.917077 + 91A 2.023709 92A 2.053746 93A 2.136997 + 94A 2.301575 95A 2.355002 96A 2.613456 + 97A 2.677037 98A 2.694888 99A 2.755999 + 100A 2.773010 101A 2.788802 102A 2.836255 + 103A 2.840682 104A 2.916091 105A 2.963365 + 106A 2.979641 107A 2.991705 108A 3.039915 + 109A 3.052744 110A 3.129687 111A 3.137876 + 112A 3.147850 113A 3.155208 114A 3.244080 + 115A 3.259555 116A 3.294333 117A 3.314367 + 118A 3.342167 119A 3.422823 120A 3.431515 + 121A 3.533123 122A 3.564563 123A 3.588110 + 124A 3.627788 125A 3.640406 126A 3.679402 + 127A 3.713545 128A 3.739019 129A 3.864460 + 130A 3.875511 131A 3.937208 132A 3.974559 + 133A 3.998605 134A 4.017810 135A 4.093466 + 136A 4.111754 137A 4.123870 138A 4.160962 + 139A 4.181011 140A 4.207929 141A 4.216245 + 142A 4.244307 143A 4.248379 144A 4.336607 + 145A 4.362675 146A 4.386331 147A 4.416730 + 148A 4.535234 149A 4.558945 150A 4.609936 + 151A 4.655039 152A 4.693997 153A 4.717652 + 154A 4.892855 155A 4.913920 156A 4.939741 + 157A 4.952953 158A 5.012049 159A 5.070396 + 160A 5.246373 161A 5.293864 162A 5.347947 + 163A 5.357896 164A 5.364785 165A 5.373530 + 166A 5.390169 167A 5.418753 168A 5.480380 + 169A 5.558268 170A 5.620145 171A 5.692490 + 172A 5.711134 173A 5.756651 174A 5.791996 + 175A 23.799935 176A 23.927837 + + Final Occupation by Irrep: + A + DOCC [ 9 ] + + @DF-RKS Final Energy: -79.86854931656606 + + => Energetics <= + + Nuclear Repulsion Energy = 42.1144322518140228 + One-Electron Energy = -189.0217292834274190 + Two-Electron Energy = 75.8975285315186738 + DFT Exchange-Correlation Energy = -8.8527898464713530 + Empirical Dispersion Energy = -0.0059909700000000 + VV10 Nonlocal Energy = 0.0000000000000000 + Total Energy = -79.8685493165660603 + +Computation Completed + + +Properties will be evaluated at 0.000000, 0.000000, 0.000000 [a0] + +Properties computed using the SCF density matrix + + + Multipole Moments: + + ------------------------------------------------------------------------------------ + Multipole Electronic (a.u.) Nuclear (a.u.) Total (a.u.) + ------------------------------------------------------------------------------------ + + L = 1. Multiply by 2.5417464519 to convert [e a0] to [Debye] + Dipole X : 0.0200295 -0.0224186 -0.0023891 + Dipole Y : -0.0036566 0.0049638 0.0013072 + Dipole Z : -0.0746146 0.0833353 0.0087207 + Magnitude : 0.0091361 + + ------------------------------------------------------------------------------------ + +*** tstop() called on exp-2-41 at Sat Dec 10 09:14:39 2022 +Module time: + user time = 55.28 seconds = 0.92 minutes + system time = 0.33 seconds = 0.01 minutes + total time = 57 seconds = 0.95 minutes +Total time: + user time = 55.28 seconds = 0.92 minutes + system time = 0.33 seconds = 0.01 minutes + total time = 57 seconds = 0.95 minutes + +*** tstart() called on exp-2-41 +*** at Sat Dec 10 09:14:39 2022 + + + ------------------------------------------------------------ + SCF GRAD + Rob Parrish, Justin Turney, + Andy Simmonett, and Alex Sokolov + ------------------------------------------------------------ + + ==> Geometry <== + + Molecular point group: c1 + Full point group: C1 + + Geometry (in Bohr), charge = 0, multiplicity = 1: + + Center X Y Z Mass + ------------ ----------------- ----------------- ----------------- ----------------- + C 1.309059187335 -0.530960676560 0.283395850372 12.000000000000 + C -1.305263812665 0.530120323440 -0.297504149628 12.000000000000 + H 2.346254187335 -1.337363676560 -1.334794149628 1.007825032230 + H 0.931624187335 -2.053154676560 1.656377850372 1.007825032230 + H 2.513533187335 0.904343323440 1.196493850372 1.007825032230 + H -2.757838812665 -0.942676676560 -0.553430149628 1.007825032230 + H -1.178330812665 1.650444323440 -2.050622149628 1.007825032230 + H -1.900432812665 1.788413323440 1.253959850372 1.007825032230 + + Nuclear repulsion = 42.114432251814023 + + ==> Basis Set <== + + Basis Set: DEF2-TZVPPD + Blend: DEF2-TZVPPD + Number of shells: 68 + Number of basis functions: 176 + Number of Cartesian functions: 194 + Spherical Harmonics?: true + Max angular momentum: 3 + + ==> DFJKGrad: Density-Fitted SCF Gradients <== + + Gradient: 1 + J tasked: Yes + K tasked: Yes + wK tasked: Yes + Omega: 3.000E-01 + OpenMP threads: 1 + Integrals threads: 1 + Memory [MiB]: 375 + Schwarz Cutoff: 1E-12 + Fitting Condition: 1E-10 + + => Auxiliary Basis Set <= + + Basis Set: (DEF2-TZVPPD AUX) + Blend: DEF2-UNIVERSAL-JKFIT + Number of shells: 86 + Number of basis functions: 258 + Number of Cartesian functions: 298 + Spherical Harmonics?: true + Max angular momentum: 4 + + ==> DFT Potential <== + + => LibXC <= + + Version 5.1.5 + S. Lehtola, C. Steigemann, M. J. Oliveira, and M. A. Marques, SoftwareX 7, 1 (2018) (10.1016/j.softx.2017.11.002) + + => Composite Functional: WB97M-D3BJ <= + + wB97M-V with D3(BJ) instead of VV10 dispersion + + A. Najib, L. Goerigk, J. Comput. Theory Chem.,14, 5725, 2018 + N. Mardirossian, M. Head-Gordon, J. Chem. Phys. 144, 214110, 2016 + + + Deriv = 1 + GGA = TRUE + Meta = TRUE + + Exchange Hybrid = TRUE + MP2 Hybrid = FALSE + + => Exchange-Correlation Functionals <= + + 1.0000 wB97M-V exchange-correlation functional + + => Exact (HF) Exchange <= + + 0.8500 HF,LR [omega = 0.3000] + 0.1500 HF + + => LibXC Density Thresholds <== + + XC_HYB_MGGA_XC_WB97M_V: 1.00E-13 + + => Molecular Quadrature <= + + Radial Scheme = TREUTLER + Pruning Scheme = NONE + Nuclear Scheme = TREUTLER + + Blocking Scheme = OCTREE + BS radius alpha = 1 + Pruning alpha = 1 + Radial Points = 75 + Spherical Points = 302 + Total Points = 174231 + Total Blocks = 1336 + Max Points = 256 + Max Functions = 176 + Weights Tolerance = 1.00E-15 + + + -Total Gradient: + Atom X Y Z + ------ ----------------- ----------------- ----------------- + 1 0.001895773784 0.011781866898 -0.015170522698 + 2 -0.000546756434 -0.012395177679 0.012855204444 + 3 0.008623824979 -0.004386034056 -0.005762912894 + 4 -0.013730630020 -0.003687033163 0.003133079806 + 5 0.004399576588 0.007252138017 0.005168262011 + 6 -0.008316925113 -0.006142832108 -0.000486968302 + 7 0.007554932585 0.001672379716 -0.007775590500 + 8 0.000118796203 0.005904507716 0.008042064203 + + +*** tstop() called on exp-2-41 at Sat Dec 10 09:14:47 2022 +Module time: + user time = 8.05 seconds = 0.13 minutes + system time = 0.04 seconds = 0.00 minutes + total time = 8 seconds = 0.13 minutes +Total time: + user time = 63.34 seconds = 1.06 minutes + system time = 0.37 seconds = 0.01 minutes + total time = 65 seconds = 1.08 minutes + ## Total Gradient (Symmetry 0) ## + Irrep: 1 Size: 8 x 3 + + 1 2 3 + + 1 0.00189577378438 0.01178186689846 -0.01517052269765 + 2 -0.00054675643432 -0.01239517767892 0.01285520444405 + 3 0.00862382497882 -0.00438603405641 -0.00576291289370 + 4 -0.01373063001962 -0.00368703316336 0.00313307980576 + 5 0.00439957658795 0.00725213801722 0.00516826201141 + 6 -0.00831692511314 -0.00614283210761 -0.00048696830158 + 7 0.00755493258543 0.00167237971637 -0.00777559049988 + 8 0.00011879620295 0.00590450771644 0.00804206420271 + + + + + Psi4 stopped on: Saturday, 10 December 2022 09:14AM + Psi4 wall time for execution: 0:01:04.42 + +*** Psi4 exiting successfully. Buy a developer a beer! diff --git a/tests/pwmat/config_ref_ch4.py b/tests/pwmat/config_ref_ch4.py index 71aef7fe..72499398 100644 --- a/tests/pwmat/config_ref_ch4.py +++ b/tests/pwmat/config_ref_ch4.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np diff --git a/tests/pwmat/config_ref_oh.py b/tests/pwmat/config_ref_oh.py index 6f3e0561..ad546019 100644 --- a/tests/pwmat/config_ref_oh.py +++ b/tests/pwmat/config_ref_oh.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import numpy as np diff --git a/tests/test_abacus_md.py b/tests/test_abacus_md.py index 782ed521..ddcb7734 100644 --- a/tests/test_abacus_md.py +++ b/tests/test_abacus_md.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_abacus_pw_scf.py b/tests/test_abacus_pw_scf.py index eb712fbe..8d13dddc 100644 --- a/tests/test_abacus_pw_scf.py +++ b/tests/test_abacus_pw_scf.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import shutil import unittest diff --git a/tests/test_abacus_relax.py b/tests/test_abacus_relax.py index 65d73e53..b752a426 100644 --- a/tests/test_abacus_relax.py +++ b/tests/test_abacus_relax.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import shutil import unittest diff --git a/tests/test_abacus_stru_dump.py b/tests/test_abacus_stru_dump.py index 46cb5de6..356aa57f 100644 --- a/tests/test_abacus_stru_dump.py +++ b/tests/test_abacus_stru_dump.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_amber_md.py b/tests/test_amber_md.py index 3995371e..b0a06058 100644 --- a/tests/test_amber_md.py +++ b/tests/test_amber_md.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import shutil import unittest diff --git a/tests/test_amber_sqm.py b/tests/test_amber_sqm.py index 7f14ff84..b7f09110 100644 --- a/tests/test_amber_sqm.py +++ b/tests/test_amber_sqm.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import shutil import unittest diff --git a/tests/test_ase_traj.py b/tests/test_ase_traj.py index b6eab27e..8e4a6e12 100644 --- a/tests/test_ase_traj.py +++ b/tests/test_ase_traj.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from comp_sys import CompLabeledSys, CompSys, IsPBC diff --git a/tests/test_bond_order_system.py b/tests/test_bond_order_system.py index 41a167fb..104e18f1 100644 --- a/tests/test_bond_order_system.py +++ b/tests/test_bond_order_system.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import glob import os import unittest diff --git a/tests/test_cell_to_low_triangle.py b/tests/test_cell_to_low_triangle.py index c080c8e5..34d0a90a 100644 --- a/tests/test_cell_to_low_triangle.py +++ b/tests/test_cell_to_low_triangle.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_cli.py b/tests/test_cli.py index 423b8896..9d70db5f 100644 --- a/tests/test_cli.py +++ b/tests/test_cli.py @@ -1,4 +1,7 @@ +from __future__ import annotations + import subprocess as sp +import sys import unittest from context import dpdata @@ -26,3 +29,12 @@ def setUpClass(cls) -> None: @classmethod def tearDownClass(cls) -> None: cls.system = None + + +class TestClassScript(unittest.TestCase): + def test_class_script(self): + expected_version = dpdata.__version__ + output = sp.check_output([sys.executable, "-m", "dpdata", "--version"]).decode( + "ascii" + ) + assert output.splitlines()[0] == f"dpdata v{expected_version}" diff --git a/tests/test_corr.py b/tests/test_corr.py index 463c99af..a7c6f7c4 100644 --- a/tests/test_corr.py +++ b/tests/test_corr.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from comp_sys import CompLabeledSys, IsPBC diff --git a/tests/test_cp2k_aimd_output.py b/tests/test_cp2k_aimd_output.py index bce24250..46f292b1 100644 --- a/tests/test_cp2k_aimd_output.py +++ b/tests/test_cp2k_aimd_output.py @@ -1,4 +1,6 @@ # %% +from __future__ import annotations + import unittest from comp_sys import CompLabeledSys diff --git a/tests/test_cp2k_output.py b/tests/test_cp2k_output.py index 0e4b153d..da58e87c 100644 --- a/tests/test_cp2k_output.py +++ b/tests/test_cp2k_output.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from comp_sys import CompLabeledSys diff --git a/tests/test_custom_data_type.py b/tests/test_custom_data_type.py index 006d6b01..e94ba5e0 100644 --- a/tests/test_custom_data_type.py +++ b/tests/test_custom_data_type.py @@ -1,6 +1,8 @@ +from __future__ import annotations + import unittest -import h5py +import h5py # noqa: TID253 import numpy as np import dpdata diff --git a/tests/test_deepmd_comp.py b/tests/test_deepmd_comp.py index 46f8e741..28428786 100644 --- a/tests/test_deepmd_comp.py +++ b/tests/test_deepmd_comp.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import shutil import unittest diff --git a/tests/test_deepmd_hdf5.py b/tests/test_deepmd_hdf5.py index 20d16c37..b4a22f3c 100644 --- a/tests/test_deepmd_hdf5.py +++ b/tests/test_deepmd_hdf5.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_deepmd_mixed.py b/tests/test_deepmd_mixed.py index 7e522e06..02044932 100644 --- a/tests/test_deepmd_mixed.py +++ b/tests/test_deepmd_mixed.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import shutil import unittest diff --git a/tests/test_deepmd_raw.py b/tests/test_deepmd_raw.py index 1b056726..af875fde 100644 --- a/tests/test_deepmd_raw.py +++ b/tests/test_deepmd_raw.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import shutil import unittest diff --git a/tests/test_dftbplus.py b/tests/test_dftbplus.py index 2a2913a5..29cdaa92 100644 --- a/tests/test_dftbplus.py +++ b/tests/test_dftbplus.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_elements_index.py b/tests/test_elements_index.py index 45408b4d..186d7b80 100644 --- a/tests/test_elements_index.py +++ b/tests/test_elements_index.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from dpdata.system import elements_index_map diff --git a/tests/test_empty.py b/tests/test_empty.py index 8787f954..12913bab 100644 --- a/tests/test_empty.py +++ b/tests/test_empty.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_fhi_md_multi_elem_output.py b/tests/test_fhi_md_multi_elem_output.py index a20c45bd..b11a52f5 100644 --- a/tests/test_fhi_md_multi_elem_output.py +++ b/tests/test_fhi_md_multi_elem_output.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_fhi_md_output.py b/tests/test_fhi_md_output.py index d205e391..391cc319 100644 --- a/tests/test_fhi_md_output.py +++ b/tests/test_fhi_md_output.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_fhi_output.py b/tests/test_fhi_output.py index 067e5f69..bd3582f3 100644 --- a/tests/test_fhi_output.py +++ b/tests/test_fhi_output.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_from_pymatgen.py b/tests/test_from_pymatgen.py new file mode 100644 index 00000000..7689a9d5 --- /dev/null +++ b/tests/test_from_pymatgen.py @@ -0,0 +1,32 @@ +from __future__ import annotations + +import os +import unittest + +from comp_sys import CompSys +from context import dpdata + +try: + from pymatgen.core import Structure # noqa: F401 + + exist_module = True +except Exception: + exist_module = False + + +@unittest.skipIf(not exist_module, "skip pymatgen") +class TestFormPytmatgen(unittest.TestCase, CompSys): + def setUp(self): + structure = Structure.from_file(os.path.join("poscars", "POSCAR.P42nmc")) + self.system_1 = dpdata.System(structure, fmt="pymatgen/structure") + self.system_2 = dpdata.System( + os.path.join("poscars", "POSCAR.P42nmc"), fmt="poscar" + ) + self.places = 6 + self.e_places = 6 + self.f_places = 6 + self.v_places = 6 + + +if __name__ == "__main__": + unittest.main() diff --git a/tests/test_gaussian_driver.py b/tests/test_gaussian_driver.py index 07150bc7..ff163848 100644 --- a/tests/test_gaussian_driver.py +++ b/tests/test_gaussian_driver.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import importlib import os import shutil diff --git a/tests/test_gaussian_gjf.py b/tests/test_gaussian_gjf.py index 2e5f4ea8..6bed23f6 100644 --- a/tests/test_gaussian_gjf.py +++ b/tests/test_gaussian_gjf.py @@ -1,27 +1,29 @@ -import os -import unittest - -from comp_sys import CompSys -from context import dpdata - - -class TestGaussianGJF(unittest.TestCase): - def setUp(self): - self.system = dpdata.LabeledSystem("poscars/OUTCAR.h2o.md", fmt="vasp/outcar") - - def test_dump_gaussian_gjf(self): - self.system.to_gaussian_gjf("tmp.gjf", keywords="force b3lyp/6-31g*") - os.remove("tmp.gjf") - - -class TestGaussianGJFComp(unittest.TestCase, CompSys): - def setUp(self): - self.system_1 = dpdata.LabeledSystem( - "poscars/OUTCAR.h2o.md", fmt="vasp/outcar" - )[0] - self.system_1.to_gaussian_gjf("tmp.gjf", keywords="force b3lyp/6-31g*") - self.system_2 = dpdata.System( - "tmp.gjf", fmt="gaussian/gjf", type_map=self.system_1.get_atom_names() - ) - os.remove("tmp.gjf") - self.places = 6 +from __future__ import annotations + +import os +import unittest + +from comp_sys import CompSys +from context import dpdata + + +class TestGaussianGJF(unittest.TestCase): + def setUp(self): + self.system = dpdata.LabeledSystem("poscars/OUTCAR.h2o.md", fmt="vasp/outcar") + + def test_dump_gaussian_gjf(self): + self.system.to_gaussian_gjf("tmp.gjf", keywords="force b3lyp/6-31g*") + os.remove("tmp.gjf") + + +class TestGaussianGJFComp(unittest.TestCase, CompSys): + def setUp(self): + self.system_1 = dpdata.LabeledSystem( + "poscars/OUTCAR.h2o.md", fmt="vasp/outcar" + )[0] + self.system_1.to_gaussian_gjf("tmp.gjf", keywords="force b3lyp/6-31g*") + self.system_2 = dpdata.System( + "tmp.gjf", fmt="gaussian/gjf", type_map=self.system_1.get_atom_names() + ) + os.remove("tmp.gjf") + self.places = 6 diff --git a/tests/test_gaussian_log.py b/tests/test_gaussian_log.py index 6622e684..784fd594 100644 --- a/tests/test_gaussian_log.py +++ b/tests/test_gaussian_log.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_gromacs_gro.py b/tests/test_gromacs_gro.py index 2971755f..674c6510 100644 --- a/tests/test_gromacs_gro.py +++ b/tests/test_gromacs_gro.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_json.py b/tests/test_json.py index 545e5db8..0b6f1b9d 100644 --- a/tests/test_json.py +++ b/tests/test_json.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from comp_sys import CompLabeledSys, IsPBC diff --git a/tests/test_lammps_dump_idx.py b/tests/test_lammps_dump_idx.py index 272cc222..39379158 100644 --- a/tests/test_lammps_dump_idx.py +++ b/tests/test_lammps_dump_idx.py @@ -1,4 +1,5 @@ # The index should map to that in the dump file +from __future__ import annotations import os import unittest diff --git a/tests/test_lammps_dump_shift_origin.py b/tests/test_lammps_dump_shift_origin.py index 4ecd6f87..a7444234 100644 --- a/tests/test_lammps_dump_shift_origin.py +++ b/tests/test_lammps_dump_shift_origin.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from comp_sys import CompSys, IsPBC diff --git a/tests/test_lammps_dump_skipload.py b/tests/test_lammps_dump_skipload.py index 224ec6d1..299e1db4 100644 --- a/tests/test_lammps_dump_skipload.py +++ b/tests/test_lammps_dump_skipload.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_lammps_dump_to_system.py b/tests/test_lammps_dump_to_system.py index af9748a5..4d634037 100644 --- a/tests/test_lammps_dump_to_system.py +++ b/tests/test_lammps_dump_to_system.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_lammps_dump_unfold.py b/tests/test_lammps_dump_unfold.py index 1e78d975..587602c8 100644 --- a/tests/test_lammps_dump_unfold.py +++ b/tests/test_lammps_dump_unfold.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_lammps_lmp_dump.py b/tests/test_lammps_lmp_dump.py index 8e9cfb32..25525f76 100644 --- a/tests/test_lammps_lmp_dump.py +++ b/tests/test_lammps_lmp_dump.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_lammps_lmp_to_system.py b/tests/test_lammps_lmp_to_system.py index 19e13312..444b1dd4 100644 --- a/tests/test_lammps_lmp_to_system.py +++ b/tests/test_lammps_lmp_to_system.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_lammps_read_from_trajs.py b/tests/test_lammps_read_from_trajs.py index f1e5afdd..578ae471 100644 --- a/tests/test_lammps_read_from_trajs.py +++ b/tests/test_lammps_read_from_trajs.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_msd.py b/tests/test_msd.py index 52b1ce93..7148b0b5 100644 --- a/tests/test_msd.py +++ b/tests/test_msd.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_multisystems.py b/tests/test_multisystems.py index 2bda13a9..88d4593a 100644 --- a/tests/test_multisystems.py +++ b/tests/test_multisystems.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import tempfile import unittest diff --git a/tests/test_n2p2.py b/tests/test_n2p2.py index 855a2752..32ac6447 100644 --- a/tests/test_n2p2.py +++ b/tests/test_n2p2.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_openmx.py b/tests/test_openmx.py index 0705ed0a..2122e8f4 100644 --- a/tests/test_openmx.py +++ b/tests/test_openmx.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_openmx_check_convergence.py b/tests/test_openmx_check_convergence.py index 362c89c5..b19ad6e8 100644 --- a/tests/test_openmx_check_convergence.py +++ b/tests/test_openmx_check_convergence.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_orca_spout.py b/tests/test_orca_spout.py index ecb1a5ca..7e8cb717 100644 --- a/tests/test_orca_spout.py +++ b/tests/test_orca_spout.py @@ -1,90 +1,92 @@ -import unittest - -import numpy as np -from comp_sys import CompLabeledSys, IsNoPBC -from context import dpdata - - -class TestOrcaSP(unittest.TestCase, CompLabeledSys, IsNoPBC): - def setUp(self): - energy_convert = dpdata.unit.EnergyConversion("hartree", "eV").value() - force_convert = dpdata.unit.ForceConversion( - "hartree/bohr", "eV/angstrom" - ).value() - - self.system_1 = dpdata.LabeledSystem("orca/orca.spout", fmt="orca/spout") - - self.system_2 = dpdata.LabeledSystem( - data={ - "atom_types": np.array( - [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 2, 1, 1, 1, 1, 3, 1, 3, 1] - ), - "atom_names": ["C", "H", "N", "O"], - "atom_numbs": [8, 11, 1, 2], - "coords": np.array( - [ - [ - [-1.74744e00, 2.17247e00, 3.84400e-02], - [-3.05879e00, 1.67227e00, 3.01100e-02], - [-3.27420e00, 2.83660e-01, -7.86000e-03], - [-2.17997e00, -5.85250e-01, -3.67900e-02], - [-6.42570e-01, 1.30482e00, 1.03900e-02], - [-8.75230e-01, -8.54100e-02, -2.75900e-02], - [-1.58753e00, 3.24402e00, 6.79500e-02], - [-6.23100e-02, -7.96870e-01, -5.06600e-02], - [-2.34094e00, -1.65578e00, -6.62400e-02], - [7.43270e-01, 1.92237e00, 2.35500e-02], - [1.91059e00, 9.25720e-01, 4.06000e-03], - [8.36210e-01, 2.54508e00, 9.40240e-01], - [8.33280e-01, 2.58745e00, -8.63170e-01], - [3.18351e00, 1.63882e00, 3.70200e-02], - [1.86317e00, 2.99040e-01, -9.14520e-01], - [1.84793e00, 2.69100e-01, 8.99400e-01], - [3.28398e00, 2.20442e00, -8.37230e-01], - [3.95753e00, 9.35910e-01, 5.24200e-02], - [-4.10991e00, 2.51820e00, 5.88000e-02], - [-3.99914e00, 3.47933e00, 8.64100e-02], - [-4.52084e00, -2.33960e-01, -1.68400e-02], - [-5.31660e00, 3.15930e-01, 2.60000e-03], - ] - ] - ), - "energies": np.array([-513.113388868587]) * energy_convert, - "forces": np.array( - [ - [ - [-5.7786180e-03, -2.4701072e-02, -6.2814900e-04], - [3.2387534e-02, 2.0888587e-02, 4.9131600e-04], - [-1.3022767e-02, 1.3820567e-02, 4.5543300e-04], - [-4.4279100e-04, 1.4037682e-02, 4.7424800e-04], - [-6.3908530e-03, -8.4241470e-03, -1.2989690e-03], - [-8.9298450e-03, 1.6404774e-02, 5.9260500e-04], - [-1.0737810e-03, -1.5698400e-04, 4.1875000e-05], - [4.6807600e-04, 2.2149790e-03, -4.0880000e-06], - [-3.9808540e-03, 2.3696040e-03, 1.0808900e-04], - [5.0405390e-03, 1.0389430e-03, 2.3300390e-03], - [3.1264600e-03, 2.7682000e-04, -3.8873520e-03], - [1.8491730e-03, -4.7411320e-03, -1.3538358e-02], - [3.7527600e-04, -4.2966570e-03, 1.1656289e-02], - [2.0499798e-02, -7.3734830e-03, -2.0336553e-02], - [-6.7151250e-03, 1.3060670e-03, 1.2263601e-02], - [1.6883400e-03, 6.5851660e-03, -1.2895903e-02], - [5.3261000e-04, -2.0068781e-02, 2.8391439e-02], - [-2.2997109e-02, 2.6866202e-02, -3.1128700e-03], - [-2.7960063e-02, 6.0005960e-03, 2.3320500e-04], - [1.5089874e-02, -3.2118582e-02, -9.5217200e-04], - [-1.9753810e-02, -1.1993684e-02, -2.8813700e-04], - [3.5987936e-02, 2.0645360e-03, -9.5588000e-05], - ] - ] - ) - * force_convert, - "cells": np.zeros((1, 3, 3)), - "orig": np.zeros(3), - "nopbc": True, - } - ) - self.places = 6 - self.e_places = 9 - self.f_places = 9 - self.v_places = 6 +from __future__ import annotations + +import unittest + +import numpy as np +from comp_sys import CompLabeledSys, IsNoPBC +from context import dpdata + + +class TestOrcaSP(unittest.TestCase, CompLabeledSys, IsNoPBC): + def setUp(self): + energy_convert = dpdata.unit.EnergyConversion("hartree", "eV").value() + force_convert = dpdata.unit.ForceConversion( + "hartree/bohr", "eV/angstrom" + ).value() + + self.system_1 = dpdata.LabeledSystem("orca/orca.spout", fmt="orca/spout") + + self.system_2 = dpdata.LabeledSystem( + data={ + "atom_types": np.array( + [0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 1, 1, 2, 1, 1, 1, 1, 3, 1, 3, 1] + ), + "atom_names": ["C", "H", "N", "O"], + "atom_numbs": [8, 11, 1, 2], + "coords": np.array( + [ + [ + [-1.74744e00, 2.17247e00, 3.84400e-02], + [-3.05879e00, 1.67227e00, 3.01100e-02], + [-3.27420e00, 2.83660e-01, -7.86000e-03], + [-2.17997e00, -5.85250e-01, -3.67900e-02], + [-6.42570e-01, 1.30482e00, 1.03900e-02], + [-8.75230e-01, -8.54100e-02, -2.75900e-02], + [-1.58753e00, 3.24402e00, 6.79500e-02], + [-6.23100e-02, -7.96870e-01, -5.06600e-02], + [-2.34094e00, -1.65578e00, -6.62400e-02], + [7.43270e-01, 1.92237e00, 2.35500e-02], + [1.91059e00, 9.25720e-01, 4.06000e-03], + [8.36210e-01, 2.54508e00, 9.40240e-01], + [8.33280e-01, 2.58745e00, -8.63170e-01], + [3.18351e00, 1.63882e00, 3.70200e-02], + [1.86317e00, 2.99040e-01, -9.14520e-01], + [1.84793e00, 2.69100e-01, 8.99400e-01], + [3.28398e00, 2.20442e00, -8.37230e-01], + [3.95753e00, 9.35910e-01, 5.24200e-02], + [-4.10991e00, 2.51820e00, 5.88000e-02], + [-3.99914e00, 3.47933e00, 8.64100e-02], + [-4.52084e00, -2.33960e-01, -1.68400e-02], + [-5.31660e00, 3.15930e-01, 2.60000e-03], + ] + ] + ), + "energies": np.array([-513.113388868587]) * energy_convert, + "forces": np.array( + [ + [ + [-5.7786180e-03, -2.4701072e-02, -6.2814900e-04], + [3.2387534e-02, 2.0888587e-02, 4.9131600e-04], + [-1.3022767e-02, 1.3820567e-02, 4.5543300e-04], + [-4.4279100e-04, 1.4037682e-02, 4.7424800e-04], + [-6.3908530e-03, -8.4241470e-03, -1.2989690e-03], + [-8.9298450e-03, 1.6404774e-02, 5.9260500e-04], + [-1.0737810e-03, -1.5698400e-04, 4.1875000e-05], + [4.6807600e-04, 2.2149790e-03, -4.0880000e-06], + [-3.9808540e-03, 2.3696040e-03, 1.0808900e-04], + [5.0405390e-03, 1.0389430e-03, 2.3300390e-03], + [3.1264600e-03, 2.7682000e-04, -3.8873520e-03], + [1.8491730e-03, -4.7411320e-03, -1.3538358e-02], + [3.7527600e-04, -4.2966570e-03, 1.1656289e-02], + [2.0499798e-02, -7.3734830e-03, -2.0336553e-02], + [-6.7151250e-03, 1.3060670e-03, 1.2263601e-02], + [1.6883400e-03, 6.5851660e-03, -1.2895903e-02], + [5.3261000e-04, -2.0068781e-02, 2.8391439e-02], + [-2.2997109e-02, 2.6866202e-02, -3.1128700e-03], + [-2.7960063e-02, 6.0005960e-03, 2.3320500e-04], + [1.5089874e-02, -3.2118582e-02, -9.5217200e-04], + [-1.9753810e-02, -1.1993684e-02, -2.8813700e-04], + [3.5987936e-02, 2.0645360e-03, -9.5588000e-05], + ] + ] + ) + * force_convert, + "cells": np.zeros((1, 3, 3)), + "orig": np.zeros(3), + "nopbc": True, + } + ) + self.places = 6 + self.e_places = 9 + self.f_places = 9 + self.v_places = 6 diff --git a/tests/test_periodic_table.py b/tests/test_periodic_table.py index 6b856e91..3cf36b99 100644 --- a/tests/test_periodic_table.py +++ b/tests/test_periodic_table.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from context import dpdata diff --git a/tests/test_perturb.py b/tests/test_perturb.py index b89a8c7f..eea71116 100644 --- a/tests/test_perturb.py +++ b/tests/test_perturb.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from unittest.mock import patch diff --git a/tests/test_pick_atom_idx.py b/tests/test_pick_atom_idx.py index 0dc06991..ef3368f3 100644 --- a/tests/test_pick_atom_idx.py +++ b/tests/test_pick_atom_idx.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from comp_sys import CompSys, IsNoPBC diff --git a/tests/test_predict.py b/tests/test_predict.py index f08125ab..6ab00be3 100644 --- a/tests/test_predict.py +++ b/tests/test_predict.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_psi4.py b/tests/test_psi4.py index b9c2124e..5454fb5a 100644 --- a/tests/test_psi4.py +++ b/tests/test_psi4.py @@ -1,95 +1,97 @@ -import tempfile -import textwrap -import unittest - -import numpy as np -from comp_sys import CompLabeledSys, IsNoPBC -from context import dpdata - - -class TestPsi4Output(unittest.TestCase, CompLabeledSys, IsNoPBC): - def setUp(self): - length_convert = dpdata.unit.LengthConversion("bohr", "angstrom").value() - energy_convert = dpdata.unit.EnergyConversion("hartree", "eV").value() - force_convert = dpdata.unit.ForceConversion( - "hartree/bohr", "eV/angstrom" - ).value() - - self.system_1 = dpdata.LabeledSystem("psi4/psi4.out", fmt="psi4/out") - - self.system_2 = dpdata.LabeledSystem( - data={ - "atom_types": np.array([0, 0, 1, 1, 1, 1, 1, 1]), - "atom_names": ["C", "H"], - "atom_numbs": [2, 6], - "coords": np.array( - [ - [ - [1.309059187335, -0.530960676560, 0.283395850372], - [-1.305263812665, 0.530120323440, -0.297504149628], - [2.346254187335, -1.337363676560, -1.334794149628], - [0.931624187335, -2.053154676560, 1.656377850372], - [2.513533187335, 0.904343323440, 1.196493850372], - [-2.757838812665, -0.942676676560, -0.553430149628], - [-1.178330812665, 1.650444323440, -2.050622149628], - [-1.900432812665, 1.788413323440, 1.253959850372], - ] - ] - ) - * length_convert, - "energies": np.array([-79.8685493165660603]) * energy_convert, - "forces": -np.array( - [ - [ - [0.00189577378438, 0.01178186689846, -0.01517052269765], - [-0.00054675643432, -0.01239517767892, 0.01285520444405], - [0.00862382497882, -0.00438603405641, -0.00576291289370], - [-0.01373063001962, -0.00368703316336, 0.00313307980576], - [0.00439957658795, 0.00725213801722, 0.00516826201141], - [-0.00831692511314, -0.00614283210761, -0.00048696830158], - [0.00755493258543, 0.00167237971637, -0.00777559049988], - [0.00011879620295, 0.00590450771644, 0.00804206420271], - ] - ] - ) - * force_convert, - "cells": np.zeros((1, 3, 3)), - "orig": np.zeros(3), - "nopbc": True, - } - ) - self.places = 6 - self.e_places = 6 - self.f_places = 6 - self.v_places = 6 - - -class TestPsi4Input(unittest.TestCase): - def test_psi4_input(self): - system = dpdata.LabeledSystem("psi4/psi4.out", fmt="psi4/out") - with tempfile.NamedTemporaryFile("r") as f: - system.to_psi4_inp(f.name, method="WB97M-D3BJ", basis="def2-TZVPPD") - content = f.read() - self.assertEqual( - content, - textwrap.dedent( - """\ - molecule { - C 0.692724290 -0.280972290 0.149966626 - C -0.690715864 0.280527594 -0.157432416 - H 1.241584247 -0.707702380 -0.706342645 - H 0.492994289 -1.086482665 0.876517411 - H 1.330104482 0.478557878 0.633157279 - H -1.459385451 -0.498843014 -0.292862623 - H -0.623545813 0.873377524 -1.085142510 - H -1.005665735 0.946387574 0.663566976 - 0 1 - } - set basis def2-TZVPPD - set gradient_write on - G, wfn = gradient("WB97M-D3BJ", return_wfn=True) - wfn.energy() - wfn.gradient().print_out() - """ - ), - ) +from __future__ import annotations + +import tempfile +import textwrap +import unittest + +import numpy as np +from comp_sys import CompLabeledSys, IsNoPBC +from context import dpdata + + +class TestPsi4Output(unittest.TestCase, CompLabeledSys, IsNoPBC): + def setUp(self): + length_convert = dpdata.unit.LengthConversion("bohr", "angstrom").value() + energy_convert = dpdata.unit.EnergyConversion("hartree", "eV").value() + force_convert = dpdata.unit.ForceConversion( + "hartree/bohr", "eV/angstrom" + ).value() + + self.system_1 = dpdata.LabeledSystem("psi4/psi4.out", fmt="psi4/out") + + self.system_2 = dpdata.LabeledSystem( + data={ + "atom_types": np.array([0, 0, 1, 1, 1, 1, 1, 1]), + "atom_names": ["C", "H"], + "atom_numbs": [2, 6], + "coords": np.array( + [ + [ + [1.309059187335, -0.530960676560, 0.283395850372], + [-1.305263812665, 0.530120323440, -0.297504149628], + [2.346254187335, -1.337363676560, -1.334794149628], + [0.931624187335, -2.053154676560, 1.656377850372], + [2.513533187335, 0.904343323440, 1.196493850372], + [-2.757838812665, -0.942676676560, -0.553430149628], + [-1.178330812665, 1.650444323440, -2.050622149628], + [-1.900432812665, 1.788413323440, 1.253959850372], + ] + ] + ) + * length_convert, + "energies": np.array([-79.8685493165660603]) * energy_convert, + "forces": -np.array( + [ + [ + [0.00189577378438, 0.01178186689846, -0.01517052269765], + [-0.00054675643432, -0.01239517767892, 0.01285520444405], + [0.00862382497882, -0.00438603405641, -0.00576291289370], + [-0.01373063001962, -0.00368703316336, 0.00313307980576], + [0.00439957658795, 0.00725213801722, 0.00516826201141], + [-0.00831692511314, -0.00614283210761, -0.00048696830158], + [0.00755493258543, 0.00167237971637, -0.00777559049988], + [0.00011879620295, 0.00590450771644, 0.00804206420271], + ] + ] + ) + * force_convert, + "cells": np.zeros((1, 3, 3)), + "orig": np.zeros(3), + "nopbc": True, + } + ) + self.places = 6 + self.e_places = 6 + self.f_places = 6 + self.v_places = 6 + + +class TestPsi4Input(unittest.TestCase): + def test_psi4_input(self): + system = dpdata.LabeledSystem("psi4/psi4.out", fmt="psi4/out") + with tempfile.NamedTemporaryFile("r") as f: + system.to_psi4_inp(f.name, method="WB97M-D3BJ", basis="def2-TZVPPD") + content = f.read() + self.assertEqual( + content, + textwrap.dedent( + """\ + molecule { + C 0.692724290 -0.280972290 0.149966626 + C -0.690715864 0.280527594 -0.157432416 + H 1.241584247 -0.707702380 -0.706342645 + H 0.492994289 -1.086482665 0.876517411 + H 1.330104482 0.478557878 0.633157279 + H -1.459385451 -0.498843014 -0.292862623 + H -0.623545813 0.873377524 -1.085142510 + H -1.005665735 0.946387574 0.663566976 + 0 1 + } + set basis def2-TZVPPD + set gradient_write on + G, wfn = gradient("WB97M-D3BJ", return_wfn=True) + wfn.energy() + wfn.gradient().print_out() + """ + ), + ) diff --git a/tests/test_pwmat_config_dump.py b/tests/test_pwmat_config_dump.py index 9389c7a9..e4d5a5a8 100644 --- a/tests/test_pwmat_config_dump.py +++ b/tests/test_pwmat_config_dump.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_pwmat_config_to_system.py b/tests/test_pwmat_config_to_system.py index 0956f956..59fd7339 100644 --- a/tests/test_pwmat_config_to_system.py +++ b/tests/test_pwmat_config_to_system.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_pwmat_mlmd.py b/tests/test_pwmat_mlmd.py index 4a920c15..8dcdb1ef 100644 --- a/tests/test_pwmat_mlmd.py +++ b/tests/test_pwmat_mlmd.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_pwmat_movement.py b/tests/test_pwmat_movement.py index 68a9e681..14e976b2 100644 --- a/tests/test_pwmat_movement.py +++ b/tests/test_pwmat_movement.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_pymatgen_molecule.py b/tests/test_pymatgen_molecule.py index 231bd97f..e6a1b5ee 100644 --- a/tests/test_pymatgen_molecule.py +++ b/tests/test_pymatgen_molecule.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_qe_cp_traj.py b/tests/test_qe_cp_traj.py index 6a963106..9e062986 100644 --- a/tests/test_qe_cp_traj.py +++ b/tests/test_qe_cp_traj.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_qe_cp_traj_skipload.py b/tests/test_qe_cp_traj_skipload.py index 2964e716..43cbe88d 100644 --- a/tests/test_qe_cp_traj_skipload.py +++ b/tests/test_qe_cp_traj_skipload.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_qe_pw_scf.py b/tests/test_qe_pw_scf.py index 57a739fb..8703e7c2 100644 --- a/tests/test_qe_pw_scf.py +++ b/tests/test_qe_pw_scf.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_qe_pw_scf_crystal_atomic_positions.py b/tests/test_qe_pw_scf_crystal_atomic_positions.py index 01c4df21..383ea6cd 100644 --- a/tests/test_qe_pw_scf_crystal_atomic_positions.py +++ b/tests/test_qe_pw_scf_crystal_atomic_positions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_qe_pw_scf_energy_bug.py b/tests/test_qe_pw_scf_energy_bug.py index 8360a7a9..b66ce924 100644 --- a/tests/test_qe_pw_scf_energy_bug.py +++ b/tests/test_qe_pw_scf_energy_bug.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from context import dpdata diff --git a/tests/test_quip_gap_xyz.py b/tests/test_quip_gap_xyz.py index b383bd2f..a265544c 100644 --- a/tests/test_quip_gap_xyz.py +++ b/tests/test_quip_gap_xyz.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from comp_sys import CompLabeledSys, IsPBC diff --git a/tests/test_remove_atom_names.py b/tests/test_remove_atom_names.py index d2d4abc7..9fbd8faf 100644 --- a/tests/test_remove_atom_names.py +++ b/tests/test_remove_atom_names.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from comp_sys import CompLabeledSys, IsNoPBC diff --git a/tests/test_remove_outlier.py b/tests/test_remove_outlier.py index b2cb52fc..c08de0bf 100644 --- a/tests/test_remove_outlier.py +++ b/tests/test_remove_outlier.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_remove_pbc.py b/tests/test_remove_pbc.py index d5befd77..d70a2f02 100644 --- a/tests/test_remove_pbc.py +++ b/tests/test_remove_pbc.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_replace.py b/tests/test_replace.py index b16c388b..b9194137 100644 --- a/tests/test_replace.py +++ b/tests/test_replace.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from unittest.mock import patch diff --git a/tests/test_replicate.py b/tests/test_replicate.py index 99104c3c..3add2dc0 100644 --- a/tests/test_replicate.py +++ b/tests/test_replicate.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from comp_sys import CompSys, IsPBC diff --git a/tests/test_shuffle.py b/tests/test_shuffle.py index 9c462214..3ac33c2f 100644 --- a/tests/test_shuffle.py +++ b/tests/test_shuffle.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from comp_sys import CompLabeledSys, IsPBC diff --git a/tests/test_siesta_aiMD_output.py b/tests/test_siesta_aiMD_output.py index a1ba31b6..4dcb0445 100644 --- a/tests/test_siesta_aiMD_output.py +++ b/tests/test_siesta_aiMD_output.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_siesta_output.py b/tests/test_siesta_output.py index 9ff0167a..c649f7d0 100644 --- a/tests/test_siesta_output.py +++ b/tests/test_siesta_output.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_split_dataset.py b/tests/test_split_dataset.py index a5419b7b..ac0960cf 100644 --- a/tests/test_split_dataset.py +++ b/tests/test_split_dataset.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_sqm_driver.py b/tests/test_sqm_driver.py index 3dbc6df4..d7c0da73 100644 --- a/tests/test_sqm_driver.py +++ b/tests/test_sqm_driver.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import shutil import unittest diff --git a/tests/test_stat.py b/tests/test_stat.py index 9ae8a175..863cea6c 100644 --- a/tests/test_stat.py +++ b/tests/test_stat.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from context import dpdata diff --git a/tests/test_system_append.py b/tests/test_system_append.py index a2c30b23..7c325113 100644 --- a/tests/test_system_append.py +++ b/tests/test_system_append.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_system_apply_pbc.py b/tests/test_system_apply_pbc.py index 9cf44ae0..2114cf6a 100644 --- a/tests/test_system_apply_pbc.py +++ b/tests/test_system_apply_pbc.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_system_set_type.py b/tests/test_system_set_type.py index 4bb14b62..d8362ec7 100644 --- a/tests/test_system_set_type.py +++ b/tests/test_system_set_type.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_to_ase.py b/tests/test_to_ase.py index 60dc931d..09b830ba 100644 --- a/tests/test_to_ase.py +++ b/tests/test_to_ase.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_to_list.py b/tests/test_to_list.py index d559ffce..998f1265 100644 --- a/tests/test_to_list.py +++ b/tests/test_to_list.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from comp_sys import CompLabeledSys, IsPBC diff --git a/tests/test_to_pymatgen.py b/tests/test_to_pymatgen.py index d5815396..72d1b27a 100644 --- a/tests/test_to_pymatgen.py +++ b/tests/test_to_pymatgen.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest @@ -5,7 +7,7 @@ from context import dpdata try: - from pymatgen import Structure # noqa: F401 + from pymatgen.core import Structure # noqa: F401 exist_module = True except Exception: @@ -19,7 +21,7 @@ def setUp(self): system_1.from_lammps_lmp( os.path.join("poscars", "conf.lmp"), type_map=["O", "H"] ) - system_1.to_pymatgen_structure()[0].to("poscar", "tmp.POSCAR") + system_1.to_pymatgen_structure()[0].to(filename="tmp.POSCAR", fmt="poscar") self.system_1 = system_1 self.system_2 = dpdata.System("tmp.POSCAR") self.places = 6 diff --git a/tests/test_to_pymatgen_entry.py b/tests/test_to_pymatgen_entry.py index fd8f40fc..dfdeb468 100644 --- a/tests/test_to_pymatgen_entry.py +++ b/tests/test_to_pymatgen_entry.py @@ -1,8 +1,10 @@ +from __future__ import annotations + import os import unittest from context import dpdata -from monty.serialization import loadfn +from monty.serialization import loadfn # noqa: TID253 try: from pymatgen.entries.computed_entries import ComputedStructureEntry # noqa: F401 diff --git a/tests/test_type_map.py b/tests/test_type_map.py index 2cc50865..92d25ada 100644 --- a/tests/test_type_map.py +++ b/tests/test_type_map.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest from itertools import permutations diff --git a/tests/test_vasp_outcar.py b/tests/test_vasp_outcar.py index fb2ec1c9..832b0a91 100644 --- a/tests/test_vasp_outcar.py +++ b/tests/test_vasp_outcar.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_vasp_poscar_dump.py b/tests/test_vasp_poscar_dump.py index a81cbe94..62f21598 100644 --- a/tests/test_vasp_poscar_dump.py +++ b/tests/test_vasp_poscar_dump.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_vasp_poscar_to_system.py b/tests/test_vasp_poscar_to_system.py index dcb83bfd..7457d33d 100644 --- a/tests/test_vasp_poscar_to_system.py +++ b/tests/test_vasp_poscar_to_system.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_vasp_unconverged_outcar.py b/tests/test_vasp_unconverged_outcar.py index 7e1b3535..1f3b3d2d 100644 --- a/tests/test_vasp_unconverged_outcar.py +++ b/tests/test_vasp_unconverged_outcar.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_vasp_xml.py b/tests/test_vasp_xml.py index cc0bbb41..0b917754 100644 --- a/tests/test_vasp_xml.py +++ b/tests/test_vasp_xml.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import unittest import numpy as np diff --git a/tests/test_water_ions.py b/tests/test_water_ions.py index 788030f3..40c1c143 100644 --- a/tests/test_water_ions.py +++ b/tests/test_water_ions.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import unittest diff --git a/tests/test_xyz.py b/tests/test_xyz.py index a84ad28b..d9bcf70e 100644 --- a/tests/test_xyz.py +++ b/tests/test_xyz.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import tempfile import unittest