From ad2c656baffce72bd173cbb737283cad94a1c0f7 Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Mon, 18 Oct 2021 21:44:20 -0400 Subject: [PATCH 01/23] feat: initial commit --- codeliciousness/Basis-Set-Selector.md | 39 +++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 codeliciousness/Basis-Set-Selector.md diff --git a/codeliciousness/Basis-Set-Selector.md b/codeliciousness/Basis-Set-Selector.md new file mode 100644 index 00000000..09d31285 --- /dev/null +++ b/codeliciousness/Basis-Set-Selector.md @@ -0,0 +1,39 @@ +# Basis set selector (Chemistry) + +> Ideal candidate: scientists skilled in Density Functional Theory and proficient in python. + +# Overview + +The aim of this task is to create a simple python package that implements automatic basis set selection mechanism for a quantum chemistry engine. + +# Requirements + +1. automatically find the basis set delivering a particular precision, passed as argument (eg. within 0.01% from reference) +1. use either experimental data or higher-fidelity modeling results (eg. coupled cluster) as reference data +1. example properties to converge: HOMO-LUMO gaps, vibrational frequencies + +# Expectations + +- mine reference data for use during the project +- correctly find a basis set that satisfies a desired tolerance for a set of 10-100 molecules, starting from H2, as simplest, up to a 10-20-atom ones +- modular and object-oriented implementation +- commit early and often - at least once per 24 hours + +# Timeline + +We leave exact timing to the candidate. Must fit Within 5 days total. + +# User story + +As a user of this software I can start it passing: + +- molecular structure +- reference datapoint +- tolerance (precision) + +as parameters and get the basis set that satisfies the tolerance criterion. + +# Notes + +- create an account at exabyte.io and use it for the calculation purposes +- suggested modeling engine: NWCHEM or SIESTA From 0c663933f7b31298e8f7ef3c5929dd0a6c924dfe Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Mon, 18 Oct 2021 22:51:30 -0400 Subject: [PATCH 02/23] feat: initial cli --- codeliciousness/basistron/__init__.py | 0 codeliciousness/basistron/cli.py | 54 +++++++++++++++++++++++++++ codeliciousness/basistron/main.py | 7 ++++ codeliciousness/basistron/model.py | 37 ++++++++++++++++++ 4 files changed, 98 insertions(+) create mode 100644 codeliciousness/basistron/__init__.py create mode 100644 codeliciousness/basistron/cli.py create mode 100644 codeliciousness/basistron/main.py create mode 100644 codeliciousness/basistron/model.py diff --git a/codeliciousness/basistron/__init__.py b/codeliciousness/basistron/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/codeliciousness/basistron/cli.py b/codeliciousness/basistron/cli.py new file mode 100644 index 00000000..43e9c55a --- /dev/null +++ b/codeliciousness/basistron/cli.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +import os + +from argparse import ArgumentParser, Namespace + +from .model import Driver, Property + + +def get_parser() -> ArgumentParser: + parser = ArgumentParser( + description="Run basis set selection" + ) + parser.add_argument( + "--xyz_path", + type=str, + required=True, + help="path to an XYZ file available on the filesystem", + ) + parser.add_argument( + "--target_property", + type=str, + required=True, + help="property against which basis set selection is evaluated", + ) + parser.add_argument( + "--reference_value", + type=float, + required=True, + help="reference property value (assumes atomic units)", + ) + return parser + + +def process_args(args: Namespace) -> Driver: + if not os.path.isfile(args.xyz_path): + raise FileNotFoundError + # load xyz data + with open(args.xyz_path, "r") as f: + xyz_data = [ + ln.strip().split() for ln in f.readlines()[2:] + ] + # validate target property + if not Property.is_valid_property(args.target_property): + raise Exception("unrecognized property") + # optional tolerance (default defined in Driver) + tol = getattr(args, "reference_tolerance", None) + return Driver( + xyz_data=xyz_data, + target_property=args.target_property, + reference_value=args.reference_value, + reference_tolerance=tol, + ) + + diff --git a/codeliciousness/basistron/main.py b/codeliciousness/basistron/main.py new file mode 100644 index 00000000..254c765e --- /dev/null +++ b/codeliciousness/basistron/main.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- + + +if __name__ == "__main__": + from basistron import cli + parser = cli.get_parser() + driver = cli.process_args(parser.parse_args()) diff --git a/codeliciousness/basistron/model.py b/codeliciousness/basistron/model.py new file mode 100644 index 00000000..0f3a0057 --- /dev/null +++ b/codeliciousness/basistron/model.py @@ -0,0 +1,37 @@ +# -*- coding: utf-8 -*- + +from enum import Enum + +from typing import List, Tuple, Optional, Union + +from pydantic import BaseModel + + +class Property(Enum): + """Provide different scopes for properties.""" + + @classmethod + def is_valid_property(cls: Enum, prop: str) -> bool: + """Validate that provided target property is recognized.""" + for sub in cls.__subclasses__(): + if prop in sub.__members__: + return True + return False + +class SinglePointProperty(Property): + """Properties only requiring a total energy convergence.""" + energy_convergence = 0 + homo_lumo_gap = 1 + +class RelaxationProperty(Property): + """Properties requiring a full relaxation.""" + vibrational_frequencies = 0 + + + +class Driver(BaseModel): + """Abstraction layer allowing multiple modes of execution.""" + xyz_data: List[Tuple[str, float, float, float]] + target_property: str + reference_value: Optional[Union[str, float]] = None + reference_tolerance: Optional[float] = 0.01 From 0cd577520278ac5377ebc6c4487d211cc91ba87d Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Mon, 18 Oct 2021 22:52:30 -0400 Subject: [PATCH 03/23] test: cli tests --- codeliciousness/test/conftest.py | 26 ++++++++++ codeliciousness/test/test_cli.py | 82 ++++++++++++++++++++++++++++++++ 2 files changed, 108 insertions(+) create mode 100644 codeliciousness/test/conftest.py create mode 100644 codeliciousness/test/test_cli.py diff --git a/codeliciousness/test/conftest.py b/codeliciousness/test/conftest.py new file mode 100644 index 00000000..16e6cf82 --- /dev/null +++ b/codeliciousness/test/conftest.py @@ -0,0 +1,26 @@ +# -*- coding: utf-8 -*- + +import pytest + +import pathlib + + +@pytest.fixture +def tmppath(tmpdir): + return pathlib.Path(tmpdir) + + +@pytest.fixture +def h2(): + return """2 + +H 0.0 0.0 0.0 +H 0.0 0.0 0.7""" + + +@pytest.fixture +def h2dat(): + return [ + ("H", 0.0, 0.0, 0.0), + ("H", 0.0, 0.0, 0.7), + ] diff --git a/codeliciousness/test/test_cli.py b/codeliciousness/test/test_cli.py new file mode 100644 index 00000000..4986193c --- /dev/null +++ b/codeliciousness/test/test_cli.py @@ -0,0 +1,82 @@ +# -*- coding: utf-8 -*- + +import pytest + +from basistron import cli +from basistron.model import Driver + +command = [ + "--target_property", + "energy_convergence", + "--reference_value", + "-100", + "--xyz_path", + "/path/to/file", +] + + +def mock_file(tmppath, h2): + path = (tmppath / "h2.xyz").as_posix() + with open(path, "w") as f: + f.write(h2) + return path + + +@pytest.mark.parametrize( + "input_data, expected, raises", + [ + ([], None, True), + ( + ["--xyz_path", "/path/to/file"], + None, + True, + ), + ( + [ + "--xyz_path", + "/path/to/file", + "--target_property", + "energy_convergence", + ], + None, + True, + ), + ( + command, + { + "xyz_path": "/path/to/file", + "target_property": "energy_convergence", + "reference_value": -100.0, + }, + False, + ), + ], +) +def test_get_parser(input_data, expected, raises): + parser = cli.get_parser() + if raises: + with pytest.raises(SystemExit): + parser.parse_args(input_data) + else: + args = parser.parse_args(input_data) + for key, val in expected.items(): + assert getattr(args, key) == val + + +def test_process_args(tmppath, h2, h2dat): + path = mock_file(tmppath, h2) + parser = cli.get_parser() + args = parser.parse_args(command[:-1] + [path]) + ret = cli.process_args(args) + assert isinstance(ret, Driver) + assert ret.xyz_data == h2dat + + +def test_process_args_fail(tmppath, h2, h2dat): + path = mock_file(tmppath, h2) + parser = cli.get_parser() + cmd = command.copy() + cmd[1] = "not_recognized" + args = parser.parse_args(cmd[:-1] + [path]) + with pytest.raises(Exception): + cli.process_args(args) From a9d19adfbc3945aa1279a2514fbc465653a5892f Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Mon, 18 Oct 2021 22:53:25 -0400 Subject: [PATCH 04/23] feat: initial dependencies --- codeliciousness/poetry.lock | 444 +++++++++++++++++++++++++++++++++ codeliciousness/pyproject.toml | 17 ++ 2 files changed, 461 insertions(+) create mode 100644 codeliciousness/poetry.lock create mode 100644 codeliciousness/pyproject.toml diff --git a/codeliciousness/poetry.lock b/codeliciousness/poetry.lock new file mode 100644 index 00000000..11aebcac --- /dev/null +++ b/codeliciousness/poetry.lock @@ -0,0 +1,444 @@ +[[package]] +name = "anyio" +version = "3.3.4" +description = "High level compatibility layer for multiple asynchronous event loop implementations" +category = "main" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +idna = ">=2.8" +sniffio = ">=1.1" + +[package.extras] +doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] +test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] +trio = ["trio (>=0.16)"] + +[[package]] +name = "atomicwrites" +version = "1.4.0" +description = "Atomic file writes." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "attrs" +version = "21.2.0" +description = "Classes Without Boilerplate" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[package.extras] +dev = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface", "furo", "sphinx", "sphinx-notfound-page", "pre-commit"] +docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] +tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] +tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] + +[[package]] +name = "black" +version = "21.9b0" +description = "The uncompromising code formatter." +category = "dev" +optional = false +python-versions = ">=3.6.2" + +[package.dependencies] +click = ">=7.1.2" +mypy-extensions = ">=0.4.3" +pathspec = ">=0.9.0,<1" +platformdirs = ">=2" +regex = ">=2020.1.8" +tomli = ">=0.2.6,<2.0.0" +typing-extensions = [ + {version = ">=3.10.0.0", markers = "python_version < \"3.10\""}, + {version = "!=3.10.0.1", markers = "python_version >= \"3.10\""}, +] + +[package.extras] +colorama = ["colorama (>=0.4.3)"] +d = ["aiohttp (>=3.6.0)", "aiohttp-cors (>=0.4.0)"] +jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] +python2 = ["typed-ast (>=1.4.2)"] +uvloop = ["uvloop (>=0.15.2)"] + +[[package]] +name = "click" +version = "8.0.3" +description = "Composable command line interface toolkit" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +colorama = {version = "*", markers = "platform_system == \"Windows\""} + +[[package]] +name = "colorama" +version = "0.4.4" +description = "Cross-platform colored terminal text." +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" + +[[package]] +name = "fastapi" +version = "0.70.0" +description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" +starlette = "0.16.0" + +[package.extras] +all = ["requests (>=2.24.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<3.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] +dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] +doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=7.1.9,<8.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"] +test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"] + +[[package]] +name = "idna" +version = "3.3" +description = "Internationalized Domain Names in Applications (IDNA)" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "mypy-extensions" +version = "0.4.3" +description = "Experimental type system extensions for programs checked with the mypy typechecker." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "packaging" +version = "21.0" +description = "Core utilities for Python packages" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +pyparsing = ">=2.0.2" + +[[package]] +name = "pathspec" +version = "0.9.0" +description = "Utility library for gitignore style pattern matching of file paths." +category = "dev" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,>=2.7" + +[[package]] +name = "platformdirs" +version = "2.4.0" +description = "A small Python module for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +docs = ["Sphinx (>=4)", "furo (>=2021.7.5b38)", "proselint (>=0.10.2)", "sphinx-autodoc-typehints (>=1.12)"] +test = ["appdirs (==1.4.4)", "pytest (>=6)", "pytest-cov (>=2.7)", "pytest-mock (>=3.6)"] + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "py" +version = "1.10.0" +description = "library with cross-python path, ini-parsing, io, code, log facilities" +category = "dev" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" + +[[package]] +name = "pydantic" +version = "1.8.2" +description = "Data validation and settings management using python 3.6 type hinting" +category = "main" +optional = false +python-versions = ">=3.6.1" + +[package.dependencies] +typing-extensions = ">=3.7.4.3" + +[package.extras] +dotenv = ["python-dotenv (>=0.10.4)"] +email = ["email-validator (>=1.0.3)"] + +[[package]] +name = "pyparsing" +version = "2.4.7" +description = "Python parsing module" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "pytest" +version = "6.2.5" +description = "pytest: simple powerful testing with Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +atomicwrites = {version = ">=1.0", markers = "sys_platform == \"win32\""} +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +py = ">=1.8.2" +toml = "*" + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] + +[[package]] +name = "regex" +version = "2021.10.8" +description = "Alternative regular expression module, to replace re." +category = "dev" +optional = false +python-versions = "*" + +[[package]] +name = "sniffio" +version = "1.2.0" +description = "Sniff out which async library your code is running under" +category = "main" +optional = false +python-versions = ">=3.5" + +[[package]] +name = "starlette" +version = "0.16.0" +description = "The little ASGI library that shines." +category = "main" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +anyio = ">=3.0.0,<4" + +[package.extras] +full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "graphene"] + +[[package]] +name = "toml" +version = "0.10.2" +description = "Python Library for Tom's Obvious, Minimal Language" +category = "dev" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" + +[[package]] +name = "tomli" +version = "1.2.1" +description = "A lil' TOML parser" +category = "dev" +optional = false +python-versions = ">=3.6" + +[[package]] +name = "typing-extensions" +version = "3.10.0.2" +description = "Backported and Experimental Type Hints for Python 3.5+" +category = "main" +optional = false +python-versions = "*" + +[metadata] +lock-version = "1.1" +python-versions = "^3.9" +content-hash = "12680b53480c36b3b338621e8f7d59a6cd002195af6d7b13bac1d4eed48ce8b0" + +[metadata.files] +anyio = [ + {file = "anyio-3.3.4-py3-none-any.whl", hash = "sha256:4fd09a25ab7fa01d34512b7249e366cd10358cdafc95022c7ff8c8f8a5026d66"}, + {file = "anyio-3.3.4.tar.gz", hash = "sha256:67da67b5b21f96b9d3d65daa6ea99f5d5282cb09f50eb4456f8fb51dffefc3ff"}, +] +atomicwrites = [ + {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, + {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, +] +attrs = [ + {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, + {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, +] +black = [ + {file = "black-21.9b0-py3-none-any.whl", hash = "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115"}, + {file = "black-21.9b0.tar.gz", hash = "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"}, +] +click = [ + {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, + {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, +] +colorama = [ + {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, + {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, +] +fastapi = [ + {file = "fastapi-0.70.0-py3-none-any.whl", hash = "sha256:a36d5f2fad931aa3575c07a3472c784e81f3e664e3bb5c8b9c88d0ec1104f59c"}, + {file = "fastapi-0.70.0.tar.gz", hash = "sha256:66da43cfe5185ea1df99552acffd201f1832c6b364e0f4136c0a99f933466ced"}, +] +idna = [ + {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, + {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, +] +iniconfig = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] +mypy-extensions = [ + {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, + {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, +] +packaging = [ + {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, + {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, +] +pathspec = [ + {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, + {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, +] +platformdirs = [ + {file = "platformdirs-2.4.0-py3-none-any.whl", hash = "sha256:8868bbe3c3c80d42f20156f22e7131d2fb321f5bc86a2a345375c6481a67021d"}, + {file = "platformdirs-2.4.0.tar.gz", hash = "sha256:367a5e80b3d04d2428ffa76d33f124cf11e8fff2acdaa9b43d545f5c7d661ef2"}, +] +pluggy = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] +py = [ + {file = "py-1.10.0-py2.py3-none-any.whl", hash = "sha256:3b80836aa6d1feeaa108e046da6423ab8f6ceda6468545ae8d02d9d58d18818a"}, + {file = "py-1.10.0.tar.gz", hash = "sha256:21b81bda15b66ef5e1a777a21c4dcd9c20ad3efd0b3f817e7a809035269e1bd3"}, +] +pydantic = [ + {file = "pydantic-1.8.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:05ddfd37c1720c392f4e0d43c484217b7521558302e7069ce8d318438d297739"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux1_i686.whl", hash = "sha256:a7c6002203fe2c5a1b5cbb141bb85060cbff88c2d78eccbc72d97eb7022c43e4"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_i686.whl", hash = "sha256:589eb6cd6361e8ac341db97602eb7f354551482368a37f4fd086c0733548308e"}, + {file = "pydantic-1.8.2-cp36-cp36m-manylinux2014_x86_64.whl", hash = "sha256:10e5622224245941efc193ad1d159887872776df7a8fd592ed746aa25d071840"}, + {file = "pydantic-1.8.2-cp36-cp36m-win_amd64.whl", hash = "sha256:99a9fc39470010c45c161a1dc584997f1feb13f689ecf645f59bb4ba623e586b"}, + {file = "pydantic-1.8.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a83db7205f60c6a86f2c44a61791d993dff4b73135df1973ecd9eed5ea0bda20"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux1_i686.whl", hash = "sha256:41b542c0b3c42dc17da70554bc6f38cbc30d7066d2c2815a94499b5684582ecb"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_i686.whl", hash = "sha256:ea5cb40a3b23b3265f6325727ddfc45141b08ed665458be8c6285e7b85bd73a1"}, + {file = "pydantic-1.8.2-cp37-cp37m-manylinux2014_x86_64.whl", hash = "sha256:18b5ea242dd3e62dbf89b2b0ec9ba6c7b5abaf6af85b95a97b00279f65845a23"}, + {file = "pydantic-1.8.2-cp37-cp37m-win_amd64.whl", hash = "sha256:234a6c19f1c14e25e362cb05c68afb7f183eb931dd3cd4605eafff055ebbf287"}, + {file = "pydantic-1.8.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:021ea0e4133e8c824775a0cfe098677acf6fa5a3cbf9206a376eed3fc09302cd"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux1_i686.whl", hash = "sha256:e710876437bc07bd414ff453ac8ec63d219e7690128d925c6e82889d674bb505"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_i686.whl", hash = "sha256:ac8eed4ca3bd3aadc58a13c2aa93cd8a884bcf21cb019f8cfecaae3b6ce3746e"}, + {file = "pydantic-1.8.2-cp38-cp38-manylinux2014_x86_64.whl", hash = "sha256:4a03cbbe743e9c7247ceae6f0d8898f7a64bb65800a45cbdc52d65e370570820"}, + {file = "pydantic-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:8621559dcf5afacf0069ed194278f35c255dc1a1385c28b32dd6c110fd6531b3"}, + {file = "pydantic-1.8.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:8b223557f9510cf0bfd8b01316bf6dd281cf41826607eada99662f5e4963f316"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux1_i686.whl", hash = "sha256:244ad78eeb388a43b0c927e74d3af78008e944074b7d0f4f696ddd5b2af43c62"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_i686.whl", hash = "sha256:05ef5246a7ffd2ce12a619cbb29f3307b7c4509307b1b49f456657b43529dc6f"}, + {file = "pydantic-1.8.2-cp39-cp39-manylinux2014_x86_64.whl", hash = "sha256:54cd5121383f4a461ff7644c7ca20c0419d58052db70d8791eacbbe31528916b"}, + {file = "pydantic-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:4be75bebf676a5f0f87937c6ddb061fa39cbea067240d98e298508c1bda6f3f3"}, + {file = "pydantic-1.8.2-py3-none-any.whl", hash = "sha256:fec866a0b59f372b7e776f2d7308511784dace622e0992a0b59ea3ccee0ae833"}, + {file = "pydantic-1.8.2.tar.gz", hash = "sha256:26464e57ccaafe72b7ad156fdaa4e9b9ef051f69e175dbbb463283000c05ab7b"}, +] +pyparsing = [ + {file = "pyparsing-2.4.7-py2.py3-none-any.whl", hash = "sha256:ef9d7589ef3c200abe66653d3f1ab1033c3c419ae9b9bdb1240a85b024efc88b"}, + {file = "pyparsing-2.4.7.tar.gz", hash = "sha256:c203ec8783bf771a155b207279b9bccb8dea02d8f0c9e5f8ead507bc3246ecc1"}, +] +pytest = [ + {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, + {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, +] +regex = [ + {file = "regex-2021.10.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:094a905e87a4171508c2a0e10217795f83c636ccc05ddf86e7272c26e14056ae"}, + {file = "regex-2021.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:981c786293a3115bc14c103086ae54e5ee50ca57f4c02ce7cf1b60318d1e8072"}, + {file = "regex-2021.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b0f2f874c6a157c91708ac352470cb3bef8e8814f5325e3c5c7a0533064c6a24"}, + {file = "regex-2021.10.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51feefd58ac38eb91a21921b047da8644155e5678e9066af7bcb30ee0dca7361"}, + {file = "regex-2021.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8de658d7db5987b11097445f2b1f134400e2232cb40e614e5f7b6f5428710e"}, + {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1ce02f420a7ec3b2480fe6746d756530f69769292eca363218c2291d0b116a01"}, + {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39079ebf54156be6e6902f5c70c078f453350616cfe7bfd2dd15bdb3eac20ccc"}, + {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ff24897f6b2001c38a805d53b6ae72267025878d35ea225aa24675fbff2dba7f"}, + {file = "regex-2021.10.8-cp310-cp310-win32.whl", hash = "sha256:c6569ba7b948c3d61d27f04e2b08ebee24fec9ff8e9ea154d8d1e975b175bfa7"}, + {file = "regex-2021.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:45cb0f7ff782ef51bc79e227a87e4e8f24bc68192f8de4f18aae60b1d60bc152"}, + {file = "regex-2021.10.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fab3ab8aedfb443abb36729410403f0fe7f60ad860c19a979d47fb3eb98ef820"}, + {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74e55f8d66f1b41d44bc44c891bcf2c7fad252f8f323ee86fba99d71fd1ad5e3"}, + {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d52c5e089edbdb6083391faffbe70329b804652a53c2fdca3533e99ab0580d9"}, + {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1abbd95cbe9e2467cac65c77b6abd9223df717c7ae91a628502de67c73bf6838"}, + {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9b5c215f3870aa9b011c00daeb7be7e1ae4ecd628e9beb6d7e6107e07d81287"}, + {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f540f153c4f5617bc4ba6433534f8916d96366a08797cbbe4132c37b70403e92"}, + {file = "regex-2021.10.8-cp36-cp36m-win32.whl", hash = "sha256:1f51926db492440e66c89cd2be042f2396cf91e5b05383acd7372b8cb7da373f"}, + {file = "regex-2021.10.8-cp36-cp36m-win_amd64.whl", hash = "sha256:5f55c4804797ef7381518e683249310f7f9646da271b71cb6b3552416c7894ee"}, + {file = "regex-2021.10.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb2baff66b7d2267e07ef71e17d01283b55b3cc51a81b54cc385e721ae172ba4"}, + {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e527ab1c4c7cf2643d93406c04e1d289a9d12966529381ce8163c4d2abe4faf"}, + {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c98b013273e9da5790ff6002ab326e3f81072b4616fd95f06c8fa733d2745f"}, + {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:55ef044899706c10bc0aa052f2fc2e58551e2510694d6aae13f37c50f3f6ff61"}, + {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0ab3530a279a3b7f50f852f1bab41bc304f098350b03e30a3876b7dd89840e"}, + {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a37305eb3199d8f0d8125ec2fb143ba94ff6d6d92554c4b8d4a8435795a6eccd"}, + {file = "regex-2021.10.8-cp37-cp37m-win32.whl", hash = "sha256:2efd47704bbb016136fe34dfb74c805b1ef5c7313aef3ce6dcb5ff844299f432"}, + {file = "regex-2021.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:924079d5590979c0e961681507eb1773a142553564ccae18d36f1de7324e71ca"}, + {file = "regex-2021.10.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:19b8f6d23b2dc93e8e1e7e288d3010e58fafed323474cf7f27ab9451635136d9"}, + {file = "regex-2021.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b09d3904bf312d11308d9a2867427479d277365b1617e48ad09696fa7dfcdf59"}, + {file = "regex-2021.10.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:951be934dc25d8779d92b530e922de44dda3c82a509cdb5d619f3a0b1491fafa"}, + {file = "regex-2021.10.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f125fce0a0ae4fd5c3388d369d7a7d78f185f904c90dd235f7ecf8fe13fa741"}, + {file = "regex-2021.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f199419a81c1016e0560c39773c12f0bd924c37715bffc64b97140d2c314354"}, + {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:09e1031e2059abd91177c302da392a7b6859ceda038be9e015b522a182c89e4f"}, + {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c070d5895ac6aeb665bd3cd79f673775caf8d33a0b569e98ac434617ecea57d"}, + {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:176796cb7f82a7098b0c436d6daac82f57b9101bb17b8e8119c36eecf06a60a3"}, + {file = "regex-2021.10.8-cp38-cp38-win32.whl", hash = "sha256:5e5796d2f36d3c48875514c5cd9e4325a1ca172fc6c78b469faa8ddd3d770593"}, + {file = "regex-2021.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:e4204708fa116dd03436a337e8e84261bc8051d058221ec63535c9403a1582a1"}, + {file = "regex-2021.10.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6dcf53d35850ce938b4f044a43b33015ebde292840cef3af2c8eb4c860730fff"}, + {file = "regex-2021.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b8b6ee6555b6fbae578f1468b3f685cdfe7940a65675611365a7ea1f8d724991"}, + {file = "regex-2021.10.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e2ec1c106d3f754444abf63b31e5c4f9b5d272272a491fa4320475aba9e8157c"}, + {file = "regex-2021.10.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:973499dac63625a5ef9dfa4c791aa33a502ddb7615d992bdc89cf2cc2285daa3"}, + {file = "regex-2021.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88dc3c1acd3f0ecfde5f95c32fcb9beda709dbdf5012acdcf66acbc4794468eb"}, + {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4786dae85c1f0624ac77cb3813ed99267c9adb72e59fdc7297e1cf4d6036d493"}, + {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe6ce4f3d3c48f9f402da1ceb571548133d3322003ce01b20d960a82251695d2"}, + {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9e3e2cea8f1993f476a6833ef157f5d9e8c75a59a8d8b0395a9a6887a097243b"}, + {file = "regex-2021.10.8-cp39-cp39-win32.whl", hash = "sha256:82cfb97a36b1a53de32b642482c6c46b6ce80803854445e19bc49993655ebf3b"}, + {file = "regex-2021.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:b04e512eb628ea82ed86eb31c0f7fc6842b46bf2601b66b1356a7008327f7700"}, + {file = "regex-2021.10.8.tar.gz", hash = "sha256:26895d7c9bbda5c52b3635ce5991caa90fbb1ddfac9c9ff1c7ce505e2282fb2a"}, +] +sniffio = [ + {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, + {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, +] +starlette = [ + {file = "starlette-0.16.0-py3-none-any.whl", hash = "sha256:38eb24bf705a2c317e15868e384c1b8a12ca396e5a3c3a003db7e667c43f939f"}, + {file = "starlette-0.16.0.tar.gz", hash = "sha256:e1904b5d0007aee24bdd3c43994be9b3b729f4f58e740200de1d623f8c3a8870"}, +] +toml = [ + {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, + {file = "toml-0.10.2.tar.gz", hash = "sha256:b3bda1d108d5dd99f4a20d24d9c348e91c4db7ab1b749200bded2f839ccbe68f"}, +] +tomli = [ + {file = "tomli-1.2.1-py3-none-any.whl", hash = "sha256:8dd0e9524d6f386271a36b41dbf6c57d8e32fd96fd22b6584679dc569d20899f"}, + {file = "tomli-1.2.1.tar.gz", hash = "sha256:a5b75cb6f3968abb47af1b40c1819dc519ea82bcc065776a866e8d74c5ca9442"}, +] +typing-extensions = [ + {file = "typing_extensions-3.10.0.2-py2-none-any.whl", hash = "sha256:d8226d10bc02a29bcc81df19a26e56a9647f8b0a6d4a83924139f4a8b01f17b7"}, + {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, + {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, +] diff --git a/codeliciousness/pyproject.toml b/codeliciousness/pyproject.toml new file mode 100644 index 00000000..370d483b --- /dev/null +++ b/codeliciousness/pyproject.toml @@ -0,0 +1,17 @@ +[tool.poetry] +name = "basistron" +version = "0.1.0" +description = "The basis set selector" +authors = ["codeliciousness "] + +[tool.poetry.dependencies] +python = "^3.9" +fastapi = "^0.70.0" + +[tool.poetry.dev-dependencies] +pytest = "^6.2.5" +black = "^21.9b0" + +[build-system] +requires = ["poetry-core>=1.0.0"] +build-backend = "poetry.core.masonry.api" From ad34968413eec374dc52323388cc6f33299d00a9 Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Tue, 19 Oct 2021 20:05:04 -0400 Subject: [PATCH 05/23] feat: requests and coverage --- codeliciousness/poetry.lock | 136 ++++++++++++++++++++++++++++++++- codeliciousness/pyproject.toml | 2 + 2 files changed, 137 insertions(+), 1 deletion(-) diff --git a/codeliciousness/poetry.lock b/codeliciousness/poetry.lock index 11aebcac..d040953c 100644 --- a/codeliciousness/poetry.lock +++ b/codeliciousness/poetry.lock @@ -64,6 +64,25 @@ jupyter = ["ipython (>=7.8.0)", "tokenize-rt (>=3.2.0)"] python2 = ["typed-ast (>=1.4.2)"] uvloop = ["uvloop (>=0.15.2)"] +[[package]] +name = "certifi" +version = "2021.10.8" +description = "Python package for providing Mozilla's CA Bundle." +category = "main" +optional = false +python-versions = "*" + +[[package]] +name = "charset-normalizer" +version = "2.0.7" +description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +category = "main" +optional = false +python-versions = ">=3.5.0" + +[package.extras] +unicode_backport = ["unicodedata2"] + [[package]] name = "click" version = "8.0.3" @@ -83,6 +102,20 @@ category = "dev" optional = false python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*" +[[package]] +name = "coverage" +version = "6.0.2" +description = "Code coverage measurement for Python" +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + [[package]] name = "fastapi" version = "0.70.0" @@ -220,6 +253,21 @@ toml = "*" [package.extras] testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "requests", "xmlschema"] +[[package]] +name = "pytest-cov" +version = "3.0.0" +description = "Pytest plugin for measuring coverage." +category = "dev" +optional = false +python-versions = ">=3.6" + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] + [[package]] name = "regex" version = "2021.10.8" @@ -228,6 +276,24 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "requests" +version = "2.26.0" +description = "Python HTTP for Humans." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" + +[package.dependencies] +certifi = ">=2017.4.17" +charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} +idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} +urllib3 = ">=1.21.1,<1.27" + +[package.extras] +socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] + [[package]] name = "sniffio" version = "1.2.0" @@ -274,10 +340,23 @@ category = "main" optional = false python-versions = "*" +[[package]] +name = "urllib3" +version = "1.26.7" +description = "HTTP library with thread-safe connection pooling, file post, and more." +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" + +[package.extras] +brotli = ["brotlipy (>=0.6.0)"] +secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] +socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] + [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "12680b53480c36b3b338621e8f7d59a6cd002195af6d7b13bac1d4eed48ce8b0" +content-hash = "21bf5bdc4991b122108cec168b431b700ea325a23e1a0db70c36dcab9667957b" [metadata.files] anyio = [ @@ -296,6 +375,14 @@ black = [ {file = "black-21.9b0-py3-none-any.whl", hash = "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115"}, {file = "black-21.9b0.tar.gz", hash = "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"}, ] +certifi = [ + {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, + {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, +] +charset-normalizer = [ + {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"}, + {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"}, +] click = [ {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, {file = "click-8.0.3.tar.gz", hash = "sha256:410e932b050f5eed773c4cda94de75971c89cdb3155a72a0831139a79e5ecb5b"}, @@ -304,6 +391,41 @@ colorama = [ {file = "colorama-0.4.4-py2.py3-none-any.whl", hash = "sha256:9f47eda37229f68eee03b24b9748937c7dc3868f906e8ba69fbcbdd3bc5dc3e2"}, {file = "colorama-0.4.4.tar.gz", hash = "sha256:5941b2b48a20143d2267e95b1c2a7603ce057ee39fd88e7329b0c292aa16869b"}, ] +coverage = [ + {file = "coverage-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:1549e1d08ce38259de2bc3e9a0d5f3642ff4a8f500ffc1b2df73fd621a6cdfc0"}, + {file = "coverage-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bcae10fccb27ca2a5f456bf64d84110a5a74144be3136a5e598f9d9fb48c0caa"}, + {file = "coverage-6.0.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:53a294dc53cfb39c74758edaa6305193fb4258a30b1f6af24b360a6c8bd0ffa7"}, + {file = "coverage-6.0.2-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:8251b37be1f2cd9c0e5ccd9ae0380909c24d2a5ed2162a41fcdbafaf59a85ebd"}, + {file = "coverage-6.0.2-cp310-cp310-win32.whl", hash = "sha256:db42baa892cba723326284490283a68d4de516bfb5aaba369b4e3b2787a778b7"}, + {file = "coverage-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:bbffde2a68398682623d9dd8c0ca3f46fda074709b26fcf08ae7a4c431a6ab2d"}, + {file = "coverage-6.0.2-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:60e51a3dd55540bec686d7fff61b05048ca31e804c1f32cbb44533e6372d9cc3"}, + {file = "coverage-6.0.2-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6a6a9409223a27d5ef3cca57dd7cd4dfcb64aadf2fad5c3b787830ac9223e01a"}, + {file = "coverage-6.0.2-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4b34ae4f51bbfa5f96b758b55a163d502be3dcb24f505d0227858c2b3f94f5b9"}, + {file = "coverage-6.0.2-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:3bbda1b550e70fa6ac40533d3f23acd4f4e9cb4e6e77251ce77fdf41b3309fb2"}, + {file = "coverage-6.0.2-cp36-cp36m-win32.whl", hash = "sha256:4e28d2a195c533b58fc94a12826f4431726d8eb029ac21d874345f943530c122"}, + {file = "coverage-6.0.2-cp36-cp36m-win_amd64.whl", hash = "sha256:a82d79586a0a4f5fd1cf153e647464ced402938fbccb3ffc358c7babd4da1dd9"}, + {file = "coverage-6.0.2-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3be1206dc09fb6298de3fce70593e27436862331a85daee36270b6d0e1c251c4"}, + {file = "coverage-6.0.2-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9cd3828bbe1a40070c11fe16a51df733fd2f0cb0d745fb83b7b5c1f05967df7"}, + {file = "coverage-6.0.2-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:d036dc1ed8e1388e995833c62325df3f996675779541f682677efc6af71e96cc"}, + {file = "coverage-6.0.2-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:04560539c19ec26995ecfb3d9307ff154fbb9a172cb57e3b3cfc4ced673103d1"}, + {file = "coverage-6.0.2-cp37-cp37m-win32.whl", hash = "sha256:e4fb7ced4d9dec77d6cf533acfbf8e1415fe799430366affb18d69ee8a3c6330"}, + {file = "coverage-6.0.2-cp37-cp37m-win_amd64.whl", hash = "sha256:77b1da5767ed2f44611bc9bc019bc93c03fa495728ec389759b6e9e5039ac6b1"}, + {file = "coverage-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:61b598cbdbaae22d9e34e3f675997194342f866bb1d781da5d0be54783dce1ff"}, + {file = "coverage-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:36e9040a43d2017f2787b28d365a4bb33fcd792c7ff46a047a04094dc0e2a30d"}, + {file = "coverage-6.0.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9f1627e162e3864a596486774876415a7410021f4b67fd2d9efdf93ade681afc"}, + {file = "coverage-6.0.2-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:e7a0b42db2a47ecb488cde14e0f6c7679a2c5a9f44814393b162ff6397fcdfbb"}, + {file = "coverage-6.0.2-cp38-cp38-win32.whl", hash = "sha256:a1b73c7c4d2a42b9d37dd43199c5711d91424ff3c6c22681bc132db4a4afec6f"}, + {file = "coverage-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:1db67c497688fd4ba85b373b37cc52c50d437fd7267520ecd77bddbd89ea22c9"}, + {file = "coverage-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:f2f184bf38e74f152eed7f87e345b51f3ab0b703842f447c22efe35e59942c24"}, + {file = "coverage-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cd1cf1deb3d5544bd942356364a2fdc8959bad2b6cf6eb17f47d301ea34ae822"}, + {file = "coverage-6.0.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:ad9b8c1206ae41d46ec7380b78ba735ebb77758a650643e841dd3894966c31d0"}, + {file = "coverage-6.0.2-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:381d773d896cc7f8ba4ff3b92dee4ed740fb88dfe33b6e42efc5e8ab6dfa1cfe"}, + {file = "coverage-6.0.2-cp39-cp39-win32.whl", hash = "sha256:424c44f65e8be58b54e2b0bd1515e434b940679624b1b72726147cfc6a9fc7ce"}, + {file = "coverage-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:abbff240f77347d17306d3201e14431519bf64495648ca5a49571f988f88dee9"}, + {file = "coverage-6.0.2-pp36-none-any.whl", hash = "sha256:7092eab374346121805fb637572483270324407bf150c30a3b161fc0c4ca5164"}, + {file = "coverage-6.0.2-pp37-none-any.whl", hash = "sha256:30922626ce6f7a5a30bdba984ad21021529d3d05a68b4f71ea3b16bda35b8895"}, + {file = "coverage-6.0.2.tar.gz", hash = "sha256:6807947a09510dc31fa86f43595bf3a14017cd60bf633cc746d52141bfa6b149"}, +] fastapi = [ {file = "fastapi-0.70.0-py3-none-any.whl", hash = "sha256:a36d5f2fad931aa3575c07a3472c784e81f3e664e3bb5c8b9c88d0ec1104f59c"}, {file = "fastapi-0.70.0.tar.gz", hash = "sha256:66da43cfe5185ea1df99552acffd201f1832c6b364e0f4136c0a99f933466ced"}, @@ -372,6 +494,10 @@ pytest = [ {file = "pytest-6.2.5-py3-none-any.whl", hash = "sha256:7310f8d27bc79ced999e760ca304d69f6ba6c6649c0b60fb0e04a4a77cacc134"}, {file = "pytest-6.2.5.tar.gz", hash = "sha256:131b36680866a76e6781d13f101efb86cf674ebb9762eb70d3082b6f29889e89"}, ] +pytest-cov = [ + {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, + {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, +] regex = [ {file = "regex-2021.10.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:094a905e87a4171508c2a0e10217795f83c636ccc05ddf86e7272c26e14056ae"}, {file = "regex-2021.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:981c786293a3115bc14c103086ae54e5ee50ca57f4c02ce7cf1b60318d1e8072"}, @@ -421,6 +547,10 @@ regex = [ {file = "regex-2021.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:b04e512eb628ea82ed86eb31c0f7fc6842b46bf2601b66b1356a7008327f7700"}, {file = "regex-2021.10.8.tar.gz", hash = "sha256:26895d7c9bbda5c52b3635ce5991caa90fbb1ddfac9c9ff1c7ce505e2282fb2a"}, ] +requests = [ + {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, + {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, +] sniffio = [ {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, @@ -442,3 +572,7 @@ typing-extensions = [ {file = "typing_extensions-3.10.0.2-py3-none-any.whl", hash = "sha256:f1d25edafde516b146ecd0613dabcc61409817af4766fbbcfb8d1ad4ec441a34"}, {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, ] +urllib3 = [ + {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, + {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, +] diff --git a/codeliciousness/pyproject.toml b/codeliciousness/pyproject.toml index 370d483b..d0ef7a24 100644 --- a/codeliciousness/pyproject.toml +++ b/codeliciousness/pyproject.toml @@ -7,10 +7,12 @@ authors = ["codeliciousness "] [tool.poetry.dependencies] python = "^3.9" fastapi = "^0.70.0" +requests = "^2.26.0" [tool.poetry.dev-dependencies] pytest = "^6.2.5" black = "^21.9b0" +pytest-cov = "^3.0.0" [build-system] requires = ["poetry-core>=1.0.0"] From f2432456b9f2798c0fac4f00bbca67e439a8e275 Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Tue, 19 Oct 2021 23:07:54 -0400 Subject: [PATCH 06/23] feat: simple client --- codeliciousness/basistron/client.py | 83 +++++++++++++++++ codeliciousness/basistron/utils.py | 64 ++++++++++++++ codeliciousness/poetry.lock | 132 ++++++++++++---------------- codeliciousness/pyproject.toml | 5 +- codeliciousness/test/test_client.py | 15 ++++ 5 files changed, 222 insertions(+), 77 deletions(-) create mode 100644 codeliciousness/basistron/client.py create mode 100644 codeliciousness/basistron/utils.py create mode 100644 codeliciousness/test/test_client.py diff --git a/codeliciousness/basistron/client.py b/codeliciousness/basistron/client.py new file mode 100644 index 00000000..671d1f17 --- /dev/null +++ b/codeliciousness/basistron/client.py @@ -0,0 +1,83 @@ +# -*- coding: utf-8 -*- +import os +from types import ModuleType +from typing import Dict + +from exabyte_api_client import endpoints + +from basistron import utils + +log = utils.get_logger(__name__) + + +def _collect_endpoints() -> Dict[str, ModuleType]: + """Collect all the exabyte clients and + wrap them in a single API Client.""" + + def _iter_module(module: ModuleType): + for k, v in vars(module).items(): + if k.startswith("__"): + continue + if k.isupper(): + continue + if k in ["json"]: + continue + yield k, v + + apis = {} + # TODO : missing charges endpoint + for _, val in _iter_module(endpoints): + if isinstance(val, ModuleType): + for sub, cls in _iter_module(val): + if sub.startswith("Base"): + continue + if sub.endswith("Endpoint") or sub.endswith("Endpoints"): + key = sub.replace("Endpoints", "").replace("Endpoint", "").lower() + apis[key] = cls + return apis + +class Client(utils.Log): + + _endpoints = _collect_endpoints() + + def get_endpoint(self, name: str): + endpoint = self._endpoints.get(name) + if endpoint is None: + self.log.warning(f"name {name} not found in {self._endpoints.keys()}") + return + args = ( + utils.env.exabyte_host, + utils.env.exabyte_port, + utils.env.exabyte_username, + utils.env.exabyte_password, + ) if name == "login" else ( + utils.env.exabyte_host, + utils.env.exabyte_port, + utils.env.exabyte_client_id, + utils.env.exabyte_client_secret, + ) + return endpoint(*args) + + @property + def owner_query(self): + return {"owner._id": utils.env.exabyte_client_id} + + @property + def default_query(self): + return {"isDefault": True, **self.owner_query} + + def __init__(self): + tokens = self.get_endpoint("login").login() + os.environ["EXABYTE_CLIENT_ID"] = tokens["X-Account-Id"] + os.environ["EXABYTE_CLIENT_SECRET"] = tokens["X-Auth-Token"] + + +if __name__ == "__main__": + c = Client() + project = c.get_endpoint("project") + [project_data] = project.list(c.default_query) + project_id = project_data["_id"] + owner_id = project_data["owner"]["_id"] + print("default project data", project_id, owner_id) + workflows = c.get_endpoint("workflow") + print(len(workflows.list(c.default_query))) diff --git a/codeliciousness/basistron/utils.py b/codeliciousness/basistron/utils.py new file mode 100644 index 00000000..8e1c8d8c --- /dev/null +++ b/codeliciousness/basistron/utils.py @@ -0,0 +1,64 @@ +# -*- coding: utf-8 -*- +import os +import logging + +logging.basicConfig() + + +def get_logger(name, level=logging.INFO): + log = logging.getLogger(name) + log.setLevel(level) + return log + + +def default_cache_dir(): + path = os.path.join( + os.path.expanduser("~"), + ".basistron", + ) + os.makedirs(path, exist_ok=True) + return path + + +class Log: + + @property + def log(self): + return get_logger( + ".".join([ + self.__module__, + self.__class__.__name__, + ]) + ) + +class _env: + """Namespace collecting all environment variables + used within the application.""" + + @property + def exabyte_host(self): + return os.getenv("EXABYTE_HOST", "platform.exabyte.io") + + @property + def exabyte_port(self): + return os.getenv("EXABYTE_PORT", 443) + + @property + def exabyte_username(self): + return os.getenv("EXABYTE_USERNAME") + + @property + def exabyte_password(self): + return os.getenv("EXABYTE_PASSWORD") + + @property + def exabyte_client_id(self): + """Used as X-Account-Id header""" + return os.getenv("EXABYTE_CLIENT_ID") + + @property + def exabyte_client_secret(self): + """Used as X-Account-Id header""" + return os.getenv("EXABYTE_CLIENT_SECRET") + +env = _env() diff --git a/codeliciousness/poetry.lock b/codeliciousness/poetry.lock index d040953c..ee5d4137 100644 --- a/codeliciousness/poetry.lock +++ b/codeliciousness/poetry.lock @@ -1,20 +1,3 @@ -[[package]] -name = "anyio" -version = "3.3.4" -description = "High level compatibility layer for multiple asynchronous event loop implementations" -category = "main" -optional = false -python-versions = ">=3.6.2" - -[package.dependencies] -idna = ">=2.8" -sniffio = ">=1.1" - -[package.extras] -doc = ["sphinx-rtd-theme", "sphinx-autodoc-typehints (>=1.2.0)"] -test = ["coverage[toml] (>=4.5)", "hypothesis (>=4.0)", "pytest (>=6.0)", "pytest-mock (>=3.6.1)", "trustme", "uvloop (<0.15)", "mock (>=4)", "uvloop (>=0.15)"] -trio = ["trio (>=0.16)"] - [[package]] name = "atomicwrites" version = "1.4.0" @@ -73,15 +56,12 @@ optional = false python-versions = "*" [[package]] -name = "charset-normalizer" -version = "2.0.7" -description = "The Real First Universal Charset Detector. Open, modern and actively maintained alternative to Chardet." +name = "chardet" +version = "3.0.4" +description = "Universal encoding detector for Python 2 and 3" category = "main" optional = false -python-versions = ">=3.5.0" - -[package.extras] -unicode_backport = ["unicodedata2"] +python-versions = "*" [[package]] name = "click" @@ -116,9 +96,30 @@ tomli = {version = "*", optional = true, markers = "extra == \"toml\""} [package.extras] toml = ["tomli"] +[[package]] +name = "exabyte-api-client" +version = "2021.6.25" +description = "Exabyte Python Client for RESTful API" +category = "main" +optional = false +python-versions = ">=3.6" +develop = false + +[package.dependencies] +requests = "2.20.1" + +[package.extras] +test = ["coverage[toml] (>=5.3)", "mock (>=1.3.0)"] + +[package.source] +type = "git" +url = "https://github.com/exabyte-io/api-client" +reference = "2021.06.25" +resolved_reference = "c9266b53ec03748063180fea88fe2722ff72549d" + [[package]] name = "fastapi" -version = "0.70.0" +version = "0.68.2" description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" category = "main" optional = false @@ -126,21 +127,21 @@ python-versions = ">=3.6.1" [package.dependencies] pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = "0.16.0" +starlette = "0.14.2" [package.extras] -all = ["requests (>=2.24.0,<3.0.0)", "jinja2 (>=2.11.2,<4.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<3.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] -dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)"] +all = ["requests (>=2.24.0,<3.0.0)", "aiofiles (>=0.5.0,<0.8.0)", "jinja2 (>=2.11.2,<3.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<2.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "graphene (>=2.1.8,<3.0.0)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)"] +dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)", "graphene (>=2.1.8,<3.0.0)"] doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=7.1.9,<8.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"] -test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "flask (>=1.1.2,<3.0.0)", "anyio[trio] (>=3.2.1,<4.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"] +test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "pytest-asyncio (>=0.14.0,<0.16.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "aiofiles (>=0.5.0,<0.8.0)", "flask (>=1.1.2,<2.0.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"] [[package]] name = "idna" -version = "3.3" +version = "2.7" description = "Internationalized Domain Names in Applications (IDNA)" category = "main" optional = false -python-versions = ">=3.5" +python-versions = "*" [[package]] name = "iniconfig" @@ -278,43 +279,32 @@ python-versions = "*" [[package]] name = "requests" -version = "2.26.0" +version = "2.20.1" description = "Python HTTP for Humans." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, !=3.5.*" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" [package.dependencies] certifi = ">=2017.4.17" -charset-normalizer = {version = ">=2.0.0,<2.1.0", markers = "python_version >= \"3\""} -idna = {version = ">=2.5,<4", markers = "python_version >= \"3\""} -urllib3 = ">=1.21.1,<1.27" +chardet = ">=3.0.2,<3.1.0" +idna = ">=2.5,<2.8" +urllib3 = ">=1.21.1,<1.25" [package.extras] +security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] -use_chardet_on_py3 = ["chardet (>=3.0.2,<5)"] - -[[package]] -name = "sniffio" -version = "1.2.0" -description = "Sniff out which async library your code is running under" -category = "main" -optional = false -python-versions = ">=3.5" [[package]] name = "starlette" -version = "0.16.0" +version = "0.14.2" description = "The little ASGI library that shines." category = "main" optional = false python-versions = ">=3.6" -[package.dependencies] -anyio = ">=3.0.0,<4" - [package.extras] -full = ["itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests", "graphene"] +full = ["aiofiles", "graphene", "itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] [[package]] name = "toml" @@ -342,27 +332,22 @@ python-versions = "*" [[package]] name = "urllib3" -version = "1.26.7" +version = "1.24.3" description = "HTTP library with thread-safe connection pooling, file post, and more." category = "main" optional = false -python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*, <4" +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, <4" [package.extras] -brotli = ["brotlipy (>=0.6.0)"] secure = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)", "certifi", "ipaddress"] socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "21bf5bdc4991b122108cec168b431b700ea325a23e1a0db70c36dcab9667957b" +content-hash = "e803855a9c21a62b9569bdc15ed8c7c2e24f9539fe1b038da28a13e69d21c495" [metadata.files] -anyio = [ - {file = "anyio-3.3.4-py3-none-any.whl", hash = "sha256:4fd09a25ab7fa01d34512b7249e366cd10358cdafc95022c7ff8c8f8a5026d66"}, - {file = "anyio-3.3.4.tar.gz", hash = "sha256:67da67b5b21f96b9d3d65daa6ea99f5d5282cb09f50eb4456f8fb51dffefc3ff"}, -] atomicwrites = [ {file = "atomicwrites-1.4.0-py2.py3-none-any.whl", hash = "sha256:6d1784dea7c0c8d4a5172b6c620f40b6e4cbfdf96d783691f2e1302a7b88e197"}, {file = "atomicwrites-1.4.0.tar.gz", hash = "sha256:ae70396ad1a434f9c7046fd2dd196fc04b12f9e91ffb859164193be8b6168a7a"}, @@ -379,9 +364,9 @@ certifi = [ {file = "certifi-2021.10.8-py2.py3-none-any.whl", hash = "sha256:d62a0163eb4c2344ac042ab2bdf75399a71a2d8c7d47eac2e2ee91b9d6339569"}, {file = "certifi-2021.10.8.tar.gz", hash = "sha256:78884e7c1d4b00ce3cea67b44566851c4343c120abd683433ce934a68ea58872"}, ] -charset-normalizer = [ - {file = "charset-normalizer-2.0.7.tar.gz", hash = "sha256:e019de665e2bcf9c2b64e2e5aa025fa991da8720daa3c1138cadd2fd1856aed0"}, - {file = "charset_normalizer-2.0.7-py3-none-any.whl", hash = "sha256:f7af805c321bfa1ce6714c51f254e0d5bb5e5834039bc17db7ebe3a4cec9492b"}, +chardet = [ + {file = "chardet-3.0.4-py2.py3-none-any.whl", hash = "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"}, + {file = "chardet-3.0.4.tar.gz", hash = "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae"}, ] click = [ {file = "click-8.0.3-py3-none-any.whl", hash = "sha256:353f466495adaeb40b6b5f592f9f91cb22372351c84caeb068132442a4518ef3"}, @@ -426,13 +411,14 @@ coverage = [ {file = "coverage-6.0.2-pp37-none-any.whl", hash = "sha256:30922626ce6f7a5a30bdba984ad21021529d3d05a68b4f71ea3b16bda35b8895"}, {file = "coverage-6.0.2.tar.gz", hash = "sha256:6807947a09510dc31fa86f43595bf3a14017cd60bf633cc746d52141bfa6b149"}, ] +exabyte-api-client = [] fastapi = [ - {file = "fastapi-0.70.0-py3-none-any.whl", hash = "sha256:a36d5f2fad931aa3575c07a3472c784e81f3e664e3bb5c8b9c88d0ec1104f59c"}, - {file = "fastapi-0.70.0.tar.gz", hash = "sha256:66da43cfe5185ea1df99552acffd201f1832c6b364e0f4136c0a99f933466ced"}, + {file = "fastapi-0.68.2-py3-none-any.whl", hash = "sha256:36bcdd3dbea87c586061005e4a40b9bd0145afd766655b4e0ec1d8870b32555c"}, + {file = "fastapi-0.68.2.tar.gz", hash = "sha256:38526fc46bda73f7ec92033952677323c16061e70a91d15c95f18b11895da494"}, ] idna = [ - {file = "idna-3.3-py3-none-any.whl", hash = "sha256:84d9dd047ffa80596e0f246e2eab0b391788b0503584e8945f2368256d2735ff"}, - {file = "idna-3.3.tar.gz", hash = "sha256:9d643ff0a55b762d5cdb124b8eaa99c66322e2157b69160bc32796e824360e6d"}, + {file = "idna-2.7-py2.py3-none-any.whl", hash = "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e"}, + {file = "idna-2.7.tar.gz", hash = "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"}, ] iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, @@ -548,16 +534,12 @@ regex = [ {file = "regex-2021.10.8.tar.gz", hash = "sha256:26895d7c9bbda5c52b3635ce5991caa90fbb1ddfac9c9ff1c7ce505e2282fb2a"}, ] requests = [ - {file = "requests-2.26.0-py2.py3-none-any.whl", hash = "sha256:6c1246513ecd5ecd4528a0906f910e8f0f9c6b8ec72030dc9fd154dc1a6efd24"}, - {file = "requests-2.26.0.tar.gz", hash = "sha256:b8aa58f8cf793ffd8782d3d8cb19e66ef36f7aba4353eec859e74678b01b07a7"}, -] -sniffio = [ - {file = "sniffio-1.2.0-py3-none-any.whl", hash = "sha256:471b71698eac1c2112a40ce2752bb2f4a4814c22a54a3eed3676bc0f5ca9f663"}, - {file = "sniffio-1.2.0.tar.gz", hash = "sha256:c4666eecec1d3f50960c6bdf61ab7bc350648da6c126e3cf6898d8cd4ddcd3de"}, + {file = "requests-2.20.1-py2.py3-none-any.whl", hash = "sha256:65b3a120e4329e33c9889db89c80976c5272f56ea92d3e74da8a463992e3ff54"}, + {file = "requests-2.20.1.tar.gz", hash = "sha256:ea881206e59f41dbd0bd445437d792e43906703fff75ca8ff43ccdb11f33f263"}, ] starlette = [ - {file = "starlette-0.16.0-py3-none-any.whl", hash = "sha256:38eb24bf705a2c317e15868e384c1b8a12ca396e5a3c3a003db7e667c43f939f"}, - {file = "starlette-0.16.0.tar.gz", hash = "sha256:e1904b5d0007aee24bdd3c43994be9b3b729f4f58e740200de1d623f8c3a8870"}, + {file = "starlette-0.14.2-py3-none-any.whl", hash = "sha256:3c8e48e52736b3161e34c9f0e8153b4f32ec5d8995a3ee1d59410d92f75162ed"}, + {file = "starlette-0.14.2.tar.gz", hash = "sha256:7d49f4a27f8742262ef1470608c59ddbc66baf37c148e938c7038e6bc7a998aa"}, ] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, @@ -573,6 +555,6 @@ typing-extensions = [ {file = "typing_extensions-3.10.0.2.tar.gz", hash = "sha256:49f75d16ff11f1cd258e1b988ccff82a3ca5570217d7ad8c5f48205dd99a677e"}, ] urllib3 = [ - {file = "urllib3-1.26.7-py2.py3-none-any.whl", hash = "sha256:c4fdf4019605b6e5423637e01bc9fe4daef873709a7973e195ceba0a62bbc844"}, - {file = "urllib3-1.26.7.tar.gz", hash = "sha256:4987c65554f7a2dbf30c18fd48778ef124af6fab771a377103da0585e2336ece"}, + {file = "urllib3-1.24.3-py2.py3-none-any.whl", hash = "sha256:a637e5fae88995b256e3409dc4d52c2e2e0ba32c42a6365fee8bbd2238de3cfb"}, + {file = "urllib3-1.24.3.tar.gz", hash = "sha256:2393a695cd12afedd0dcb26fe5d50d0cf248e5a66f75dbd89a3d4eb333a61af4"}, ] diff --git a/codeliciousness/pyproject.toml b/codeliciousness/pyproject.toml index d0ef7a24..0ce4dbda 100644 --- a/codeliciousness/pyproject.toml +++ b/codeliciousness/pyproject.toml @@ -6,8 +6,9 @@ authors = ["codeliciousness "] [tool.poetry.dependencies] python = "^3.9" -fastapi = "^0.70.0" -requests = "^2.26.0" +fastapi = "0.68.2" +requests = "2.20.1" +exabyte-api-client = {git = "https://github.com/exabyte-io/api-client", rev = "2021.06.25"} [tool.poetry.dev-dependencies] pytest = "^6.2.5" diff --git a/codeliciousness/test/test_client.py b/codeliciousness/test/test_client.py new file mode 100644 index 00000000..022ad33f --- /dev/null +++ b/codeliciousness/test/test_client.py @@ -0,0 +1,15 @@ + +from basistron import client, utils + + +def test_client(monkeypatch): + monkeypatch.setenv("EXABYTE_USERNAME", "test") + monkeypatch.setenv("EXABYTE_PASSWORD", "test") + def login(self): + return {"X-Account-Id": "test", "X-Auth-Token": "test"} + monkeypatch.setattr( + "exabyte_api_client.endpoints.login.LoginEndpoint.login", login + ) + c = client.Client() + assert utils.env.exabyte_client_id == "test" + assert utils.env.exabyte_client_secret == "test" From 0545f3185d64815865c7fadbf9442ad93b3cc37b Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Wed, 20 Oct 2021 19:17:53 -0400 Subject: [PATCH 07/23] feat: xyz file to job submission --- codeliciousness/basistron/cli.py | 8 ++++---- codeliciousness/basistron/model.py | 20 ++++++++++++++++---- codeliciousness/basistron/utils.py | 2 ++ codeliciousness/test/test_cli.py | 4 ++-- 4 files changed, 24 insertions(+), 10 deletions(-) diff --git a/codeliciousness/basistron/cli.py b/codeliciousness/basistron/cli.py index 43e9c55a..174ab9ea 100644 --- a/codeliciousness/basistron/cli.py +++ b/codeliciousness/basistron/cli.py @@ -3,7 +3,7 @@ from argparse import ArgumentParser, Namespace -from .model import Driver, Property +from .model import Execution, Property def get_parser() -> ArgumentParser: @@ -31,9 +31,9 @@ def get_parser() -> ArgumentParser: return parser -def process_args(args: Namespace) -> Driver: +def process_args(args: Namespace) -> Execution: if not os.path.isfile(args.xyz_path): - raise FileNotFoundError + raise FileNotFoundError(args.xyz_path) # load xyz data with open(args.xyz_path, "r") as f: xyz_data = [ @@ -44,7 +44,7 @@ def process_args(args: Namespace) -> Driver: raise Exception("unrecognized property") # optional tolerance (default defined in Driver) tol = getattr(args, "reference_tolerance", None) - return Driver( + return Execution( xyz_data=xyz_data, target_property=args.target_property, reference_value=args.reference_value, diff --git a/codeliciousness/basistron/model.py b/codeliciousness/basistron/model.py index 0f3a0057..50a316c9 100644 --- a/codeliciousness/basistron/model.py +++ b/codeliciousness/basistron/model.py @@ -2,7 +2,7 @@ from enum import Enum -from typing import List, Tuple, Optional, Union +from typing import List, Tuple, Optional, Union, Dict, Any from pydantic import BaseModel @@ -29,9 +29,21 @@ class RelaxationProperty(Property): -class Driver(BaseModel): - """Abstraction layer allowing multiple modes of execution.""" - xyz_data: List[Tuple[str, float, float, float]] +class Execution(BaseModel): + """The state of a given execution.""" + xyz_data: Tuple[Tuple[str, float, float, float], ...] target_property: str reference_value: Optional[Union[str, float]] = None reference_tolerance: Optional[float] = 0.01 + + def xyz_data_to_dict(self) -> Dict[str, List[Dict[str, Any]]]: + elements = [] + coordinates = [] + for i, (sym, *val) in enumerate(self.xyz_data): + i += 1 + elements.append({"id": i, "value": sym}) + coordinates.append({"id": i, "value": val}) + return { + "elements": elements, + "coordinates": coordinates, + } \ No newline at end of file diff --git a/codeliciousness/basistron/utils.py b/codeliciousness/basistron/utils.py index 8e1c8d8c..320d0a08 100644 --- a/codeliciousness/basistron/utils.py +++ b/codeliciousness/basistron/utils.py @@ -45,10 +45,12 @@ def exabyte_port(self): @property def exabyte_username(self): + """Used to obtain header values below""" return os.getenv("EXABYTE_USERNAME") @property def exabyte_password(self): + """Used to obtain header values below""" return os.getenv("EXABYTE_PASSWORD") @property diff --git a/codeliciousness/test/test_cli.py b/codeliciousness/test/test_cli.py index 4986193c..7f265163 100644 --- a/codeliciousness/test/test_cli.py +++ b/codeliciousness/test/test_cli.py @@ -3,7 +3,7 @@ import pytest from basistron import cli -from basistron.model import Driver +from basistron.model import Execution command = [ "--target_property", @@ -68,7 +68,7 @@ def test_process_args(tmppath, h2, h2dat): parser = cli.get_parser() args = parser.parse_args(command[:-1] + [path]) ret = cli.process_args(args) - assert isinstance(ret, Driver) + assert isinstance(ret, Execution) assert ret.xyz_data == h2dat From d84de1fb861db9059cef51eccd5167f13648cf93 Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Wed, 20 Oct 2021 19:18:08 -0400 Subject: [PATCH 08/23] fix: tabs to spaces --- codeliciousness/basistron/client.py | 196 ++++++++++++++++++---------- 1 file changed, 128 insertions(+), 68 deletions(-) diff --git a/codeliciousness/basistron/client.py b/codeliciousness/basistron/client.py index 671d1f17..306ad96f 100644 --- a/codeliciousness/basistron/client.py +++ b/codeliciousness/basistron/client.py @@ -1,8 +1,9 @@ # -*- coding: utf-8 -*- import os from types import ModuleType -from typing import Dict +from typing import Dict, Any, Union, List +from requests import HTTPError from exabyte_api_client import endpoints from basistron import utils @@ -11,73 +12,132 @@ def _collect_endpoints() -> Dict[str, ModuleType]: - """Collect all the exabyte clients and - wrap them in a single API Client.""" - - def _iter_module(module: ModuleType): - for k, v in vars(module).items(): - if k.startswith("__"): - continue - if k.isupper(): - continue - if k in ["json"]: - continue - yield k, v - - apis = {} - # TODO : missing charges endpoint - for _, val in _iter_module(endpoints): - if isinstance(val, ModuleType): - for sub, cls in _iter_module(val): - if sub.startswith("Base"): - continue - if sub.endswith("Endpoint") or sub.endswith("Endpoints"): - key = sub.replace("Endpoints", "").replace("Endpoint", "").lower() - apis[key] = cls - return apis + """Collect all the exabyte clients and + wrap them in a single API Client.""" + + def _iter_module(module: ModuleType): + for k, v in vars(module).items(): + if k.startswith("__"): + continue + if k.isupper(): + continue + if k in ["json"]: + continue + yield k, v + + apis = {} + # TODO : missing charges endpoint + for _, val in _iter_module(endpoints): + if isinstance(val, ModuleType): + for sub, cls in _iter_module(val): + if sub.startswith("Base"): + continue + if sub.endswith("Endpoint") or sub.endswith("Endpoints"): + key = sub.replace("Endpoints", "").replace("Endpoint", "").lower() + apis[key] = cls + return apis class Client(utils.Log): + """Wrapper around endpoints API for simplicity.""" + + __endpoints = _collect_endpoints() + + def get_endpoint(self, name: str) -> endpoints.BaseEndpoint: + """Return an instance of an exabyte Endpoint and store + it for subsequent calls to the same endpoint.""" + endpoint = self._endpoints.get(name) + if endpoint is not None: + return endpoint + endpoint = self.__endpoints.get(name) + if endpoint is None: + self.log.warning(f"name {name} not found in {self._endpoints.keys()}") + return + args = ( + utils.env.exabyte_host, + utils.env.exabyte_port, + utils.env.exabyte_username, + utils.env.exabyte_password, + ) if name == "login" else ( + utils.env.exabyte_host, + utils.env.exabyte_port, + utils.env.exabyte_client_id, + utils.env.exabyte_client_secret, + ) + self._endpoints[name] = endpoint(*args) + return self._endpoints[name] + + def get_project(self, query: Dict[str, Any] = None) -> Dict[str, Any]: + project = self.get_endpoint("project") + [project_data] = project.list(query or self.default_query) + return project_data + + def get_workflow(self, query: Dict[str, Any] = None) -> Dict[str, Any]: + workflow = self.get_endpoint("workflow") + [workflow_data] = workflow.list(query or self.default_query) + return workflow_data + + def get_input_template(self) -> Dict[str, Any]: + workflow = self.get_workflow() + [unit] = workflow["subworkflows"][0]["units"] + return unit["input"][0] + + def get_job_config( + self, + owner_id: str, + material_id: str, + workflow_id: str, + job_name: str, + ) -> Dict[str, Union[str, Dict[str, str]]]: + return { + "owner": { + "_id": owner_id, + }, + "_material": { + "_id": material_id, + }, + "workflow": { + "_id": workflow_id, + }, + "name": job_name, + } + + def get_material_config( + self, + name: str, + basis: Dict[str, List[Dict[str, Any]]], + ) -> Dict[str, Any]: + return { + "name": name, + "basis": { + "units": "cartesian", + "name": "basis", + **basis, + }, + "tags": ["basistron"] + } + + def submit_job(self, config: Dict[str, str]): + jobs = self.get_endpoint("job") + job = jobs.create(config) + jobs.submit(job["_id"]) + return job + + @property + def owner_query(self) -> Dict[str, str]: + return {"owner._id": utils.env.exabyte_client_id} + + @property + def default_query(self) -> Dict[str, Any]: + return {"isDefault": True, **self.owner_query} - _endpoints = _collect_endpoints() - - def get_endpoint(self, name: str): - endpoint = self._endpoints.get(name) - if endpoint is None: - self.log.warning(f"name {name} not found in {self._endpoints.keys()}") - return - args = ( - utils.env.exabyte_host, - utils.env.exabyte_port, - utils.env.exabyte_username, - utils.env.exabyte_password, - ) if name == "login" else ( - utils.env.exabyte_host, - utils.env.exabyte_port, - utils.env.exabyte_client_id, - utils.env.exabyte_client_secret, - ) - return endpoint(*args) - - @property - def owner_query(self): - return {"owner._id": utils.env.exabyte_client_id} - - @property - def default_query(self): - return {"isDefault": True, **self.owner_query} - - def __init__(self): - tokens = self.get_endpoint("login").login() - os.environ["EXABYTE_CLIENT_ID"] = tokens["X-Account-Id"] - os.environ["EXABYTE_CLIENT_SECRET"] = tokens["X-Auth-Token"] - - -if __name__ == "__main__": - c = Client() - project = c.get_endpoint("project") - [project_data] = project.list(c.default_query) - project_id = project_data["_id"] - owner_id = project_data["owner"]["_id"] - print("default project data", project_id, owner_id) - workflows = c.get_endpoint("workflow") - print(len(workflows.list(c.default_query))) + def __init__(self): + self._endpoints = {} + try: + tokens = self.get_endpoint("login").login() + os.environ["EXABYTE_CLIENT_ID"] = tokens["X-Account-Id"] + os.environ["EXABYTE_CLIENT_SECRET"] = tokens["X-Auth-Token"] + except HTTPError: + self.log.error( + "authentication failure, client is useless. are " + "EXABYTE_USERNAME+EXABYTE_PASSWORD in the environment?" + ) \ No newline at end of file From 6725171f29dc1d468bf887194789b43730d853e3 Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Wed, 20 Oct 2021 19:21:09 -0400 Subject: [PATCH 09/23] feat: initial app --- codeliciousness/basistron/app.py | 36 ++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 codeliciousness/basistron/app.py diff --git a/codeliciousness/basistron/app.py b/codeliciousness/basistron/app.py new file mode 100644 index 00000000..f2da88c4 --- /dev/null +++ b/codeliciousness/basistron/app.py @@ -0,0 +1,36 @@ + +# -*- coding: utf-8 -*- +import os +import sys + +from basistron import cli +from basistron import utils +from basistron import client + +log = utils.get_logger("basistron.app") + + +def main(args): + + parser = cli.get_parser() + driver = cli.process_args(parser.parse_args(args)) + log.info(f"starting basis set selector for {driver.target_property}") + + c = client.Client() + config = c.get_material_config("", driver.xyz_data_to_dict()) + material = c.get_endpoint("material").create(config) + workflow = c.get_workflow() + job_cfg = c.get_job_config( + workflow["owner"]["_id"], + material["_id"], + workflow["_id"], + "basistron.app", + ) + job = c.submit_job(job_cfg) + + + +if __name__ == "__main__": + main(sys.argv[1:]) + + From 964eac9206bd0ad1b733899f957972c7fb2ce345 Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Wed, 20 Oct 2021 19:21:49 -0400 Subject: [PATCH 10/23] feat: scripts --- codeliciousness/run.sh | 6 ++++++ codeliciousness/test.sh | 3 +++ 2 files changed, 9 insertions(+) create mode 100755 codeliciousness/run.sh create mode 100755 codeliciousness/test.sh diff --git a/codeliciousness/run.sh b/codeliciousness/run.sh new file mode 100755 index 00000000..cb800f56 --- /dev/null +++ b/codeliciousness/run.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +python -m basistron.app \ + --xyz_path h2.xyz \ + --target_property homo_lumo_gap \ + --reference_value 100.0 diff --git a/codeliciousness/test.sh b/codeliciousness/test.sh new file mode 100755 index 00000000..2972cb3c --- /dev/null +++ b/codeliciousness/test.sh @@ -0,0 +1,3 @@ +#!/bin/bash + +pytest test/ --cov=basistron From 87c15f891d57cc8d84b95dccc48e6d863e079bc9 Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Wed, 20 Oct 2021 19:24:12 -0400 Subject: [PATCH 11/23] docs: ambitious readme.. --- codeliciousness/basistron/README.md | 84 +++++++++++++++++++++++++++++ 1 file changed, 84 insertions(+) create mode 100644 codeliciousness/basistron/README.md diff --git a/codeliciousness/basistron/README.md b/codeliciousness/basistron/README.md new file mode 100644 index 00000000..ed8e5714 --- /dev/null +++ b/codeliciousness/basistron/README.md @@ -0,0 +1,84 @@ +BasisTron +========= + +BasisTron is the automatic basis set selection tool you've +always needed but have never had the time to write yourself. + +Since this is a POC rather than a robust operational program, +please follow these manual setup instructions to ensure your +BasisTron experience is a smooth one. BasisTron relies on two +databases, a basis set database and a reference data +database. For the purposes of this project, the basis set +database is provided by the EMSL Basis Set Exchange and the +reference data "database" is provided by CCCBDB. + +Installing the basis set database +--------------------------------- + +* Navigate to https://www.basissetexchange.org +* Click on the Download button at the top of the page + - Choose NWChem as the Basis Set Format + - Choose tar + bz2 as the Archive Type +* Press the Download button + +After you have downloaded the basis set tarball, follow these +steps in a terminal (assuming your tarball was downloaded to +`~/Downloads`). + +```bash +VERSION=v0.8.13 # at the time of project inception +mkdir -p ~/.basistron/basis/ +mv ~/Downloads/basis_sets-nwchem-${VERSION}.tar.bz2 ~/.basistron/basis/ +cd ~/.basistron/basis/ +bunzip2 basis_sets-nwchem-${VERSION}.tar.bz2 +tar -xvf basis_sets-nwchem-${VERSION}.tar +``` + +This provides the basis set database that BasisTron uses to +systematically rank and choose basis sets for a given system. + + +Installing the reference data database +-------------------------------------- + +There is no conveniently obtained "dump" for the CCCBDB. Therefore, +a small API client serves to dynamically fetch relevant reference +data at run-time. Query results are persisted to disk so subsequent +calls for the same data avoid the network. Persisted queries are +stored in `~/.basistron/cccbdb/` internally and should not be +accessed outside of the provided API. + + +Program Usage +============= + +The environment for this program is managed with `poetry`. It can +be installed using pip into a matching python version. + +```bash +$ python --version # ensure python in your path is ~3.9 +Python 3.9.x +$ python -m pip install poetry +... +$ poetry install +... +$ poetry shell +``` + +The `poetry shell` command spawns a subshell with a virtualenv-like +experience. Then the BasisTron program can be executed using the +following command pattern: + +```bash +export EXABYTE_USERNAME=yourusername +export EXABYTE_PASSWORD=yourpassword + +python -m basistron.app \ + --xyz_path /path/to/file \ + --target_property homo_lumo_gap \ + --reference_value 2.0 +``` + +The program assumes the contents of the XYZ file are in units of +angstroms and constitute a neutral singlet electronic configuration. + From e1e0aa4ac2e3f569d49341254538acd8d1c3a001 Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Thu, 21 Oct 2021 15:05:00 -0400 Subject: [PATCH 12/23] feat: pydantic and bs4 --- codeliciousness/poetry.lock | 143 +++++++++++++++------------------ codeliciousness/pyproject.toml | 3 +- 2 files changed, 65 insertions(+), 81 deletions(-) diff --git a/codeliciousness/poetry.lock b/codeliciousness/poetry.lock index ee5d4137..9d2393a7 100644 --- a/codeliciousness/poetry.lock +++ b/codeliciousness/poetry.lock @@ -20,6 +20,21 @@ docs = ["furo", "sphinx", "zope.interface", "sphinx-notfound-page"] tests = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins", "zope.interface"] tests_no_zope = ["coverage[toml] (>=5.0.2)", "hypothesis", "pympler", "pytest (>=4.3.0)", "six", "mypy", "pytest-mypy-plugins"] +[[package]] +name = "beautifulsoup4" +version = "4.10.0" +description = "Screen-scraping library" +category = "main" +optional = false +python-versions = ">3.0.0" + +[package.dependencies] +soupsieve = ">1.2" + +[package.extras] +html5lib = ["html5lib"] +lxml = ["lxml"] + [[package]] name = "black" version = "21.9b0" @@ -117,24 +132,6 @@ url = "https://github.com/exabyte-io/api-client" reference = "2021.06.25" resolved_reference = "c9266b53ec03748063180fea88fe2722ff72549d" -[[package]] -name = "fastapi" -version = "0.68.2" -description = "FastAPI framework, high performance, easy to learn, fast to code, ready for production" -category = "main" -optional = false -python-versions = ">=3.6.1" - -[package.dependencies] -pydantic = ">=1.6.2,<1.7 || >1.7,<1.7.1 || >1.7.1,<1.7.2 || >1.7.2,<1.7.3 || >1.7.3,<1.8 || >1.8,<1.8.1 || >1.8.1,<2.0.0" -starlette = "0.14.2" - -[package.extras] -all = ["requests (>=2.24.0,<3.0.0)", "aiofiles (>=0.5.0,<0.8.0)", "jinja2 (>=2.11.2,<3.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "itsdangerous (>=1.1.0,<2.0.0)", "pyyaml (>=5.3.1,<6.0.0)", "graphene (>=2.1.8,<3.0.0)", "ujson (>=4.0.1,<5.0.0)", "orjson (>=3.2.1,<4.0.0)", "email_validator (>=1.1.1,<2.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)"] -dev = ["python-jose[cryptography] (>=3.3.0,<4.0.0)", "passlib[bcrypt] (>=1.7.2,<2.0.0)", "autoflake (>=1.4.0,<2.0.0)", "flake8 (>=3.8.3,<4.0.0)", "uvicorn[standard] (>=0.12.0,<0.16.0)", "graphene (>=2.1.8,<3.0.0)"] -doc = ["mkdocs (>=1.1.2,<2.0.0)", "mkdocs-material (>=7.1.9,<8.0.0)", "mdx-include (>=1.4.1,<2.0.0)", "mkdocs-markdownextradata-plugin (>=0.1.7,<0.3.0)", "typer-cli (>=0.0.12,<0.0.13)", "pyyaml (>=5.3.1,<6.0.0)"] -test = ["pytest (>=6.2.4,<7.0.0)", "pytest-cov (>=2.12.0,<4.0.0)", "pytest-asyncio (>=0.14.0,<0.16.0)", "mypy (==0.910)", "flake8 (>=3.8.3,<4.0.0)", "black (==21.9b0)", "isort (>=5.0.6,<6.0.0)", "requests (>=2.24.0,<3.0.0)", "httpx (>=0.14.0,<0.19.0)", "email_validator (>=1.1.1,<2.0.0)", "sqlalchemy (>=1.3.18,<1.5.0)", "peewee (>=3.13.3,<4.0.0)", "databases[sqlite] (>=0.3.2,<0.6.0)", "orjson (>=3.2.1,<4.0.0)", "ujson (>=4.0.1,<5.0.0)", "python-multipart (>=0.0.5,<0.0.6)", "aiofiles (>=0.5.0,<0.8.0)", "flask (>=1.1.2,<2.0.0)", "async_exit_stack (>=1.0.1,<2.0.0)", "async_generator (>=1.10,<2.0.0)", "types-ujson (==0.1.1)", "types-orjson (==3.6.0)", "types-dataclasses (==0.1.7)"] - [[package]] name = "idna" version = "2.7" @@ -271,7 +268,7 @@ testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtuale [[package]] name = "regex" -version = "2021.10.8" +version = "2021.10.21" description = "Alternative regular expression module, to replace re." category = "dev" optional = false @@ -296,16 +293,13 @@ security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] [[package]] -name = "starlette" -version = "0.14.2" -description = "The little ASGI library that shines." +name = "soupsieve" +version = "2.2.1" +description = "A modern CSS selector implementation for Beautiful Soup." category = "main" optional = false python-versions = ">=3.6" -[package.extras] -full = ["aiofiles", "graphene", "itsdangerous", "jinja2", "python-multipart", "pyyaml", "requests"] - [[package]] name = "toml" version = "0.10.2" @@ -345,7 +339,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "e803855a9c21a62b9569bdc15ed8c7c2e24f9539fe1b038da28a13e69d21c495" +content-hash = "2549292b9c4c6bac0dcab335eb7018d4db14a47bceb0f72e3443e85d43162483" [metadata.files] atomicwrites = [ @@ -356,6 +350,10 @@ attrs = [ {file = "attrs-21.2.0-py2.py3-none-any.whl", hash = "sha256:149e90d6d8ac20db7a955ad60cf0e6881a3f20d37096140088356da6c716b0b1"}, {file = "attrs-21.2.0.tar.gz", hash = "sha256:ef6aaac3ca6cd92904cdd0d83f629a15f18053ec84e6432106f7a4d04ae4f5fb"}, ] +beautifulsoup4 = [ + {file = "beautifulsoup4-4.10.0-py3-none-any.whl", hash = "sha256:9a315ce70049920ea4572a4055bc4bd700c940521d36fc858205ad4fcde149bf"}, + {file = "beautifulsoup4-4.10.0.tar.gz", hash = "sha256:c23ad23c521d818955a4151a67d81580319d4bf548d3d49f4223ae041ff98891"}, +] black = [ {file = "black-21.9b0-py3-none-any.whl", hash = "sha256:380f1b5da05e5a1429225676655dddb96f5ae8c75bdf91e53d798871b902a115"}, {file = "black-21.9b0.tar.gz", hash = "sha256:7de4cfc7eb6b710de325712d40125689101d21d25283eed7e9998722cf10eb91"}, @@ -412,10 +410,6 @@ coverage = [ {file = "coverage-6.0.2.tar.gz", hash = "sha256:6807947a09510dc31fa86f43595bf3a14017cd60bf633cc746d52141bfa6b149"}, ] exabyte-api-client = [] -fastapi = [ - {file = "fastapi-0.68.2-py3-none-any.whl", hash = "sha256:36bcdd3dbea87c586061005e4a40b9bd0145afd766655b4e0ec1d8870b32555c"}, - {file = "fastapi-0.68.2.tar.gz", hash = "sha256:38526fc46bda73f7ec92033952677323c16061e70a91d15c95f18b11895da494"}, -] idna = [ {file = "idna-2.7-py2.py3-none-any.whl", hash = "sha256:156a6814fb5ac1fc6850fb002e0852d56c0c8d2531923a51032d1b70760e186e"}, {file = "idna-2.7.tar.gz", hash = "sha256:684a38a6f903c1d71d6d5fac066b58d7768af4de2b832e426ec79c30daa94a16"}, @@ -485,61 +479,50 @@ pytest-cov = [ {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, ] regex = [ - {file = "regex-2021.10.8-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:094a905e87a4171508c2a0e10217795f83c636ccc05ddf86e7272c26e14056ae"}, - {file = "regex-2021.10.8-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:981c786293a3115bc14c103086ae54e5ee50ca57f4c02ce7cf1b60318d1e8072"}, - {file = "regex-2021.10.8-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b0f2f874c6a157c91708ac352470cb3bef8e8814f5325e3c5c7a0533064c6a24"}, - {file = "regex-2021.10.8-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:51feefd58ac38eb91a21921b047da8644155e5678e9066af7bcb30ee0dca7361"}, - {file = "regex-2021.10.8-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ea8de658d7db5987b11097445f2b1f134400e2232cb40e614e5f7b6f5428710e"}, - {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1ce02f420a7ec3b2480fe6746d756530f69769292eca363218c2291d0b116a01"}, - {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:39079ebf54156be6e6902f5c70c078f453350616cfe7bfd2dd15bdb3eac20ccc"}, - {file = "regex-2021.10.8-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ff24897f6b2001c38a805d53b6ae72267025878d35ea225aa24675fbff2dba7f"}, - {file = "regex-2021.10.8-cp310-cp310-win32.whl", hash = "sha256:c6569ba7b948c3d61d27f04e2b08ebee24fec9ff8e9ea154d8d1e975b175bfa7"}, - {file = "regex-2021.10.8-cp310-cp310-win_amd64.whl", hash = "sha256:45cb0f7ff782ef51bc79e227a87e4e8f24bc68192f8de4f18aae60b1d60bc152"}, - {file = "regex-2021.10.8-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:fab3ab8aedfb443abb36729410403f0fe7f60ad860c19a979d47fb3eb98ef820"}, - {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:74e55f8d66f1b41d44bc44c891bcf2c7fad252f8f323ee86fba99d71fd1ad5e3"}, - {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3d52c5e089edbdb6083391faffbe70329b804652a53c2fdca3533e99ab0580d9"}, - {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:1abbd95cbe9e2467cac65c77b6abd9223df717c7ae91a628502de67c73bf6838"}, - {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b9b5c215f3870aa9b011c00daeb7be7e1ae4ecd628e9beb6d7e6107e07d81287"}, - {file = "regex-2021.10.8-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f540f153c4f5617bc4ba6433534f8916d96366a08797cbbe4132c37b70403e92"}, - {file = "regex-2021.10.8-cp36-cp36m-win32.whl", hash = "sha256:1f51926db492440e66c89cd2be042f2396cf91e5b05383acd7372b8cb7da373f"}, - {file = "regex-2021.10.8-cp36-cp36m-win_amd64.whl", hash = "sha256:5f55c4804797ef7381518e683249310f7f9646da271b71cb6b3552416c7894ee"}, - {file = "regex-2021.10.8-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:fb2baff66b7d2267e07ef71e17d01283b55b3cc51a81b54cc385e721ae172ba4"}, - {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9e527ab1c4c7cf2643d93406c04e1d289a9d12966529381ce8163c4d2abe4faf"}, - {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36c98b013273e9da5790ff6002ab326e3f81072b4616fd95f06c8fa733d2745f"}, - {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:55ef044899706c10bc0aa052f2fc2e58551e2510694d6aae13f37c50f3f6ff61"}, - {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:aa0ab3530a279a3b7f50f852f1bab41bc304f098350b03e30a3876b7dd89840e"}, - {file = "regex-2021.10.8-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a37305eb3199d8f0d8125ec2fb143ba94ff6d6d92554c4b8d4a8435795a6eccd"}, - {file = "regex-2021.10.8-cp37-cp37m-win32.whl", hash = "sha256:2efd47704bbb016136fe34dfb74c805b1ef5c7313aef3ce6dcb5ff844299f432"}, - {file = "regex-2021.10.8-cp37-cp37m-win_amd64.whl", hash = "sha256:924079d5590979c0e961681507eb1773a142553564ccae18d36f1de7324e71ca"}, - {file = "regex-2021.10.8-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:19b8f6d23b2dc93e8e1e7e288d3010e58fafed323474cf7f27ab9451635136d9"}, - {file = "regex-2021.10.8-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:b09d3904bf312d11308d9a2867427479d277365b1617e48ad09696fa7dfcdf59"}, - {file = "regex-2021.10.8-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:951be934dc25d8779d92b530e922de44dda3c82a509cdb5d619f3a0b1491fafa"}, - {file = "regex-2021.10.8-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f125fce0a0ae4fd5c3388d369d7a7d78f185f904c90dd235f7ecf8fe13fa741"}, - {file = "regex-2021.10.8-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5f199419a81c1016e0560c39773c12f0bd924c37715bffc64b97140d2c314354"}, - {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:09e1031e2059abd91177c302da392a7b6859ceda038be9e015b522a182c89e4f"}, - {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9c070d5895ac6aeb665bd3cd79f673775caf8d33a0b569e98ac434617ecea57d"}, - {file = "regex-2021.10.8-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:176796cb7f82a7098b0c436d6daac82f57b9101bb17b8e8119c36eecf06a60a3"}, - {file = "regex-2021.10.8-cp38-cp38-win32.whl", hash = "sha256:5e5796d2f36d3c48875514c5cd9e4325a1ca172fc6c78b469faa8ddd3d770593"}, - {file = "regex-2021.10.8-cp38-cp38-win_amd64.whl", hash = "sha256:e4204708fa116dd03436a337e8e84261bc8051d058221ec63535c9403a1582a1"}, - {file = "regex-2021.10.8-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:6dcf53d35850ce938b4f044a43b33015ebde292840cef3af2c8eb4c860730fff"}, - {file = "regex-2021.10.8-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:b8b6ee6555b6fbae578f1468b3f685cdfe7940a65675611365a7ea1f8d724991"}, - {file = "regex-2021.10.8-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:e2ec1c106d3f754444abf63b31e5c4f9b5d272272a491fa4320475aba9e8157c"}, - {file = "regex-2021.10.8-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:973499dac63625a5ef9dfa4c791aa33a502ddb7615d992bdc89cf2cc2285daa3"}, - {file = "regex-2021.10.8-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:88dc3c1acd3f0ecfde5f95c32fcb9beda709dbdf5012acdcf66acbc4794468eb"}, - {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:4786dae85c1f0624ac77cb3813ed99267c9adb72e59fdc7297e1cf4d6036d493"}, - {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:fe6ce4f3d3c48f9f402da1ceb571548133d3322003ce01b20d960a82251695d2"}, - {file = "regex-2021.10.8-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:9e3e2cea8f1993f476a6833ef157f5d9e8c75a59a8d8b0395a9a6887a097243b"}, - {file = "regex-2021.10.8-cp39-cp39-win32.whl", hash = "sha256:82cfb97a36b1a53de32b642482c6c46b6ce80803854445e19bc49993655ebf3b"}, - {file = "regex-2021.10.8-cp39-cp39-win_amd64.whl", hash = "sha256:b04e512eb628ea82ed86eb31c0f7fc6842b46bf2601b66b1356a7008327f7700"}, - {file = "regex-2021.10.8.tar.gz", hash = "sha256:26895d7c9bbda5c52b3635ce5991caa90fbb1ddfac9c9ff1c7ce505e2282fb2a"}, + {file = "regex-2021.10.21-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:edff4e31d159672a7b9d70164b21289e4b53b239ce1dc945bf9643d266537573"}, + {file = "regex-2021.10.21-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6432daf42f2c487b357e1aa0bdc43193f050ff53a3188bfab20b88202b53027"}, + {file = "regex-2021.10.21-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:468de52dd3f20187ab5ca4fd265c1bea61a5346baef01ad0333a5e89fa9fad29"}, + {file = "regex-2021.10.21-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c5a2ac760f2fc13a1c58131ec217779911890899ce1a0a63c9409bd23fecde6f"}, + {file = "regex-2021.10.21-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ad1fedca001fefc3030d1e9022b038af429e58dc06a7e9c55e40bd1f834582ec"}, + {file = "regex-2021.10.21-cp310-cp310-win32.whl", hash = "sha256:9c613d797a3790f6b12e78a61e1cd29df7fc88135218467cf8b0891353292b9c"}, + {file = "regex-2021.10.21-cp310-cp310-win_amd64.whl", hash = "sha256:678d9a4ce79e1eaa4ebe88bc9769df52919eb30c597576a0deba1f3cf2360e65"}, + {file = "regex-2021.10.21-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:2044174af237bb9c56ecc07294cf38623ee379e8dca14b01e970f8b015c71917"}, + {file = "regex-2021.10.21-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:98743a2d827a135bf3390452be18d95839b947a099734d53c17e09a64fc09480"}, + {file = "regex-2021.10.21-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f1b23304855303bd97b5954edab63b8ddd56c91c41c6d4eba408228c0bae95f3"}, + {file = "regex-2021.10.21-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:19c4fd59747236423016ccd89b9a6485d958bf1aa7a8a902a6ba28029107a87f"}, + {file = "regex-2021.10.21-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:130a002fa386c976615a2f6d6dff0fcc25da24858994a36b14d2e3129dce7de2"}, + {file = "regex-2021.10.21-cp36-cp36m-win32.whl", hash = "sha256:8bd83d9b8ee125350cd666b55294f4bc9993c4f0d9b1be9344a318d0762e94cc"}, + {file = "regex-2021.10.21-cp36-cp36m-win_amd64.whl", hash = "sha256:98fe0e1b07a314f0a86dc58af4e717c379d48a403eddd8d966ab9b8bf91ce164"}, + {file = "regex-2021.10.21-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:ded4748c7be6f31fb207387ee83a3a0f625e700defe32f268cb1d350ed6e4a66"}, + {file = "regex-2021.10.21-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f3da121de36a9ead0f32b44ea720ee8c87edbb59dca6bb980d18377d84ad58a3"}, + {file = "regex-2021.10.21-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:b9dfba513eae785e3d868803f5a7e21a032cb2b038fa4a1ea7ec691037426ad3"}, + {file = "regex-2021.10.21-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2ff91696888755e96230138355cbe8ce2965d930d967d6cff7c636082d038c78"}, + {file = "regex-2021.10.21-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:0f82de529d7595011a40573cc0f27422e59cafa94943b64a4d17d966d75f2c01"}, + {file = "regex-2021.10.21-cp37-cp37m-win32.whl", hash = "sha256:164e51ace4d00f07c519f85ec2209e8faaeab18bc77be6b35685c18d4ac1c22a"}, + {file = "regex-2021.10.21-cp37-cp37m-win_amd64.whl", hash = "sha256:e39eafa854e469d7225066c806c76b9a0acba5ff5ce36c82c0224b75e24888f2"}, + {file = "regex-2021.10.21-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:740a28580520b099b804776db1e919360fcbf30a734a14c5985d5e39a39e7237"}, + {file = "regex-2021.10.21-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de7dbf72ae80f06e79444ff9614fb5e3a7956645d513b0e12d1bbe6f3ccebd11"}, + {file = "regex-2021.10.21-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:dc1a9bedf389bf3d3627a4d2b21cbdc5fe5e0f029d1f465972f4437833dcc946"}, + {file = "regex-2021.10.21-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:9cd14f22425beecf727f6dbdf5c893e46ecbc5ff16197c16a6f38a9066f2d4d5"}, + {file = "regex-2021.10.21-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:5b75a3db3aab0bfa51b6af3f820760779d360eb79f59e32c88c7fba648990b4f"}, + {file = "regex-2021.10.21-cp38-cp38-win32.whl", hash = "sha256:f68c71aabb10b1352a06515e25a425a703ba85660ae04cf074da5eb91c0af5e5"}, + {file = "regex-2021.10.21-cp38-cp38-win_amd64.whl", hash = "sha256:c0f49f1f03be3e4a5faaadc35db7afa2b83a871943b889f9f7bba56e0e2e8bd5"}, + {file = "regex-2021.10.21-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:201890fdc8a65396cfb6aa4493201353b2a6378e27d2de65234446f8329233cb"}, + {file = "regex-2021.10.21-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd1bfc6b7347de9f0ae1fb6f9080426bed6a9ca55b5766fa4fdf7b3a29ccae9c"}, + {file = "regex-2021.10.21-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:72a0b98d41c4508ed23a96eef41090f78630b44ba746e28cd621ecbe961e0a16"}, + {file = "regex-2021.10.21-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3b5a0660a63b0703380758a7141b96cc1c1a13dee2b8e9c280a2522962fd12af"}, + {file = "regex-2021.10.21-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:f82d3adde46ac9188db3aa7e6e1690865ebb6448d245df5a3ea22284f70d9e46"}, + {file = "regex-2021.10.21-cp39-cp39-win32.whl", hash = "sha256:bc4637390235f1e3e2fcdd3e904ca0b42aa655ae28a78072248b2992b4ad4c08"}, + {file = "regex-2021.10.21-cp39-cp39-win_amd64.whl", hash = "sha256:74d03c256cf0aed81997e87be8e24297b5792c9718f3a735f5055ddfad392f06"}, + {file = "regex-2021.10.21.tar.gz", hash = "sha256:4832736b3f24617e63dc919ce8c4215680ba94250a5d9e710fcc0c5f457b5028"}, ] requests = [ {file = "requests-2.20.1-py2.py3-none-any.whl", hash = "sha256:65b3a120e4329e33c9889db89c80976c5272f56ea92d3e74da8a463992e3ff54"}, {file = "requests-2.20.1.tar.gz", hash = "sha256:ea881206e59f41dbd0bd445437d792e43906703fff75ca8ff43ccdb11f33f263"}, ] -starlette = [ - {file = "starlette-0.14.2-py3-none-any.whl", hash = "sha256:3c8e48e52736b3161e34c9f0e8153b4f32ec5d8995a3ee1d59410d92f75162ed"}, - {file = "starlette-0.14.2.tar.gz", hash = "sha256:7d49f4a27f8742262ef1470608c59ddbc66baf37c148e938c7038e6bc7a998aa"}, +soupsieve = [ + {file = "soupsieve-2.2.1-py3-none-any.whl", hash = "sha256:c2c1c2d44f158cdbddab7824a9af8c4f83c76b1e23e049479aa432feb6c4c23b"}, + {file = "soupsieve-2.2.1.tar.gz", hash = "sha256:052774848f448cf19c7e959adf5566904d525f33a3f8b6ba6f6f8f26ec7de0cc"}, ] toml = [ {file = "toml-0.10.2-py2.py3-none-any.whl", hash = "sha256:806143ae5bfb6a3c6e736a764057db0e6a0e05e338b5630894a5f779cabb4f9b"}, diff --git a/codeliciousness/pyproject.toml b/codeliciousness/pyproject.toml index 0ce4dbda..b062e21a 100644 --- a/codeliciousness/pyproject.toml +++ b/codeliciousness/pyproject.toml @@ -6,9 +6,10 @@ authors = ["codeliciousness "] [tool.poetry.dependencies] python = "^3.9" -fastapi = "0.68.2" +pydantic = "1.8.2" requests = "2.20.1" exabyte-api-client = {git = "https://github.com/exabyte-io/api-client", rev = "2021.06.25"} +beautifulsoup4 = "^4.10.0" [tool.poetry.dev-dependencies] pytest = "^6.2.5" From d3fd29184739295d9d6deb3a769915a312831e98 Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Thu, 21 Oct 2021 15:05:38 -0400 Subject: [PATCH 13/23] fix: convert xyz angstroms to bohr --- codeliciousness/basistron/model.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/codeliciousness/basistron/model.py b/codeliciousness/basistron/model.py index 50a316c9..2b8c3d75 100644 --- a/codeliciousness/basistron/model.py +++ b/codeliciousness/basistron/model.py @@ -37,13 +37,14 @@ class Execution(BaseModel): reference_tolerance: Optional[float] = 0.01 def xyz_data_to_dict(self) -> Dict[str, List[Dict[str, Any]]]: + ang2au = 1.889723 elements = [] coordinates = [] for i, (sym, *val) in enumerate(self.xyz_data): i += 1 elements.append({"id": i, "value": sym}) - coordinates.append({"id": i, "value": val}) + coordinates.append({"id": i, "value": val * ang2au}) return { "elements": elements, "coordinates": coordinates, - } \ No newline at end of file + } From 338633ac821fc0453d67fd17819755f33e77ca71 Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Thu, 21 Oct 2021 15:31:03 -0400 Subject: [PATCH 14/23] fix: test correct type --- codeliciousness/test/conftest.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/codeliciousness/test/conftest.py b/codeliciousness/test/conftest.py index 16e6cf82..1feee70d 100644 --- a/codeliciousness/test/conftest.py +++ b/codeliciousness/test/conftest.py @@ -20,7 +20,7 @@ def h2(): @pytest.fixture def h2dat(): - return [ + return ( ("H", 0.0, 0.0, 0.0), ("H", 0.0, 0.0, 0.7), - ] + ) From bd7a83f3f9c79cceeb7f3ebb1edc36807f2b3fde Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Thu, 21 Oct 2021 15:38:51 -0400 Subject: [PATCH 15/23] feat: basis set api --- codeliciousness/basistron/basis.py | 205 ++++ codeliciousness/basistron/static/__init__.py | 0 codeliciousness/basistron/static/basis.nw | 1128 ++++++++++++++++++ codeliciousness/test/test_basis.py | 47 + 4 files changed, 1380 insertions(+) create mode 100644 codeliciousness/basistron/basis.py create mode 100644 codeliciousness/basistron/static/__init__.py create mode 100644 codeliciousness/basistron/static/basis.nw create mode 100644 codeliciousness/test/test_basis.py diff --git a/codeliciousness/basistron/basis.py b/codeliciousness/basistron/basis.py new file mode 100644 index 00000000..6c14a2e2 --- /dev/null +++ b/codeliciousness/basistron/basis.py @@ -0,0 +1,205 @@ +# -*- coding: utf-8 -*- +import os +import bz2 +import glob +import requests + +from collections import defaultdict +from typing import Optional, List, Tuple, Dict, Any + +from basistron import utils + +log = utils.get_logger(__name__) + + +class State: + """Finite state machine for file parsing.""" + + shell_map = { + "S": 0, + "P": 1, + "D": 2, + "F": 3, + "G": 4, + "H": 5, + "I": 6, + "J": 7, + "K": 8, + "L": 9, + "M": 10, + } + + def __init__(self): + self.live = False + self.skip = False + self.scheme = None + self.symbol = None + self.shell = 0 + self.func = -1 + + def update(self, line: str): + """Update the state based on contents of a line from + the NWChem basis set file format.""" + if line.startswith("#BASIS SET:"): + self.scheme = line.replace("#BASIS SET:", "") + self.skip = True + if line.startswith("BASIS"): + self.live = True + self.skip = True + elif line.startswith("END"): + self.live = False + self.scheme = None + self.symbol = None + self.shell = 0 + self.func = -1 + + def emit_tuple(self, line_list: List[str]) -> Optional[Tuple]: + """Emit structured data when appropriate.""" + try: + float(line_list[0]) + except ValueError: + self.symbol = line_list[0] + self.shell = self.shell_map[line_list[1]] + self.func += 1 + else: + return ( + self.scheme, + self.symbol, + self.shell, + self.func, + float(line_list[0]), + float(line_list[1]), + ) + + +class Basis(object): + + BSE_URL = "http://basissetexchange.org/download/current/nwchem/tbz" + TARBALL = "nwchem_basis_sets.tar.bz2" + + @classmethod + def download_basis_sets(cls, cache_dir: Optional[str] = None) -> None: + """This doesn't work quite right so manual download + instructions are provided in the README.md.""" + cache_dir = cache_dir or utils.default_cache_dir() + os.makedirs(cache_dir, exist_ok=True) + resp = requests.get( + cls.BSE_URL, + allow_redirects=True, + headers={"Content-Type": "application/xml"}, + ) + resp.raise_for_status() + path = os.path.join(cache_dir, cls.TARBALL) + with bz2.open(path, "w") as f: + f.write(resp.content) + + @classmethod + def load_basis_sets( + cls, + cache_dir: Optional[str] = None, + unpacked_dir: Optional[str] = None, + ) -> Dict[str, Any]: + """ "Collect all the basis set data for ranking.""" + cache_dir = cache_dir or utils.default_cache_dir() + unpacked_dir = unpacked_dir or "basis_set_bundle-nwchem-bib" + basis_dir = os.path.join(cache_dir, unpacked_dir) + basis_set_files = sorted(glob.glob(os.path.join(basis_dir, "*nw"))) + log.info(f"loading {len(basis_set_files)} basis set files") + data = {} + for basis_set_file in basis_set_files: + try: + result = cls.parse_basis_set(basis_set_file) + except KeyError: # skip support for SP hybrid shells + continue + data.update(result) + return data + + @classmethod + def rank_basis_sets(cls, basis_data: Dict[str, Any]) -> Dict[str, Any]: + """Regroups basis sets by symbol and sorts the + available basis sets by total number of contracted, + total number of primitive, then number of contracted, + then number of primitive functions in each shell + respectively. Assumes basis_data comes from + load_basis_sets.""" + ordered = defaultdict(list) + for basis, data in basis_data.items(): + for symbol, contraction in data["contractions"].items(): + ordered[symbol].append( + { + "basis": basis, + "sort_by": cls.get_key_from_contraction(contraction), + } + ) + for sets in ordered.values(): + sets.sort(key=lambda obj: obj["sort_by"]) + return ordered + + @staticmethod + def get_allowed_basis_sets(ranked: Dict[str, Any], symbols: List[str]) -> List[str]: + """Gets allowed basis sets for a given set of symbols. + Maintains sorted order of first symbol provided. Assumes + ranked takes the form of the output of rank_basis_sets.""" + allowed = None + for symbol in symbols: + sets = [obj["basis"] for obj in ranked[symbol]] + if allowed is None: + allowed = sets + allowed = [basis for basis in allowed if basis in sets] + return allowed + + @staticmethod + def get_key_from_contraction( + contraction: str, + ) -> Tuple[Tuple[int, ...], Tuple[int, ...]]: + """Create the sort key used for ranking basis sets. + Updates to the structure for sorting can be extended here.""" + primitive, contracted = contraction.split(" -> ") + + def parse_num(string: str): + """If it's stupid but it works..""" + ints, i, s = [], 0, "" + while i < len(string): + c = string[i] + if c.isdigit(): + s += c + else: + if s: + ints.append(int(s)) + s = "" + i += 1 + return ints + + return tuple(parse_num(contracted)), tuple(parse_num(primitive)) + + @staticmethod + def parse_basis_set(basis_path: str): + """Rudimentary nwchem basis set file + parsing using a finite-state machine.""" + + state = State() + contractions = {} + data = [] + + with open(basis_path, "r") as f: + for line in f: + line = line.strip() + state.update(line) + if state.live and not state.skip: + try: + scheme, symbol, *dat = state.emit_tuple(line.split()) + contractions[symbol] = scheme + data.append((symbol, *dat)) + except TypeError: + continue + state.skip = False + + file_name = basis_path.split("/")[-1] + basis_name = ".".join(file_name.split(".")[:-1]) + + return { + basis_name: { + "data": data, + "contractions": contractions, + } + } diff --git a/codeliciousness/basistron/static/__init__.py b/codeliciousness/basistron/static/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/codeliciousness/basistron/static/basis.nw b/codeliciousness/basistron/static/basis.nw new file mode 100644 index 00000000..62c26bb4 --- /dev/null +++ b/codeliciousness/basistron/static/basis.nw @@ -0,0 +1,1128 @@ +#---------------------------------------------------------------------- +# Basis Set Exchange +# Version v0.8.13 +# https://www.basissetexchange.org +#---------------------------------------------------------------------- +# Basis set: cc-pVDZ +# Description: cc-pVDZ +# Role: orbital +# Version: 0 (Data from the Original Basis Set Exchange) +#---------------------------------------------------------------------- + + +BASIS "ao basis" PRINT +#BASIS SET: (4s,1p) -> [2s,1p] +H S + 13.0100000 0.0196850 0.0000000 + 1.9620000 0.1379770 0.0000000 + 0.4446000 0.4781480 0.0000000 + 0.1220000 0.5012400 1.0000000 +H P + 0.7270000 1.0000000 +#BASIS SET: (4s,1p) -> [2s,1p] +He S + 38.3600000 0.0238090 0.0000000 + 5.7700000 0.1548910 0.0000000 + 1.2400000 0.4699870 0.0000000 + 0.2976000 0.5130270 1.0000000 +He P + 1.2750000 1.0000000 +#BASIS SET: (9s,4p,1d) -> [3s,2p,1d] +Li S + 1469.0000000 0.0007660 -0.0001200 0.0000000 + 220.5000000 0.0058920 -0.0009230 0.0000000 + 50.2600000 0.0296710 -0.0046890 0.0000000 + 14.2400000 0.1091800 -0.0176820 0.0000000 + 4.5810000 0.2827890 -0.0489020 0.0000000 + 1.5800000 0.4531230 -0.0960090 0.0000000 + 0.5640000 0.2747740 -0.1363800 0.0000000 + 0.0734500 0.0097510 0.5751020 0.0000000 + 0.0280500 -0.0031800 0.5176610 1.0000000 +Li P + 1.5340000 0.0227840 0.0000000 + 0.2749000 0.1391070 0.0000000 + 0.0736200 0.5003750 0.0000000 + 0.0240300 0.5084740 1.0000000 +Li D + 0.1239000 1.0000000 +#BASIS SET: (9s,4p,1d) -> [3s,2p,1d] +Be S + 2940.0000000 0.0006800 -0.0001230 0.0000000 + 441.2000000 0.0052360 -0.0009660 0.0000000 + 100.5000000 0.0266060 -0.0048310 0.0000000 + 28.4300000 0.0999930 -0.0193140 0.0000000 + 9.1690000 0.2697020 -0.0532800 0.0000000 + 3.1960000 0.4514690 -0.1207230 0.0000000 + 1.1590000 0.2950740 -0.1334350 0.0000000 + 0.1811000 0.0125870 0.5307670 0.0000000 + 0.0589000 -0.0037560 0.5801170 1.0000000 +Be P + 3.6190000 0.0291110 0.0000000 + 0.7110000 0.1693650 0.0000000 + 0.1951000 0.5134580 0.0000000 + 0.0601800 0.4793380 1.0000000 +Be D + 0.2380000 1.0000000 +#BASIS SET: (9s,4p,1d) -> [3s,2p,1d] +B S + 4570.0000000 0.0006960 -0.0001390 0.0000000 + 685.9000000 0.0053530 -0.0010970 0.0000000 + 156.5000000 0.0271340 -0.0054440 0.0000000 + 44.4700000 0.1013800 -0.0219160 0.0000000 + 14.4800000 0.2720550 -0.0597510 0.0000000 + 5.1310000 0.4484030 -0.1387320 0.0000000 + 1.8980000 0.2901230 -0.1314820 0.0000000 + 0.3329000 0.0143220 0.5395260 0.0000000 + 0.1043000 -0.0034860 0.5807740 1.0000000 +B P + 6.0010000 0.0354810 0.0000000 + 1.2410000 0.1980720 0.0000000 + 0.3364000 0.5052300 0.0000000 + 0.0953800 0.4794990 1.0000000 +B D + 0.3430000 1.0000000 +#BASIS SET: (9s,4p,1d) -> [3s,2p,1d] +C S + 6665.0000000 0.0006920 -0.0001460 0.0000000 + 1000.0000000 0.0053290 -0.0011540 0.0000000 + 228.0000000 0.0270770 -0.0057250 0.0000000 + 64.7100000 0.1017180 -0.0233120 0.0000000 + 21.0600000 0.2747400 -0.0639550 0.0000000 + 7.4950000 0.4485640 -0.1499810 0.0000000 + 2.7970000 0.2850740 -0.1272620 0.0000000 + 0.5215000 0.0152040 0.5445290 0.0000000 + 0.1596000 -0.0031910 0.5804960 1.0000000 +C P + 9.4390000 0.0381090 0.0000000 + 2.0020000 0.2094800 0.0000000 + 0.5456000 0.5085570 0.0000000 + 0.1517000 0.4688420 1.0000000 +C D + 0.5500000 1.0000000 +#BASIS SET: (9s,4p,1d) -> [3s,2p,1d] +N S + 9046.0000000 0.0007000 -0.0001530 0.0000000 + 1357.0000000 0.0053890 -0.0012080 0.0000000 + 309.3000000 0.0274060 -0.0059920 0.0000000 + 87.7300000 0.1032070 -0.0245440 0.0000000 + 28.5600000 0.2787230 -0.0674590 0.0000000 + 10.2100000 0.4485400 -0.1580780 0.0000000 + 3.8380000 0.2782380 -0.1218310 0.0000000 + 0.7466000 0.0154400 0.5490030 0.0000000 + 0.2248000 -0.0028640 0.5788150 1.0000000 +N P + 13.5500000 0.0399190 0.0000000 + 2.9170000 0.2171690 0.0000000 + 0.7973000 0.5103190 0.0000000 + 0.2185000 0.4622140 1.0000000 +N D + 0.8170000 1.0000000 +#BASIS SET: (9s,4p,1d) -> [3s,2p,1d] +O S + 11720.0000000 0.0007100 -0.0001600 0.0000000 + 1759.0000000 0.0054700 -0.0012630 0.0000000 + 400.8000000 0.0278370 -0.0062670 0.0000000 + 113.7000000 0.1048000 -0.0257160 0.0000000 + 37.0300000 0.2830620 -0.0709240 0.0000000 + 13.2700000 0.4487190 -0.1654110 0.0000000 + 5.0250000 0.2709520 -0.1169550 0.0000000 + 1.0130000 0.0154580 0.5573680 0.0000000 + 0.3023000 -0.0025850 0.5727590 1.0000000 +O P + 17.7000000 0.0430180 0.0000000 + 3.8540000 0.2289130 0.0000000 + 1.0460000 0.5087280 0.0000000 + 0.2753000 0.4605310 1.0000000 +O D + 1.1850000 1.0000000 +#BASIS SET: (9s,4p,1d) -> [3s,2p,1d] +F S + 14710.0000000 0.0007210 -0.0001650 0.0000000 + 2207.0000000 0.0055530 -0.0013080 0.0000000 + 502.8000000 0.0282670 -0.0064950 0.0000000 + 142.6000000 0.1064440 -0.0266910 0.0000000 + 46.4700000 0.2868140 -0.0736900 0.0000000 + 16.7000000 0.4486410 -0.1707760 0.0000000 + 6.3560000 0.2647610 -0.1123270 0.0000000 + 1.3160000 0.0153330 0.5628140 0.0000000 + 0.3897000 -0.0023320 0.5687780 1.0000000 +F P + 22.6700000 0.0448780 0.0000000 + 4.9770000 0.2357180 0.0000000 + 1.3470000 0.5085210 0.0000000 + 0.3471000 0.4581200 1.0000000 +F D + 1.6400000 1.0000000 +#BASIS SET: (9s,4p,1d) -> [3s,2p,1d] +Ne S + 17880.0000000 0.0007380 -0.0001720 0.0000000 + 2683.0000000 0.0056770 -0.0013570 0.0000000 + 611.5000000 0.0288830 -0.0067370 0.0000000 + 173.5000000 0.1085400 -0.0276630 0.0000000 + 56.6400000 0.2909070 -0.0762080 0.0000000 + 20.4200000 0.4483240 -0.1752270 0.0000000 + 7.8100000 0.2580260 -0.1070380 0.0000000 + 1.6530000 0.0150630 0.5670500 0.0000000 + 0.4869000 -0.0021000 0.5652160 1.0000000 +Ne P + 28.3900000 0.0460870 0.0000000 + 6.2700000 0.2401810 0.0000000 + 1.6950000 0.5087440 0.0000000 + 0.4317000 0.4556600 1.0000000 +Ne D + 2.2020000 1.0000000 +#BASIS SET: (12s,8p,1d) -> [4s,3p,1d] +Na S + 31700.0000000 0.458878E-03 -0.112162E-03 0.170160E-04 0.0000000 + 4755.0000000 0.355070E-02 -0.868512E-03 0.130693E-03 0.0000000 + 1082.0000000 0.182618E-01 -0.451330E-02 0.687784E-03 0.0000000 + 306.4000000 0.716650E-01 -0.181436E-01 0.272359E-02 0.0000000 + 99.5300000 0.212346E+00 -0.580799E-01 0.895529E-02 0.0000000 + 35.4200000 0.416203E+00 -0.137653E+00 0.207832E-01 0.0000000 + 13.3000000 0.373020E+00 -0.193908E+00 0.319380E-01 0.0000000 + 4.3920000 0.625054E-01 0.858009E-01 -0.191368E-01 0.0000000 + 1.6760000 -0.624532E-02 0.604419E+00 -0.102595E+00 0.0000000 + 0.5889000 0.243374E-02 0.441719E+00 -0.198945E+00 0.0000000 + 0.0564000 -0.442381E-03 0.130547E-01 0.655952E+00 0.0000000 + 0.0230700 0.241924E-03 -0.568085E-02 0.431153E+00 1.0000000 +Na P + 138.1000000 0.579641E-02 -0.581531E-03 0.0000000 + 32.2400000 0.415756E-01 -0.407306E-02 0.0000000 + 9.9850000 0.162873E+00 -0.167937E-01 0.0000000 + 3.4840000 0.359401E+00 -0.353268E-01 0.0000000 + 1.2310000 0.449988E+00 -0.521971E-01 0.0000000 + 0.4177000 0.227507E+00 -0.168359E-01 0.0000000 + 0.0651300 0.808247E-02 0.434613E+00 0.0000000 + 0.0205300 -0.196293E-02 0.658218E+00 1.0000000 +Na D + 0.0973000 1.0000000 +#BASIS SET: (12s,8p,1d) -> [4s,3p,1d] +Mg S + 47390.0000000 0.346023E-03 -0.877839E-04 0.169628E-04 0.0000000 + 7108.0000000 0.268077E-02 -0.674725E-03 0.129865E-03 0.0000000 + 1618.0000000 0.138367E-01 -0.355603E-02 0.688831E-03 0.0000000 + 458.4000000 0.551767E-01 -0.142154E-01 0.273533E-02 0.0000000 + 149.3000000 0.169660E+00 -0.476748E-01 0.931224E-02 0.0000000 + 53.5900000 0.364703E+00 -0.114892E+00 0.223265E-01 0.0000000 + 20.7000000 0.406856E+00 -0.200676E+00 0.411195E-01 0.0000000 + 8.3840000 0.135089E+00 -0.341224E-01 0.545642E-02 0.0000000 + 2.5420000 0.490884E-02 0.570454E+00 -0.134012E+00 0.0000000 + 0.8787000 0.286460E-03 0.542309E+00 -0.256176E+00 0.0000000 + 0.1077000 0.264590E-04 0.218128E-01 0.605856E+00 0.0000000 + 0.0399900 -0.112708E-04 -0.827700E-02 0.509446E+00 1.0000000 +Mg P + 179.9000000 0.538161E-02 -0.865948E-03 0.0000000 + 42.1400000 0.392418E-01 -0.615978E-02 0.0000000 + 13.1300000 0.157445E+00 -0.261519E-01 0.0000000 + 4.6280000 0.358535E+00 -0.570647E-01 0.0000000 + 1.6700000 0.457226E+00 -0.873906E-01 0.0000000 + 0.5857000 0.215918E+00 -0.122990E-01 0.0000000 + 0.1311000 0.664948E-02 0.502085E+00 0.0000000 + 0.0411200 -0.125304E-03 0.597245E+00 1.0000000 +Mg D + 0.1870000 1.0000000 +#BASIS SET: (12s,8p,1d) -> [4s,3p,1d] +Al S + 64150.0000000 0.290250E-03 -0.758048E-04 0.175078E-04 0.0000000 + 9617.0000000 0.225064E-02 -0.581791E-03 0.134208E-03 0.0000000 + 2189.0000000 0.116459E-01 -0.308113E-02 0.712442E-03 0.0000000 + 620.5000000 0.467377E-01 -0.123112E-01 0.284330E-02 0.0000000 + 202.7000000 0.146299E+00 -0.419781E-01 0.976842E-02 0.0000000 + 73.1500000 0.330283E+00 -0.103371E+00 0.241850E-01 0.0000000 + 28.5500000 0.415861E+00 -0.196308E+00 0.474993E-01 0.0000000 + 11.7700000 0.189253E+00 -0.830002E-01 0.203621E-01 0.0000000 + 3.3000000 0.115889E-01 0.541040E+00 -0.158788E+00 0.0000000 + 1.1730000 -0.128385E-02 0.578796E+00 -0.311694E+00 0.0000000 + 0.1752000 0.425883E-03 0.288147E-01 0.620147E+00 0.0000000 + 0.0647300 -0.199280E-03 -0.953795E-02 0.520943E+00 1.0000000 +Al P + 258.8000000 0.406847E-02 -0.748053E-03 0.0000000 + 60.8900000 0.306815E-01 -0.545796E-02 0.0000000 + 19.1400000 0.129149E+00 -0.245371E-01 0.0000000 + 6.8810000 0.320831E+00 -0.582138E-01 0.0000000 + 2.5740000 0.453815E+00 -0.983756E-01 0.0000000 + 0.9572000 0.275066E+00 -0.260064E-01 0.0000000 + 0.2099000 0.190807E-01 0.464020E+00 0.0000000 + 0.0598600 -0.312848E-02 0.648870E+00 1.0000000 +Al D + 0.1890000 1.0000000 +#BASIS SET: (12s,8p,1d) -> [4s,3p,1d] +Si S + 78860.0000000 0.270443E-03 -0.723177E-04 0.185113E-04 0.0000000 + 11820.0000000 0.209717E-02 -0.555116E-03 0.142236E-03 0.0000000 + 2692.0000000 0.108506E-01 -0.293805E-02 0.752185E-03 0.0000000 + 763.4000000 0.436754E-01 -0.117687E-01 0.302279E-02 0.0000000 + 249.6000000 0.137653E+00 -0.402907E-01 0.103677E-01 0.0000000 + 90.2800000 0.316644E+00 -0.100609E+00 0.262563E-01 0.0000000 + 35.2900000 0.418581E+00 -0.196528E+00 0.523989E-01 0.0000000 + 14.5100000 0.210212E+00 -0.102382E+00 0.290959E-01 0.0000000 + 4.0530000 0.144952E-01 0.527190E+00 -0.178003E+00 0.0000000 + 1.4820000 -0.203590E-02 0.593251E+00 -0.346874E+00 0.0000000 + 0.2517000 0.624186E-03 0.332652E-01 0.623020E+00 0.0000000 + 0.0924300 -0.282872E-03 -0.973662E-02 0.537712E+00 1.0000000 +Si P + 315.9000000 0.392656E-02 -0.858302E-03 0.0000000 + 74.4200000 0.298811E-01 -0.630328E-02 0.0000000 + 23.4800000 0.127212E+00 -0.288255E-01 0.0000000 + 8.4880000 0.320943E+00 -0.694560E-01 0.0000000 + 3.2170000 0.455429E+00 -0.119493E+00 0.0000000 + 1.2290000 0.268563E+00 -0.199581E-01 0.0000000 + 0.2964000 0.188336E-01 0.510268E+00 0.0000000 + 0.0876800 -0.262431E-02 0.600382E+00 1.0000000 +Si D + 0.2750000 1.0000000 +#BASIS SET: (12s,8p,1d) -> [4s,3p,1d] +P S + 94840.0000000 0.255509E-03 -0.696939E-04 0.191199E-04 0.0000000 + 14220.0000000 0.198193E-02 -0.535266E-03 0.147223E-03 0.0000000 + 3236.0000000 0.102760E-01 -0.283709E-02 0.777912E-03 0.0000000 + 917.1000000 0.414823E-01 -0.113983E-01 0.314546E-02 0.0000000 + 299.5000000 0.131984E+00 -0.392929E-01 0.108200E-01 0.0000000 + 108.1000000 0.308662E+00 -0.996364E-01 0.279957E-01 0.0000000 + 42.1800000 0.420647E+00 -0.197983E+00 0.563978E-01 0.0000000 + 17.2800000 0.222878E+00 -0.114860E+00 0.358190E-01 0.0000000 + 4.8580000 0.164035E-01 0.518595E+00 -0.193387E+00 0.0000000 + 1.8180000 -0.254255E-02 0.601847E+00 -0.372097E+00 0.0000000 + 0.3372000 0.748050E-03 0.368612E-01 0.624246E+00 0.0000000 + 0.1232000 -0.330963E-03 -0.970759E-02 0.551721E+00 1.0000000 +P P + 370.5000000 0.395005E-02 -0.959832E-03 0.0000000 + 87.3300000 0.302492E-01 -0.711177E-02 0.0000000 + 27.5900000 0.129554E+00 -0.327122E-01 0.0000000 + 10.0000000 0.327594E+00 -0.795784E-01 0.0000000 + 3.8250000 0.456992E+00 -0.135016E+00 0.0000000 + 1.4940000 0.253086E+00 -0.910585E-02 0.0000000 + 0.3921000 0.168798E-01 0.537802E+00 0.0000000 + 0.1186000 -0.207093E-02 0.569066E+00 1.0000000 +P D + 0.3730000 1.0000000 +#BASIS SET: (12s,8p,1d) -> [4s,3p,1d] +S S + 110800.0000000 0.247635E-03 -0.687039E-04 0.199077E-04 0.0000000 + 16610.0000000 0.192026E-02 -0.527681E-03 0.153483E-03 0.0000000 + 3781.0000000 0.996192E-02 -0.279671E-02 0.809503E-03 0.0000000 + 1071.0000000 0.402975E-01 -0.112651E-01 0.328974E-02 0.0000000 + 349.8000000 0.128604E+00 -0.388834E-01 0.112967E-01 0.0000000 + 126.3000000 0.303480E+00 -0.995025E-01 0.296385E-01 0.0000000 + 49.2600000 0.421432E+00 -0.199740E+00 0.599851E-01 0.0000000 + 20.1600000 0.230781E+00 -0.123360E+00 0.413248E-01 0.0000000 + 5.7200000 0.178971E-01 0.513194E+00 -0.207474E+00 0.0000000 + 2.1820000 -0.297516E-02 0.607120E+00 -0.392889E+00 0.0000000 + 0.4327000 0.849522E-03 0.396753E-01 0.632840E+00 0.0000000 + 0.1570000 -0.367936E-03 -0.946864E-02 0.556924E+00 1.0000000 +S P + 399.7000000 0.447541E-02 -0.116251E-02 0.0000000 + 94.1900000 0.341708E-01 -0.865664E-02 0.0000000 + 29.7500000 0.144250E+00 -0.390886E-01 0.0000000 + 10.7700000 0.353928E+00 -0.934625E-01 0.0000000 + 4.1190000 0.459085E+00 -0.147994E+00 0.0000000 + 1.6250000 0.206383E+00 0.301904E-01 0.0000000 + 0.4726000 0.102141E-01 0.561573E+00 0.0000000 + 0.1407000 -0.603122E-04 0.534776E+00 1.0000000 +S D + 0.4790000 1.0000000 +#BASIS SET: (12s,8p,1d) -> [4s,3p,1d] +Cl S + 127900.0000000 0.241153E-03 -0.678922E-04 0.204986E-04 0.0000000 + 19170.0000000 0.187095E-02 -0.521836E-03 0.158298E-03 0.0000000 + 4363.0000000 0.970827E-02 -0.276513E-02 0.833639E-03 0.0000000 + 1236.0000000 0.393153E-01 -0.111537E-01 0.339880E-02 0.0000000 + 403.6000000 0.125932E+00 -0.385919E-01 0.116738E-01 0.0000000 + 145.7000000 0.299341E+00 -0.994848E-01 0.309622E-01 0.0000000 + 56.8100000 0.421886E+00 -0.201392E+00 0.629533E-01 0.0000000 + 23.2300000 0.237201E+00 -0.130313E+00 0.460257E-01 0.0000000 + 6.6440000 0.191531E-01 0.509443E+00 -0.219312E+00 0.0000000 + 2.5750000 -0.334792E-02 0.610725E+00 -0.408773E+00 0.0000000 + 0.5371000 0.929883E-03 0.421549E-01 0.638465E+00 0.0000000 + 0.1938000 -0.396379E-03 -0.923427E-02 0.562362E+00 1.0000000 +Cl P + 417.6000000 0.525982E-02 -0.143570E-02 0.0000000 + 98.3300000 0.398332E-01 -0.107796E-01 0.0000000 + 31.0400000 0.164655E+00 -0.470075E-01 0.0000000 + 11.1900000 0.387322E+00 -0.111030E+00 0.0000000 + 4.2490000 0.457072E+00 -0.153275E+00 0.0000000 + 1.6240000 0.151636E+00 0.894609E-01 0.0000000 + 0.5322000 0.181615E-02 0.579444E+00 0.0000000 + 0.1620000 0.188296E-02 0.483272E+00 1.0000000 +Cl D + 0.6000000 1.0000000 +#BASIS SET: (12s,8p,1d) -> [4s,3p,1d] +Ar S + 145700.0000000 0.236700E-03 -0.674910E-04 0.210457E-04 0.0000000 + 21840.0000000 0.183523E-02 -0.518522E-03 0.162565E-03 0.0000000 + 4972.0000000 0.952860E-02 -0.274825E-02 0.855463E-03 0.0000000 + 1408.0000000 0.386283E-01 -0.111007E-01 0.349745E-02 0.0000000 + 459.7000000 0.124081E+00 -0.384820E-01 0.120156E-01 0.0000000 + 165.9000000 0.296471E+00 -0.997599E-01 0.321368E-01 0.0000000 + 64.6900000 0.422068E+00 -0.203088E+00 0.655279E-01 0.0000000 + 26.4400000 0.241711E+00 -0.135608E+00 0.499370E-01 0.0000000 + 7.6280000 0.200509E-01 0.507195E+00 -0.229769E+00 0.0000000 + 2.9960000 -0.361000E-02 0.612898E+00 -0.421006E+00 0.0000000 + 0.6504000 0.975607E-03 0.442968E-01 0.642331E+00 0.0000000 + 0.2337000 -0.411316E-03 -0.899278E-02 0.567540E+00 1.0000000 +Ar P + 453.7000000 0.570555E-02 -0.160655E-02 0.0000000 + 106.8000000 0.430460E-01 -0.121714E-01 0.0000000 + 33.7300000 0.176591E+00 -0.520789E-01 0.0000000 + 12.1300000 0.406863E+00 -0.123737E+00 0.0000000 + 4.5940000 0.452549E+00 -0.151619E+00 0.0000000 + 1.6780000 0.122801E+00 0.142425E+00 0.0000000 + 0.5909000 -0.445996E-02 0.584501E+00 0.0000000 + 0.1852000 0.205225E-02 0.437540E+00 1.0000000 +Ar D + 0.7380000 1.0000000 +#BASIS SET: (14s,11p,5d) -> [5s,4p,2d] +Ca S + 190000.7000000 0.00022145 -0.00006453 0.00002223 0.00000531 0.0000000 + 28481.4600000 0.00171830 -0.00049662 0.00017170 0.00004111 0.0000000 + 6482.7010000 0.00892348 -0.00262826 0.00090452 0.00021568 0.0000000 + 1835.8910000 0.03630183 -0.01066845 0.00370343 0.00088827 0.0000000 + 598.7243000 0.11762223 -0.03713509 0.01283750 0.00305813 0.0000000 + 215.8841000 0.28604352 -0.09804284 0.03475459 0.00837608 0.0000000 + 84.0124200 0.42260708 -0.20342692 0.07303491 0.01741056 0.0000000 + 34.2248800 0.25774366 -0.15244655 0.06100083 0.01515453 0.0000000 + 10.0249700 0.02391893 0.48279406 -0.24292928 -0.06207919 0.0000000 + 4.0559200 -0.00495218 0.62923839 -0.48708500 -0.12611803 0.0000000 + 1.0202610 0.00171779 0.06164842 0.56502804 0.17360694 0.0000000 + 0.4268650 -0.00089209 -0.01479971 0.65574386 0.37822943 0.0000000 + 0.0633470 0.00024510 0.00361089 0.02672894 -0.65964698 0.0000000 + 0.0263010 -0.00012395 -0.00179273 -0.00999959 -0.49022159 1.0000000 +Ca P + 1072.0430000 0.00198166 -0.00064891 0.00013595 0.00000000 + 253.8439000 0.01612944 -0.00527907 0.00109420 0.00000000 + 81.3162600 0.07657851 -0.02581131 0.00542680 0.00000000 + 30.2418300 0.23269594 -0.08062892 0.01674718 0.00000000 + 12.1011000 0.42445210 -0.15846552 0.03389863 0.00000000 + 5.0225540 0.37326402 -0.12816816 0.02531183 0.00000000 + 1.9092200 0.07868530 0.25610103 -0.05895713 0.00000000 + 0.7713040 -0.00599927 0.58724068 -0.15876120 0.00000000 + 0.3005700 0.00264257 0.30372561 -0.08554523 0.00000000 + 0.0766490 -0.00085694 0.01416451 0.54464665 0.00000000 + 0.0277720 0.00033147 -0.00115224 0.56631276 1.00000000 +Ca D + 10.3182000 0.03284900 0.00000000 + 2.5924200 0.14819200 0.00000000 + 0.7617000 0.31092100 0.00000000 + 0.2083800 0.45219500 0.00000000 + 0.0537000 0.48086500 1.00000000 +#BASIS SET: (20s,16p,8d,2f) -> [6s,5p,3d,1f] +Sc S + 2.715278E+06 8.147221E-06 -4.722109E-06 9.139905E-07 -2.201951E-07 -3.757238E-07 0.000000E+00 + 4.065984E+05 6.334788E-05 -3.671829E-05 7.108513E-06 -1.711419E-06 -2.981907E-06 0.000000E+00 + 9.253004E+04 3.330384E-04 -1.930883E-04 3.738126E-05 -9.008469E-06 -1.522586E-05 0.000000E+00 + 2.620792E+04 1.404055E-03 -8.146870E-04 1.578828E-04 -3.799997E-05 -6.684686E-05 0.000000E+00 + 8.549429E+03 5.081725E-03 -2.955526E-03 5.737686E-04 -1.383227E-04 -2.313129E-04 0.000000E+00 + 3.085975E+03 1.626926E-02 -9.520035E-03 1.859244E-03 -4.473692E-04 -7.959729E-04 0.000000E+00 + 1.203172E+03 4.624577E-02 -2.746858E-02 5.433182E-03 -1.310691E-03 -2.161961E-03 0.000000E+00 + 4.984869E+02 1.137223E-01 -6.991528E-02 1.425387E-02 -3.429860E-03 -6.206459E-03 0.000000E+00 + 2.167360E+02 2.257636E-01 -1.499251E-01 3.246144E-02 -7.847579E-03 -1.261905E-02 0.000000E+00 + 9.787476E+01 3.106700E-01 -2.459153E-01 6.003454E-02 -1.447189E-02 -2.739459E-02 0.000000E+00 + 4.520433E+01 2.191906E-01 -2.401293E-01 6.916105E-02 -1.690669E-02 -2.336516E-02 0.000000E+00 + 2.021187E+01 7.215879E-02 3.567987E-02 -2.113084E-02 5.396115E-03 -5.734627E-03 0.000000E+00 + 9.574751E+00 1.187030E-01 4.915023E-01 -2.666832E-01 6.671062E-02 1.536025E-01 0.000000E+00 + 4.540346E+00 1.220532E-01 4.911381E-01 -4.367591E-01 1.178356E-01 1.447100E-01 0.000000E+00 + 1.995687E+00 2.136795E-02 9.120633E-02 6.498243E-02 -2.738134E-02 9.359699E-02 0.000000E+00 + 9.422150E-01 -5.357246E-04 -5.356723E-03 7.009599E-01 -2.260149E-01 -8.687730E-01 0.000000E+00 + 4.178450E-01 2.435774E-04 8.812836E-04 4.515562E-01 -3.073539E-01 2.114597E-02 0.000000E+00 + 9.576100E-02 -8.796617E-05 -7.605536E-04 3.011910E-02 2.544054E-01 2.275498E+00 0.000000E+00 + 5.135100E-02 7.878246E-05 6.340116E-04 -1.329480E-02 5.981590E-01 -1.190770E+00 0.000000E+00 + 2.387800E-02 -1.637155E-05 -1.556163E-04 4.633679E-03 3.115202E-01 -7.674257E-01 1.000000E+00 +Sc P + 1.059219E+04 4.500000E-05 -1.500000E-05 -4.000000E-06 4.000000E-06 0.000000E+00 + 2.507533E+03 4.010000E-04 -1.310000E-04 -3.200000E-05 3.900000E-05 0.000000E+00 + 8.144571E+02 2.302000E-03 -7.570000E-04 -1.850000E-04 2.210000E-04 0.000000E+00 + 3.115195E+02 1.003700E-02 -3.318000E-03 -8.080000E-04 9.840000E-04 0.000000E+00 + 1.319617E+02 3.495400E-02 -1.170600E-02 -2.870000E-03 3.423000E-03 0.000000E+00 + 5.998718E+01 9.790900E-02 -3.360400E-02 -8.207000E-03 9.993000E-03 0.000000E+00 + 2.866250E+01 2.106800E-01 -7.487900E-02 -1.847300E-02 2.191600E-02 0.000000E+00 + 1.410851E+01 3.300930E-01 -1.225480E-01 -3.010100E-02 3.700800E-02 0.000000E+00 + 7.103706E+00 3.310270E-01 -1.302760E-01 -3.294300E-02 3.779400E-02 0.000000E+00 + 3.609200E+00 1.579600E-01 1.459600E-02 7.958000E-03 -4.379000E-03 0.000000E+00 + 1.776070E+00 2.209900E-02 3.091840E-01 8.799300E-02 -1.101640E-01 0.000000E+00 + 8.547600E-01 -1.605000E-03 4.629980E-01 1.523770E-01 -1.610170E-01 0.000000E+00 + 4.022390E-01 -1.326000E-03 3.049570E-01 9.717000E-02 -1.824820E-01 0.000000E+00 + 1.546650E-01 -2.800000E-04 5.087800E-02 -2.569380E-01 3.886110E-01 0.000000E+00 + 6.494500E-02 3.400000E-05 -4.493000E-03 -5.878150E-01 6.911000E-01 0.000000E+00 + 2.635900E-02 -1.300000E-05 1.832000E-03 -3.054210E-01 7.960400E-02 1.000000E+00 +Sc D + 5.051380E+01 4.266000E-03 -4.389000E-03 0.000000E+00 + 1.474050E+01 2.770800E-02 -2.836300E-02 0.000000E+00 + 5.195000E+00 1.000010E-01 -1.051370E-01 0.000000E+00 + 2.028460E+00 2.315810E-01 -2.348540E-01 0.000000E+00 + 8.040860E-01 3.460330E-01 -3.246090E-01 0.000000E+00 + 3.076890E-01 3.733740E-01 -6.428900E-02 0.000000E+00 + 1.113920E-01 2.642880E-01 6.017490E-01 0.000000E+00 + 3.735200E-02 6.366700E-02 3.903000E-01 1.000000E+00 +Sc F + 7.126000E-01 3.617450E-01 + 1.636000E-01 8.218680E-01 +#BASIS SET: (20s,16p,8d,2f) -> [6s,5p,3d,1f] +Ti S + 3.014643E+06 8.060782E-06 -4.630486E-06 9.230559E-07 -2.180323E-07 -3.975126E-07 0.000000E+00 + 4.514329E+05 6.267518E-05 -3.600451E-05 7.178974E-06 -1.694860E-06 -3.161080E-06 0.000000E+00 + 1.027338E+05 3.295006E-04 -1.893420E-04 3.775134E-05 -8.919208E-06 -1.609375E-05 0.000000E+00 + 2.909817E+04 1.389203E-03 -7.988781E-04 1.594532E-04 -3.763633E-05 -7.092947E-05 0.000000E+00 + 9.492330E+03 5.028469E-03 -2.898698E-03 5.795150E-04 -1.369575E-04 -2.442710E-04 0.000000E+00 + 3.426346E+03 1.610419E-02 -9.339701E-03 1.878414E-03 -4.432894E-04 -8.457892E-04 0.000000E+00 + 1.335896E+03 4.581232E-02 -2.697464E-02 5.492747E-03 -1.298868E-03 -2.282208E-03 0.000000E+00 + 5.535026E+02 1.128613E-01 -6.878913E-02 1.443297E-02 -3.406752E-03 -6.619873E-03 0.000000E+00 + 2.406925E+02 2.248193E-01 -1.481037E-01 3.296408E-02 -7.810829E-03 -1.335024E-02 0.000000E+00 + 1.087293E+02 3.114571E-01 -2.445253E-01 6.125493E-02 -1.449245E-02 -2.955830E-02 0.000000E+00 + 5.026457E+01 2.224995E-01 -2.419916E-01 7.134113E-02 -1.708136E-02 -2.477039E-02 0.000000E+00 + 2.258004E+01 7.293128E-02 3.183790E-02 -1.973150E-02 4.897666E-03 -8.414624E-03 0.000000E+00 + 1.071432E+01 1.160683E-01 4.932686E-01 -2.741869E-01 6.753108E-02 1.693855E-01 0.000000E+00 + 5.093546E+00 1.194774E-01 4.939655E-01 -4.440977E-01 1.173318E-01 1.500787E-01 0.000000E+00 + 2.244183E+00 2.097868E-02 9.196313E-02 7.776084E-02 -2.985025E-02 9.787777E-02 0.000000E+00 + 1.059570E+00 -5.091715E-04 -5.316992E-03 7.068444E-01 -2.277634E-01 -9.653608E-01 0.000000E+00 + 4.688490E-01 2.217859E-04 8.085624E-04 4.413892E-01 -2.928115E-01 1.489721E-01 0.000000E+00 + 1.061430E-01 -7.636896E-05 -6.918459E-04 2.799769E-02 2.665300E-01 2.191179E+00 0.000000E+00 + 5.526200E-02 7.719539E-05 6.086512E-04 -1.210790E-02 5.912406E-01 -1.243325E+00 0.000000E+00 + 2.546500E-02 -1.149056E-05 -1.313842E-04 4.324762E-03 3.037229E-01 -6.711916E-01 1.000000E+00 +Ti P + 1.191203E+04 4.400000E-05 -1.500000E-05 4.000000E-06 4.000000E-06 0.000000E+00 + 2.819947E+03 3.910000E-04 -1.310000E-04 3.100000E-05 3.900000E-05 0.000000E+00 + 9.159479E+02 2.248000E-03 -7.550000E-04 1.820000E-04 2.230000E-04 0.000000E+00 + 3.503842E+02 9.823000E-03 -3.319000E-03 7.950000E-04 9.920000E-04 0.000000E+00 + 1.484825E+02 3.433800E-02 -1.175000E-02 2.833000E-03 3.476000E-03 0.000000E+00 + 6.753944E+01 9.666600E-02 -3.392200E-02 8.154000E-03 1.017200E-02 0.000000E+00 + 3.230332E+01 2.094170E-01 -7.616400E-02 1.847200E-02 2.257600E-02 0.000000E+00 + 1.592786E+01 3.301890E-01 -1.257020E-01 3.040000E-02 3.823800E-02 0.000000E+00 + 8.038035E+00 3.319360E-01 -1.330980E-01 3.304700E-02 3.933700E-02 0.000000E+00 + 4.093916E+00 1.584880E-01 1.740600E-02 -8.251000E-03 -6.106000E-03 0.000000E+00 + 2.022390E+00 2.231000E-02 3.151650E-01 -8.855400E-02 -1.129620E-01 0.000000E+00 + 9.761020E-01 -1.566000E-03 4.618140E-01 -1.496120E-01 -1.681140E-01 0.000000E+00 + 4.595950E-01 -1.324000E-03 2.998560E-01 -9.422700E-02 -1.659320E-01 0.000000E+00 + 1.771520E-01 -2.710000E-04 5.000000E-02 2.508460E-01 3.914030E-01 0.000000E+00 + 7.351700E-02 3.200000E-05 -4.230000E-03 5.866430E-01 6.818400E-01 0.000000E+00 + 2.940100E-02 -1.200000E-05 1.725000E-03 3.135350E-01 8.403100E-02 1.000000E+00 +Ti D + 6.401300E+01 3.887000E-03 -3.970000E-03 0.000000E+00 + 1.881790E+01 2.639900E-02 -2.687300E-02 0.000000E+00 + 6.728700E+00 9.751100E-02 -1.022750E-01 0.000000E+00 + 2.664130E+00 2.328480E-01 -2.377280E-01 0.000000E+00 + 1.078680E+00 3.531520E-01 -3.121140E-01 0.000000E+00 + 4.232090E-01 3.721860E-01 -4.237800E-02 0.000000E+00 + 1.559990E-01 2.476720E-01 5.886580E-01 0.000000E+00 + 5.188400E-02 5.823600E-02 4.103020E-01 1.000000E+00 +Ti F + 1.227400E+00 3.581580E-01 + 2.788000E-01 8.257940E-01 +#BASIS SET: (20s,16p,8d,2f) -> [6s,5p,3d,1f] +V S + 3.321857E+06 8.039999E-06 -4.503003E-06 9.320648E-07 -2.158944E-07 -4.093416E-07 0.000000E+00 + 4.974356E+05 6.251402E-05 -3.501295E-05 7.249306E-06 -1.678519E-06 -3.258956E-06 0.000000E+00 + 1.132027E+05 3.286553E-04 -1.841339E-04 3.811967E-05 -8.831213E-06 -1.656390E-05 0.000000E+00 + 3.206333E+04 1.385697E-03 -7.769216E-04 1.610238E-04 -3.727769E-05 -7.316689E-05 0.000000E+00 + 1.045962E+04 5.016217E-03 -2.819505E-03 5.852210E-04 -1.356099E-04 -2.512784E-04 0.000000E+00 + 3.775506E+03 1.606931E-02 -9.087486E-03 1.897502E-03 -4.392351E-04 -8.732657E-04 0.000000E+00 + 1.472040E+03 4.574242E-02 -2.627134E-02 5.550909E-03 -1.286948E-03 -2.347654E-03 0.000000E+00 + 6.099331E+02 1.128544E-01 -6.712726E-02 1.460584E-02 -3.382149E-03 -6.853150E-03 0.000000E+00 + 2.652634E+02 2.254344E-01 -1.451130E-01 3.342974E-02 -7.765646E-03 -1.376420E-02 0.000000E+00 + 1.198607E+02 3.140461E-01 -2.412483E-01 6.235722E-02 -1.447985E-02 -3.084679E-02 0.000000E+00 + 5.544891E+01 2.267819E-01 -2.416314E-01 7.312435E-02 -1.715502E-02 -2.562208E-02 0.000000E+00 + 2.498372E+01 7.334069E-02 3.067362E-02 -1.911472E-02 4.610101E-03 -1.005123E-02 0.000000E+00 + 1.188056E+01 1.102474E-01 4.970415E-01 -2.817249E-01 6.827831E-02 1.795330E-01 0.000000E+00 + 5.660311E+00 1.131358E-01 4.958875E-01 -4.488151E-01 1.161368E-01 1.522400E-01 0.000000E+00 + 2.495703E+00 1.971295E-02 9.181868E-02 9.202696E-02 -3.277049E-02 9.483887E-02 0.000000E+00 + 1.177866E+00 -4.719088E-04 -5.392514E-03 7.110117E-01 -2.280000E-01 -1.014876E+00 0.000000E+00 + 5.200440E-01 1.861606E-04 7.102380E-04 4.309274E-01 -2.793991E-01 2.308810E-01 0.000000E+00 + 1.159650E-01 -6.208598E-05 -6.363128E-04 2.604589E-02 2.771165E-01 2.113321E+00 0.000000E+00 + 5.893800E-02 7.295314E-05 5.979932E-04 -1.101049E-02 5.852999E-01 -1.253048E+00 0.000000E+00 + 2.694600E-02 -6.362062E-06 -1.100879E-04 4.106300E-03 2.963946E-01 -6.139502E-01 1.000000E+00 +V P + 1.327320E+04 4.300000E-05 -1.500000E-05 4.000000E-06 4.000000E-06 0.000000E+00 + 3.142126E+03 3.840000E-04 -1.310000E-04 3.200000E-05 3.900000E-05 0.000000E+00 + 1.020588E+03 2.210000E-03 -7.550000E-04 1.830000E-04 2.230000E-04 0.000000E+00 + 3.904407E+02 9.678000E-03 -3.325000E-03 8.020000E-04 9.960000E-04 0.000000E+00 + 1.655043E+02 3.393600E-02 -1.181100E-02 2.862000E-03 3.498000E-03 0.000000E+00 + 7.532006E+01 9.591700E-02 -3.425600E-02 8.287000E-03 1.029600E-02 0.000000E+00 + 3.605503E+01 2.088530E-01 -7.736300E-02 1.887000E-02 2.296200E-02 0.000000E+00 + 1.780436E+01 3.306600E-01 -1.284560E-01 3.130700E-02 3.920800E-02 0.000000E+00 + 9.002929E+00 3.323120E-01 -1.350780E-01 3.366000E-02 3.994300E-02 0.000000E+00 + 4.594544E+00 1.581880E-01 2.083800E-02 -9.479000E-03 -7.121000E-03 0.000000E+00 + 2.276760E+00 2.225200E-02 3.204990E-01 -9.231300E-02 -1.162250E-01 0.000000E+00 + 1.101178E+00 -1.565000E-03 4.602600E-01 -1.489890E-01 -1.694960E-01 0.000000E+00 + 5.186380E-01 -1.353000E-03 2.953460E-01 -8.364400E-02 -1.553740E-01 0.000000E+00 + 2.005650E-01 -2.650000E-04 4.904600E-02 2.493390E-01 3.950220E-01 0.000000E+00 + 8.129100E-02 2.900000E-05 -3.824000E-03 5.805150E-01 6.789080E-01 0.000000E+00 + 3.179500E-02 -1.100000E-05 1.585000E-03 3.223800E-01 8.312200E-02 1.000000E+00 +V D + 7.761150E+01 3.595000E-03 -3.818000E-03 0.000000E+00 + 2.291590E+01 2.521000E-02 -2.671700E-02 0.000000E+00 + 8.279540E+00 9.478600E-02 -1.036900E-01 0.000000E+00 + 3.309930E+00 2.303630E-01 -2.476890E-01 0.000000E+00 + 1.358630E+00 3.528940E-01 -3.115230E-01 0.000000E+00 + 5.413500E-01 3.704140E-01 -2.282700E-02 0.000000E+00 + 2.023560E-01 2.457180E-01 5.697260E-01 0.000000E+00 + 6.756800E-02 6.099300E-02 4.194930E-01 1.000000E+00 +V F + 1.748800E+00 3.900680E-01 + 4.057000E-01 8.008410E-01 +#BASIS SET: (20s,16p,8d,2f) -> [6s,5p,3d,1f] +Cr S + 6.177194E+06 4.128667E-06 -2.301772E-06 4.862957E-07 -1.102451E-07 2.179893E-07 0.000000E+00 + 9.249295E+05 3.210767E-05 -1.789536E-05 3.776645E-06 -8.530233E-07 1.612940E-06 0.000000E+00 + 2.104865E+05 1.688416E-04 -9.416174E-05 1.990664E-05 -4.520358E-06 9.111842E-06 0.000000E+00 + 5.962005E+04 7.128520E-04 -3.975074E-04 8.389164E-05 -1.891612E-05 3.500645E-05 0.000000E+00 + 1.945076E+04 2.589325E-03 -1.447025E-03 3.065706E-04 -6.974344E-05 1.435315E-04 0.000000E+00 + 7.022056E+03 8.377350E-03 -4.694622E-03 9.944107E-04 -2.237867E-04 4.035896E-04 0.000000E+00 + 2.738763E+03 2.441725E-02 -1.382387E-02 2.961959E-03 -6.754503E-04 1.425177E-03 0.000000E+00 + 1.135814E+03 6.365135E-02 -3.674643E-02 7.969473E-03 -1.789346E-03 3.114009E-03 0.000000E+00 + 4.950923E+02 1.427618E-01 -8.647185E-02 1.955017E-02 -4.477858E-03 9.814449E-03 0.000000E+00 + 2.247487E+02 2.541275E-01 -1.696735E-01 4.085035E-02 -9.140144E-03 1.474698E-02 0.000000E+00 + 1.053836E+02 3.009512E-01 -2.507089E-01 6.929003E-02 -1.610562E-02 3.911512E-02 0.000000E+00 + 5.019359E+01 1.766513E-01 -1.961156E-01 6.146984E-02 -1.334870E-02 9.170888E-03 0.000000E+00 + 2.224957E+01 6.936709E-02 1.457244E-01 -6.981302E-02 1.426027E-02 1.559878E-02 0.000000E+00 + 1.098265E+01 1.179579E-01 5.466706E-01 -3.517597E-01 8.931690E-02 -2.816844E-01 0.000000E+00 + 5.383665E+00 8.916187E-02 3.979434E-01 -3.828629E-01 8.885279E-02 -6.895261E-03 0.000000E+00 + 2.343685E+00 1.103630E-02 5.277007E-02 2.676401E-01 -6.368776E-02 -1.769781E-01 0.000000E+00 + 1.105202E+00 -3.546048E-04 -4.374537E-03 7.175950E-01 -2.783262E-01 1.443061E+00 0.000000E+00 + 4.878480E-01 1.057311E-04 3.204035E-04 3.020814E-01 -1.830071E-01 -1.029318E+00 0.000000E+00 + 8.959900E-02 1.114640E-05 -5.142077E-05 7.749514E-03 6.790937E-01 -1.307667E+00 0.000000E+00 + 3.342300E-02 2.661387E-05 1.584134E-04 2.696096E-04 4.672953E-01 1.503842E+00 1.000000E+00 +Cr P + 1.445420E+04 4.400000E-05 -1.500000E-05 4.000000E-06 4.000000E-06 0.000000E+00 + 3.421676E+03 3.890000E-04 -1.350000E-04 3.200000E-05 4.000000E-05 0.000000E+00 + 1.111387E+03 2.241000E-03 -7.770000E-04 1.850000E-04 2.290000E-04 0.000000E+00 + 4.251918E+02 9.821000E-03 -3.427000E-03 8.100000E-04 1.019000E-03 0.000000E+00 + 1.802623E+02 3.447100E-02 -1.218900E-02 2.906000E-03 3.602000E-03 0.000000E+00 + 8.206117E+01 9.746000E-02 -3.538800E-02 8.391000E-03 1.055000E-02 0.000000E+00 + 3.929726E+01 2.119850E-01 -7.991500E-02 1.919300E-02 2.370200E-02 0.000000E+00 + 1.941959E+01 3.339900E-01 -1.323350E-01 3.156400E-02 3.998800E-02 0.000000E+00 + 9.828899E+00 3.301370E-01 -1.354010E-01 3.341700E-02 4.043700E-02 0.000000E+00 + 5.016810E+00 1.522270E-01 3.200800E-02 -1.290700E-02 -1.207400E-02 0.000000E+00 + 2.487091E+00 2.042500E-02 3.338490E-01 -9.365900E-02 -1.189390E-01 0.000000E+00 + 1.198780E+00 -1.360000E-03 4.617730E-01 -1.499770E-01 -1.781000E-01 0.000000E+00 + 5.586950E-01 -1.195000E-03 2.812900E-01 -6.723400E-02 -1.238650E-01 0.000000E+00 + 2.089240E-01 -1.970000E-04 4.184300E-02 2.707590E-01 4.297220E-01 0.000000E+00 + 8.460800E-02 2.300000E-05 -4.002000E-03 5.758070E-01 6.507860E-01 0.000000E+00 + 3.325800E-02 -9.000000E-06 1.521000E-03 3.011210E-01 6.417100E-02 1.000000E+00 +Cr D + 8.857680E+01 3.621000E-03 -4.122000E-03 0.000000E+00 + 2.620450E+01 2.576600E-02 -2.930700E-02 0.000000E+00 + 9.517470E+00 9.755600E-02 -1.150620E-01 0.000000E+00 + 3.822480E+00 2.363120E-01 -2.730680E-01 0.000000E+00 + 1.575120E+00 3.582860E-01 -3.144230E-01 0.000000E+00 + 6.289280E-01 3.685430E-01 4.209700E-02 0.000000E+00 + 2.344240E-01 2.354940E-01 5.914030E-01 0.000000E+00 + 7.681500E-02 5.315600E-02 3.582150E-01 1.000000E+00 +Cr F + 2.221100E+00 4.235450E-01 + 5.231000E-01 7.741140E-01 +#BASIS SET: (20s,16p,8d,2f) -> [6s,5p,3d,1f] +Mn S + 3.960805E+06 8.242127E-06 -3.936095E-06 9.462709E-07 -2.095391E-07 -4.121231E-07 0.000000E+00 + 5.931155E+05 6.408587E-05 -3.060481E-05 7.360584E-06 -1.629439E-06 -3.282099E-06 0.000000E+00 + 1.349768E+05 3.369253E-04 -1.609626E-04 3.869935E-05 -8.570592E-06 -1.667433E-05 0.000000E+00 + 3.823067E+04 1.420648E-03 -6.792348E-04 1.635110E-04 -3.619272E-05 -7.369999E-05 0.000000E+00 + 1.247154E+04 5.143683E-03 -2.466182E-03 5.941775E-04 -1.316146E-04 -2.529495E-04 0.000000E+00 + 4.501743E+03 1.648569E-02 -7.957629E-03 1.927737E-03 -4.266810E-04 -8.801425E-04 0.000000E+00 + 1.755212E+03 4.698560E-02 -2.307248E-02 5.641731E-03 -1.250270E-03 -2.365482E-03 0.000000E+00 + 7.273039E+02 1.162437E-01 -5.932956E-02 1.487848E-02 -3.294665E-03 -6.926354E-03 0.000000E+00 + 3.163678E+02 2.335277E-01 -1.299451E-01 3.414783E-02 -7.581860E-03 -1.393851E-02 0.000000E+00 + 1.430098E+02 3.292837E-01 -2.212352E-01 6.405794E-02 -1.422864E-02 -3.143840E-02 0.000000E+00 + 6.621805E+01 2.440304E-01 -2.292550E-01 7.557659E-02 -1.693796E-02 -2.625749E-02 0.000000E+00 + 2.991896E+01 7.219806E-02 3.580733E-02 -1.946070E-02 4.454298E-03 -1.048313E-02 0.000000E+00 + 1.430318E+01 7.687806E-02 5.107602E-01 -2.957874E-01 6.867042E-02 1.856472E-01 0.000000E+00 + 6.839451E+00 7.852235E-02 5.008307E-01 -4.521170E-01 1.113335E-01 1.524839E-01 0.000000E+00 + 3.012374E+00 1.294109E-02 9.011830E-02 1.224531E-01 -3.900820E-02 7.411368E-02 0.000000E+00 + 1.418808E+00 -3.784873E-04 -6.909909E-03 7.169756E-01 -2.215755E-01 -1.018097E+00 0.000000E+00 + 6.236240E-01 -2.503203E-05 -1.912925E-04 4.092712E-01 -2.544359E-01 2.980372E-01 0.000000E+00 + 1.340980E-01 -2.421517E-05 -6.032312E-04 2.221969E-02 2.865866E-01 1.971989E+00 0.000000E+00 + 6.554800E-02 3.462071E-05 5.621608E-04 -9.011202E-03 5.755741E-01 -1.179253E+00 0.000000E+00 + 2.958400E-02 4.261482E-07 -1.021109E-04 3.691727E-03 2.898778E-01 -5.837703E-01 1.000000E+00 +Mn P + 1.620586E+04 4.200000E-05 -1.500000E-05 3.000000E-06 4.000000E-06 0.000000E+00 + 3.836274E+03 3.730000E-04 -1.290000E-04 3.000000E-05 4.000000E-05 0.000000E+00 + 1.246048E+03 2.149000E-03 -7.480000E-04 1.720000E-04 2.260000E-04 0.000000E+00 + 4.767535E+02 9.445000E-03 -3.308000E-03 7.620000E-04 1.013000E-03 0.000000E+00 + 2.021895E+02 3.329700E-02 -1.181100E-02 2.726000E-03 3.575000E-03 0.000000E+00 + 9.209487E+01 9.475900E-02 -3.453300E-02 7.976000E-03 1.061200E-02 0.000000E+00 + 4.414720E+01 2.081440E-01 -7.878500E-02 1.828700E-02 2.390200E-02 0.000000E+00 + 2.185468E+01 3.318050E-01 -1.321830E-01 3.077600E-02 4.127900E-02 0.000000E+00 + 1.108596E+01 3.331750E-01 -1.371950E-01 3.237300E-02 4.147500E-02 0.000000E+00 + 5.674108E+00 1.576010E-01 2.707500E-02 -9.978000E-03 -9.458000E-03 0.000000E+00 + 2.823170E+00 2.144500E-02 3.288910E-01 -9.052900E-02 -1.236950E-01 0.000000E+00 + 1.368621E+00 -2.558000E-03 4.572800E-01 -1.380040E-01 -1.743920E-01 0.000000E+00 + 6.444310E-01 -2.027000E-03 2.889080E-01 -7.796500E-02 -1.291700E-01 0.000000E+00 + 2.483820E-01 -3.600000E-04 4.743300E-02 2.295600E-01 4.003480E-01 0.000000E+00 + 9.725500E-02 3.400000E-05 -3.522000E-03 5.761220E-01 6.696460E-01 0.000000E+00 + 3.663300E-02 -1.300000E-05 1.456000E-03 3.485380E-01 8.273200E-02 1.000000E+00 +Mn D + 1.006630E+02 3.579000E-03 -3.454000E-03 0.000000E+00 + 2.983360E+01 2.582700E-02 -2.492500E-02 0.000000E+00 + 1.088940E+01 9.855900E-02 -9.763500E-02 0.000000E+00 + 4.393580E+00 2.383270E-01 -2.366920E-01 0.000000E+00 + 1.817820E+00 3.587070E-01 -2.923500E-01 0.000000E+00 + 7.278270E-01 3.650920E-01 -4.973000E-03 0.000000E+00 + 2.712950E-01 2.337380E-01 5.065880E-01 0.000000E+00 + 8.830900E-02 5.661800E-02 4.979510E-01 1.000000E+00 +Mn F + 2.703200E+00 4.267760E-01 + 6.438000E-01 7.697990E-01 +#BASIS SET: (20s,16p,8d,2f) -> [6s,5p,3d,1f] +Fe S + 4.316265E+06 8.048803E-06 -4.155954E-06 9.532178E-07 -2.063008E-07 -4.009367E-07 0.000000E+00 + 6.463424E+05 6.258306E-05 -3.231401E-05 7.414605E-06 -1.604169E-06 -3.189255E-06 0.000000E+00 + 1.470897E+05 3.290239E-04 -1.699525E-04 3.898393E-05 -8.438437E-06 -1.623079E-05 0.000000E+00 + 4.166152E+04 1.387355E-03 -7.171369E-04 1.647152E-04 -3.563151E-05 -7.157920E-05 0.000000E+00 + 1.359077E+04 5.023256E-03 -2.603625E-03 5.985980E-04 -1.295998E-04 -2.463958E-04 0.000000E+00 + 4.905750E+03 1.610140E-02 -8.399109E-03 1.942390E-03 -4.201534E-04 -8.544907E-04 0.000000E+00 + 1.912746E+03 4.590034E-02 -2.434109E-02 5.687237E-03 -1.231954E-03 -2.307593E-03 0.000000E+00 + 7.926043E+02 1.136154E-01 -6.251948E-02 1.501329E-02 -3.248922E-03 -6.728292E-03 0.000000E+00 + 3.448065E+02 2.283869E-01 -1.365929E-01 3.452455E-02 -7.493717E-03 -1.366165E-02 0.000000E+00 + 1.558999E+02 3.221159E-01 -2.312707E-01 6.495820E-02 -1.410102E-02 -3.062240E-02 0.000000E+00 + 7.223091E+01 2.383661E-01 -2.383734E-01 7.716194E-02 -1.691600E-02 -2.631137E-02 0.000000E+00 + 3.272506E+01 7.404667E-02 3.123837E-02 -1.873411E-02 4.218996E-03 -9.760183E-03 0.000000E+00 + 1.566762E+01 9.214197E-02 5.086818E-01 -3.009185E-01 6.833810E-02 1.801906E-01 0.000000E+00 + 7.503483E+00 9.339790E-02 4.987695E-01 -4.554661E-01 1.098201E-01 1.529634E-01 0.000000E+00 + 3.312223E+00 1.573965E-02 9.033552E-02 1.286463E-01 -4.009005E-02 5.505413E-02 0.000000E+00 + 1.558471E+00 -4.186682E-04 -6.005337E-03 7.183316E-01 -2.174739E-01 -9.551364E-01 0.000000E+00 + 6.839140E-01 5.376318E-05 2.312454E-04 4.051743E-01 -2.465135E-01 2.586813E-01 0.000000E+00 + 1.467570E-01 -3.816654E-05 -5.643680E-04 2.168227E-02 2.731435E-01 1.834049E+00 0.000000E+00 + 7.058300E-02 4.319603E-05 4.992260E-04 -8.343566E-03 5.748321E-01 -9.333240E-01 0.000000E+00 + 3.144900E-02 -3.401019E-06 -1.015293E-04 3.658979E-03 3.012713E-01 -6.981605E-01 1.000000E+00 +Fe P + 1.774569E+04 4.100000E-05 -1.500000E-05 3.000000E-06 5.000000E-06 0.000000E+00 + 4.200721E+03 3.690000E-04 -1.300000E-04 2.900000E-05 4.200000E-05 0.000000E+00 + 1.364429E+03 2.129000E-03 -7.510000E-04 1.650000E-04 2.410000E-04 0.000000E+00 + 5.220806E+02 9.369000E-03 -3.329000E-03 7.340000E-04 1.085000E-03 0.000000E+00 + 2.214595E+02 3.309700E-02 -1.191200E-02 2.626000E-03 3.831000E-03 0.000000E+00 + 1.009096E+02 9.443100E-02 -3.493300E-02 7.725000E-03 1.142300E-02 0.000000E+00 + 4.840115E+01 2.080770E-01 -7.998900E-02 1.773300E-02 2.579200E-02 0.000000E+00 + 2.398536E+01 3.323330E-01 -1.346360E-01 3.005500E-02 4.481800E-02 0.000000E+00 + 1.218250E+01 3.329870E-01 -1.385980E-01 3.109400E-02 4.459800E-02 0.000000E+00 + 6.242298E+00 1.568430E-01 3.027800E-02 -1.004800E-02 -1.117700E-02 0.000000E+00 + 3.110944E+00 2.154900E-02 3.332160E-01 -8.830600E-02 -1.381340E-01 0.000000E+00 + 1.509958E+00 -2.095000E-03 4.561530E-01 -1.298240E-01 -1.882850E-01 0.000000E+00 + 7.108450E-01 -1.739000E-03 2.850510E-01 -7.693700E-02 -1.073990E-01 0.000000E+00 + 2.731900E-01 -3.000000E-04 4.614400E-02 2.126610E-01 4.448630E-01 0.000000E+00 + 1.042330E-01 2.900000E-05 -3.249000E-03 5.730610E-01 6.402390E-01 0.000000E+00 + 3.829100E-02 -1.100000E-05 1.357000E-03 3.696510E-01 6.445700E-02 1.000000E+00 +Fe D + 1.133440E+02 3.530000E-03 -3.890000E-03 0.000000E+00 + 3.364140E+01 2.578400E-02 -2.844200E-02 0.000000E+00 + 1.233100E+01 9.911900E-02 -1.124290E-01 0.000000E+00 + 4.994780E+00 2.390730E-01 -2.742570E-01 0.000000E+00 + 2.072800E+00 3.571990E-01 -3.155460E-01 0.000000E+00 + 8.307530E-01 3.621880E-01 5.710900E-02 0.000000E+00 + 3.091780E-01 2.364610E-01 5.636040E-01 0.000000E+00 + 1.001300E-01 6.011800E-02 3.846370E-01 1.000000E+00 +Fe F + 3.224300E+00 4.222490E-01 + 7.758000E-01 7.714680E-01 +#BASIS SET: (20s,16p,8d,2f) -> [6s,5p,3d,1f] +Co S + 4.675675E+06 7.979026E-06 -4.200240E-06 9.592692E-07 -2.028840E-07 -3.863053E-07 0.000000E+00 + 7.001615E+05 6.204071E-05 -3.265831E-05 7.461851E-06 -1.577580E-06 -3.068788E-06 0.000000E+00 + 1.593373E+05 3.261735E-04 -1.717644E-04 3.923137E-05 -8.298813E-06 -1.564826E-05 0.000000E+00 + 4.513046E+04 1.375360E-03 -7.247853E-04 1.657706E-04 -3.504154E-05 -6.883588E-05 0.000000E+00 + 1.472238E+04 4.979997E-03 -2.631462E-03 6.024335E-04 -1.274655E-04 -2.377367E-04 0.000000E+00 + 5.314222E+03 1.596434E-02 -8.489272E-03 1.955217E-03 -4.132695E-04 -8.213173E-04 0.000000E+00 + 2.072018E+03 4.552086E-02 -2.460619E-02 5.726326E-03 -1.212261E-03 -2.229630E-03 0.000000E+00 + 8.586188E+02 1.127385E-01 -6.322059E-02 1.512984E-02 -3.199318E-03 -6.467841E-03 0.000000E+00 + 3.735497E+02 2.268262E-01 -1.381957E-01 3.483973E-02 -7.390972E-03 -1.325463E-02 0.000000E+00 + 1.689229E+02 3.203074E-01 -2.340680E-01 6.570351E-02 -1.393649E-02 -2.946686E-02 0.000000E+00 + 7.829639E+01 2.374021E-01 -2.415002E-01 7.831503E-02 -1.678575E-02 -2.599066E-02 0.000000E+00 + 3.552123E+01 7.477686E-02 3.035312E-02 -1.877037E-02 4.149856E-03 -8.499807E-03 0.000000E+00 + 1.704144E+01 9.581872E-02 5.101341E-01 -3.062663E-01 6.797646E-02 1.727316E-01 0.000000E+00 + 8.173000E+00 9.649911E-02 4.974939E-01 -4.566429E-01 1.075807E-01 1.512189E-01 0.000000E+00 + 3.610318E+00 1.623362E-02 8.970746E-02 1.378169E-01 -4.166022E-02 3.554509E-02 0.000000E+00 + 1.697047E+00 -4.535497E-04 -5.941034E-03 7.193676E-01 -2.128044E-01 -8.829353E-01 0.000000E+00 + 7.435320E-01 5.113519E-05 2.175362E-04 3.992579E-01 -2.381360E-01 2.143530E-01 0.000000E+00 + 1.583440E-01 -4.174508E-05 -5.480155E-04 2.079933E-02 2.650788E-01 1.711865E+00 0.000000E+00 + 7.503600E-02 4.027577E-05 4.525804E-04 -7.820663E-03 5.722774E-01 -7.140037E-01 0.000000E+00 + 3.309100E-02 -5.789067E-06 -1.066748E-04 3.533911E-03 3.091556E-01 -8.027727E-01 1.000000E+00 +Co P + 1.926778E+04 4.100000E-05 -1.500000E-05 -3.000000E-06 5.000000E-06 0.000000E+00 + 4.560986E+03 3.690000E-04 -1.310000E-04 -2.900000E-05 4.500000E-05 0.000000E+00 + 1.481436E+03 2.128000E-03 -7.580000E-04 -1.670000E-04 2.550000E-04 0.000000E+00 + 5.668671E+02 9.372000E-03 -3.363000E-03 -7.420000E-04 1.144000E-03 0.000000E+00 + 2.404910E+02 3.315500E-02 -1.205400E-02 -2.662000E-03 4.061000E-03 0.000000E+00 + 1.096105E+02 9.475200E-02 -3.542400E-02 -7.841000E-03 1.209500E-02 0.000000E+00 + 5.259491E+01 2.090930E-01 -8.128700E-02 -1.805100E-02 2.747600E-02 0.000000E+00 + 2.608361E+01 3.337220E-01 -1.369080E-01 -3.058000E-02 4.755700E-02 0.000000E+00 + 1.326143E+01 3.322080E-01 -1.390190E-01 -3.131200E-02 4.730200E-02 0.000000E+00 + 6.799778E+00 1.546130E-01 3.546800E-02 1.131100E-02 -1.441800E-02 0.000000E+00 + 3.393414E+00 2.090200E-02 3.384980E-01 8.999000E-02 -1.500620E-01 0.000000E+00 + 1.648766E+00 -2.024000E-03 4.544330E-01 1.307330E-01 -1.990920E-01 0.000000E+00 + 7.762820E-01 -1.697000E-03 2.797930E-01 7.180800E-02 -7.978300E-02 0.000000E+00 + 2.980030E-01 -2.800000E-04 4.477600E-02 -2.216580E-01 4.590350E-01 0.000000E+00 + 1.136180E-01 2.600000E-05 -3.151000E-03 -5.710250E-01 6.174950E-01 0.000000E+00 + 4.162400E-02 -1.000000E-05 1.317000E-03 -3.637890E-01 6.469000E-02 1.000000E+00 +Co D + 1.262640E+02 3.510000E-03 -4.067000E-03 0.000000E+00 + 3.752260E+01 2.588400E-02 -3.005300E-02 0.000000E+00 + 1.380210E+01 1.000580E-01 -1.196200E-01 0.000000E+00 + 5.609270E+00 2.405470E-01 -2.915130E-01 0.000000E+00 + 2.333690E+00 3.568430E-01 -3.180480E-01 0.000000E+00 + 9.364150E-01 3.595790E-01 9.169800E-02 0.000000E+00 + 3.482370E-01 2.366290E-01 5.608230E-01 0.000000E+00 + 1.123530E-01 6.212900E-02 3.586780E-01 1.000000E+00 +Co F + 3.772400E+00 4.239660E-01 + 9.170000E-01 7.684290E-01 +#BASIS SET: (20s,16p,8d,2f) -> [6s,5p,3d,1f] +Ni S + 5.045991E+06 8.208996E-06 -3.657849E-06 9.594149E-07 -2.013753E-07 -3.924245E-07 0.000000E+00 + 7.556142E+05 6.382884E-05 -2.844094E-05 7.462614E-06 -1.565832E-06 -3.113909E-06 0.000000E+00 + 1.719568E+05 3.355800E-04 -1.495928E-04 3.923843E-05 -8.237182E-06 -1.590447E-05 0.000000E+00 + 4.870479E+04 1.415075E-03 -6.313009E-04 1.657868E-04 -3.478105E-05 -6.981394E-05 0.000000E+00 + 1.588841E+04 5.124444E-03 -2.293052E-03 6.025905E-04 -1.265265E-04 -2.417848E-04 0.000000E+00 + 5.735123E+03 1.643256E-02 -7.405123E-03 1.955662E-03 -4.102589E-04 -8.326195E-04 0.000000E+00 + 2.236137E+03 4.689398E-02 -2.152032E-02 5.730391E-03 -1.203834E-03 -2.270294E-03 0.000000E+00 + 9.266468E+02 1.163534E-01 -5.560974E-02 1.514756E-02 -3.179062E-03 -6.557427E-03 0.000000E+00 + 4.031743E+02 2.350511E-01 -1.230176E-01 3.493499E-02 -7.353828E-03 -1.354288E-02 0.000000E+00 + 1.823476E+02 3.350184E-01 -2.130104E-01 6.598072E-02 -1.389022E-02 -2.989768E-02 0.000000E+00 + 8.454885E+01 2.534779E-01 -2.265837E-01 7.893083E-02 -1.677875E-02 -2.693106E-02 0.000000E+00 + 3.839634E+01 7.300901E-02 3.546796E-02 -1.906249E-02 4.163378E-03 -7.827693E-03 0.000000E+00 + 1.845859E+01 6.184244E-02 5.181697E-01 -3.095921E-01 6.814703E-02 1.741667E-01 0.000000E+00 + 8.863548E+00 6.302956E-02 5.025630E-01 -4.558610E-01 1.061029E-01 1.595468E-01 0.000000E+00 + 3.916227E+00 1.008063E-02 8.955674E-02 1.482931E-01 -4.339980E-02 1.995550E-02 0.000000E+00 + 1.838870E+00 -2.244528E-04 -7.031311E-03 7.134039E-01 -2.094950E-01 -8.897000E-01 0.000000E+00 + 8.043620E-01 -5.932767E-05 -4.339167E-04 3.976063E-01 -2.310271E-01 2.486892E-01 0.000000E+00 + 1.697970E-01 -1.158562E-05 -5.831711E-04 2.295523E-02 2.590532E-01 1.613012E+00 0.000000E+00 + 7.930600E-02 8.115109E-06 4.228788E-04 -9.151758E-03 5.691426E-01 -5.990277E-01 0.000000E+00 + 3.467700E-02 -1.681699E-06 -1.266714E-04 3.875414E-03 3.158125E-01 -8.369078E-01 1.000000E+00 +Ni P + 2.102792E+04 4.100000E-05 -1.500000E-05 3.000000E-06 6.000000E-06 0.000000E+00 + 4.977560E+03 3.630000E-04 -1.290000E-04 2.600000E-05 5.300000E-05 0.000000E+00 + 1.616740E+03 2.097000E-03 -7.490000E-04 1.520000E-04 3.050000E-04 0.000000E+00 + 6.186718E+02 9.250000E-03 -3.328000E-03 6.780000E-04 1.364000E-03 0.000000E+00 + 2.625183E+02 3.279600E-02 -1.194700E-02 2.427000E-03 4.876000E-03 0.000000E+00 + 1.196907E+02 9.400400E-02 -3.524200E-02 7.201000E-03 1.450300E-02 0.000000E+00 + 5.746585E+01 2.082800E-01 -8.120400E-02 1.657800E-02 3.329600E-02 0.000000E+00 + 2.852829E+01 3.336540E-01 -1.374930E-01 2.839200E-02 5.748200E-02 0.000000E+00 + 1.452148E+01 3.329040E-01 -1.392260E-01 2.859900E-02 5.870200E-02 0.000000E+00 + 7.453850E+00 1.553720E-01 3.601600E-02 -1.013200E-02 -1.990400E-02 0.000000E+00 + 3.723553E+00 2.085900E-02 3.391280E-01 -8.291200E-02 -1.946950E-01 0.000000E+00 + 1.809813E+00 -2.440000E-03 4.504720E-01 -1.159980E-01 -2.396130E-01 0.000000E+00 + 8.513360E-01 -1.998000E-03 2.817830E-01 -7.279500E-02 -2.232000E-03 0.000000E+00 + 3.248140E-01 -3.380000E-04 4.789800E-02 1.956400E-01 5.214350E-01 0.000000E+00 + 1.195220E-01 3.500000E-05 -2.987000E-03 5.670990E-01 5.455400E-01 0.000000E+00 + 4.236600E-02 -1.200000E-05 1.309000E-03 3.952700E-01 4.362200E-02 1.000000E+00 +Ni D + 1.402527E+02 3.376000E-03 -3.495000E-03 0.000000E+00 + 4.172610E+01 2.514100E-02 -2.601500E-02 0.000000E+00 + 1.539810E+01 9.774600E-02 -1.038760E-01 0.000000E+00 + 6.277100E+00 2.347090E-01 -2.520700E-01 0.000000E+00 + 2.618500E+00 3.469450E-01 -2.945800E-01 0.000000E+00 + 1.052600E+00 3.510680E-01 1.152000E-03 0.000000E+00 + 3.916000E-01 2.502550E-01 4.385890E-01 0.000000E+00 + 1.262000E-01 1.000820E-01 5.436260E-01 1.000000E+00 +Ni F + 4.345500E+00 4.174290E-01 + 1.068000E+00 7.714830E-01 +#BASIS SET: (20s,16p,8d,2f) -> [6s,5p,3d,1f] +Cu S + 5.430321E+06 7.801026E-06 -4.404706E-06 9.704682E-07 -1.959354E-07 -3.532229E-07 0.000000E+00 + 8.131665E+05 6.065666E-05 -3.424801E-05 7.549245E-06 -1.523472E-06 -2.798812E-06 0.000000E+00 + 1.850544E+05 3.188964E-04 -1.801238E-04 3.968892E-05 -8.014808E-06 -1.432517E-05 0.000000E+00 + 5.241466E+04 1.344687E-03 -7.600455E-04 1.677200E-04 -3.383992E-05 -6.270946E-05 0.000000E+00 + 1.709868E+04 4.869050E-03 -2.759348E-03 6.095101E-04 -1.231191E-04 -2.179490E-04 0.000000E+00 + 6.171994E+03 1.561013E-02 -8.900970E-03 1.978846E-03 -3.992085E-04 -7.474316E-04 0.000000E+00 + 2.406481E+03 4.452077E-02 -2.579378E-02 5.798049E-03 -1.171900E-03 -2.049271E-03 0.000000E+00 + 9.972584E+02 1.103111E-01 -6.623861E-02 1.534158E-02 -3.096141E-03 -5.885203E-03 0.000000E+00 + 4.339289E+02 2.220342E-01 -1.445927E-01 3.540484E-02 -7.171993E-03 -1.226885E-02 0.000000E+00 + 1.962869E+02 3.133739E-01 -2.440110E-01 6.702098E-02 -1.356621E-02 -2.683147E-02 0.000000E+00 + 9.104280E+01 2.315121E-01 -2.504837E-01 8.026945E-02 -1.643989E-02 -2.479261E-02 0.000000E+00 + 4.138425E+01 7.640920E-02 2.852577E-02 -1.927231E-02 4.107628E-03 -5.984746E-03 0.000000E+00 + 1.993278E+01 1.103818E-01 5.115874E-01 -3.160129E-01 6.693964E-02 1.557124E-01 0.000000E+00 + 9.581891E+00 1.094372E-01 4.928061E-01 -4.573162E-01 1.028221E-01 1.436683E-01 0.000000E+00 + 4.234516E+00 1.836311E-02 8.788437E-02 1.550841E-01 -4.422945E-02 8.374103E-03 0.000000E+00 + 1.985814E+00 -6.043084E-04 -5.820281E-03 7.202872E-01 -2.031191E-01 -7.460711E-01 0.000000E+00 + 8.670830E-01 5.092245E-05 2.013508E-04 3.885122E-01 -2.230022E-01 1.244367E-01 0.000000E+00 + 1.813390E-01 -5.540730E-05 -5.182553E-04 1.924326E-02 2.517975E-01 1.510110E+00 0.000000E+00 + 8.365700E-02 3.969482E-05 3.731503E-04 -7.103807E-03 5.650091E-01 -3.477122E-01 0.000000E+00 + 3.626700E-02 -1.269538E-05 -1.193171E-04 3.272906E-03 3.247243E-01 -9.774169E-01 1.000000E+00 +Cu P + 2.276057E+04 4.000000E-05 -1.500000E-05 3.000000E-06 5.000000E-06 0.000000E+00 + 5.387679E+03 3.610000E-04 -1.310000E-04 2.500000E-05 4.900000E-05 0.000000E+00 + 1.749945E+03 2.083000E-03 -7.550000E-04 1.470000E-04 2.780000E-04 0.000000E+00 + 6.696653E+02 9.197000E-03 -3.359000E-03 6.560000E-04 1.253000E-03 0.000000E+00 + 2.841948E+02 3.266000E-02 -1.208100E-02 2.351000E-03 4.447000E-03 0.000000E+00 + 1.296077E+02 9.379500E-02 -3.570300E-02 7.004000E-03 1.337000E-02 0.000000E+00 + 6.225415E+01 2.082740E-01 -8.250200E-02 1.613100E-02 3.046900E-02 0.000000E+00 + 3.092964E+01 3.339930E-01 -1.398900E-01 2.777000E-02 5.344700E-02 0.000000E+00 + 1.575827E+01 3.324930E-01 -1.407290E-01 2.756700E-02 5.263900E-02 0.000000E+00 + 8.094211E+00 1.547280E-01 3.876600E-02 -1.011500E-02 -1.688100E-02 0.000000E+00 + 4.046921E+00 2.127100E-02 3.426950E-01 -8.100900E-02 -1.794480E-01 0.000000E+00 + 1.967869E+00 -1.690000E-03 4.523100E-01 -1.104090E-01 -2.095880E-01 0.000000E+00 + 9.252950E-01 -1.516000E-03 2.770540E-01 -7.173200E-02 -3.963300E-02 0.000000E+00 + 3.529920E-01 -2.420000E-04 4.388500E-02 1.879300E-01 5.021300E-01 0.000000E+00 + 1.273070E-01 2.300000E-05 -2.802000E-03 5.646290E-01 5.811110E-01 0.000000E+00 + 4.435600E-02 -9.000000E-06 1.152000E-03 4.070000E-01 4.566600E-02 1.000000E+00 +Cu D + 1.738970E+02 2.700000E-03 -3.363000E-03 0.000000E+00 + 5.188690E+01 2.090900E-02 -2.607900E-02 0.000000E+00 + 1.934190E+01 8.440800E-02 -1.082310E-01 0.000000E+00 + 7.975720E+00 2.139990E-01 -2.822170E-01 0.000000E+00 + 3.398230E+00 3.359800E-01 -3.471900E-01 0.000000E+00 + 1.409320E+00 3.573010E-01 2.671100E-02 0.000000E+00 + 5.488580E-01 2.645780E-01 4.920470E-01 0.000000E+00 + 1.901990E-01 1.039720E-01 4.384220E-01 1.000000E+00 +Cu F + 5.028600E+00 4.242800E-01 + 1.259400E+00 7.630250E-01 +#BASIS SET: (20s,16p,8d,2f) -> [6s,5p,3d,1f] +Zn S + 5.820021E+06 8.549241E-06 -2.640069E-06 9.967103E-07 1.995818E-07 -5.435910E-07 0.000000E+00 + 8.715234E+05 6.647410E-05 -2.052720E-05 7.754163E-06 1.552973E-06 -4.336894E-06 0.000000E+00 + 1.983350E+05 3.494962E-04 -1.079859E-04 4.076019E-05 8.161259E-06 -2.197572E-05 0.000000E+00 + 5.617631E+04 1.473832E-03 -4.558577E-04 1.722811E-04 3.450747E-05 -9.747392E-05 0.000000E+00 + 1.832582E+04 5.338330E-03 -1.657758E-03 6.259370E-04 1.253275E-04 -3.331615E-04 0.000000E+00 + 6.614955E+03 1.712708E-02 -5.368492E-03 2.032855E-03 4.072990E-04 -1.166192E-03 0.000000E+00 + 2.579199E+03 4.894085E-02 -1.571249E-02 5.954646E-03 1.192734E-03 -3.119308E-03 0.000000E+00 + 1.068849E+03 1.217934E-01 -4.122558E-02 1.576640E-02 3.163140E-03 -9.239504E-03 0.000000E+00 + 4.651045E+02 2.476589E-01 -9.406459E-02 3.637638E-02 7.303942E-03 -1.855471E-02 0.000000E+00 + 2.104130E+02 3.582431E-01 -1.719954E-01 6.892343E-02 1.391279E-02 -4.281189E-02 0.000000E+00 + 9.761629E+01 2.798174E-01 -1.958523E-01 8.238093E-02 1.670620E-02 -3.571095E-02 0.000000E+00 + 4.438020E+01 6.857491E-02 4.532907E-02 -2.011360E-02 -4.035586E-03 -1.638350E-02 0.000000E+00 + 2.142308E+01 -1.311092E-03 5.244442E-01 -3.252526E-01 -6.968861E-02 2.644664E-01 0.000000E+00 + 1.030891E+01 1.914001E-03 5.006142E-01 -4.602899E-01 -1.030105E-01 2.086588E-01 0.000000E+00 + 4.553645E+00 -8.759220E-04 8.945527E-02 1.635546E-01 4.471442E-02 -1.774382E-02 0.000000E+00 + 2.132821E+00 3.740096E-04 -2.146262E-03 7.297118E-01 2.150027E-01 -1.353873E+00 0.000000E+00 + 9.296970E-01 -1.401399E-04 2.112113E-03 3.769751E-01 2.220163E-01 8.182926E-01 0.000000E+00 + 1.921470E-01 4.757132E-05 -4.133980E-04 1.433224E-02 -3.114776E-01 1.695036E+00 0.000000E+00 + 8.759500E-02 -3.642711E-05 3.209752E-04 -6.671210E-03 -5.693429E-01 -1.388656E+00 0.000000E+00 + 3.770200E-02 1.153248E-05 -1.016140E-04 1.766214E-03 -2.678440E-01 -2.188900E-01 1.000000E+00 +Zn P + 2.441198E+04 -1.500000E-05 3.000000E-06 5.000000E-06 4.100000E-05 0.000000E+00 + 5.778518E+03 -1.350000E-04 2.500000E-05 4.200000E-05 3.610000E-04 0.000000E+00 + 1.876862E+03 -7.820000E-04 1.440000E-04 2.380000E-04 2.088000E-03 0.000000E+00 + 7.182361E+02 -3.478000E-03 6.450000E-04 1.088000E-03 9.221000E-03 0.000000E+00 + 3.048327E+02 -1.252000E-02 2.311000E-03 3.821000E-03 3.277300E-02 0.000000E+00 + 1.390453E+02 -3.701600E-02 6.898000E-03 1.164400E-02 9.417900E-02 0.000000E+00 + 6.680417E+01 -8.555900E-02 1.588200E-02 2.616700E-02 2.091320E-01 0.000000E+00 + 3.320699E+01 -1.447180E-01 2.735000E-02 4.675000E-02 3.345690E-01 0.000000E+00 + 1.692816E+01 -1.434420E-01 2.662100E-02 4.330900E-02 3.303590E-01 0.000000E+00 + 8.696229E+00 4.359500E-02 -1.085800E-02 -1.342900E-02 1.523470E-01 0.000000E+00 + 4.350510E+00 3.488880E-01 -7.985300E-02 -1.538970E-01 2.298400E-02 0.000000E+00 + 2.116523E+00 4.538650E-01 -1.061270E-01 -1.674130E-01 1.607000E-03 0.000000E+00 + 9.953870E-01 2.685940E-01 -6.888300E-02 -8.499500E-02 4.680000E-04 0.000000E+00 + 3.781120E-01 3.886800E-02 1.843850E-01 4.508130E-01 6.600000E-05 0.000000E+00 + 1.345790E-01 -2.492000E-03 5.617880E-01 6.408690E-01 -2.000000E-06 0.000000E+00 + 4.628200E-02 1.014000E-03 4.144160E-01 5.417200E-02 0.000000E+00 1.000000E+00 +Zn D + 2.056177E+02 2.342000E-03 3.279000E-03 0.000000E+00 + 6.144981E+01 1.860600E-02 2.617600E-02 0.000000E+00 + 2.305689E+01 7.710200E-02 1.113670E-01 0.000000E+00 + 9.577739E+00 2.020260E-01 3.045810E-01 0.000000E+00 + 4.133734E+00 3.294540E-01 3.862990E-01 0.000000E+00 + 1.747518E+00 3.609760E-01 -5.837500E-02 0.000000E+00 + 6.995600E-01 2.716570E-01 -5.388760E-01 0.000000E+00 + 2.516080E-01 1.049810E-01 -3.454730E-01 1.000000E+00 +Zn F + 5.734400E+00 4.311320E-01 + 1.461500E+00 7.546420E-01 +#BASIS SET: (14s,11p,6d) -> [5s,4p,2d] +Ga S + 485130.0000000 0.0002068 -0.0000643 0.0000245 -0.0000057 0.0000000 + 72719.0000000 0.0016047 -0.0004954 0.0001895 -0.0000440 0.0000000 + 16552.0000000 0.0083402 -0.0026208 0.0009964 -0.0002305 0.0000000 + 4687.8000000 0.0340248 -0.0106839 0.0041082 -0.0009544 0.0000000 + 1529.1000000 0.1111699 -0.0374123 0.0142938 -0.0033055 0.0000000 + 551.8100000 0.2753930 -0.1009636 0.0398034 -0.0092888 0.0000000 + 215.1800000 0.4212628 -0.2145141 0.0855940 -0.0198644 0.0000000 + 88.1740000 0.2738906 -0.1752297 0.0796305 -0.0190888 0.0000000 + 27.1540000 0.0283720 0.4831599 -0.2939107 0.0732356 0.0000000 + 11.5030000 -0.0062931 0.6323677 -0.5263914 0.1341526 0.0000000 + 3.3018000 0.0020606 0.0684942 0.5864249 -0.1831929 0.0000000 + 1.3314000 -0.0009269 -0.0118712 0.6726347 -0.3571308 0.0000000 + 0.1931600 0.0002273 0.0026652 0.0276123 0.6246013 0.0000000 + 0.0708950 -0.0001063 -0.0012251 -0.0093651 0.5238430 1.0000000 +Ga P + 3248.6000000 0.0015260 -0.0005803 0.0000950 0.0000000 + 769.9700000 0.0127486 -0.0048647 0.0007832 0.0000000 + 248.2000000 0.0633742 -0.0248394 0.0040855 0.0000000 + 93.3640000 0.2065775 -0.0841759 0.0135987 0.0000000 + 38.2510000 0.4092963 -0.1800885 0.0302695 0.0000000 + 16.4220000 0.3919183 -0.1585555 0.0241790 0.0000000 + 6.7918000 0.1029441 0.2355376 -0.0423777 0.0000000 + 2.8336000 -0.0007203 0.5820587 -0.1265661 0.0000000 + 1.1062000 0.0020950 0.3366619 -0.0499444 0.0000000 + 0.2225000 -0.0003290 0.0171912 0.4494199 0.0000000 + 0.0617720 0.0001162 -0.0033265 0.6718899 1.0000000 +Ga D + 65.3370000 0.0273825 0.0000000 + 18.4970000 0.1510805 0.0000000 + 6.3150000 0.3749217 0.0000000 + 2.1635000 0.4750799 0.0000000 + 0.6667500 0.2982750 0.0000000 + 0.1884000 0.0000000 1.0000000 +#BASIS SET: (14s,11p,6d) -> [5s,4p,2d] +Ge S + 521800.0000000 0.0002045 -0.0000638 0.0000246 -0.0000063 0.0000000 + 78214.0000000 0.0015868 -0.0004916 0.0001900 -0.0000486 0.0000000 + 17803.0000000 0.0082480 -0.0026002 0.0009993 -0.0002553 0.0000000 + 5041.9000000 0.0336649 -0.0106080 0.0041200 -0.0010560 0.0000000 + 1644.5000000 0.1101249 -0.0371602 0.0143557 -0.0036674 0.0000000 + 593.4300000 0.2735607 -0.1005790 0.0400375 -0.0103053 0.0000000 + 231.3600000 0.4210670 -0.2143977 0.0865794 -0.0222200 0.0000000 + 94.7620000 0.2766791 -0.1782617 0.0815861 -0.0215275 0.0000000 + 29.2740000 0.0292180 0.4777404 -0.2934770 0.0806752 0.0000000 + 12.4500000 -0.0065903 0.6355983 -0.5367983 0.1524958 0.0000000 + 3.6463000 0.0022430 0.0722174 0.5637985 -0.1980528 0.0000000 + 1.5025000 -0.0010382 -0.0127265 0.6947182 -0.4073954 0.0000000 + 0.2450300 0.0002695 0.0029608 0.0315730 0.6477288 0.0000000 + 0.0915940 -0.0001228 -0.0013292 -0.0098949 0.5222033 1.0000000 +Ge P + 3568.1000000 0.0014591 -0.0005630 0.0001115 0.0000000 + 845.7200000 0.0122176 -0.0047354 0.0009212 0.0000000 + 272.7400000 0.0610490 -0.0242643 0.0048273 0.0000000 + 102.6800000 0.2008039 -0.0830900 0.0162272 0.0000000 + 42.1480000 0.4038942 -0.1800247 0.0366354 0.0000000 + 18.1490000 0.3970027 -0.1663295 0.0307867 0.0000000 + 7.5934000 0.1105481 0.2193717 -0.0480643 0.0000000 + 3.1964000 0.0000768 0.5820239 -0.1559804 0.0000000 + 1.2743000 0.0021263 0.3477720 -0.0632370 0.0000000 + 0.2825800 -0.0003744 0.0192455 0.5040819 0.0000000 + 0.0840900 0.0001321 -0.0034825 0.6182200 1.0000000 +Ge D + 74.7620000 0.0257684 0.0000000 + 21.3020000 0.1454421 0.0000000 + 7.3436000 0.3713721 0.0000000 + 2.5651000 0.4800002 0.0000000 + 0.8197000 0.2896800 0.0000000 + 0.2470000 0.0000000 1.0000000 +#BASIS SET: (14s,11p,6d) -> [5s,4p,2d] +As S + 559583.7900000 0.0002024 -0.0000634 0.0000246 -0.0000068 0.0000000 + 83879.3300000 0.0015709 -0.0004883 0.0001907 -0.0000525 0.0000000 + 19092.6680000 0.0081662 -0.0025821 0.0010031 -0.0002756 0.0000000 + 5407.3925000 0.0333399 -0.0105402 0.0041353 -0.0011389 0.0000000 + 1763.7559000 0.1091726 -0.0369325 0.0144259 -0.0039646 0.0000000 + 636.4567200 0.2718853 -0.1002355 0.0402962 -0.0111423 0.0000000 + 248.0884300 0.4208509 -0.2142948 0.0875670 -0.0241991 0.0000000 + 101.5785100 0.2792257 -0.1810526 0.0835178 -0.0236339 0.0000000 + 31.4755130 0.0300301 0.4725410 -0.2932935 0.0866317 0.0000000 + 13.4372820 -0.0068804 0.6386194 -0.5470520 0.1685839 0.0000000 + 4.0086900 0.0024240 0.0758107 0.5438738 -0.2091425 0.0000000 + 1.6849290 -0.0011491 -0.0135278 0.7143591 -0.4500918 0.0000000 + 0.3000190 0.0003095 0.0031970 0.0353443 0.6603978 0.0000000 + 0.1135870 -0.0001377 -0.0014056 -0.0102892 0.5284152 1.0000000 +As P + 3886.3564000 0.0014097 -0.0005519 0.0001236 0.0000000 + 921.2020100 0.0118277 -0.0046550 0.0010240 0.0000000 + 297.1931900 0.0593280 -0.0239176 0.0053805 0.0000000 + 111.9750800 0.1965115 -0.0825627 0.0182443 0.0000000 + 46.0346210 0.3997891 -0.1806791 0.0415979 0.0000000 + 19.8741940 0.4004653 -0.1724848 0.0362998 0.0000000 + 8.3860880 0.1164196 0.2086700 -0.0523569 0.0000000 + 3.5587280 0.0006918 0.5823622 -0.1791667 0.0000000 + 1.4472820 0.0021633 0.3537465 -0.0740477 0.0000000 + 0.3477790 -0.0004150 0.0206439 0.5358094 0.0000000 + 0.1076990 0.0001452 -0.0036382 0.5888104 1.0000000 +As D + 84.4242340 0.0245288 0.0000000 + 24.1815890 0.1411340 0.0000000 + 8.4017770 0.3687579 0.0000000 + 2.9805020 0.4840626 0.0000000 + 0.9790030 0.2824434 0.0000000 + 0.3098000 0.0000000 1.0000000 +#BASIS SET: (14s,11p,6d) -> [5s,4p,2d] +Se S + 598990.0000000 0.0002004 -0.0000629 0.0000247 -0.0000072 0.0000000 + 89783.0000000 0.0015554 -0.0004850 0.0001913 -0.0000559 0.0000000 + 20435.0000000 0.0080872 -0.0025644 0.0010068 -0.0002938 0.0000000 + 5786.9000000 0.0330344 -0.0104761 0.0041514 -0.0012136 0.0000000 + 1887.3000000 0.1082924 -0.0367223 0.0144991 -0.0042340 0.0000000 + 680.9700000 0.2703361 -0.0999225 0.0405658 -0.0119035 0.0000000 + 265.3900000 0.4206236 -0.2141973 0.0885364 -0.0260206 0.0000000 + 108.6300000 0.2815922 -0.1836593 0.0854212 -0.0256148 0.0000000 + 33.7600000 0.0308110 0.4675454 -0.2932581 0.0919427 0.0000000 + 14.4650000 -0.0071617 0.6414740 -0.5570727 0.1838700 0.0000000 + 4.3890000 0.0026022 0.0792569 0.5261436 -0.2188461 0.0000000 + 1.8783000 -0.0012583 -0.0142697 0.7320371 -0.4896524 0.0000000 + 0.3585900 0.0003465 0.0033792 0.0388246 0.6775818 0.0000000 + 0.1364900 -0.0001503 -0.0014537 -0.0105036 0.5296721 1.0000000 +Se P + 4135.6000000 0.0014127 -0.0005610 0.0001366 0.0000000 + 980.3400000 0.0118588 -0.0047340 0.0011308 0.0000000 + 316.3500000 0.0595153 -0.0243504 0.0059581 0.0000000 + 119.2500000 0.1972201 -0.0841071 0.0201866 0.0000000 + 49.0680000 0.4007439 -0.1841384 0.0461939 0.0000000 + 21.2120000 0.3994740 -0.1735004 0.0394050 0.0000000 + 8.9462000 0.1153364 0.2167263 -0.0592846 0.0000000 + 3.8236000 0.0002219 0.5850099 -0.2014663 0.0000000 + 1.5883000 0.0022838 0.3416816 -0.0687821 0.0000000 + 0.4096900 -0.0004756 0.0199125 0.5595944 0.0000000 + 0.1245900 0.0001516 -0.0026131 0.5709784 1.0000000 +Se D + 94.4720000 0.0234982 0.0000000 + 27.1800000 0.1375183 0.0000000 + 9.5068000 0.3664824 0.0000000 + 3.4168000 0.4874717 0.0000000 + 1.1479000 0.2765769 0.0000000 + 0.3682000 0.0000000 1.0000000 +#BASIS SET: (14s,11p,6d) -> [5s,4p,2d] +Br S + 640100.0000000 0.0001984 -0.0000625 0.0000248 -0.0000076 0.0000000 + 95938.0000000 0.0015400 -0.0004816 0.0001919 -0.0000588 0.0000000 + 21833.0000000 0.0080096 -0.0025466 0.0010100 -0.0003092 0.0000000 + 6181.9000000 0.0327341 -0.0104112 0.0041659 -0.0012766 0.0000000 + 2015.7000000 0.1074480 -0.0365179 0.0145683 -0.0044634 0.0000000 + 727.1000000 0.2688946 -0.0996295 0.0408345 -0.0125575 0.0000000 + 283.2800000 0.4204411 -0.2141310 0.0894859 -0.0276145 0.0000000 + 115.9100000 0.2838041 -0.1860911 0.0872786 -0.0273945 0.0000000 + 36.1240000 0.0315455 0.4628261 -0.2933644 0.0964094 0.0000000 + 15.5320000 -0.0074268 0.6441141 -0.5667109 0.1976871 0.0000000 + 4.7857000 0.0027728 0.0825502 0.5105658 -0.2266693 0.0000000 + 2.0817000 -0.0013635 -0.0149694 0.7477214 -0.5241165 0.0000000 + 0.4202800 0.0003812 0.0035288 0.0421512 0.6889865 0.0000000 + 0.1606900 -0.0001615 -0.0014909 -0.0106612 0.5344331 1.0000000 +Br P + 4340.8000000 0.0014448 -0.0005819 0.0001518 0.0000000 + 1028.9000000 0.0121288 -0.0049065 0.0012563 0.0000000 + 332.0200000 0.0608077 -0.0252514 0.0066224 0.0000000 + 125.1600000 0.2009358 -0.0869445 0.0223816 0.0000000 + 51.5110000 0.4047419 -0.1893422 0.0509717 0.0000000 + 22.2810000 0.3957151 -0.1710882 0.0414009 0.0000000 + 9.3417000 0.1102213 0.2368755 -0.0703970 0.0000000 + 4.0132000 -0.0009090 0.5898400 -0.2232540 0.0000000 + 1.7002000 0.0024832 0.3171944 -0.0564179 0.0000000 + 0.4719400 -0.0005744 0.0179833 0.5808079 0.0000000 + 0.1442100 0.0001691 -0.0014683 0.5508132 1.0000000 +Br D + 104.8300000 0.0226583 0.0000000 + 30.2720000 0.1345895 0.0000000 + 10.6490000 0.3647181 0.0000000 + 3.8696000 0.4904196 0.0000000 + 1.3239000 0.2713885 0.0000000 + 0.4098000 0.0000000 1.0000000 +#BASIS SET: (14s,11p,6d) -> [5s,4p,2d] +Kr S + 681358.8200000 0.0001969 -0.0000622 0.0000249 -0.0000079 0.0000000 + 102126.4800000 0.0015286 -0.0004794 0.0001928 -0.0000614 0.0000000 + 23243.7100000 0.0079500 -0.0025341 0.0010149 -0.0003230 0.0000000 + 6582.0073000 0.0324938 -0.0103636 0.0041857 -0.0013330 0.0000000 + 2146.4286000 0.1067240 -0.0363516 0.0146459 -0.0046672 0.0000000 + 774.3378200 0.2675701 -0.0993737 0.0411070 -0.0131352 0.0000000 + 301.6702000 0.4201851 -0.2140610 0.0903955 -0.0290342 0.0000000 + 123.4118400 0.2858015 -0.1883192 0.0890623 -0.0290173 0.0000000 + 38.5675510 0.0322461 0.4583816 -0.2935718 0.1002664 0.0000000 + 16.6373790 -0.0076828 0.6465664 -0.5759698 0.2103818 0.0000000 + 5.1987950 0.0029393 0.0856579 0.4968578 -0.2332471 0.0000000 + 2.2948140 -0.0014662 -0.0156123 0.7616895 -0.5546497 0.0000000 + 0.4852110 0.0004144 0.0036490 0.0453267 0.6969522 0.0000000 + 0.1862700 -0.0001720 -0.0015189 -0.0107722 0.5408152 1.0000000 +Kr P + 4474.2699000 0.0015195 -0.0006208 0.0001701 0.0000000 + 1060.5790000 0.0127424 -0.0052212 0.0014064 0.0000000 + 342.2081200 0.0636465 -0.0268463 0.0073963 0.0000000 + 128.9984200 0.2085635 -0.0915823 0.0248254 0.0000000 + 53.0872220 0.4122423 -0.1968164 0.0557155 0.0000000 + 22.9594250 0.3878103 -0.1634750 0.0412132 0.0000000 + 9.5073000 0.1003820 0.2738204 -0.0876057 0.0000000 + 4.0830550 -0.0025078 0.5981592 -0.2440586 0.0000000 + 1.7504460 0.0027139 0.2750453 -0.0295007 0.0000000 + 0.5291900 -0.0006977 0.0127706 0.6012295 0.0000000 + 0.1643690 0.0002107 -0.0010135 0.5254807 1.0000000 +Kr D + 115.5253200 0.0219557 0.0000000 + 33.4652460 0.1321620 0.0000000 + 11.8304590 0.3633484 0.0000000 + 4.3397710 0.4929582 0.0000000 + 1.5075240 0.2667560 0.0000000 + 0.5030000 0.0000000 1.0000000 +END diff --git a/codeliciousness/test/test_basis.py b/codeliciousness/test/test_basis.py new file mode 100644 index 00000000..8f0fa010 --- /dev/null +++ b/codeliciousness/test/test_basis.py @@ -0,0 +1,47 @@ +import os +import importlib +import pytest + +from basistron.basis import Basis + +class response: + def __init__(self, text=""): + self.text = text + self.status_code = 200 + self.content = b"" + def raise_for_status(self): + pass + +def test_download_basis(monkeypatch, tmppath): + def get(url, **kwargs): + return response("basis set data") + monkeypatch.setattr("basistron.basis.requests.get", get) + path = (tmppath / "subdir").as_posix() + Basis.download_basis_sets(cache_dir=path) + +def setup_basis(tmppath): + unpacked_dir = "subdir" + (tmppath / unpacked_dir).mkdir() + cache_dir = tmppath.as_posix() + with open(os.path.join(cache_dir, unpacked_dir, "basis.nw"), "w") as f: + obj = importlib.resources.read_text("basistron.static", "basis.nw") + f.write(obj) + return cache_dir, unpacked_dir + +def test_load_basis(tmppath): + cache_dir, unpacked_dir = setup_basis(tmppath) + data = Basis.load_basis_sets(cache_dir=cache_dir, unpacked_dir=unpacked_dir) + assert data + +def test_rank_basis(tmppath): + cache_dir, unpacked_dir = setup_basis(tmppath) + data = Basis.load_basis_sets(cache_dir=cache_dir, unpacked_dir=unpacked_dir) + rank = Basis.rank_basis_sets(data) + assert rank + +def test_get_allowed_basis(tmppath): + cache_dir, unpacked_dir = setup_basis(tmppath) + data = Basis.load_basis_sets(cache_dir=cache_dir, unpacked_dir=unpacked_dir) + rank = Basis.rank_basis_sets(data) + allowed = Basis.get_allowed_basis_sets(rank, ["C", "H", "Kr"]) + assert allowed == ["basis"] From 61ce5fb44a07b0fe868cd090ce1377a6b1af58b9 Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Thu, 21 Oct 2021 15:40:09 -0400 Subject: [PATCH 16/23] docs: todo list --- codeliciousness/basistron/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/codeliciousness/basistron/README.md b/codeliciousness/basistron/README.md index ed8e5714..b164ce10 100644 --- a/codeliciousness/basistron/README.md +++ b/codeliciousness/basistron/README.md @@ -1,6 +1,24 @@ BasisTron ========= +TODO +---- + +* Basis + - how to update workflow model with basis set info + +* Cccbdb + - client + - provide reference data given simple chemical formula + +* Driver + - provide simple chemical formula to app + +* App + - sanity check reference data to input + - poll running jobs for results + - re-submission loop + BasisTron is the automatic basis set selection tool you've always needed but have never had the time to write yourself. From 6f623cd6b558ea05ff20d255b22f827a61ba368b Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Thu, 21 Oct 2021 19:47:07 -0400 Subject: [PATCH 17/23] wip: cccbdb api --- codeliciousness/basistron/cccbdb.py | 124 ++++++++++++++++++++++++++++ codeliciousness/basistron/parser.py | 48 +++++++++++ 2 files changed, 172 insertions(+) create mode 100644 codeliciousness/basistron/cccbdb.py create mode 100644 codeliciousness/basistron/parser.py diff --git a/codeliciousness/basistron/cccbdb.py b/codeliciousness/basistron/cccbdb.py new file mode 100644 index 00000000..49fb6b95 --- /dev/null +++ b/codeliciousness/basistron/cccbdb.py @@ -0,0 +1,124 @@ +# -*- coding: utf-8 -*- +import requests +from functools import partialmethod +from urllib.parse import urljoin + +from typing import Dict, Any, Optional + +from bs4 import BeautifulSoup +from bs4.element import Tag + +from basistron import utils +from basistron import parser + +log = utils.get_logger(__name__) + +def _borrowed_headers(referer): + return { + 'Host': 'cccbdb.nist.gov', + 'Connection': 'keep-alive', + 'Content-Length': '26', + 'Pragma': 'no-cache', + 'Cache-Control': 'no-cache', + 'Origin': 'http://cccbdb.nist.gov', + 'Upgrade-Insecure-Requests': '1', + 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', + 'Content-Type': 'application/x-www-form-urlencoded', + 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', + 'Referer': referer, + 'Accept-Encoding': 'gzip, deflate', + 'Accept-Language': 'en-CA,en-GB;q=0.8,en-US;q=0.6,en;q=0.4', + } + +class Cccbdb: + """Wrapper around interactivity with the CCCBDB and + filesystem caching of CCCBDB data.""" + + TIMEOUT = 30000 + EXT_FMT = "{}x.asp".format + BASE_URL = "http://cccbdb.nist.gov" + FORM_EXT = "getform" + DUMP_EXT = "carttabdump" + EXPT_EXT = "exp1" + + POL_CALC = "polcalc1" + + def get_calculated_data(self, formula: str, property: str = POL_CALC): + soup = self.post( + self.FORM_EXT, + referer=property, + data={ + "formula": formula, + "submit1": "Submit", + } + ) + print(soup) + tables = soup.find_all("table") + print(len(tables), [len(table) for table in tables]) + import pprint + # pprint.pprint(tables[0]) + # pprint.pprint(tables[1]) +# tables = soup.find_all("table") +# log.info(f"found {len(tables)} tables") +# parse = parser.TableParser() +# parse.feed(str(soup)) +# for table in parse.tables: +# log.info(f"table({len(table)},{len(table[0])})") +# print(table) + + + def get_experimental_data(self, formula: str, path: str = EXPT_EXT): + [form] = self.get(path).find_all("form") + reduced = self.reduce_form(form) + data = {inp["name"]: inp["value"] for inp in reduced["inputs"]} + resp = self.post(reduced["action"], data=data) + tables = resp.find_all("table") + log.info(f"found {len(tables)} tables") + parse = parser.TableParser() + parse.feed(str(resp)) + print(parse.tables) + + @staticmethod + def reduce_form(form: Tag) -> Dict[str, Any]: + return { + "action": form.attrs.get("action").lower(), + "method": form.attrs.get("method", "get").lower(), + "inputs": [ + { + "type": inp.attrs.get("type", "text"), + "name": inp.attrs.get("name"), + "value": inp.attrs.get("value"), + } + for inp in form.find_all("input") + ] + } + + def __init__(self): + self.session = requests.Session() + + def _make_request(self, method: str, path: str, referer: Optional[str] = None, **kwargs): + url = urljoin(self.BASE_URL, self.EXT_FMT(path)) + headers = kwargs.get("headers", {}) + if referer is not None: + headers.update(_borrowed_headers(url)) + kwargs["allow_redirects"] = False + kwargs["headers"] = headers + log.info(f"calling {method} {url}") + res = self.session.request(method, url, timeout=self.TIMEOUT, **kwargs) + res.raise_for_status() + log.info(f"status code {res.status_code}") + if referer is not None and res.status_code == 302: + url = urljoin(self.BASE_URL, self.EXT_FMT(referer.replace("1", "2"))) + log.info(f"redirect url get {url}") + res = self.session.request("get", url, timeout=self.TIMEOUT) + res.raise_for_status() + log.info(f"status code {res.status_code}") + return BeautifulSoup(res.content, "html.parser") + + get = partialmethod(_make_request, "get") + post = partialmethod(_make_request, "post") + + +if __name__ == "__main__": + c = Cccbdb() + c.get_calculated_data("CH4") \ No newline at end of file diff --git a/codeliciousness/basistron/parser.py b/codeliciousness/basistron/parser.py new file mode 100644 index 00000000..30153057 --- /dev/null +++ b/codeliciousness/basistron/parser.py @@ -0,0 +1,48 @@ +from html.parser import HTMLParser + +class TableParser(HTMLParser): + + def __init__(self): + super().__init__() + self.td = False + self.th = False + self.skip = False + self.live = False + self.current_table = [] + self.current_row = [] + self.current_cell = [] + self.tables = [] + + def handle_starttag(self, tag, attrs): + if tag == "td": + self.td = True + self.live = True + if tag == "th": + self.th = True + if len(attrs) and attrs[0][0] == "rowspan": + self.skip = True + if tag == "a" and self.td: + self.current_cell.append(attrs[0][1]) + + def handle_data(self, data): + if not self.skip and (self.td or self.th): + self.current_cell.append(data.strip()) + + def handle_endtag(self, tag): + if tag == "td": + self.td = False + if tag == "th": + self.th = False + if tag in ["td", "th"]: + if not self.skip: + self.current_row.append(self.current_cell[::-1]) + self.current_cell = [] + self.skip = False + if tag == "tr": + self.current_table.append(self.current_row) + self.current_row = [] + if tag == "table": + self.tables.append(self.current_table) + self.current_table = [] + + From 44c232ef5e0b67ed984a7aa28bffdf15b0c79e6d Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Fri, 22 Oct 2021 13:01:28 -0400 Subject: [PATCH 18/23] feat: pandas as a crutch --- codeliciousness/poetry.lock | 164 ++++++++++++++++++++++++++++++++- codeliciousness/pyproject.toml | 1 + 2 files changed, 164 insertions(+), 1 deletion(-) diff --git a/codeliciousness/poetry.lock b/codeliciousness/poetry.lock index 9d2393a7..dba9b5e2 100644 --- a/codeliciousness/poetry.lock +++ b/codeliciousness/poetry.lock @@ -156,6 +156,22 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "numpy" +version = "1.21.1" +description = "NumPy is the fundamental package for array computing with Python." +category = "main" +optional = false +python-versions = ">=3.7" + +[[package]] +name = "numpy" +version = "1.21.3" +description = "NumPy is the fundamental package for array computing with Python." +category = "main" +optional = false +python-versions = ">=3.7,<3.11" + [[package]] name = "packaging" version = "21.0" @@ -167,6 +183,27 @@ python-versions = ">=3.6" [package.dependencies] pyparsing = ">=2.0.2" +[[package]] +name = "pandas" +version = "1.3.4" +description = "Powerful data structures for data analysis, time series, and statistics" +category = "main" +optional = false +python-versions = ">=3.7.1" + +[package.dependencies] +numpy = [ + {version = ">=1.17.3", markers = "platform_machine != \"aarch64\" and platform_machine != \"arm64\" and python_version < \"3.10\""}, + {version = ">=1.19.2", markers = "platform_machine == \"aarch64\" and python_version < \"3.10\""}, + {version = ">=1.20.0", markers = "platform_machine == \"arm64\" and python_version < \"3.10\""}, + {version = ">=1.21.0", markers = "python_version >= \"3.10\""}, +] +python-dateutil = ">=2.7.3" +pytz = ">=2017.3" + +[package.extras] +test = ["hypothesis (>=3.58)", "pytest (>=6.0)", "pytest-xdist"] + [[package]] name = "pathspec" version = "0.9.0" @@ -266,6 +303,25 @@ pytest = ">=4.6" [package.extras] testing = ["fields", "hunter", "process-tests", "six", "pytest-xdist", "virtualenv"] +[[package]] +name = "python-dateutil" +version = "2.8.2" +description = "Extensions to the standard Python datetime module" +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" + +[package.dependencies] +six = ">=1.5" + +[[package]] +name = "pytz" +version = "2021.3" +description = "World timezone definitions, modern and historical" +category = "main" +optional = false +python-versions = "*" + [[package]] name = "regex" version = "2021.10.21" @@ -292,6 +348,14 @@ urllib3 = ">=1.21.1,<1.25" security = ["pyOpenSSL (>=0.14)", "cryptography (>=1.3.4)", "idna (>=2.0.0)"] socks = ["PySocks (>=1.5.6,!=1.5.7)", "win-inet-pton"] +[[package]] +name = "six" +version = "1.16.0" +description = "Python 2 and 3 compatibility utilities" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*" + [[package]] name = "soupsieve" version = "2.2.1" @@ -339,7 +403,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "2549292b9c4c6bac0dcab335eb7018d4db14a47bceb0f72e3443e85d43162483" +content-hash = "b52db717f2f3a75cd8bb273f482a01bf9fff0d3a3dc910fd6a4fa2ab2f33328a" [metadata.files] atomicwrites = [ @@ -422,10 +486,96 @@ mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] +numpy = [ + {file = "numpy-1.21.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a75b4498b1e93d8b700282dc8e655b8bd559c0904b3910b144646dbbbc03e062"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1412aa0aec3e00bc23fbb8664d76552b4efde98fb71f60737c83efbac24112f1"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e46ceaff65609b5399163de5893d8f2a82d3c77d5e56d976c8b5fb01faa6b671"}, + {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c6a2324085dd52f96498419ba95b5777e40b6bcbc20088fddb9e8cbb58885e8e"}, + {file = "numpy-1.21.1-cp37-cp37m-win32.whl", hash = "sha256:73101b2a1fef16602696d133db402a7e7586654682244344b8329cdcbbb82172"}, + {file = "numpy-1.21.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7a708a79c9a9d26904d1cca8d383bf869edf6f8e7650d85dbc77b041e8c5a0f8"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95b995d0c413f5d0428b3f880e8fe1660ff9396dcd1f9eedbc311f37b5652e16"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:635e6bd31c9fb3d475c8f44a089569070d10a9ef18ed13738b03049280281267"}, + {file = "numpy-1.21.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a3d5fb89bfe21be2ef47c0614b9c9c707b7362386c9a3ff1feae63e0267ccb6"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a326af80e86d0e9ce92bcc1e65c8ff88297de4fa14ee936cb2293d414c9ec63"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:791492091744b0fe390a6ce85cc1bf5149968ac7d5f0477288f78c89b385d9af"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0318c465786c1f63ac05d7c4dbcecd4d2d7e13f0959b01b534ea1e92202235c5"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a513bd9c1551894ee3d31369f9b07460ef223694098cf27d399513415855b68"}, + {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91c6f5fc58df1e0a3cc0c3a717bb3308ff850abdaa6d2d802573ee2b11f674a8"}, + {file = "numpy-1.21.1-cp38-cp38-win32.whl", hash = "sha256:978010b68e17150db8765355d1ccdd450f9fc916824e8c4e35ee620590e234cd"}, + {file = "numpy-1.21.1-cp38-cp38-win_amd64.whl", hash = "sha256:9749a40a5b22333467f02fe11edc98f022133ee1bfa8ab99bda5e5437b831214"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d7a4aeac3b94af92a9373d6e77b37691b86411f9745190d2c351f410ab3a791f"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9e7912a56108aba9b31df688a4c4f5cb0d9d3787386b87d504762b6754fbb1b"}, + {file = "numpy-1.21.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:25b40b98ebdd272bc3020935427a4530b7d60dfbe1ab9381a39147834e985eac"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a92c5aea763d14ba9d6475803fc7904bda7decc2a0a68153f587ad82941fec1"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05a0f648eb28bae4bcb204e6fd14603de2908de982e761a2fc78efe0f19e96e1"}, + {file = "numpy-1.21.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f01f28075a92eede918b965e86e8f0ba7b7797a95aa8d35e1cc8821f5fc3ad6a"}, + {file = "numpy-1.21.1-cp39-cp39-win32.whl", hash = "sha256:88c0b89ad1cc24a5efbb99ff9ab5db0f9a86e9cc50240177a571fbe9c2860ac2"}, + {file = "numpy-1.21.1-cp39-cp39-win_amd64.whl", hash = "sha256:01721eefe70544d548425a07c80be8377096a54118070b8a62476866d5208e33"}, + {file = "numpy-1.21.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d4d1de6e6fb3d28781c73fbde702ac97f03d79e4ffd6598b880b2d95d62ead4"}, + {file = "numpy-1.21.1.zip", hash = "sha256:dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd"}, + {file = "numpy-1.21.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:508b0b513fa1266875524ba8a9ecc27b02ad771fe1704a16314dc1a816a68737"}, + {file = "numpy-1.21.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5dfe9d6a4c39b8b6edd7990091fea4f852888e41919d0e6722fe78dd421db0eb"}, + {file = "numpy-1.21.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a10968963640e75cc0193e1847616ab4c718e83b6938ae74dea44953950f6b7"}, + {file = "numpy-1.21.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:49c6249260890e05b8111ebfc391ed58b3cb4b33e63197b2ec7f776e45330721"}, + {file = "numpy-1.21.3-cp310-cp310-win_amd64.whl", hash = "sha256:f8f4625536926a155b80ad2bbff44f8cc59e9f2ad14cdda7acf4c135b4dc8ff2"}, + {file = "numpy-1.21.3-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:e54af82d68ef8255535a6cdb353f55d6b8cf418a83e2be3569243787a4f4866f"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:f41b018f126aac18583956c54544db437f25c7ee4794bcb23eb38bef8e5e192a"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:50cd26b0cf6664cb3b3dd161ba0a09c9c1343db064e7c69f9f8b551f5104d654"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4cc9b512e9fb590797474f58b7f6d1f1b654b3a94f4fa8558b48ca8b3cfc97cf"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:88a5d6b268e9ad18f3533e184744acdaa2e913b13148160b1152300c949bbb5f"}, + {file = "numpy-1.21.3-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:3c09418a14471c7ae69ba682e2428cae5b4420a766659605566c0fa6987f6b7e"}, + {file = "numpy-1.21.3-cp37-cp37m-win32.whl", hash = "sha256:90bec6a86b348b4559b6482e2b684db4a9a7eed1fa054b86115a48d58fbbf62a"}, + {file = "numpy-1.21.3-cp37-cp37m-win_amd64.whl", hash = "sha256:043e83bfc274649c82a6f09836943e4a4aebe5e33656271c7dbf9621dd58b8ec"}, + {file = "numpy-1.21.3-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:75621882d2230ab77fb6a03d4cbccd2038511491076e7964ef87306623aa5272"}, + {file = "numpy-1.21.3-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:188031f833bbb623637e66006cf75e933e00e7231f67e2b45cf8189612bb5dc3"}, + {file = "numpy-1.21.3-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:160ccc1bed3a8371bf0d760971f09bfe80a3e18646620e9ded0ad159d9749baa"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:29fb3dcd0468b7715f8ce2c0c2d9bbbaf5ae686334951343a41bd8d155c6ea27"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:32437f0b275c1d09d9c3add782516413e98cd7c09e6baf4715cbce781fc29912"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e606e6316911471c8d9b4618e082635cfe98876007556e89ce03d52ff5e8fcf0"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a99a6b067e5190ac6d12005a4d85aa6227c5606fa93211f86b1dafb16233e57d"}, + {file = "numpy-1.21.3-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:dde972a1e11bb7b702ed0e447953e7617723760f420decb97305e66fb4afc54f"}, + {file = "numpy-1.21.3-cp38-cp38-win32.whl", hash = "sha256:fe52dbe47d9deb69b05084abd4b0df7abb39a3c51957c09f635520abd49b29dd"}, + {file = "numpy-1.21.3-cp38-cp38-win_amd64.whl", hash = "sha256:75eb7cadc8da49302f5b659d40ba4f6d94d5045fbd9569c9d058e77b0514c9e4"}, + {file = "numpy-1.21.3-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:2a6ee9620061b2a722749b391c0d80a0e2ae97290f1b32e28d5a362e21941ee4"}, + {file = "numpy-1.21.3-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:5c4193f70f8069550a1788bd0cd3268ab7d3a2b70583dfe3b2e7f421e9aace06"}, + {file = "numpy-1.21.3-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:28f15209fb535dd4c504a7762d3bc440779b0e37d50ed810ced209e5cea60d96"}, + {file = "numpy-1.21.3-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:c6c2d535a7beb1f8790aaa98fd089ceab2e3dd7ca48aca0af7dc60e6ef93ffe1"}, + {file = "numpy-1.21.3-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:bffa2eee3b87376cc6b31eee36d05349571c236d1de1175b804b348dc0941e3f"}, + {file = "numpy-1.21.3-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cc14e7519fab2a4ed87d31f99c31a3796e4e1fe63a86ebdd1c5a1ea78ebd5896"}, + {file = "numpy-1.21.3-cp39-cp39-win32.whl", hash = "sha256:dd0482f3fc547f1b1b5d6a8b8e08f63fdc250c58ce688dedd8851e6e26cff0f3"}, + {file = "numpy-1.21.3-cp39-cp39-win_amd64.whl", hash = "sha256:300321e3985c968e3ae7fbda187237b225f3ffe6528395a5b7a5407f73cf093e"}, + {file = "numpy-1.21.3-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:98339aa9911853f131de11010f6dd94c8cec254d3d1f7261528c3b3e3219f139"}, + {file = "numpy-1.21.3.zip", hash = "sha256:63571bb7897a584ca3249c86dd01c10bcb5fe4296e3568b2e9c1a55356b6410e"}, +] packaging = [ {file = "packaging-21.0-py3-none-any.whl", hash = "sha256:c86254f9220d55e31cc94d69bade760f0847da8000def4dfe1c6b872fd14ff14"}, {file = "packaging-21.0.tar.gz", hash = "sha256:7dc96269f53a4ccec5c0670940a4281106dd0bb343f47b7471f779df49c2fbe7"}, ] +pandas = [ + {file = "pandas-1.3.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:372d72a3d8a5f2dbaf566a5fa5fa7f230842ac80f29a931fb4b071502cf86b9a"}, + {file = "pandas-1.3.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d99d2350adb7b6c3f7f8f0e5dfb7d34ff8dd4bc0a53e62c445b7e43e163fce63"}, + {file = "pandas-1.3.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:c2646458e1dce44df9f71a01dc65f7e8fa4307f29e5c0f2f92c97f47a5bf22f5"}, + {file = "pandas-1.3.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5298a733e5bfbb761181fd4672c36d0c627320eb999c59c65156c6a90c7e1b4f"}, + {file = "pandas-1.3.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:22808afb8f96e2269dcc5b846decacb2f526dd0b47baebc63d913bf847317c8f"}, + {file = "pandas-1.3.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:b528e126c13816a4374e56b7b18bfe91f7a7f6576d1aadba5dee6a87a7f479ae"}, + {file = "pandas-1.3.4-cp37-cp37m-win32.whl", hash = "sha256:fe48e4925455c964db914b958f6e7032d285848b7538a5e1b19aeb26ffaea3ec"}, + {file = "pandas-1.3.4-cp37-cp37m-win_amd64.whl", hash = "sha256:eaca36a80acaacb8183930e2e5ad7f71539a66805d6204ea88736570b2876a7b"}, + {file = "pandas-1.3.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:42493f8ae67918bf129869abea8204df899902287a7f5eaf596c8e54e0ac7ff4"}, + {file = "pandas-1.3.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a388960f979665b447f0847626e40f99af8cf191bce9dc571d716433130cb3a7"}, + {file = "pandas-1.3.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5ba0aac1397e1d7b654fccf263a4798a9e84ef749866060d19e577e927d66e1b"}, + {file = "pandas-1.3.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:f567e972dce3bbc3a8076e0b675273b4a9e8576ac629149cf8286ee13c259ae5"}, + {file = "pandas-1.3.4-cp38-cp38-win32.whl", hash = "sha256:c1aa4de4919358c5ef119f6377bc5964b3a7023c23e845d9db7d9016fa0c5b1c"}, + {file = "pandas-1.3.4-cp38-cp38-win_amd64.whl", hash = "sha256:dd324f8ee05925ee85de0ea3f0d66e1362e8c80799eb4eb04927d32335a3e44a"}, + {file = "pandas-1.3.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d47750cf07dee6b55d8423471be70d627314277976ff2edd1381f02d52dbadf9"}, + {file = "pandas-1.3.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2d1dc09c0013d8faa7474574d61b575f9af6257ab95c93dcf33a14fd8d2c1bab"}, + {file = "pandas-1.3.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:10e10a2527db79af6e830c3d5842a4d60383b162885270f8cffc15abca4ba4a9"}, + {file = "pandas-1.3.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:35c77609acd2e4d517da41bae0c11c70d31c87aae8dd1aabd2670906c6d2c143"}, + {file = "pandas-1.3.4-cp39-cp39-win32.whl", hash = "sha256:003ba92db58b71a5f8add604a17a059f3068ef4e8c0c365b088468d0d64935fd"}, + {file = "pandas-1.3.4-cp39-cp39-win_amd64.whl", hash = "sha256:a51528192755f7429c5bcc9e80832c517340317c861318fea9cea081b57c9afd"}, + {file = "pandas-1.3.4.tar.gz", hash = "sha256:a2aa18d3f0b7d538e21932f637fbfe8518d085238b429e4790a35e1e44a96ffc"}, +] pathspec = [ {file = "pathspec-0.9.0-py2.py3-none-any.whl", hash = "sha256:7d15c4ddb0b5c802d161efc417ec1a2558ea2653c2e8ad9c19098201dc1c993a"}, {file = "pathspec-0.9.0.tar.gz", hash = "sha256:e564499435a2673d586f6b2130bb5b95f04a3ba06f81b8f895b651a3c76aabb1"}, @@ -478,6 +628,14 @@ pytest-cov = [ {file = "pytest-cov-3.0.0.tar.gz", hash = "sha256:e7f0f5b1617d2210a2cabc266dfe2f4c75a8d32fb89eafb7ad9d06f6d076d470"}, {file = "pytest_cov-3.0.0-py3-none-any.whl", hash = "sha256:578d5d15ac4a25e5f961c938b85a05b09fdaae9deef3bb6de9a6e766622ca7a6"}, ] +python-dateutil = [ + {file = "python-dateutil-2.8.2.tar.gz", hash = "sha256:0123cacc1627ae19ddf3c27a5de5bd67ee4586fbdd6440d9748f8abb483d3e86"}, + {file = "python_dateutil-2.8.2-py2.py3-none-any.whl", hash = "sha256:961d03dc3453ebbc59dbdea9e4e11c5651520a876d0f4db161e8674aae935da9"}, +] +pytz = [ + {file = "pytz-2021.3-py2.py3-none-any.whl", hash = "sha256:3672058bc3453457b622aab7a1c3bfd5ab0bdae451512f6cf25f64ed37f5b87c"}, + {file = "pytz-2021.3.tar.gz", hash = "sha256:acad2d8b20a1af07d4e4c9d2e9285c5ed9104354062f275f3fcd88dcef4f1326"}, +] regex = [ {file = "regex-2021.10.21-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:edff4e31d159672a7b9d70164b21289e4b53b239ce1dc945bf9643d266537573"}, {file = "regex-2021.10.21-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d6432daf42f2c487b357e1aa0bdc43193f050ff53a3188bfab20b88202b53027"}, @@ -520,6 +678,10 @@ requests = [ {file = "requests-2.20.1-py2.py3-none-any.whl", hash = "sha256:65b3a120e4329e33c9889db89c80976c5272f56ea92d3e74da8a463992e3ff54"}, {file = "requests-2.20.1.tar.gz", hash = "sha256:ea881206e59f41dbd0bd445437d792e43906703fff75ca8ff43ccdb11f33f263"}, ] +six = [ + {file = "six-1.16.0-py2.py3-none-any.whl", hash = "sha256:8abb2f1d86890a2dfb989f9a77cfcfd3e47c2a354b01111771326f8aa26e0254"}, + {file = "six-1.16.0.tar.gz", hash = "sha256:1e61c37477a1626458e36f7b1d82aa5c9b094fa4802892072e49de9c60c4c926"}, +] soupsieve = [ {file = "soupsieve-2.2.1-py3-none-any.whl", hash = "sha256:c2c1c2d44f158cdbddab7824a9af8c4f83c76b1e23e049479aa432feb6c4c23b"}, {file = "soupsieve-2.2.1.tar.gz", hash = "sha256:052774848f448cf19c7e959adf5566904d525f33a3f8b6ba6f6f8f26ec7de0cc"}, diff --git a/codeliciousness/pyproject.toml b/codeliciousness/pyproject.toml index b062e21a..819afaf2 100644 --- a/codeliciousness/pyproject.toml +++ b/codeliciousness/pyproject.toml @@ -10,6 +10,7 @@ pydantic = "1.8.2" requests = "2.20.1" exabyte-api-client = {git = "https://github.com/exabyte-io/api-client", rev = "2021.06.25"} beautifulsoup4 = "^4.10.0" +pandas = "^1.3.4" [tool.poetry.dev-dependencies] pytest = "^6.2.5" From 9306c3d68f66b2d991ab68a51e3d5e25f38e572b Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Fri, 22 Oct 2021 15:19:48 -0400 Subject: [PATCH 19/23] feat: cccbdb scraping almost complete --- codeliciousness/basistron/cccbdb.py | 213 +++++++++++++++++----------- codeliciousness/basistron/parser.py | 86 +++++------ 2 files changed, 177 insertions(+), 122 deletions(-) diff --git a/codeliciousness/basistron/cccbdb.py b/codeliciousness/basistron/cccbdb.py index 49fb6b95..291515f4 100644 --- a/codeliciousness/basistron/cccbdb.py +++ b/codeliciousness/basistron/cccbdb.py @@ -1,9 +1,17 @@ # -*- coding: utf-8 -*- +""" +A CCCBDB scraping client. Borrows much inspiration +from https://github.com/marcelo-mason/cccbdb-calculation-parser +but the repo is dormant and non-functional. +""" +import sys import requests +from requests import HTTPError from functools import partialmethod from urllib.parse import urljoin -from typing import Dict, Any, Optional +import pandas as pd +from typing import Dict, Any, Tuple from bs4 import BeautifulSoup from bs4.element import Tag @@ -13,112 +21,153 @@ log = utils.get_logger(__name__) -def _borrowed_headers(referer): - return { - 'Host': 'cccbdb.nist.gov', +def _inspected_headers(referer: str) -> Dict[str, str]: + headers = { + 'Accept': ( + 'text/html,application/xhtml+xml,application/xml;' + 'q=0.9,image/avif,image/webp,image/apng,*/*;' + 'q=0.8,application/signed-exchange;v=b3;q=0.9' + ), + 'Accept-Encoding': 'gzip, deflate, br', + 'Accept-Language': 'en-US,en;q=0.9', + 'Cache-Control': 'max-age=0', 'Connection': 'keep-alive', 'Content-Length': '26', - 'Pragma': 'no-cache', - 'Cache-Control': 'no-cache', - 'Origin': 'http://cccbdb.nist.gov', - 'Upgrade-Insecure-Requests': '1', - 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/58.0.3029.110 Safari/537.36', 'Content-Type': 'application/x-www-form-urlencoded', - 'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8', - 'Referer': referer, - 'Accept-Encoding': 'gzip, deflate', - 'Accept-Language': 'en-CA,en-GB;q=0.8,en-US;q=0.6,en;q=0.4', + 'Host': 'cccbdb.nist.gov', + 'Origin': 'https://cccbdb.nist.gov', + 'sec-ch-ua': ( + '"Chromium";v="94", "Google Chrome";' + 'v="94", ";Not A Brand";v="99"' + ), + 'sec-ch-ua-mobile': '?0', + 'sec-ch-ua-platform': 'Windows', + 'Sec-Fetch-Dest': 'document', + 'Sec-Fetch-Mode': 'navigate', + 'Sec-Fetch-Site': 'same-origin', + 'Sec-Fetch-User': '?1', + 'Upgrade-Insecure-Requests': '1', + 'User-Agent': ( + 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' + 'AppleWebKit/537.36 (KHTML, like Gecko) ' + 'Chrome/94.0.4606.81 Safari/537.36' + ) } + if referer is not None: + headers['Referer'] = referer + return headers class Cccbdb: """Wrapper around interactivity with the CCCBDB and filesystem caching of CCCBDB data.""" - TIMEOUT = 30000 - EXT_FMT = "{}x.asp".format - BASE_URL = "http://cccbdb.nist.gov" - FORM_EXT = "getform" - DUMP_EXT = "carttabdump" - EXPT_EXT = "exp1" - - POL_CALC = "polcalc1" - - def get_calculated_data(self, formula: str, property: str = POL_CALC): - soup = self.post( - self.FORM_EXT, - referer=property, - data={ - "formula": formula, - "submit1": "Submit", - } + TIMEOUT = 10 + BASE_URL = "https://cccbdb.nist.gov" + FORM_EXT = "getformx.asp" + DUMP_EXT = "carttabdumpx.asp" + + # experimental properties + EXPT_EXT = "exp1x.asp" + + # calculated properties + POL_CALC = "polcalc1x.asp" + GEOMETRY = "geom1x.asp" + ENERGY = "energy1x.asp" + VIBRATIONS = "vibs1x.asp" + MULLIKEN = "mulliken1x.asp" + + @staticmethod + def retry_loop(func, *args, **kwargs): + tries = 0 + while True: + try: + tries += 1 + if not tries or not tries % 5: + log.info(f"calling {func.__name__} try #{tries}") + res = func(*args, **kwargs) + break + except HTTPError: + continue + except KeyboardInterrupt: + sys.exit() + return res + + def get_data(self, formula: str, property: str = POL_CALC): + """Get all the data for a chemical formula and kind of property.""" + res, form = self.get_form(property) + form_data = self.reduce_form(form, formula) + headers = _inspected_headers(res.url) + res = self.submit_form(form_data, headers) + return self.soup(res) + + def get_form(self, property: str) -> Tuple[requests.Response, Dict[str, Any]]: + """Get the structure of the form directly from the website.""" + res = self.retry_loop(self.get, property) + soup = self.soup(res) + # assert only a single form on the page + [form] = soup.find_all("form") + return res, form + + def submit_form(self, form_data: Dict[str, Any], headers: Dict[str, Any]): + """Submit the form following redirect semantics of the CCCBDB website.""" + log.info('submitting form %s', form_data["data"]) + # post the form data without redirect + self.retry_loop( + getattr(self, form_data["method"]), + form_data["action"], + data=form_data["data"], + allow_redirects=False, + headers=headers, ) - print(soup) - tables = soup.find_all("table") - print(len(tables), [len(table) for table in tables]) - import pprint - # pprint.pprint(tables[0]) - # pprint.pprint(tables[1]) -# tables = soup.find_all("table") -# log.info(f"found {len(tables)} tables") -# parse = parser.TableParser() -# parse.feed(str(soup)) -# for table in parse.tables: -# log.info(f"table({len(table)},{len(table[0])})") -# print(table) - - - def get_experimental_data(self, formula: str, path: str = EXPT_EXT): - [form] = self.get(path).find_all("form") - reduced = self.reduce_form(form) - data = {inp["name"]: inp["value"] for inp in reduced["inputs"]} - resp = self.post(reduced["action"], data=data) - tables = resp.find_all("table") - log.info(f"found {len(tables)} tables") - parse = parser.TableParser() - parse.feed(str(resp)) - print(parse.tables) - + # get the data from the redirected URL + url = headers["Referer"].replace("1", "2") + return self.retry_loop(self.get, url) + @staticmethod - def reduce_form(form: Tag) -> Dict[str, Any]: - return { + def reduce_form(form: Tag, formula: str) -> Dict[str, Any]: + reduced = { "action": form.attrs.get("action").lower(), "method": form.attrs.get("method", "get").lower(), - "inputs": [ - { - "type": inp.attrs.get("type", "text"), - "name": inp.attrs.get("name"), - "value": inp.attrs.get("value"), - } + "data": { + inp.attrs.get("name"): inp.attrs.get("value") for inp in form.find_all("input") - ] + } } + reduced["data"]["formula"] = formula + return reduced + + @staticmethod + def soup(response: requests.Response) -> BeautifulSoup: + return BeautifulSoup(response.content, "html.parser") def __init__(self): self.session = requests.Session() - def _make_request(self, method: str, path: str, referer: Optional[str] = None, **kwargs): - url = urljoin(self.BASE_URL, self.EXT_FMT(path)) - headers = kwargs.get("headers", {}) - if referer is not None: - headers.update(_borrowed_headers(url)) - kwargs["allow_redirects"] = False - kwargs["headers"] = headers + def _make_request(self, method: str, path: str, **kwargs): + url = urljoin(self.BASE_URL, path) log.info(f"calling {method} {url}") - res = self.session.request(method, url, timeout=self.TIMEOUT, **kwargs) + res = self.session.request( + method, url, timeout=self.TIMEOUT, **kwargs + ) res.raise_for_status() log.info(f"status code {res.status_code}") - if referer is not None and res.status_code == 302: - url = urljoin(self.BASE_URL, self.EXT_FMT(referer.replace("1", "2"))) - log.info(f"redirect url get {url}") - res = self.session.request("get", url, timeout=self.TIMEOUT) - res.raise_for_status() - log.info(f"status code {res.status_code}") - return BeautifulSoup(res.content, "html.parser") + return res get = partialmethod(_make_request, "get") post = partialmethod(_make_request, "post") - + if __name__ == "__main__": c = Cccbdb() - c.get_calculated_data("CH4") \ No newline at end of file + soup = c.get_data("CH4", c.POL_CALC) + tables = soup.find_all("table")[1:] + + for table in tables: + parse = parser.TableParser() + parse.feed(str(table)) + header, *rows = parse.pad_table(parse.table) + if not rows: + df = pd.DataFrame(header) + else: + df = pd.DataFrame(rows, columns=header) + print(df.head()) diff --git a/codeliciousness/basistron/parser.py b/codeliciousness/basistron/parser.py index 30153057..2272201a 100644 --- a/codeliciousness/basistron/parser.py +++ b/codeliciousness/basistron/parser.py @@ -1,48 +1,54 @@ +# -*- coding: utf-8 -*- +""" +A CCCBDB-specific table parser. Borrowed heavily +from https://github.com/marcelo-mason/cccbdb-calculation-parser +""" from html.parser import HTMLParser +from typing import List, Optional + class TableParser(HTMLParser): + """Single table parser.""" - def __init__(self): - super().__init__() - self.td = False - self.th = False - self.skip = False - self.live = False - self.current_table = [] - self.current_row = [] - self.current_cell = [] - self.tables = [] + def __init__(self): + super().__init__() + self.td = False + self.th = False + self.tr = False + self.current_cell = [] + self.current_row = [] + self.table = [] - def handle_starttag(self, tag, attrs): - if tag == "td": - self.td = True - self.live = True - if tag == "th": - self.th = True - if len(attrs) and attrs[0][0] == "rowspan": - self.skip = True - if tag == "a" and self.td: - self.current_cell.append(attrs[0][1]) + def handle_starttag(self, tag: str, attrs: List[List[str]]) -> None: + for t in ["td", "th", "tr"]: + if tag == t: + setattr(self, tag, True) - def handle_data(self, data): - if not self.skip and (self.td or self.th): - self.current_cell.append(data.strip()) - - def handle_endtag(self, tag): - if tag == "td": - self.td = False - if tag == "th": - self.th = False - if tag in ["td", "th"]: - if not self.skip: - self.current_row.append(self.current_cell[::-1]) - self.current_cell = [] - self.skip = False - if tag == "tr": - self.current_table.append(self.current_row) - self.current_row = [] - if tag == "table": - self.tables.append(self.current_table) - self.current_table = [] + def handle_data(self, data: str) -> None: + if self.td or self.th: + self.current_cell.append(data.strip()) + def handle_endtag(self, tag: str) -> None: + for t in ["td", "th", "tr"]: + if tag == t: + setattr(self, tag, False) + if tag in ["td", "th"]: + self.current_row.append(self.current_cell[::-1]) + self.current_cell = [] + if tag == "tr": + self.table.append(self.current_row) + self.current_row = [] + def pad_table(self, table: List[List[Optional[str]]]) -> List[List[str]]: + padlen = max((len(row) for row in table)) + for i, row in enumerate(table): + while len(row) < padlen: + row.insert(0, "") + flat = [] + for cell in row: + if isinstance(cell, str): + flat.append(cell) + continue + flat.append("") if not cell else flat.extend(cell) + table[i] = flat + return table \ No newline at end of file From 1617b53571aedfa053149e44b5a633bd82af2ccf Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Sat, 23 Oct 2021 01:21:12 -0400 Subject: [PATCH 20/23] feat: almost finished app --- codeliciousness/basistron/README.md | 16 ++- codeliciousness/basistron/app.py | 98 ++++++++++++++++--- codeliciousness/basistron/cccbdb.py | 58 ++++++----- codeliciousness/basistron/cli.py | 45 ++++++--- .../basistron/{client.py => exabyte.py} | 0 codeliciousness/basistron/model.py | 73 ++++++++++---- codeliciousness/basistron/parser.py | 68 ++++++++++++- codeliciousness/test.sh | 27 +++++ codeliciousness/test/test_cli.py | 23 +++-- .../test/{test_client.py => test_exabyte.py} | 4 +- 10 files changed, 308 insertions(+), 104 deletions(-) rename codeliciousness/basistron/{client.py => exabyte.py} (100%) rename codeliciousness/test/{test_client.py => test_exabyte.py} (87%) diff --git a/codeliciousness/basistron/README.md b/codeliciousness/basistron/README.md index b164ce10..21d200d1 100644 --- a/codeliciousness/basistron/README.md +++ b/codeliciousness/basistron/README.md @@ -7,17 +7,13 @@ TODO * Basis - how to update workflow model with basis set info -* Cccbdb - - client - - provide reference data given simple chemical formula - -* Driver - - provide simple chemical formula to app - * App - - sanity check reference data to input - - poll running jobs for results - - re-submission loop + - default reference level of theory, basis set + - compute allowed basis sets from reference data + - return job id of submitted job + - extras + - match ranked basis sets to allowed basis sets + - pick most compact allowed set from ranked set BasisTron is the automatic basis set selection tool you've always needed but have never had the time to write yourself. diff --git a/codeliciousness/basistron/app.py b/codeliciousness/basistron/app.py index f2da88c4..518fa43e 100644 --- a/codeliciousness/basistron/app.py +++ b/codeliciousness/basistron/app.py @@ -1,36 +1,104 @@ # -*- coding: utf-8 -*- -import os import sys +import pandas as pd +from typing import List + from basistron import cli +from basistron import basis from basistron import utils -from basistron import client +from basistron import exabyte +from basistron import cccbdb log = utils.get_logger("basistron.app") +def filter_dfs_by_name( + dfs: List[pd.DataFrame], + regime: str, + match: str = "standard", +): + """Localize heuristic table selection here.""" + log.info(f"choosing dataframe from {[df.name for df in dfs]}") + this = None + if len(dfs) == 1: + this = dfs[0] + elif regime == "calculated": + # calculated results usually show up with + # three tables of result groups + # ["empirical", "standard", "effective"] + for df in dfs: + if match in df.name: + if this is not None: + raise Exception("duplicate match logic") + this = df + break + if this is None: + raise Exception("could not find reference data") + return this + + def main(args): + """Run the BasisTron 5000!""" - parser = cli.get_parser() - driver = cli.process_args(parser.parse_args(args)) - log.info(f"starting basis set selector for {driver.target_property}") + # init + driver = cli.process_args(cli.get_parser().parse_args(args)) + formula = driver.simple_formula() + log.info(f"starting basis set selector on {formula} for {driver.property}") - c = client.Client() - config = c.get_material_config("", driver.xyz_data_to_dict()) - material = c.get_endpoint("material").create(config) - workflow = c.get_workflow() - job_cfg = c.get_job_config( + # refdata + db = cccbdb.Cccbdb() + dfs = db.get_dataframes(formula, driver.property.value) + if not dfs: + log.error("found no tables from CCCBDB") + sys.exit() + try: + df = filter_dfs_by_name(dfs, driver.regime.value) + except Exception as e: + log.error("failed to select table from reference data") + sys.exit() + + # select reference datum + if driver.value is None: + print(df) + allowed_basis_sets = [] + else: + # sanity check provided reference data + lower, upper = driver.acceptable_range() + acceptable = df[(df >= lower) & (df <= upper)] + if not acceptable.sum().sum(): + msg = f"{driver.value}±{driver.tolerance:.2f}%" + log.error(f"no reference data found within {msg}") + log.warning("subsequent analysis may fail") + allowed_basis_sets = [] + + # basis set analysis + # Of allowed_basis_sets, pick the most compact + bases = basis.Basis.load_basis_sets() + ranked = basis.Basis.rank_basis_sets(bases) + total_allowed = basis.Basis.get_allowed_basis_sets( + ranked, list(set([r[0] for r in driver.xyz_data])) + ) + log.info(f"found {len(allowed_basis_sets)} allowed basis sets") + log.info(f"ranking allowed out of {len(total_allowed)} basis sets") + + # update workflow with basis set, level of theory? + + # ship it + ebc = exabyte.Client() + config = ebc.get_material_config("", driver.xyz_data_to_dict()) + material = ebc.get_endpoint("material").create(config) + workflow = ebc.get_workflow() + job_cfg = ebc.get_job_config( workflow["owner"]["_id"], material["_id"], workflow["_id"], "basistron.app", ) - job = c.submit_job(job_cfg) - + print(job_cfg) + # job = c.submit_job(job_cfg) if __name__ == "__main__": - main(sys.argv[1:]) - - + main(sys.argv[1:]) \ No newline at end of file diff --git a/codeliciousness/basistron/cccbdb.py b/codeliciousness/basistron/cccbdb.py index 291515f4..511152c5 100644 --- a/codeliciousness/basistron/cccbdb.py +++ b/codeliciousness/basistron/cccbdb.py @@ -6,13 +6,12 @@ """ import sys import requests -from requests import HTTPError +from requests import HTTPError, ReadTimeout from functools import partialmethod from urllib.parse import urljoin import pandas as pd -from typing import Dict, Any, Tuple - +from typing import Dict, Any, Tuple, List from bs4 import BeautifulSoup from bs4.element import Tag @@ -67,14 +66,19 @@ class Cccbdb: DUMP_EXT = "carttabdumpx.asp" # experimental properties - EXPT_EXT = "exp1x.asp" + EXPT_POL = "pollistx.asp" + EXPT_VIB = "expvibs1x.asp" + EXPT_IE = "xp1x.asp?prop=8" + # general purpose + # EXPT_EXT = "exp1x.asp" # calculated properties POL_CALC = "polcalc1x.asp" - GEOMETRY = "geom1x.asp" - ENERGY = "energy1x.asp" - VIBRATIONS = "vibs1x.asp" - MULLIKEN = "mulliken1x.asp" + VIB_FREQ = "vibs1x.asp" + HOMO_LUMO = "gap1x.asp" + # extend this for more properties + # ENERGY = "energy1x.asp" + # MULLIKEN = "mulliken1x.asp" @staticmethod def retry_loop(func, *args, **kwargs): @@ -86,7 +90,7 @@ def retry_loop(func, *args, **kwargs): log.info(f"calling {func.__name__} try #{tries}") res = func(*args, **kwargs) break - except HTTPError: + except (HTTPError, ReadTimeout): continue except KeyboardInterrupt: sys.exit() @@ -120,7 +124,7 @@ def submit_form(self, form_data: Dict[str, Any], headers: Dict[str, Any]): headers=headers, ) # get the data from the redirected URL - url = headers["Referer"].replace("1", "2") + url = headers["Referer"].split("?")[0].replace("1", "2") return self.retry_loop(self.get, url) @staticmethod @@ -140,6 +144,22 @@ def reduce_form(form: Tag, formula: str) -> Dict[str, Any]: def soup(response: requests.Response) -> BeautifulSoup: return BeautifulSoup(response.content, "html.parser") + def get_dataframes(self, formula: str, property: str) -> List[pd.DataFrame]: + soup = self.get_data(formula, property) + tables = soup.find_all("table") + log.info(f"found {len(tables)} tables on page") + dfs = [] + for html in tables: + parsed = parser.TableParser() + parsed.feed(str(html)) + df = parsed.to_df() + if df is not None: + log.info(f"adding dataframe '{df.name}' of shape {df.shape}") + dfs.append(df) + else: + log.info("skipping table") + return dfs + def __init__(self): self.session = requests.Session() @@ -154,20 +174,4 @@ def _make_request(self, method: str, path: str, **kwargs): return res get = partialmethod(_make_request, "get") - post = partialmethod(_make_request, "post") - - -if __name__ == "__main__": - c = Cccbdb() - soup = c.get_data("CH4", c.POL_CALC) - tables = soup.find_all("table")[1:] - - for table in tables: - parse = parser.TableParser() - parse.feed(str(table)) - header, *rows = parse.pad_table(parse.table) - if not rows: - df = pd.DataFrame(header) - else: - df = pd.DataFrame(rows, columns=header) - print(df.head()) + post = partialmethod(_make_request, "post") \ No newline at end of file diff --git a/codeliciousness/basistron/cli.py b/codeliciousness/basistron/cli.py index 174ab9ea..6bb168e7 100644 --- a/codeliciousness/basistron/cli.py +++ b/codeliciousness/basistron/cli.py @@ -3,7 +3,7 @@ from argparse import ArgumentParser, Namespace -from .model import Execution, Property +from basistron import model def get_parser() -> ArgumentParser: @@ -17,38 +17,51 @@ def get_parser() -> ArgumentParser: help="path to an XYZ file available on the filesystem", ) parser.add_argument( - "--target_property", + "--property", type=str, + choices=set( + model.CalculatedReferenceProperty.__members__.keys(), + ).union( + model.ExperimentalReferenceProperty.__members__.keys(), + ), required=True, help="property against which basis set selection is evaluated", ) parser.add_argument( - "--reference_value", + "--value", type=float, - required=True, - help="reference property value (assumes atomic units)", + help="reference property value (optional)", + ) + parser.add_argument( + "--tolerance", + type=float, + help="allowed tolerance as % deviation from input property value", + ) + parser.add_argument( + "--regime", + type=str, + choices=list(model.ReferenceRegime.__members__.keys()), + default=model.ReferenceRegime.experimental.value, + help="use experimental or calculated data as benchmark" ) return parser -def process_args(args: Namespace) -> Execution: +def process_args(args: Namespace) -> model.Execution: + """Perform initialization validation.""" + property = model.validate_property(args.regime, args.property) if not os.path.isfile(args.xyz_path): raise FileNotFoundError(args.xyz_path) - # load xyz data with open(args.xyz_path, "r") as f: xyz_data = [ ln.strip().split() for ln in f.readlines()[2:] ] - # validate target property - if not Property.is_valid_property(args.target_property): - raise Exception("unrecognized property") - # optional tolerance (default defined in Driver) - tol = getattr(args, "reference_tolerance", None) - return Execution( + return model.Execution( xyz_data=xyz_data, - target_property=args.target_property, - reference_value=args.reference_value, - reference_tolerance=tol, + property=property, + regime=args.regime, + value=getattr(args, "value", None), + tolerance=getattr(args, "tolerance", None), ) diff --git a/codeliciousness/basistron/client.py b/codeliciousness/basistron/exabyte.py similarity index 100% rename from codeliciousness/basistron/client.py rename to codeliciousness/basistron/exabyte.py diff --git a/codeliciousness/basistron/model.py b/codeliciousness/basistron/model.py index 2b8c3d75..5c4927fe 100644 --- a/codeliciousness/basistron/model.py +++ b/codeliciousness/basistron/model.py @@ -1,40 +1,69 @@ # -*- coding: utf-8 -*- from enum import Enum +from collections import Counter from typing import List, Tuple, Optional, Union, Dict, Any - from pydantic import BaseModel +from basistron.cccbdb import Cccbdb + + +class ReferenceRegime(Enum): + experimental = "experimental" + calculated = "calculated" -class Property(Enum): - """Provide different scopes for properties.""" +class ExperimentalReferenceProperty(Enum): + """Map command-line arguments to CCCBDB URIs.""" + polarizability = Cccbdb.EXPT_POL + vibrational_frequency = Cccbdb.EXPT_VIB + homo_lumo_gap = Cccbdb.EXPT_IE - @classmethod - def is_valid_property(cls: Enum, prop: str) -> bool: - """Validate that provided target property is recognized.""" - for sub in cls.__subclasses__(): - if prop in sub.__members__: - return True - return False -class SinglePointProperty(Property): - """Properties only requiring a total energy convergence.""" - energy_convergence = 0 - homo_lumo_gap = 1 +class CalculatedReferenceProperty(Enum): + """Map command-line arguments to CCCBDB URIs.""" + polarizability = Cccbdb.POL_CALC # units angstrom^3 + vibrational_frequency = Cccbdb.VIB_FREQ # units cm-1 + homo_lumo_gap = Cccbdb.HOMO_LUMO # units eV -class RelaxationProperty(Property): - """Properties requiring a full relaxation.""" - vibrational_frequencies = 0 +def validate_property(regime: str, property: str): + typ = ExperimentalReferenceProperty if ( + regime == ReferenceRegime.experimental.value + ) else CalculatedReferenceProperty + try: + return getattr(typ, property) + except AttributeError: + raise Exception( + f"property {property} not supported in regime {regime}" + ) class Execution(BaseModel): """The state of a given execution.""" xyz_data: Tuple[Tuple[str, float, float, float], ...] - target_property: str - reference_value: Optional[Union[str, float]] = None - reference_tolerance: Optional[float] = 0.01 + property: Union[ + ExperimentalReferenceProperty, CalculatedReferenceProperty, + ] + regime: ReferenceRegime + value: Optional[float] = None + tolerance: Optional[float] = 1.0 + + def acceptable_format(self) -> str: + if self.value is None: + return None + return "{self.value}±{self.tolerance:.2f}%" + + def acceptable_range(self) -> Tuple[float, float]: + if self.value is None: + return None + lower = (1 - self.tolerance) * self.value + upper = (1 + self.tolerance) * self.value + return lower, upper + + def simple_formula(self) -> str: + symbol_count = Counter([r[0] for r in self.xyz_data]) + return ''.join([f"{k}{v}" for k, v in symbol_count.items()]) def xyz_data_to_dict(self) -> Dict[str, List[Dict[str, Any]]]: ang2au = 1.889723 @@ -43,7 +72,9 @@ def xyz_data_to_dict(self) -> Dict[str, List[Dict[str, Any]]]: for i, (sym, *val) in enumerate(self.xyz_data): i += 1 elements.append({"id": i, "value": sym}) - coordinates.append({"id": i, "value": val * ang2au}) + coordinates.append( + {"id": i, "value": [v * ang2au for v in val]} + ) return { "elements": elements, "coordinates": coordinates, diff --git a/codeliciousness/basistron/parser.py b/codeliciousness/basistron/parser.py index 2272201a..d1885463 100644 --- a/codeliciousness/basistron/parser.py +++ b/codeliciousness/basistron/parser.py @@ -4,8 +4,15 @@ from https://github.com/marcelo-mason/cccbdb-calculation-parser """ from html.parser import HTMLParser +from collections import defaultdict from typing import List, Optional +import pandas as pd +import numpy as np + +from basistron import utils + +log = utils.get_logger(__name__) class TableParser(HTMLParser): """Single table parser.""" @@ -15,21 +22,25 @@ def __init__(self): self.td = False self.th = False self.tr = False + self.caption = False + self.title = "" self.current_cell = [] self.current_row = [] self.table = [] def handle_starttag(self, tag: str, attrs: List[List[str]]) -> None: - for t in ["td", "th", "tr"]: + for t in ["td", "th", "tr", "caption"]: if tag == t: setattr(self, tag, True) def handle_data(self, data: str) -> None: if self.td or self.th: self.current_cell.append(data.strip()) + if self.caption: + self.title += data.strip() def handle_endtag(self, tag: str) -> None: - for t in ["td", "th", "tr"]: + for t in ["td", "th", "tr", "caption"]: if tag == t: setattr(self, tag, False) if tag in ["td", "th"]: @@ -51,4 +62,55 @@ def pad_table(self, table: List[List[Optional[str]]]) -> List[List[str]]: continue flat.append("") if not cell else flat.extend(cell) table[i] = flat - return table \ No newline at end of file + return table + + def to_df(self): + """This is where it gets messy.""" + padded = self.pad_table(self.table) + try: + df = pd.DataFrame(padded[1:], columns=padded[0]) + except (ValueError, TypeError): + return None + + def clean_values(df: pd.DataFrame) -> pd.DataFrame: + return df.replace(r'^\s*$', np.nan, regex=True) + + def clean_columns(df: pd.DataFrame) -> pd.DataFrame: + index = None + if df.columns[:2].tolist() == ["", ""]: + index = ["theory", "implementation"] + df.columns = index + df.columns[2:].tolist() + unique_columns = [] + seen = defaultdict(int) + for column in df.columns: + seen[column] += 1 + if seen[column] > 1: + unique_columns.append(f"{column}{seen[column]}") + else: + unique_columns.append(column) + df.columns = unique_columns + return df, index + + def clean_index(df, index): + if index is not None: + df.set_index(index, inplace=True) + try: + df.drop(("", ""), inplace=True) + except Exception as e: + log.error(f"cleaning index failed: {repr(e)}") + return df.droplevel(0) if index else df + + df = clean_values(df) + df, index = clean_columns(df) + df = clean_index(df, index) + if df.index.duplicated().sum(): + log.warning("found duplicated index entries") + + warn_threshold = len(df.index) // 2 + for column in df.columns: + df[column] = pd.to_numeric(df[column], errors="coerce") + nulls = df[column].isnull().sum() + if nulls > warn_threshold: + log.warning(f"column {column} has {nulls} nulls") + df.name = self.title + return df diff --git a/codeliciousness/test.sh b/codeliciousness/test.sh index 2972cb3c..08c304e9 100755 --- a/codeliciousness/test.sh +++ b/codeliciousness/test.sh @@ -1,3 +1,30 @@ #!/bin/bash pytest test/ --cov=basistron + +regimes="experimental calculated" + +for regime in $regimes; do + echo "${regime}" + python -m basistron.app \ + --xyz_path "h2.xyz" \ + --regime "${regime}" \ + --property vibrational_frequency \ + --tolerance 0.5 + python -m basistron.app \ + --xyz_path "h2.xyz" \ + --regime "${regime}" \ + --property homo_lumo_gap \ + --tolerance 0.5 + python -m basistron.app \ + --xyz_path "ch4.xyz" \ + --regime "${regime}" \ + --property homo_lumo_gap \ + --tolerance 0.5 +# python -m basistron.app \ +# --xyz_path "ch4.xyz" \ +# --regime "${regime}" \ +# --property vibrational_frequency \ +# --value 4407 \ +# --tolerance 0.5 +done diff --git a/codeliciousness/test/test_cli.py b/codeliciousness/test/test_cli.py index 7f265163..4853839e 100644 --- a/codeliciousness/test/test_cli.py +++ b/codeliciousness/test/test_cli.py @@ -6,9 +6,9 @@ from basistron.model import Execution command = [ - "--target_property", - "energy_convergence", - "--reference_value", + "--property", + "vibrational_frequency", + "--value", "-100", "--xyz_path", "/path/to/file", @@ -35,18 +35,21 @@ def mock_file(tmppath, h2): [ "--xyz_path", "/path/to/file", - "--target_property", - "energy_convergence", + "--property", + "vibrational_frequency", ], - None, - True, + { + "xyz_path": "/path/to/file", + "property": "vibrational_frequency", + }, + False, ), ( command, { "xyz_path": "/path/to/file", - "target_property": "energy_convergence", - "reference_value": -100.0, + "property": "vibrational_frequency", + "value": -100.0, }, False, ), @@ -76,7 +79,7 @@ def test_process_args_fail(tmppath, h2, h2dat): path = mock_file(tmppath, h2) parser = cli.get_parser() cmd = command.copy() - cmd[1] = "not_recognized" args = parser.parse_args(cmd[:-1] + [path]) + args.property = "not_recognized" with pytest.raises(Exception): cli.process_args(args) diff --git a/codeliciousness/test/test_client.py b/codeliciousness/test/test_exabyte.py similarity index 87% rename from codeliciousness/test/test_client.py rename to codeliciousness/test/test_exabyte.py index 022ad33f..546e79e2 100644 --- a/codeliciousness/test/test_client.py +++ b/codeliciousness/test/test_exabyte.py @@ -1,5 +1,5 @@ -from basistron import client, utils +from basistron import utils, exabyte def test_client(monkeypatch): @@ -10,6 +10,6 @@ def login(self): monkeypatch.setattr( "exabyte_api_client.endpoints.login.LoginEndpoint.login", login ) - c = client.Client() + c = exabyte.Client() assert utils.env.exabyte_client_id == "test" assert utils.env.exabyte_client_secret == "test" From fe501347e84b9cf085ea3af94bc7fb334b3afe9d Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Sat, 23 Oct 2021 05:56:53 -0400 Subject: [PATCH 21/23] style: add isort --- codeliciousness/basistron/app.py | 8 +--- codeliciousness/basistron/basis.py | 8 ++-- codeliciousness/basistron/cccbdb.py | 9 ++--- codeliciousness/basistron/cli.py | 1 - codeliciousness/basistron/exabyte.py | 4 +- codeliciousness/basistron/model.py | 4 +- codeliciousness/basistron/parser.py | 25 +++++++++---- codeliciousness/basistron/utils.py | 2 +- codeliciousness/poetry.lock | 56 ++++++++++------------------ codeliciousness/pyproject.toml | 1 + 10 files changed, 52 insertions(+), 66 deletions(-) diff --git a/codeliciousness/basistron/app.py b/codeliciousness/basistron/app.py index 518fa43e..62436e4c 100644 --- a/codeliciousness/basistron/app.py +++ b/codeliciousness/basistron/app.py @@ -1,15 +1,11 @@ # -*- coding: utf-8 -*- import sys +from typing import List import pandas as pd -from typing import List -from basistron import cli -from basistron import basis -from basistron import utils -from basistron import exabyte -from basistron import cccbdb +from basistron import basis, cccbdb, cli, exabyte, utils log = utils.get_logger("basistron.app") diff --git a/codeliciousness/basistron/basis.py b/codeliciousness/basistron/basis.py index 6c14a2e2..a0974b00 100644 --- a/codeliciousness/basistron/basis.py +++ b/codeliciousness/basistron/basis.py @@ -1,11 +1,11 @@ # -*- coding: utf-8 -*- -import os import bz2 import glob -import requests - +import os from collections import defaultdict -from typing import Optional, List, Tuple, Dict, Any +from typing import Any, Dict, List, Optional, Tuple + +import requests from basistron import utils diff --git a/codeliciousness/basistron/cccbdb.py b/codeliciousness/basistron/cccbdb.py index 511152c5..40fb7758 100644 --- a/codeliciousness/basistron/cccbdb.py +++ b/codeliciousness/basistron/cccbdb.py @@ -5,18 +5,17 @@ but the repo is dormant and non-functional. """ import sys -import requests -from requests import HTTPError, ReadTimeout from functools import partialmethod +from typing import Any, Dict, List, Tuple from urllib.parse import urljoin import pandas as pd -from typing import Dict, Any, Tuple, List +import requests from bs4 import BeautifulSoup from bs4.element import Tag +from requests import HTTPError, ReadTimeout -from basistron import utils -from basistron import parser +from basistron import parser, utils log = utils.get_logger(__name__) diff --git a/codeliciousness/basistron/cli.py b/codeliciousness/basistron/cli.py index 6bb168e7..22b44892 100644 --- a/codeliciousness/basistron/cli.py +++ b/codeliciousness/basistron/cli.py @@ -1,6 +1,5 @@ # -*- coding: utf-8 -*- import os - from argparse import ArgumentParser, Namespace from basistron import model diff --git a/codeliciousness/basistron/exabyte.py b/codeliciousness/basistron/exabyte.py index 306ad96f..318a5f71 100644 --- a/codeliciousness/basistron/exabyte.py +++ b/codeliciousness/basistron/exabyte.py @@ -1,10 +1,10 @@ # -*- coding: utf-8 -*- import os from types import ModuleType -from typing import Dict, Any, Union, List +from typing import Any, Dict, List, Union -from requests import HTTPError from exabyte_api_client import endpoints +from requests import HTTPError from basistron import utils diff --git a/codeliciousness/basistron/model.py b/codeliciousness/basistron/model.py index 5c4927fe..1441e813 100644 --- a/codeliciousness/basistron/model.py +++ b/codeliciousness/basistron/model.py @@ -1,9 +1,9 @@ # -*- coding: utf-8 -*- -from enum import Enum from collections import Counter +from enum import Enum +from typing import Any, Dict, List, Optional, Tuple, Union -from typing import List, Tuple, Optional, Union, Dict, Any from pydantic import BaseModel from basistron.cccbdb import Cccbdb diff --git a/codeliciousness/basistron/parser.py b/codeliciousness/basistron/parser.py index d1885463..c176386e 100644 --- a/codeliciousness/basistron/parser.py +++ b/codeliciousness/basistron/parser.py @@ -3,12 +3,12 @@ A CCCBDB-specific table parser. Borrowed heavily from https://github.com/marcelo-mason/cccbdb-calculation-parser """ -from html.parser import HTMLParser from collections import defaultdict - +from html.parser import HTMLParser from typing import List, Optional -import pandas as pd + import numpy as np +import pandas as pd from basistron import utils @@ -50,7 +50,8 @@ def handle_endtag(self, tag: str) -> None: self.table.append(self.current_row) self.current_row = [] - def pad_table(self, table: List[List[Optional[str]]]) -> List[List[str]]: + @staticmethod + def pad_table(table: List[List[Optional[str]]]) -> List[List[str]]: padlen = max((len(row) for row in table)) for i, row in enumerate(table): while len(row) < padlen: @@ -64,15 +65,20 @@ def pad_table(self, table: List[List[Optional[str]]]) -> List[List[str]]: table[i] = flat return table - def to_df(self): + def to_df(self) -> Optional[pd.DataFrame]: """This is where it gets messy.""" + padded = self.pad_table(self.table) try: df = pd.DataFrame(padded[1:], columns=padded[0]) except (ValueError, TypeError): + log.debug("failed creating dataframe") + for i, row in enumerate(padded[:2]): + log.debug(f"row[{i}]: {row}") return None def clean_values(df: pd.DataFrame) -> pd.DataFrame: + # TODO : pull out redirect links for nested data return df.replace(r'^\s*$', np.nan, regex=True) def clean_columns(df: pd.DataFrame) -> pd.DataFrame: @@ -89,6 +95,8 @@ def clean_columns(df: pd.DataFrame) -> pd.DataFrame: else: unique_columns.append(column) df.columns = unique_columns + if df.columns.duplicated().any(): + log.warning("found duplicated column entries") return df, index def clean_index(df, index): @@ -98,13 +106,14 @@ def clean_index(df, index): df.drop(("", ""), inplace=True) except Exception as e: log.error(f"cleaning index failed: {repr(e)}") - return df.droplevel(0) if index else df + df = df.droplevel(0) if index else df + if df.index.duplicated().any(): + log.warning("found duplicated index entries") + return df df = clean_values(df) df, index = clean_columns(df) df = clean_index(df, index) - if df.index.duplicated().sum(): - log.warning("found duplicated index entries") warn_threshold = len(df.index) // 2 for column in df.columns: diff --git a/codeliciousness/basistron/utils.py b/codeliciousness/basistron/utils.py index 320d0a08..b85cba63 100644 --- a/codeliciousness/basistron/utils.py +++ b/codeliciousness/basistron/utils.py @@ -1,6 +1,6 @@ # -*- coding: utf-8 -*- -import os import logging +import os logging.basicConfig() diff --git a/codeliciousness/poetry.lock b/codeliciousness/poetry.lock index dba9b5e2..8b693b64 100644 --- a/codeliciousness/poetry.lock +++ b/codeliciousness/poetry.lock @@ -148,6 +148,20 @@ category = "dev" optional = false python-versions = "*" +[[package]] +name = "isort" +version = "5.9.3" +description = "A Python utility / library to sort Python imports." +category = "dev" +optional = false +python-versions = ">=3.6.1,<4.0" + +[package.extras] +pipfile_deprecated_finder = ["pipreqs", "requirementslib"] +requirements_deprecated_finder = ["pipreqs", "pip-api"] +colors = ["colorama (>=0.4.3,<0.5.0)"] +plugins = ["setuptools"] + [[package]] name = "mypy-extensions" version = "0.4.3" @@ -156,14 +170,6 @@ category = "dev" optional = false python-versions = "*" -[[package]] -name = "numpy" -version = "1.21.1" -description = "NumPy is the fundamental package for array computing with Python." -category = "main" -optional = false -python-versions = ">=3.7" - [[package]] name = "numpy" version = "1.21.3" @@ -403,7 +409,7 @@ socks = ["PySocks (>=1.5.6,!=1.5.7,<2.0)"] [metadata] lock-version = "1.1" python-versions = "^3.9" -content-hash = "b52db717f2f3a75cd8bb273f482a01bf9fff0d3a3dc910fd6a4fa2ab2f33328a" +content-hash = "8608596ada6e540ddd5f3546677517a5661694e5b765512069b1eeb62a538396" [metadata.files] atomicwrites = [ @@ -482,39 +488,15 @@ iniconfig = [ {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, ] +isort = [ + {file = "isort-5.9.3-py3-none-any.whl", hash = "sha256:e17d6e2b81095c9db0a03a8025a957f334d6ea30b26f9ec70805411e5c7c81f2"}, + {file = "isort-5.9.3.tar.gz", hash = "sha256:9c2ea1e62d871267b78307fe511c0838ba0da28698c5732d54e2790bf3ba9899"}, +] mypy-extensions = [ {file = "mypy_extensions-0.4.3-py2.py3-none-any.whl", hash = "sha256:090fedd75945a69ae91ce1303b5824f428daf5a028d2f6ab8a299250a846f15d"}, {file = "mypy_extensions-0.4.3.tar.gz", hash = "sha256:2d82818f5bb3e369420cb3c4060a7970edba416647068eb4c5343488a6c604a8"}, ] numpy = [ - {file = "numpy-1.21.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:38e8648f9449a549a7dfe8d8755a5979b45b3538520d1e735637ef28e8c2dc50"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:fd7d7409fa643a91d0a05c7554dd68aa9c9bb16e186f6ccfe40d6e003156e33a"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:a75b4498b1e93d8b700282dc8e655b8bd559c0904b3910b144646dbbbc03e062"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1412aa0aec3e00bc23fbb8664d76552b4efde98fb71f60737c83efbac24112f1"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:e46ceaff65609b5399163de5893d8f2a82d3c77d5e56d976c8b5fb01faa6b671"}, - {file = "numpy-1.21.1-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:c6a2324085dd52f96498419ba95b5777e40b6bcbc20088fddb9e8cbb58885e8e"}, - {file = "numpy-1.21.1-cp37-cp37m-win32.whl", hash = "sha256:73101b2a1fef16602696d133db402a7e7586654682244344b8329cdcbbb82172"}, - {file = "numpy-1.21.1-cp37-cp37m-win_amd64.whl", hash = "sha256:7a708a79c9a9d26904d1cca8d383bf869edf6f8e7650d85dbc77b041e8c5a0f8"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:95b995d0c413f5d0428b3f880e8fe1660ff9396dcd1f9eedbc311f37b5652e16"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:635e6bd31c9fb3d475c8f44a089569070d10a9ef18ed13738b03049280281267"}, - {file = "numpy-1.21.1-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:4a3d5fb89bfe21be2ef47c0614b9c9c707b7362386c9a3ff1feae63e0267ccb6"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a326af80e86d0e9ce92bcc1e65c8ff88297de4fa14ee936cb2293d414c9ec63"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:791492091744b0fe390a6ce85cc1bf5149968ac7d5f0477288f78c89b385d9af"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0318c465786c1f63ac05d7c4dbcecd4d2d7e13f0959b01b534ea1e92202235c5"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:9a513bd9c1551894ee3d31369f9b07460ef223694098cf27d399513415855b68"}, - {file = "numpy-1.21.1-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:91c6f5fc58df1e0a3cc0c3a717bb3308ff850abdaa6d2d802573ee2b11f674a8"}, - {file = "numpy-1.21.1-cp38-cp38-win32.whl", hash = "sha256:978010b68e17150db8765355d1ccdd450f9fc916824e8c4e35ee620590e234cd"}, - {file = "numpy-1.21.1-cp38-cp38-win_amd64.whl", hash = "sha256:9749a40a5b22333467f02fe11edc98f022133ee1bfa8ab99bda5e5437b831214"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:d7a4aeac3b94af92a9373d6e77b37691b86411f9745190d2c351f410ab3a791f"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:d9e7912a56108aba9b31df688a4c4f5cb0d9d3787386b87d504762b6754fbb1b"}, - {file = "numpy-1.21.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:25b40b98ebdd272bc3020935427a4530b7d60dfbe1ab9381a39147834e985eac"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:8a92c5aea763d14ba9d6475803fc7904bda7decc2a0a68153f587ad82941fec1"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:05a0f648eb28bae4bcb204e6fd14603de2908de982e761a2fc78efe0f19e96e1"}, - {file = "numpy-1.21.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f01f28075a92eede918b965e86e8f0ba7b7797a95aa8d35e1cc8821f5fc3ad6a"}, - {file = "numpy-1.21.1-cp39-cp39-win32.whl", hash = "sha256:88c0b89ad1cc24a5efbb99ff9ab5db0f9a86e9cc50240177a571fbe9c2860ac2"}, - {file = "numpy-1.21.1-cp39-cp39-win_amd64.whl", hash = "sha256:01721eefe70544d548425a07c80be8377096a54118070b8a62476866d5208e33"}, - {file = "numpy-1.21.1-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:2d4d1de6e6fb3d28781c73fbde702ac97f03d79e4ffd6598b880b2d95d62ead4"}, - {file = "numpy-1.21.1.zip", hash = "sha256:dff4af63638afcc57a3dfb9e4b26d434a7a602d225b42d746ea7fe2edf1342fd"}, {file = "numpy-1.21.3-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:508b0b513fa1266875524ba8a9ecc27b02ad771fe1704a16314dc1a816a68737"}, {file = "numpy-1.21.3-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5dfe9d6a4c39b8b6edd7990091fea4f852888e41919d0e6722fe78dd421db0eb"}, {file = "numpy-1.21.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8a10968963640e75cc0193e1847616ab4c718e83b6938ae74dea44953950f6b7"}, diff --git a/codeliciousness/pyproject.toml b/codeliciousness/pyproject.toml index 819afaf2..2d01d1f2 100644 --- a/codeliciousness/pyproject.toml +++ b/codeliciousness/pyproject.toml @@ -16,6 +16,7 @@ pandas = "^1.3.4" pytest = "^6.2.5" black = "^21.9b0" pytest-cov = "^3.0.0" +isort = "^5.9.3" [build-system] requires = ["poetry-core>=1.0.0"] From eb97bf2fdeb1bcf53cdeaec3579fec88b5826f6d Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Sat, 23 Oct 2021 09:36:43 -0400 Subject: [PATCH 22/23] style: black and isort --- codeliciousness/basistron/cccbdb.py | 72 ++++++++++++++-------------- codeliciousness/basistron/exabyte.py | 27 ++++++----- codeliciousness/basistron/main.py | 7 --- codeliciousness/basistron/parser.py | 11 +++-- codeliciousness/basistron/utils.py | 13 +++-- 5 files changed, 67 insertions(+), 63 deletions(-) delete mode 100644 codeliciousness/basistron/main.py diff --git a/codeliciousness/basistron/cccbdb.py b/codeliciousness/basistron/cccbdb.py index 40fb7758..cad8c196 100644 --- a/codeliciousness/basistron/cccbdb.py +++ b/codeliciousness/basistron/cccbdb.py @@ -19,42 +19,43 @@ log = utils.get_logger(__name__) + def _inspected_headers(referer: str) -> Dict[str, str]: headers = { - 'Accept': ( - 'text/html,application/xhtml+xml,application/xml;' - 'q=0.9,image/avif,image/webp,image/apng,*/*;' - 'q=0.8,application/signed-exchange;v=b3;q=0.9' + "Accept": ( + "text/html,application/xhtml+xml,application/xml;" + "q=0.9,image/avif,image/webp,image/apng,*/*;" + "q=0.8,application/signed-exchange;v=b3;q=0.9" ), - 'Accept-Encoding': 'gzip, deflate, br', - 'Accept-Language': 'en-US,en;q=0.9', - 'Cache-Control': 'max-age=0', - 'Connection': 'keep-alive', - 'Content-Length': '26', - 'Content-Type': 'application/x-www-form-urlencoded', - 'Host': 'cccbdb.nist.gov', - 'Origin': 'https://cccbdb.nist.gov', - 'sec-ch-ua': ( - '"Chromium";v="94", "Google Chrome";' - 'v="94", ";Not A Brand";v="99"' + "Accept-Encoding": "gzip, deflate, br", + "Accept-Language": "en-US,en;q=0.9", + "Cache-Control": "max-age=0", + "Connection": "keep-alive", + "Content-Length": "26", + "Content-Type": "application/x-www-form-urlencoded", + "Host": "cccbdb.nist.gov", + "Origin": "https://cccbdb.nist.gov", + "sec-ch-ua": ( + '"Chromium";v="94", "Google Chrome";' 'v="94", ";Not A Brand";v="99"' + ), + "sec-ch-ua-mobile": "?0", + "sec-ch-ua-platform": "Windows", + "Sec-Fetch-Dest": "document", + "Sec-Fetch-Mode": "navigate", + "Sec-Fetch-Site": "same-origin", + "Sec-Fetch-User": "?1", + "Upgrade-Insecure-Requests": "1", + "User-Agent": ( + "Mozilla/5.0 (Windows NT 10.0; Win64; x64) " + "AppleWebKit/537.36 (KHTML, like Gecko) " + "Chrome/94.0.4606.81 Safari/537.36" ), - 'sec-ch-ua-mobile': '?0', - 'sec-ch-ua-platform': 'Windows', - 'Sec-Fetch-Dest': 'document', - 'Sec-Fetch-Mode': 'navigate', - 'Sec-Fetch-Site': 'same-origin', - 'Sec-Fetch-User': '?1', - 'Upgrade-Insecure-Requests': '1', - 'User-Agent': ( - 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) ' - 'AppleWebKit/537.36 (KHTML, like Gecko) ' - 'Chrome/94.0.4606.81 Safari/537.36' - ) } if referer is not None: - headers['Referer'] = referer + headers["Referer"] = referer return headers + class Cccbdb: """Wrapper around interactivity with the CCCBDB and filesystem caching of CCCBDB data.""" @@ -85,8 +86,9 @@ def retry_loop(func, *args, **kwargs): while True: try: tries += 1 - if not tries or not tries % 5: - log.info(f"calling {func.__name__} try #{tries}") + if tries > 1000: + log.error("retried {tries} times, no luck..") + sys.exit() res = func(*args, **kwargs) break except (HTTPError, ReadTimeout): @@ -113,7 +115,7 @@ def get_form(self, property: str) -> Tuple[requests.Response, Dict[str, Any]]: def submit_form(self, form_data: Dict[str, Any], headers: Dict[str, Any]): """Submit the form following redirect semantics of the CCCBDB website.""" - log.info('submitting form %s', form_data["data"]) + log.info("submitting form %s", form_data["data"]) # post the form data without redirect self.retry_loop( getattr(self, form_data["method"]), @@ -134,7 +136,7 @@ def reduce_form(form: Tag, formula: str) -> Dict[str, Any]: "data": { inp.attrs.get("name"): inp.attrs.get("value") for inp in form.find_all("input") - } + }, } reduced["data"]["formula"] = formula return reduced @@ -165,12 +167,10 @@ def __init__(self): def _make_request(self, method: str, path: str, **kwargs): url = urljoin(self.BASE_URL, path) log.info(f"calling {method} {url}") - res = self.session.request( - method, url, timeout=self.TIMEOUT, **kwargs - ) + res = self.session.request(method, url, timeout=self.TIMEOUT, **kwargs) res.raise_for_status() log.info(f"status code {res.status_code}") return res get = partialmethod(_make_request, "get") - post = partialmethod(_make_request, "post") \ No newline at end of file + post = partialmethod(_make_request, "post") diff --git a/codeliciousness/basistron/exabyte.py b/codeliciousness/basistron/exabyte.py index 318a5f71..abad9008 100644 --- a/codeliciousness/basistron/exabyte.py +++ b/codeliciousness/basistron/exabyte.py @@ -37,6 +37,7 @@ def _iter_module(module: ModuleType): apis[key] = cls return apis + class Client(utils.Log): """Wrapper around endpoints API for simplicity.""" @@ -53,15 +54,19 @@ def get_endpoint(self, name: str) -> endpoints.BaseEndpoint: self.log.warning(f"name {name} not found in {self._endpoints.keys()}") return args = ( - utils.env.exabyte_host, - utils.env.exabyte_port, - utils.env.exabyte_username, - utils.env.exabyte_password, - ) if name == "login" else ( - utils.env.exabyte_host, - utils.env.exabyte_port, - utils.env.exabyte_client_id, - utils.env.exabyte_client_secret, + ( + utils.env.exabyte_host, + utils.env.exabyte_port, + utils.env.exabyte_username, + utils.env.exabyte_password, + ) + if name == "login" + else ( + utils.env.exabyte_host, + utils.env.exabyte_port, + utils.env.exabyte_client_id, + utils.env.exabyte_client_secret, + ) ) self._endpoints[name] = endpoint(*args) return self._endpoints[name] @@ -113,7 +118,7 @@ def get_material_config( "name": "basis", **basis, }, - "tags": ["basistron"] + "tags": ["basistron"], } def submit_job(self, config: Dict[str, str]): @@ -140,4 +145,4 @@ def __init__(self): self.log.error( "authentication failure, client is useless. are " "EXABYTE_USERNAME+EXABYTE_PASSWORD in the environment?" - ) \ No newline at end of file + ) diff --git a/codeliciousness/basistron/main.py b/codeliciousness/basistron/main.py deleted file mode 100644 index 254c765e..00000000 --- a/codeliciousness/basistron/main.py +++ /dev/null @@ -1,7 +0,0 @@ -# -*- coding: utf-8 -*- - - -if __name__ == "__main__": - from basistron import cli - parser = cli.get_parser() - driver = cli.process_args(parser.parse_args()) diff --git a/codeliciousness/basistron/parser.py b/codeliciousness/basistron/parser.py index c176386e..6252f470 100644 --- a/codeliciousness/basistron/parser.py +++ b/codeliciousness/basistron/parser.py @@ -14,6 +14,7 @@ log = utils.get_logger(__name__) + class TableParser(HTMLParser): """Single table parser.""" @@ -32,7 +33,7 @@ def handle_starttag(self, tag: str, attrs: List[List[str]]) -> None: for t in ["td", "th", "tr", "caption"]: if tag == t: setattr(self, tag, True) - + def handle_data(self, data: str) -> None: if self.td or self.th: self.current_cell.append(data.strip()) @@ -79,13 +80,14 @@ def to_df(self) -> Optional[pd.DataFrame]: def clean_values(df: pd.DataFrame) -> pd.DataFrame: # TODO : pull out redirect links for nested data - return df.replace(r'^\s*$', np.nan, regex=True) + return df.replace(r"^\s*$", np.nan, regex=True) def clean_columns(df: pd.DataFrame) -> pd.DataFrame: index = None if df.columns[:2].tolist() == ["", ""]: index = ["theory", "implementation"] df.columns = index + df.columns[2:].tolist() + df.columns = [col.lower() for col in df.columns] unique_columns = [] seen = defaultdict(int) for column in df.columns: @@ -103,13 +105,14 @@ def clean_index(df, index): if index is not None: df.set_index(index, inplace=True) try: - df.drop(("", ""), inplace=True) + if ("", "") in df.index: + df.drop(("", ""), inplace=True) except Exception as e: log.error(f"cleaning index failed: {repr(e)}") df = df.droplevel(0) if index else df if df.index.duplicated().any(): log.warning("found duplicated index entries") - return df + return df[df.index.notnull()] df = clean_values(df) df, index = clean_columns(df) diff --git a/codeliciousness/basistron/utils.py b/codeliciousness/basistron/utils.py index b85cba63..59e0b078 100644 --- a/codeliciousness/basistron/utils.py +++ b/codeliciousness/basistron/utils.py @@ -21,16 +21,18 @@ def default_cache_dir(): class Log: - @property def log(self): return get_logger( - ".".join([ - self.__module__, - self.__class__.__name__, - ]) + ".".join( + [ + self.__module__, + self.__class__.__name__, + ] + ) ) + class _env: """Namespace collecting all environment variables used within the application.""" @@ -63,4 +65,5 @@ def exabyte_client_secret(self): """Used as X-Account-Id header""" return os.getenv("EXABYTE_CLIENT_SECRET") + env = _env() From 2f6c46b100b52d284c62aae2f77490e4fd1658ce Mon Sep 17 00:00:00 2001 From: codeliciousness Date: Sat, 23 Oct 2021 09:38:03 -0400 Subject: [PATCH 23/23] feat: more or less complete app --- codeliciousness/basistron/README.md | 13 +- codeliciousness/basistron/app.py | 205 ++++++++++++++++++++++------ codeliciousness/basistron/cli.py | 37 +++-- codeliciousness/basistron/model.py | 47 ++++--- codeliciousness/run.sh | 7 +- codeliciousness/test.sh | 5 +- 6 files changed, 229 insertions(+), 85 deletions(-) diff --git a/codeliciousness/basistron/README.md b/codeliciousness/basistron/README.md index 21d200d1..bbfa29a8 100644 --- a/codeliciousness/basistron/README.md +++ b/codeliciousness/basistron/README.md @@ -4,16 +4,13 @@ BasisTron TODO ---- -* Basis - - how to update workflow model with basis set info +* Cccbdb + - hash and cache queries * App - - default reference level of theory, basis set - - compute allowed basis sets from reference data - - return job id of submitted job - - extras - - match ranked basis sets to allowed basis sets - - pick most compact allowed set from ranked set + - how update workflow model with basis set + - fix geometry specification + - NWChemInputDataManager pls BasisTron is the automatic basis set selection tool you've always needed but have never had the time to write yourself. diff --git a/codeliciousness/basistron/app.py b/codeliciousness/basistron/app.py index 62436e4c..121dc5a1 100644 --- a/codeliciousness/basistron/app.py +++ b/codeliciousness/basistron/app.py @@ -1,100 +1,221 @@ - # -*- coding: utf-8 -*- +import json +import logging import sys -from typing import List +from typing import Any, Dict, List, Optional import pandas as pd -from basistron import basis, cccbdb, cli, exabyte, utils +from basistron import basis, cccbdb, cli, exabyte, model, utils log = utils.get_logger("basistron.app") +class MissingReferenceData(Exception): + pass + + def filter_dfs_by_name( dfs: List[pd.DataFrame], regime: str, match: str = "standard", -): +) -> pd.DataFrame: """Localize heuristic table selection here.""" - log.info(f"choosing dataframe from {[df.name for df in dfs]}") + log.info(f"choosing dataframe from {[df.name[:20] for df in dfs]}") this = None if len(dfs) == 1: this = dfs[0] + # calculated results usually show up with + # three tables of result groups + # ["empirical", "standard", "effective"] elif regime == "calculated": - # calculated results usually show up with - # three tables of result groups - # ["empirical", "standard", "effective"] for df in dfs: - if match in df.name: - if this is not None: - raise Exception("duplicate match logic") - this = df - break + if match in df.name: + if this is not None: + raise Exception("duplicate match logic") + this = df + break + # table structure very different for exptl data from CCCBDB + # so would need its own logic presumably + # elif regime == "experimental" if this is None: - raise Exception("could not find reference data") + raise MissingReferenceData("table filtering logic failed") return this +def set_reference_value( + df: pd.DataFrame, + driver: model.Execution, +) -> None: + """Assume input data is ordered approximately as follows: + Increasing index (ordered) values means increasing level of theory. + Increasing column (ordered) values means increasing basis quality. + """ + theory = driver.reference_theory + basis = driver.reference_basis + log.info(f"looking for reference datum @ ({theory},{basis})") + if theory not in df.index: + log.warning(f"reference theory {theory} not in {df.index.values}") + # should probably pick "best" reference theory with known available data + theory = df.index.values[-1] + log.info(f"selecting best reference theory available: {theory}") + # case insensitive comparisons but this could be better + if basis not in df.columns: + log.warning(f"reference basis {basis} not found in {df.columns.values}") + # CCCBDB order is not strictly increasing so this is a hack + basis = df.columns[len(df.columns) // 2 - 2] + log.info(f"selecting medium size reference basis set: {basis}") + value = df.loc[theory, basis] + if pd.isnull(value): + log.error(f"reference datum for ({theory},{basis}) not found") + raise MissingReferenceData("reference datum selection logic failed") + log.info(f"selected reference value = {value} @ ({theory},{basis})") + driver.reference_theory = theory + driver.reference_basis = basis + driver.value = value + + +def select_basis_set( + df: pd.DataFrame, + driver: model.Execution, +) -> str: + """Filter allowed basis sets for to determine the best available. + If a basis set cannot be found for the target level of thery, + a target level of theory will be chosen if possible. In the case + of multiple available basis sets, attempt to choose the most compact + one from the basis set database. If unavailable, assume the basis + sets are already ordered in increasing size. + """ + + def get_basis_sets( + df: pd.DataFrame, theory: str, lower: float, upper: float + ) -> Optional[str]: + try: + target = df.loc[theory] + except KeyError: + return + acceptable = target[(target >= lower) & (target <= upper)] + if acceptable.any(): + log.info(f"selecting {len(acceptable)} basis sets for {theory}") + log.info(f"bounds on selected ({acceptable.min()},{acceptable.max()})") + return acceptable.index.values.tolist() + + allowed = f"within {driver.value}±{driver.tolerance:.2f}%" + lower, upper = driver.acceptable_range() + # allow priority to user provided target theory + theories = [driver.target_theory] + theories = theories + df.index.difference(theories).tolist() + for theory in theories: + log.info(f"attempting to select basis set for target theory {theory}") + basis_sets = get_basis_sets(df, theory, lower, upper) + if basis_sets is not None: + driver.target_theory = theory + break + + if basis_sets is None: + msg = f"could not find any basis set for any theory to yield results {allowed}" + log.error(msg) + raise MissingReferenceData(f"no target data found {allowed}") + + try: + # basis set analysis doomed to fail for now + bases = basis.Basis.load_basis_sets() + ranked = basis.Basis.rank_basis_sets(bases) + # needs more cleanup to match off against CCCBDB basis set specs + total_allowed = [ + ".".join(b.lower().split(".")[:-1]) + for b in basis.Basis.get_allowed_basis_sets( + ranked, list(set([r[0] for r in driver.xyz_data])) + ) + ] + ordered = [basis for basis in total_allowed if basis in basis_sets] + except Exception: + ordered = [] + + if not ordered: + return basis_sets[0] + log.warning("did not find matching basis sets in database, skipping") + return ordered[0] + + def main(args): - """Run the BasisTron 5000!""" + """Run the BasisTron 5000! Business logic is broken into four + main parts. + + 1. Filter the CCCBDB data tables that are provided. + It is use-case specific enough to belong here. + 2. Determine the reference value (if not provided), + keeping track of the level of theory and basis + 3. Choose a basis set at a target level of theory + providing the same accuracy within the reference + tolerance. + 4. Create the material, update the workflow, submit + the job to the exabyte cluster. + """ - # init driver = cli.process_args(cli.get_parser().parse_args(args)) formula = driver.simple_formula() log.info(f"starting basis set selector on {formula} for {driver.property}") - # refdata + # step 1 db = cccbdb.Cccbdb() dfs = db.get_dataframes(formula, driver.property.value) if not dfs: log.error("found no tables from CCCBDB") - sys.exit() + return try: df = filter_dfs_by_name(dfs, driver.regime.value) - except Exception as e: - log.error("failed to select table from reference data") - sys.exit() + except MissingReferenceData as e: + log.error(f"failed to select table from reference data: {repr(e)}") + return - # select reference datum + # step 2 if driver.value is None: - print(df) - allowed_basis_sets = [] + set_reference_value(df, driver) else: - # sanity check provided reference data + # reference_theory and reference_basis are unused + # sanity check provided reference value lower, upper = driver.acceptable_range() acceptable = df[(df >= lower) & (df <= upper)] - if not acceptable.sum().sum(): + if not acceptable.any().any(): msg = f"{driver.value}±{driver.tolerance:.2f}%" log.error(f"no reference data found within {msg}") log.warning("subsequent analysis may fail") - allowed_basis_sets = [] - - # basis set analysis - # Of allowed_basis_sets, pick the most compact - bases = basis.Basis.load_basis_sets() - ranked = basis.Basis.rank_basis_sets(bases) - total_allowed = basis.Basis.get_allowed_basis_sets( - ranked, list(set([r[0] for r in driver.xyz_data])) - ) - log.info(f"found {len(allowed_basis_sets)} allowed basis sets") - log.info(f"ranking allowed out of {len(total_allowed)} basis sets") - # update workflow with basis set, level of theory? + # step 3 + orig = driver.target_theory + basis_set = select_basis_set(df, driver) + curr = driver.target_theory + if orig != curr: + msg = f"updated target theory from {orig} to {curr} to meet tolerance" + log.warning(msg) + + # step 4 + def debug(name: str, blob: Dict[str, Any]): + for ln in json.dumps(config, indent=4).splitlines(): + log.debug(f"{name}: {ln}") + + log.setLevel(logging.DEBUG) - # ship it ebc = exabyte.Client() config = ebc.get_material_config("", driver.xyz_data_to_dict()) + debug("config", config) material = ebc.get_endpoint("material").create(config) + debug("material", material) workflow = ebc.get_workflow() + debug("workflow", workflow) job_cfg = ebc.get_job_config( workflow["owner"]["_id"], material["_id"], workflow["_id"], "basistron.app", ) - print(job_cfg) - # job = c.submit_job(job_cfg) + debug("job config", job_cfg) + job = ebc.submit_job(job_cfg) + debug("job", job) + # print(json.dumps(job, indent=4)) + # log.info(f"successfully submitted job with ID={job['_id']}") if __name__ == "__main__": - main(sys.argv[1:]) \ No newline at end of file + main(sys.argv[1:]) diff --git a/codeliciousness/basistron/cli.py b/codeliciousness/basistron/cli.py index 22b44892..b4160c0e 100644 --- a/codeliciousness/basistron/cli.py +++ b/codeliciousness/basistron/cli.py @@ -6,9 +6,7 @@ def get_parser() -> ArgumentParser: - parser = ArgumentParser( - description="Run basis set selection" - ) + parser = ArgumentParser(description="Run basis set selection") parser.add_argument( "--xyz_path", type=str, @@ -18,9 +16,7 @@ def get_parser() -> ArgumentParser: parser.add_argument( "--property", type=str, - choices=set( - model.CalculatedReferenceProperty.__members__.keys(), - ).union( + choices=set(model.CalculatedReferenceProperty.__members__.keys(),).union( model.ExperimentalReferenceProperty.__members__.keys(), ), required=True, @@ -31,6 +27,24 @@ def get_parser() -> ArgumentParser: type=float, help="reference property value (optional)", ) + parser.add_argument( + "--target_theory", + type=str, + default="B3LYP", + help="target level of theory for subsequent calculation (e.g. 'B3LYP')", + ) + parser.add_argument( + "--reference_theory", + type=str, + default="CCSD(T)", + help="reference level of theory to use as benchmark (e.g. 'CCSD(T)')", + ) + parser.add_argument( + "--reference_basis", + type=str, + default="cc-pVDZ", + help="basis set to use for selecting reference value (e.g. 'cc-pVDZ')", + ) parser.add_argument( "--tolerance", type=float, @@ -41,7 +55,7 @@ def get_parser() -> ArgumentParser: type=str, choices=list(model.ReferenceRegime.__members__.keys()), default=model.ReferenceRegime.experimental.value, - help="use experimental or calculated data as benchmark" + help="use experimental or calculated data as benchmark", ) return parser @@ -52,15 +66,14 @@ def process_args(args: Namespace) -> model.Execution: if not os.path.isfile(args.xyz_path): raise FileNotFoundError(args.xyz_path) with open(args.xyz_path, "r") as f: - xyz_data = [ - ln.strip().split() for ln in f.readlines()[2:] - ] + xyz_data = [ln.strip().split() for ln in f.readlines()[2:]] return model.Execution( xyz_data=xyz_data, property=property, regime=args.regime, + target_theory=args.target_theory, + reference_theory=args.reference_theory, + reference_basis=args.reference_basis, value=getattr(args, "value", None), tolerance=getattr(args, "tolerance", None), ) - - diff --git a/codeliciousness/basistron/model.py b/codeliciousness/basistron/model.py index 1441e813..3054f6db 100644 --- a/codeliciousness/basistron/model.py +++ b/codeliciousness/basistron/model.py @@ -4,7 +4,7 @@ from enum import Enum from typing import Any, Dict, List, Optional, Tuple, Union -from pydantic import BaseModel +from pydantic import BaseModel, validator from basistron.cccbdb import Cccbdb @@ -13,8 +13,10 @@ class ReferenceRegime(Enum): experimental = "experimental" calculated = "calculated" + class ExperimentalReferenceProperty(Enum): """Map command-line arguments to CCCBDB URIs.""" + polarizability = Cccbdb.EXPT_POL vibrational_frequency = Cccbdb.EXPT_VIB homo_lumo_gap = Cccbdb.EXPT_IE @@ -22,48 +24,55 @@ class ExperimentalReferenceProperty(Enum): class CalculatedReferenceProperty(Enum): """Map command-line arguments to CCCBDB URIs.""" - polarizability = Cccbdb.POL_CALC # units angstrom^3 + + polarizability = Cccbdb.POL_CALC # units angstrom^3 vibrational_frequency = Cccbdb.VIB_FREQ # units cm-1 - homo_lumo_gap = Cccbdb.HOMO_LUMO # units eV + homo_lumo_gap = Cccbdb.HOMO_LUMO # units eV def validate_property(regime: str, property: str): - typ = ExperimentalReferenceProperty if ( - regime == ReferenceRegime.experimental.value - ) else CalculatedReferenceProperty + if regime == ReferenceRegime.experimental.value: + raise NotImplementedError("Introduce support for CCCBDB experimental data") + typ = ( + ExperimentalReferenceProperty + if (regime == ReferenceRegime.experimental.value) + else CalculatedReferenceProperty + ) try: return getattr(typ, property) except AttributeError: - raise Exception( - f"property {property} not supported in regime {regime}" - ) + raise Exception(f"property {property} not supported in regime {regime}") class Execution(BaseModel): """The state of a given execution.""" + xyz_data: Tuple[Tuple[str, float, float, float], ...] property: Union[ - ExperimentalReferenceProperty, CalculatedReferenceProperty, + ExperimentalReferenceProperty, + CalculatedReferenceProperty, ] + target_theory: str + reference_theory: str + reference_basis: str regime: ReferenceRegime value: Optional[float] = None tolerance: Optional[float] = 1.0 - def acceptable_format(self) -> str: - if self.value is None: - return None - return "{self.value}±{self.tolerance:.2f}%" + @validator("reference_basis") + def basis_to_lower(cls, v): + return v.lower() def acceptable_range(self) -> Tuple[float, float]: if self.value is None: return None - lower = (1 - self.tolerance) * self.value - upper = (1 + self.tolerance) * self.value + lower = (1 - self.tolerance / 100) * self.value + upper = (1 + self.tolerance / 100) * self.value return lower, upper def simple_formula(self) -> str: symbol_count = Counter([r[0] for r in self.xyz_data]) - return ''.join([f"{k}{v}" for k, v in symbol_count.items()]) + return "".join([f"{k}{v}" for k, v in symbol_count.items()]) def xyz_data_to_dict(self) -> Dict[str, List[Dict[str, Any]]]: ang2au = 1.889723 @@ -72,9 +81,7 @@ def xyz_data_to_dict(self) -> Dict[str, List[Dict[str, Any]]]: for i, (sym, *val) in enumerate(self.xyz_data): i += 1 elements.append({"id": i, "value": sym}) - coordinates.append( - {"id": i, "value": [v * ang2au for v in val]} - ) + coordinates.append({"id": i, "value": [v * ang2au for v in val]}) return { "elements": elements, "coordinates": coordinates, diff --git a/codeliciousness/run.sh b/codeliciousness/run.sh index cb800f56..0becb1c5 100755 --- a/codeliciousness/run.sh +++ b/codeliciousness/run.sh @@ -2,5 +2,8 @@ python -m basistron.app \ --xyz_path h2.xyz \ - --target_property homo_lumo_gap \ - --reference_value 100.0 + --property homo_lumo_gap \ + --tolerance 20 \ + --reference_theory 'CCSD(T)' \ + --target_theory B3LYP \ + --regime calculated diff --git a/codeliciousness/test.sh b/codeliciousness/test.sh index 08c304e9..924ba957 100755 --- a/codeliciousness/test.sh +++ b/codeliciousness/test.sh @@ -2,19 +2,22 @@ pytest test/ --cov=basistron -regimes="experimental calculated" +regimes="calculated" for regime in $regimes; do echo "${regime}" python -m basistron.app \ --xyz_path "h2.xyz" \ --regime "${regime}" \ + --reference_theory CCSD \ + --reference_basis asdf \ --property vibrational_frequency \ --tolerance 0.5 python -m basistron.app \ --xyz_path "h2.xyz" \ --regime "${regime}" \ --property homo_lumo_gap \ + --reference_basis cc-pvtz \ --tolerance 0.5 python -m basistron.app \ --xyz_path "ch4.xyz" \