├── bvlain ├── data │ ├── __init__.py │ ├── anion.pkl │ ├── cation.pkl │ ├── quantum_n.pkl │ ├── covalent_radii_softvb.pkl │ ├── covalent_radii.py │ └── shannon-radii.json ├── _version.py ├── __init__.py ├── potentials.py └── core.py ├── BVlain_logo.png ├── docs ├── source │ ├── theory.png │ ├── lain_.md │ ├── README.md │ ├── application.md │ ├── index.md │ ├── usage.md │ └── conf.py ├── requirements.txt ├── Makefile └── make.bat ├── MANIFEST.in ├── upload_to_pypi.txt ├── pyproject.toml ├── LICENSE ├── .gitignore ├── .readthedocs.yaml ├── setup.py └── README.md /bvlain/data/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /bvlain/_version.py: -------------------------------------------------------------------------------- 1 | __version__ = "0.25.1" -------------------------------------------------------------------------------- /BVlain_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dembart/BVlain/HEAD/BVlain_logo.png -------------------------------------------------------------------------------- /bvlain/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | from .core import Lain 3 | from ._version import __version__ -------------------------------------------------------------------------------- /bvlain/data/anion.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dembart/BVlain/HEAD/bvlain/data/anion.pkl -------------------------------------------------------------------------------- /bvlain/data/cation.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dembart/BVlain/HEAD/bvlain/data/cation.pkl -------------------------------------------------------------------------------- /docs/source/theory.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dembart/BVlain/HEAD/docs/source/theory.png -------------------------------------------------------------------------------- /bvlain/data/quantum_n.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dembart/BVlain/HEAD/bvlain/data/quantum_n.pkl -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include LICENSE 2 | include README.md 3 | include bvlain/data/*.pkl 4 | include bvlain/data/*.json -------------------------------------------------------------------------------- /bvlain/data/covalent_radii_softvb.pkl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/dembart/BVlain/HEAD/bvlain/data/covalent_radii_softvb.pkl -------------------------------------------------------------------------------- /upload_to_pypi.txt: -------------------------------------------------------------------------------- 1 | python setup.py bdist_wheel 2 | python setup.py sdist 3 | twine check dist/* 4 | python -m twine upload dist/* -------------------------------------------------------------------------------- /docs/requirements.txt: -------------------------------------------------------------------------------- 1 | ase 2 | sphinx~=5.3.0 3 | myst-parser 4 | furo 5 | nbsphinx 6 | numpy 7 | pymatgen 8 | scipy 9 | joblib 10 | -------------------------------------------------------------------------------- /docs/source/lain_.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | ```{eval-rst} 4 | .. autoclass:: bvlain.Lain 5 | :members: 6 | :undoc-members: 7 | :show-inheritance: 8 | ``` 9 | -------------------------------------------------------------------------------- /docs/source/README.md: -------------------------------------------------------------------------------- 1 | ![BVlain_logo](https://raw.githubusercontent.com/dembart/BVlain/master/BVlain_logo.png) 2 | 3 | BVlain is the module for bond valence site energy calculations and is about to solve tasks related to ionic conductivity of a tracer ion in a crystal structure. 4 | -------------------------------------------------------------------------------- /docs/source/application.md: -------------------------------------------------------------------------------- 1 | # Why? 2 | 3 | The library is an easy to use package for evaluation of a tracer/mobile ion percolation energy in crystals. Its simple apparatus and high predicting power give the opportunity to perform an accurate calculation in a minute. For more info, see {doc}`notebooks/tutorials` and {doc}`notebooks/theory`. -------------------------------------------------------------------------------- /docs/source/index.md: -------------------------------------------------------------------------------- 1 | % BVlain documentation master file, created by 2 | % sphinx-quickstart on Thu Nov 3 00:03:22 2022. 3 | % You can adapt this file completely to your liking, but it should at least 4 | % contain the root `toctree` directive. 5 | 6 | 7 | 8 | ```{include} README.md 9 | :relative-images: 10 | ``` 11 | 12 | For more info, see {doc}`usage`. {ref}`Installation`. 13 | ```{warning} 14 | This library is under active development. 15 | ``` 16 | 17 | ```{toctree} 18 | :caption: 'Contents:' 19 | :maxdepth: 2 20 | 21 | usage 22 | application 23 | notebooks/theory 24 | notebooks/tutorials 25 | lain_ 26 | 27 | ``` 28 | 29 | 30 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Minimal makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line, and also 5 | # from the environment for the first two. 6 | SPHINXOPTS ?= 7 | SPHINXBUILD ?= sphinx-build 8 | SOURCEDIR = source 9 | BUILDDIR = build 10 | 11 | # Put it first so that "make" without argument is like "make help". 12 | help: 13 | @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 14 | 15 | .PHONY: help Makefile 16 | 17 | # Catch-all target: route all unknown targets to Sphinx using the new 18 | # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). 19 | %: Makefile 20 | @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) 21 | -------------------------------------------------------------------------------- /pyproject.toml: -------------------------------------------------------------------------------- 1 | [build-system] 2 | requires = ["setuptools"] 3 | build-backend = "setuptools.build_meta" 4 | 5 | dependencies = [ 6 | "numpy", 7 | "scipy", 8 | "ase", 9 | "pymatgen", 10 | "joblib" 11 | ] 12 | 13 | 14 | [project] 15 | name = "bvlain" 16 | authors = [{name = "Artem Dembitskiy", email = "art.dembitskiy@gmail.com"}] 17 | dynamic = ["version", "description"] 18 | readme = "README.md" 19 | license = {file = "LICENSE"} 20 | 21 | 22 | [project.optional-dependencies] 23 | doc = [ 24 | 'sphinx~=5.3.0', 25 | 'myst-parser', 26 | 'furo', 27 | 'nbsphinx', 28 | 'ase' 29 | ] 30 | 31 | [tool.poetry] 32 | # ... 33 | packages = [ 34 | { include = "bvlain" }, 35 | ] 36 | 37 | [project.scripts] 38 | lain = "bvlain.cli:main" 39 | -------------------------------------------------------------------------------- /docs/source/usage.md: -------------------------------------------------------------------------------- 1 | # Usage 2 | 3 | 4 | ## Installation 5 | 6 | To install bvlain 7 | ```console 8 | $ pip install bvlain 9 | ``` 10 | 11 | ## Example 12 | 13 | ```python 14 | from bvlain import Lain 15 | 16 | file = 'LiFePO4_mp-19017_symmetrized.cif' 17 | calc = Lain(verbose = False) 18 | st = calc.read_file(file) 19 | 20 | params = {'mobile_ion': 'Li1+', 21 | 'r_cut': 10.0, 22 | 'resolution': 0.2, 23 | 'k': 100 24 | } 25 | _ = calc.bvse_distribution(**params) 26 | energies = calc.percolation_barriers(encut = 5.0) 27 | ``` 28 | The output is threshold energies for 1-3D percolation 29 | 30 | ```python 31 | >>> {'E_1D': 0.4395, 'E_2D': 3.3301, 'E_3D': 3.3594} 32 | ``` 33 | For more examples/info, see {doc}`notebooks/tutorials`, {doc}`notebooks/theory` and {doc}`lain_` -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | pushd %~dp0 4 | 5 | REM Command file for Sphinx documentation 6 | 7 | if "%SPHINXBUILD%" == "" ( 8 | set SPHINXBUILD=sphinx-build 9 | ) 10 | set SOURCEDIR=source 11 | set BUILDDIR=build 12 | 13 | %SPHINXBUILD% >NUL 2>NUL 14 | if errorlevel 9009 ( 15 | echo. 16 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 17 | echo.installed, then set the SPHINXBUILD environment variable to point 18 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 19 | echo.may add the Sphinx directory to PATH. 20 | echo. 21 | echo.If you don't have Sphinx installed, grab it from 22 | echo.https://www.sphinx-doc.org/ 23 | exit /b 1 24 | ) 25 | 26 | if "%1" == "" goto help 27 | 28 | %SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 29 | goto end 30 | 31 | :help 32 | %SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% %O% 33 | 34 | :end 35 | popd 36 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2023 Artem. D. Dembitskiy 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a copy 5 | of this software and associated documentation files (the "Software"), to deal 6 | in the Software without restriction, including without limitation the rights 7 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is 9 | furnished to do so, subject to the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all 12 | copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 20 | SOFTWARE. -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # some files 2 | test_debug.ipynb 3 | test_debug_copy.ipynb 4 | test_mace_mp.ipynb 5 | README_old.md 6 | test_debug.md 7 | theory.png 8 | *cif 9 | *csv 10 | #lesson/figures 11 | lesson 12 | #lesson/files/*.grd 13 | #lesson/*.md 14 | bvlain/cli.py 15 | 16 | 17 | # Byte-compiled / optimized / DLL files 18 | __pycache__/ 19 | *.py[cod] 20 | 21 | # C extensions 22 | *.so 23 | 24 | # Distribution / packaging 25 | bin/ 26 | build/ 27 | develop-eggs/ 28 | dist/ 29 | eggs/ 30 | lib/ 31 | lib64/ 32 | parts/ 33 | sdist/ 34 | var/ 35 | *.egg-info/ 36 | .installed.cfg 37 | *.egg 38 | 39 | 40 | 41 | # Installer logs 42 | pip-log.txt 43 | pip-delete-this-directory.txt 44 | 45 | # Unit test / coverage reports 46 | .tox/ 47 | .coverage 48 | .cache 49 | nosetests.xml 50 | coverage.xml 51 | 52 | # Translations 53 | *.mo 54 | 55 | # Mr Developer 56 | .mr.developer.cfg 57 | .project 58 | .pydevproject 59 | 60 | # Rope 61 | .ropeproject 62 | 63 | # Django stuff: 64 | *.log 65 | *.pot 66 | 67 | # OS generated files # 68 | ###################### 69 | .DS_Store 70 | .DS_Store? 71 | **/.DS_Store 72 | **/**/.DS_Store 73 | ._* 74 | .Spotlight-V100 75 | .Trashes 76 | ehthumbs.db 77 | Thumbs.db 78 | 79 | # Sphinx documentation 80 | docs/_build/ -------------------------------------------------------------------------------- /.readthedocs.yaml: -------------------------------------------------------------------------------- 1 | 2 | # version: 2 3 | 4 | # build: 5 | # os: "ubuntu-20.04" 6 | # tools: 7 | # python: "3.8" 8 | 9 | 10 | # sphinx: 11 | # configuration: docs/source/conf.py 12 | 13 | 14 | # python: 15 | # install: 16 | # - method: pip 17 | # path: . 18 | # requirements: docs/requirements.txt 19 | # extra_requirements: 20 | # - doc 21 | 22 | # .readthedocs.yaml 23 | # Read the Docs configuration file 24 | # See https://docs.readthedocs.io/en/stable/config-file/v2.html for details 25 | 26 | # Required 27 | version: 2 28 | 29 | # Set the version of Python and other tools you might need 30 | build: 31 | os: ubuntu-20.04 32 | tools: 33 | python: "3.9" 34 | # You can also specify other tool versions: 35 | # nodejs: "16" 36 | # rust: "1.55" 37 | # golang: "1.17" 38 | 39 | # Build documentation in the docs/ directory with Sphinx 40 | sphinx: 41 | configuration: docs/source/conf.py 42 | 43 | # If using Sphinx, optionally build your docs in additional formats such as PDF 44 | # formats: 45 | # - pdf 46 | 47 | # Optionally declare the Python requirements required to build your docs 48 | python: 49 | install: 50 | - requirements: docs/requirements.txt 51 | 52 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | 3 | with open("README.md", "r") as fh: 4 | long_description = fh.read() 5 | 6 | setuptools.setup( 7 | name='bvlain', 8 | version='0.25.1', 9 | py_modules = ["bvlain"], 10 | install_requires = ["numpy", 11 | "pandas", 12 | "scipy>=1.7.0", 13 | "pymatgen>=2022.5.26", 14 | "ase", 15 | "joblib", 16 | ], 17 | author="Artem Dembitskiy", 18 | author_email="art.dembitskiy@gmail.com", 19 | description="The Bond valence site energy calculator", 20 | key_words = ['percolation', 'BVSE', 'ionic', 'conductivity'], 21 | long_description=long_description, 22 | long_description_content_type="text/markdown", 23 | url="https://github.com/dembart/BVlain", 24 | package_data={"bvlain": ["*.txt", "*.rst", '*.md', "*"], 25 | '':['bvlain/data/*.pkl'], 26 | '':['bvlain/data/*.json'], 27 | }, 28 | classifiers=[ 29 | "Programming Language :: Python :: 3.8", 30 | "Programming Language :: Python :: 3.9", 31 | "Programming Language :: Python :: 3.10", 32 | "Programming Language :: Python :: 3.11", 33 | "Programming Language :: Python :: 3.12", 34 | "License :: OSI Approved :: MIT License", 35 | "Operating System :: OS Independent", 36 | ], 37 | include_package_data=True, 38 | packages=setuptools.find_packages(), 39 | # entry_points={ 40 | # 'console_scripts': [ 41 | # 'lain=bvlain.cli:main', 42 | # ], 43 | # }, 44 | ) 45 | 46 | 47 | -------------------------------------------------------------------------------- /bvlain/potentials.py: -------------------------------------------------------------------------------- 1 | import numpy as np 2 | from scipy.special import erfc 3 | 4 | class BVSEPotential: 5 | 6 | def Morse(r, r_min, d0, alpha): 7 | 8 | """ Calculate Morse-type interaction energy. 9 | Note: interaction is calculate between ions 10 | of opposite sign compared to mobile ion 11 | 12 | 13 | Parameters 14 | ---------- 15 | 16 | r: np.array of floats 17 | distance between mobile ion and framework 18 | 19 | r_min: np.array of floats 20 | minimum energy distance between mobile and framework ions 21 | 22 | d0: np.array of floats 23 | bond breaking parameter 24 | 25 | alpha: np.array of floats 26 | inverse BVS tabulated parameter b (alpha = 1 / b) 27 | 28 | Returns 29 | ---------- 30 | 31 | np.array 32 | Morse-type interaction energies 33 | """ 34 | energy = d0 * ((np.exp( alpha * (r_min - r) ) - 1) ** 2 - 1) 35 | return energy / 2 36 | 37 | 38 | 39 | def Coulomb(r, q1, q2, rc1, rc2, n1, n2, f = 0.74): 40 | 41 | 42 | """ Calculate Coulombic interaction energy. 43 | Note: interaction is calculate between ions 44 | of same sign as mobile ion 45 | 46 | Parameters 47 | ---------- 48 | 49 | q1: float 50 | formal charge of a mobile ion 51 | 52 | q2: np.array of floats 53 | formal charges of framework ions 54 | 55 | r: np.array of floats 56 | distance between mobile ion and framework 57 | 58 | rc1: float 59 | covalent radius of a mobile ion 60 | 61 | rc2: np.array of floats 62 | covalent radii of framework ions 63 | 64 | n1: int 65 | principle quantum numbers of a mobile ion 66 | 67 | n2: np.array of floats 68 | principle quantum numbers of framework ions 69 | 70 | f: float, 0.74 by default 71 | screening factor 72 | 73 | Returns 74 | ---------- 75 | 76 | np.array 77 | Coulombic interaction energies 78 | """ 79 | 80 | energy = 14.4 * (q1 * q2 / (n1 * n2) ** (1/2)) * (1 / (r)) * erfc(r / (f * (rc1 + rc2))) 81 | return energy 82 | 83 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | # Configuration file for the Sphinx documentation builder. 2 | # 3 | # This file only contains a selection of the most common options. For a full 4 | # list see the documentation: 5 | # https://www.sphinx-doc.org/en/master/usage/configuration.html 6 | 7 | # -- Path setup -------------------------------------------------------------- 8 | 9 | # If extensions (or modules to document with autodoc) are in another directory, 10 | # add these directories to sys.path here. If the directory is relative to the 11 | # documentation root, use os.path.abspath to make it absolute, like shown here. 12 | # 13 | import os 14 | import sys 15 | 16 | # Define the canonical URL if you are using a custom domain on Read the Docs 17 | html_baseurl = os.environ.get("READTHEDOCS_CANONICAL_URL", "") 18 | 19 | # Tell Jinja2 templates the build is running on Read the Docs 20 | if os.environ.get("READTHEDOCS", "") == "True": 21 | if "html_context" not in globals(): 22 | html_context = {} 23 | html_context["READTHEDOCS"] = True 24 | 25 | 26 | sys.path.insert(0, os.path.abspath('../..')) 27 | sys.path.insert(1, os.path.abspath('../../')) 28 | 29 | 30 | # -- Project information ----------------------------------------------------- 31 | 32 | 33 | project = 'bvlain' 34 | 35 | copyright = '2024, Artem Dembitskiy' 36 | author = 'Artem Dembitskiy' 37 | 38 | # The full version, including alpha/beta/rc tags 39 | release = '0.24.8' 40 | 41 | 42 | # -- General configuration --------------------------------------------------- 43 | 44 | # Add any Sphinx extension module names here, as strings. They can be 45 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 46 | # ones. 47 | extensions = [ 48 | "myst_parser", 49 | "sphinx.ext.duration", 50 | "sphinx.ext.autosectionlabel", 51 | "sphinx.ext.autodoc", 52 | "sphinx.ext.napoleon", 53 | "sphinx.ext.mathjax", 54 | "nbsphinx" 55 | ] 56 | 57 | #add_module_names = False 58 | autodoc_mock_imports = ["ase", "networkx", "pymatgen", "joblib", "numpy", "scipy"] 59 | 60 | mathjax_config = { 61 | 'TeX': {'equationNumbers': {'autoNumber': 'AMS', 'useLabelIds': True}}, 62 | } 63 | 64 | source_suffix = { 65 | '.md': 'markdown', 66 | } 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | # Add any paths that contain templates here, relative to this directory. 75 | templates_path = ['_templates'] 76 | 77 | # List of patterns, relative to source directory, that match files and 78 | # directories to ignore when looking for source files. 79 | # This pattern also affects html_static_path and html_extra_path. 80 | exclude_patterns = [] 81 | 82 | 83 | # -- Options for HTML output ------------------------------------------------- 84 | 85 | # The theme to use for HTML and HTML Help pages. See the documentation for 86 | # a list of builtin themes. 87 | # 88 | html_theme = 'furo' 89 | 90 | # Add any paths that contain custom static files (such as style sheets) here, 91 | # relative to this directory. They are copied after the builtin static files, 92 | # so a file named "default.css" will overwrite the builtin "default.css". 93 | html_static_path = ['_static'] 94 | -------------------------------------------------------------------------------- /bvlain/data/covalent_radii.py: -------------------------------------------------------------------------------- 1 | from ase.data import covalent_radii 2 | 3 | # Сovalent radii data sourced from softBV 4 | # Chen, H., Wong, L. L., & Adams, S. (2019). 5 | # SoftBV–a software tool for screening the materials genome of inorganic fast ion conductors. 6 | # Structural Science, 75(1), 18-33 7 | 8 | covalent_radii_softbv = { 9 | 1: {1: 0.37, -1: 1.14}, 10 | 3: {1: 1.31}, 11 | 4: {2: 0.91}, 12 | 5: {3: 0.71, 1: 0.71}, 13 | 6: {4: 0.77, 2: 0.77}, 14 | 7: {5: 0.74, 3: 0.74, -3: 1.39}, 15 | 8: {-2: 1.33, 6: 0.74}, 16 | 9: {-1: 1.26}, 17 | 11: {1: 1.66}, 18 | 12: {2: 1.36}, 19 | 13: {3: 1.11}, 20 | 14: {4: 1.17}, 21 | 15: {5: 1.1, 4: 1.1, 3: 1.1, -3: 1.92}, 22 | 16: {-2: 1.84, 6: 1.04, 4: 1.04}, 23 | 17: {7: 0.99, 5: 0.99, 3: 0.99, -1: 1.74}, 24 | 18: {0: 0.97}, 25 | 19: {1: 2.06}, 26 | 20: {2: 1.66}, 27 | 21: {3: 1.46}, 28 | 22: {4: 1.26, 3: 1.26, 2: 1.26}, 29 | 23: {5: 1.21, 4: 1.21, 3: 1.21, 2: 1.21}, 30 | 24: {6: 1.21, 4: 1.21, 3: 1.21, 2: 1.21, 5: 1.21}, 31 | 25: {7: 1.26, 6: 1.26, 5: 1.26, 4: 1.26, 3: 1.26, 2: 1.26}, 32 | 26: {3: 1.26, 2: 1.26, 4: 1.26}, 33 | 27: {3: 1.21, 4: 1.21, 2: 1.21, 1: 1.21}, 34 | 28: {2: 1.21, 4: 1.21, 3: 1.21}, 35 | 29: {2: 1.21, 3: 1.21, 1: 1.21}, 36 | 30: {2: 1.21}, 37 | 31: {3: 1.16, 1: 1.16}, 38 | 32: {4: 1.22, 2: 1.22}, 39 | 33: {5: 1.21, 3: 1.21, -3: 2.04}, 40 | 34: {6: 1.17, 4: 1.17, -2: 1.91}, 41 | 35: {7: 1.14, 5: 1.14, -1: 1.89}, 42 | 36: {0: 1.1}, 43 | 37: {1: 2.21}, 44 | 38: {2: 1.86}, 45 | 39: {3: 1.66}, 46 | 40: {4: 1.41, 3: 1.41, 2: 1.41}, 47 | 41: {5: 1.31, 4: 1.31, 3: 1.31, 2: 1.31}, 48 | 42: {6: 1.31, 5: 1.31, 4: 1.31, 3: 1.31, 2: 1.31}, 49 | 43: {7: 1.21, 4: 1.21}, 50 | 44: {6: 1.16, 5: 1.16, 4: 1.16, 3: 1.16}, 51 | 45: {4: 1.21, 3: 1.21}, 52 | 46: {2: 1.26, 4: 1.26}, 53 | 47: {1: 1.46, 3: 1.46, 2: 1.46}, 54 | 48: {2: 1.41}, 55 | 49: {3: 1.41, 1: 1.41}, 56 | 50: {4: 1.4, 2: 1.4}, 57 | 51: {5: 1.41, 3: 1.41, -3: 2.31}, 58 | 52: {6: 1.37, 4: 1.37, 2: 1.37, -2: 2.14}, 59 | 53: {7: 1.33, 5: 1.33, -1: 2.13}, 60 | 54: {6: 1.3, 4: 1.3, 2: 1.3}, 61 | 55: {1: 2.46}, 62 | 56: {2: 2.01}, 63 | 57: {3: 1.81}, 64 | 58: {4: 1.71, 3: 1.71}, 65 | 59: {3: 1.71}, 66 | 60: {3: 1.71}, 67 | 62: {3: 1.71}, 68 | 63: {3: 1.71, 2: 1.71}, 69 | 64: {3: 1.66}, 70 | 65: {3: 1.61, 4: 1.61}, 71 | 66: {3: 1.61}, 72 | 67: {3: 1.61}, 73 | 68: {3: 1.61}, 74 | 69: {3: 1.61}, 75 | 70: {3: 1.61, 2: 1.61}, 76 | 71: {3: 1.61}, 77 | 72: {4: 1.41}, 78 | 73: {5: 1.31, 4: 1.31, 3: 1.31, 2: 1.31}, 79 | 74: {6: 1.21, 5: 1.21, 4: 1.21, 3: 1.21, 2: 1.21}, 80 | 75: {7: 1.21, 6: 1.21, 5: 1.21, 4: 1.21, 3: 1.21}, 81 | 76: {8: 1.16, 7: 1.16, 6: 1.16, 5: 1.16, 4: 1.16}, 82 | 77: {5: 1.21, 4: 1.21, 3: 1.21}, 83 | 78: {2: 1.21, 5: 1.21, 4: 1.21, 3: 1.21}, 84 | 79: {3: 1.21, 1: 1.21}, 85 | 80: {2: 1.36, 1: 1.36}, 86 | 81: {3: 1.76, 1: 1.76}, 87 | 82: {4: 1.66, 2: 1.66}, 88 | 83: {5: 1.46, 3: 1.46}, 89 | 90: {4: 1.66}, 90 | 92: {4: 1.61, 6: 1.61} 91 | } 92 | 93 | 94 | def get_covalent_radii(z, oxi_state=None): 95 | """ 96 | Get covalent radii of an element 97 | 98 | Parameters 99 | ---------- 100 | 101 | z: int 102 | atomic number 103 | 104 | oxi_state: int, None by default 105 | valence state of an ion 106 | Note: if None will use ASE data, otherwise softBV data will be used 107 | 108 | Returns 109 | ------- 110 | covalent radii of an element: np.array 111 | meshgrid 112 | """ 113 | if oxi_state: 114 | return covalent_radii_softbv[z][oxi_state] 115 | else: 116 | return covalent_radii[z] -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![BVlain_logo](BVlain_logo.png) 2 | 3 | BVlain is a python library for bond valence site energy calculations. The functionality includes calculation of the 1-3D percolation barrier and radius of a mobile ion (e.g. Li+), calculation of the bond valence sum mismatch, writing of volumetric data files (.grd or .cube) for visualization of a mobile ion diffusion map. 4 | 5 | For more details, see [documentation.](https://bvlain.readthedocs.io/en/latest/index.html) 6 | 7 | ![License](https://img.shields.io/github/license/dembart/bvlain?color=fbf2fe) 8 | ![PyPI Downloads](https://img.shields.io/pypi/dm/BVlain?color=57328a) 9 | 10 | 11 | 12 | ## Installation 13 | 14 | 15 | ```python 16 | pip install bvlain 17 | ``` 18 | 19 | ## Examples 20 | 21 | ##### Percolation barriers 22 | 23 | 24 | ```python 25 | from bvlain import Lain 26 | 27 | file = './Downloads/LiFePO4.cif' 28 | calc = Lain(verbose = False) 29 | atoms = calc.read_file(file) # alternatively, you can use read_atoms() or read_structure() 30 | 31 | params = {'mobile_ion': 'Li1+', # mobile specie 32 | 'r_cut': 10.0, # cutoff for interaction between the mobile species and framework 33 | 'resolution': 0.2, # distance between the grid points 34 | 'k': 100, # maximum number of neighbors to be collected for each point 35 | 'use_softbv_covalent_radii': False # default is False, use True to compare results with softBV 36 | } 37 | _ = calc.bvse_distribution(**params) 38 | energies = calc.percolation_barriers(encut = 5.0) 39 | for key in energies.keys(): 40 | print(f'{key[-2:]} percolation barrier is {round(energies[key], 4)} eV') 41 | ``` 42 | 43 | 1D percolation barrier is 0.4395 eV 44 | 2D percolation barrier is 3.3301 eV 45 | 3D percolation barrier is 3.3594 eV 46 | 47 | 48 | 49 | ##### Save volumetric data for visualization (.grd or .cube) 50 | 51 | 52 | ```python 53 | from bvlain import Lain 54 | 55 | file = './Downloads/LiFePO4.cif' 56 | calc = Lain(verbose = False) 57 | atoms = calc.read_file(file) 58 | 59 | params = {'mobile_ion': 'Li1+', # mobile specie 60 | 'r_cut': 10.0, # cutoff for interaction between the mobile species and framework 61 | 'resolution': 0.2, # distance between the grid points 62 | 'k': 100 # maximum number of neighbors to be collected for each point 63 | } 64 | _ = calc.bvse_distribution(**params) 65 | 66 | calc.write_grd(file + '_bvse', task = 'bvse') # saves .grd file 67 | # calc.write_cube(file + '_bvse', task = 'bvse') # alternatively, save .cube file 68 | ``` 69 | 70 | ##### Percolation radii 71 | 72 | 73 | ```python 74 | from bvlain import Lain 75 | 76 | file = './Downloads/LiFePO4.cif' 77 | calc = Lain(verbose = False) 78 | atoms = calc.read_file(file) 79 | 80 | params = {'mobile_ion': 'Li1+', # mobile specie 81 | 'r_cut': 10.0, # cutoff for interaction between the mobile species and framework 82 | 'resolution': 0.2, # distance between the grid points 83 | } 84 | _ = calc.void_distribution(**params) 85 | radii = calc.percolation_radii() 86 | for key in radii.keys(): 87 | print(f'{key[-2:]} percolation barrier is {round(radii[key], 4)} angstrom') 88 | ``` 89 | 90 | 1D percolation barrier is 0.3943 angstrom 91 | 2D percolation barrier is 0.2957 angstrom 92 | 3D percolation barrier is 0.1972 angstrom 93 | 94 | ```python 95 | calc.write_grd(file + '_void', task = 'void') # # save void distribution 96 | ``` 97 | 98 | ##### Bond valence sum mismatch 99 | 100 | 101 | ```python 102 | from bvlain import Lain 103 | 104 | file = './Downloads/LiFePO4.cif' 105 | calc = Lain(verbose = False) 106 | atoms = calc.read_file(file) 107 | dataframe = calc.mismatch(r_cut = 3.5) 108 | ``` 109 | 110 | 111 | For more examples, see [documentation.](https://bvlain.readthedocs.io/en/latest/index.html) 112 | 113 | The library is under active development and it is not guaranteed that there are no bugs. If you observe not expected results, errors, please report an issue at github. 114 | 115 | 116 | 117 | 118 | -------------------------------------------------------------------------------- /bvlain/data/shannon-radii.json: -------------------------------------------------------------------------------- 1 | {"Ru": {"8": {"IV": {"r_crystal": 0.5, "remark": "", "spin": "", "r_ionic": 0.36}}, "3": {"VI": {"r_crystal": 0.82, "remark": "", "spin": "", "r_ionic": 0.68}}, "5": {"VI": {"r_crystal": 0.705, "remark": "ER", "spin": "", "r_ionic": 0.565}}, "4": {"VI": {"r_crystal": 0.76, "remark": "RM", "spin": "", "r_ionic": 0.62}}, "7": {"IV": {"r_crystal": 0.52, "remark": "", "spin": "", "r_ionic": 0.38}}}, "Re": {"5": {"VI": {"r_crystal": 0.72, "remark": "E", "spin": "", "r_ionic": 0.58}}, "4": {"VI": {"r_crystal": 0.77, "remark": "RM", "spin": "", "r_ionic": 0.63}}, "7": {"VI": {"r_crystal": 0.67, "remark": "", "spin": "", "r_ionic": 0.53}, "IV": {"r_crystal": 0.52, "remark": "", "spin": "", "r_ionic": 0.38}}, "6": {"VI": {"r_crystal": 0.69, "remark": "E", "spin": "", "r_ionic": 0.55}}}, "Ra": {"2": {"XII": {"r_crystal": 1.84, "remark": "R", "spin": "", "r_ionic": 1.7}, "VIII": {"r_crystal": 1.62, "remark": "R", "spin": "", "r_ionic": 1.48}}}, "Rb": {"1": {"IX": {"r_crystal": 1.77, "remark": "E", "spin": "", "r_ionic": 1.63}, "XI": {"r_crystal": 1.83, "remark": "", "spin": "", "r_ionic": 1.69}, "VI": {"r_crystal": 1.66, "remark": "", "spin": "", "r_ionic": 1.52}, "VII": {"r_crystal": 1.7, "remark": "", "spin": "", "r_ionic": 1.56}, "VIII": {"r_crystal": 1.75, "remark": "", "spin": "", "r_ionic": 1.61}, "XIV": {"r_crystal": 1.97, "remark": "", "spin": "", "r_ionic": 1.83}, "XII": {"r_crystal": 1.86, "remark": "", "spin": "", "r_ionic": 1.72}, "X": {"r_crystal": 1.8, "remark": "", "spin": "", "r_ionic": 1.66}}}, "Rh": {"3": {"VI": {"r_crystal": 0.805, "remark": "R", "spin": "", "r_ionic": 0.665}}, "5": {"VI": {"r_crystal": 0.69, "remark": "", "spin": "", "r_ionic": 0.55}}, "4": {"VI": {"r_crystal": 0.74, "remark": "RM", "spin": "", "r_ionic": 0.6}}}, "Be": {"2": {"VI": {"r_crystal": 0.59, "remark": "C", "spin": "", "r_ionic": 0.45}, "III": {"r_crystal": 0.3, "remark": "", "spin": "", "r_ionic": 0.16}, "IV": {"r_crystal": 0.41, "remark": "*", "spin": "", "r_ionic": 0.27}}}, "Ba": {"2": {"IX": {"r_crystal": 1.61, "remark": "", "spin": "", "r_ionic": 1.47}, "XI": {"r_crystal": 1.71, "remark": "", "spin": "", "r_ionic": 1.57}, "VI": {"r_crystal": 1.49, "remark": "", "spin": "", "r_ionic": 1.35}, "VII": {"r_crystal": 1.52, "remark": "C", "spin": "", "r_ionic": 1.38}, "VIII": {"r_crystal": 1.56, "remark": "", "spin": "", "r_ionic": 1.42}, "XII": {"r_crystal": 1.75, "remark": "C", "spin": "", "r_ionic": 1.61}, "X": {"r_crystal": 1.66, "remark": "", "spin": "", "r_ionic": 1.52}}}, "Bi": {"3": {"VI": {"r_crystal": 1.17, "remark": "R*", "spin": "", "r_ionic": 1.03}, "VIII": {"r_crystal": 1.31, "remark": "R", "spin": "", "r_ionic": 1.17}, "V": {"r_crystal": 1.1, "remark": "C", "spin": "", "r_ionic": 0.96}}, "5": {"VI": {"r_crystal": 0.9, "remark": "E", "spin": "", "r_ionic": 0.76}}}, "Bk": {"3": {"VI": {"r_crystal": 1.1, "remark": "R", "spin": "", "r_ionic": 0.96}}, "4": {"VI": {"r_crystal": 0.97, "remark": "R", "spin": "", "r_ionic": 0.83}, "VIII": {"r_crystal": 1.07, "remark": "R", "spin": "", "r_ionic": 0.93}}}, "Br": {"5": {"IIIPY": {"r_crystal": 0.45, "remark": "", "spin": "", "r_ionic": 0.31}}, "3": {"IVSQ": {"r_crystal": 0.73, "remark": "", "spin": "", "r_ionic": 0.59}}, "-1": {"VI": {"r_crystal": 1.82, "remark": "P", "spin": "", "r_ionic": 1.96}}, "7": {"VI": {"r_crystal": 0.53, "remark": "A", "spin": "", "r_ionic": 0.39}, "IV": {"r_crystal": 0.39, "remark": "", "spin": "", "r_ionic": 0.25}}}, "D": {"1": {"II": {"r_crystal": 0.04, "remark": "", "spin": "", "r_ionic": -0.1}}}, "H": {"1": {"I": {"r_crystal": -0.24, "remark": "", "spin": "", "r_ionic": -0.38}, "II": {"r_crystal": -0.04, "remark": "", "spin": "", "r_ionic": -0.18}}}, "P": {"3": {"VI": {"r_crystal": 0.58, "remark": "A", "spin": "", "r_ionic": 0.44}}, "5": {"VI": {"r_crystal": 0.52, "remark": "C", "spin": "", "r_ionic": 0.38}, "V": {"r_crystal": 0.43, "remark": "", "spin": "", "r_ionic": 0.29}, "IV": {"r_crystal": 0.31, "remark": "*", "spin": "", "r_ionic": 0.17}}}, "Os": {"8": {"IV": {"r_crystal": 0.53, "remark": "", "spin": "", "r_ionic": 0.39}}, "5": {"VI": {"r_crystal": 0.715, "remark": "E", "spin": "", "r_ionic": 0.575}}, "4": {"VI": {"r_crystal": 0.77, "remark": "RM", "spin": "", "r_ionic": 0.63}}, "7": {"VI": {"r_crystal": 0.665, "remark": "E", "spin": "", "r_ionic": 0.525}}, "6": {"VI": {"r_crystal": 0.685, "remark": "E", "spin": "", "r_ionic": 0.545}, "V": {"r_crystal": 0.63, "remark": "", "spin": "", "r_ionic": 0.49}}}, "OH": {"-1": {"II": {"r_crystal": 1.18, "remark": "", "spin": "", "r_ionic": 1.32}, "VI": {"r_crystal": 1.23, "remark": "E", "spin": "", "r_ionic": 1.37}, "III": {"r_crystal": 1.2, "remark": "", "spin": "", "r_ionic": 1.34}, "IV": {"r_crystal": 1.21, "remark": "E", "spin": "", "r_ionic": 1.35}}}, "Ge": {"2": {"VI": {"r_crystal": 0.87, "remark": "A", "spin": "", "r_ionic": 0.73}}, "4": {"VI": {"r_crystal": 0.67, "remark": "R*", "spin": "", "r_ionic": 0.53}, "IV": {"r_crystal": 0.53, "remark": "*", "spin": "", "r_ionic": 0.39}}}, "Gd": {"3": {"VI": {"r_crystal": 1.078, "remark": "R", "spin": "", "r_ionic": 0.938}, "VII": {"r_crystal": 1.14, "remark": "", "spin": "", "r_ionic": 1}, "VIII": {"r_crystal": 1.193, "remark": "R", "spin": "", "r_ionic": 1.053}, "IX": {"r_crystal": 1.247, "remark": "RC", "spin": "", "r_ionic": 1.107}}}, "Ga": {"3": {"VI": {"r_crystal": 0.76, "remark": "R*", "spin": "", "r_ionic": 0.62}, "V": {"r_crystal": 0.69, "remark": "", "spin": "", "r_ionic": 0.55}, "IV": {"r_crystal": 0.61, "remark": "*", "spin": "", "r_ionic": 0.47}}}, "Pr": {"3": {"VI": {"r_crystal": 1.13, "remark": "R", "spin": "", "r_ionic": 0.99}, "VIII": {"r_crystal": 1.266, "remark": "R", "spin": "", "r_ionic": 1.126}, "IX": {"r_crystal": 1.319, "remark": "R", "spin": "", "r_ionic": 1.179}}, "4": {"VI": {"r_crystal": 0.99, "remark": "R", "spin": "", "r_ionic": 0.85}, "VIII": {"r_crystal": 1.1, "remark": "R", "spin": "", "r_ionic": 0.96}}}, "Pt": {"2": {"IVSQ": {"r_crystal": 0.74, "remark": "", "spin": "", "r_ionic": 0.6}, "VI": {"r_crystal": 0.94, "remark": "A", "spin": "", "r_ionic": 0.8}}, "5": {"VI": {"r_crystal": 0.71, "remark": "ER", "spin": "", "r_ionic": 0.57}}, "4": {"VI": {"r_crystal": 0.765, "remark": "R", "spin": "", "r_ionic": 0.625}}}, "Pu": {"3": {"VI": {"r_crystal": 1.14, "remark": "R", "spin": "", "r_ionic": 1}}, "5": {"VI": {"r_crystal": 0.88, "remark": "E", "spin": "", "r_ionic": 0.74}}, "4": {"VI": {"r_crystal": 1, "remark": "R", "spin": "", "r_ionic": 0.86}, "VIII": {"r_crystal": 1.1, "remark": "", "spin": "", "r_ionic": 0.96}}, "6": {"VI": {"r_crystal": 0.85, "remark": "R", "spin": "", "r_ionic": 0.71}}}, "C": {"4": {"VI": {"r_crystal": 0.3, "remark": "A", "spin": "", "r_ionic": 0.16}, "III": {"r_crystal": 0.06, "remark": "", "spin": "", "r_ionic": -0.08}, "IV": {"r_crystal": 0.29, "remark": "P", "spin": "", "r_ionic": 0.15}}}, "Pb": {"2": {"IX": {"r_crystal": 1.49, "remark": "C", "spin": "", "r_ionic": 1.35}, "XI": {"r_crystal": 1.59, "remark": "C", "spin": "", "r_ionic": 1.45}, "VI": {"r_crystal": 1.33, "remark": "", "spin": "", "r_ionic": 1.19}, "VII": {"r_crystal": 1.37, "remark": "C", "spin": "", "r_ionic": 1.23}, "VIII": {"r_crystal": 1.43, "remark": "C", "spin": "", "r_ionic": 1.29}, "XII": {"r_crystal": 1.63, "remark": "", "spin": "", "r_ionic": 1.49}, "IVPY": {"r_crystal": 1.12, "remark": "C", "spin": "", "r_ionic": 0.98}, "X": {"r_crystal": 1.54, "remark": "C", "spin": "", "r_ionic": 1.4}}, "4": {"VI": {"r_crystal": 0.915, "remark": "R", "spin": "", "r_ionic": 0.775}, "V": {"r_crystal": 0.87, "remark": "E", "spin": "", "r_ionic": 0.73}, "VIII": {"r_crystal": 1.08, "remark": "R", "spin": "", "r_ionic": 0.94}, "IV": {"r_crystal": 0.79, "remark": "E", "spin": "", "r_ionic": 0.65}}}, "Pa": {"3": {"VI": {"r_crystal": 1.18, "remark": "E", "spin": "", "r_ionic": 1.04}}, "5": {"VI": {"r_crystal": 0.92, "remark": "", "spin": "", "r_ionic": 0.78}, "VIII": {"r_crystal": 1.05, "remark": "", "spin": "", "r_ionic": 0.91}, "IX": {"r_crystal": 1.09, "remark": "", "spin": "", "r_ionic": 0.95}}, "4": {"VI": {"r_crystal": 1.04, "remark": "R", "spin": "", "r_ionic": 0.9}, "VIII": {"r_crystal": 1.15, "remark": "", "spin": "", "r_ionic": 1.01}}}, "Pd": {"1": {"II": {"r_crystal": 0.73, "remark": "", "spin": "", "r_ionic": 0.59}}, "3": {"VI": {"r_crystal": 0.9, "remark": "", "spin": "", "r_ionic": 0.76}}, "2": {"IVSQ": {"r_crystal": 0.78, "remark": "", "spin": "", "r_ionic": 0.64}, "VI": {"r_crystal": 1, "remark": "", "spin": "", "r_ionic": 0.86}}, "4": {"VI": {"r_crystal": 0.755, "remark": "R", "spin": "", "r_ionic": 0.615}}}, "Xe": {"8": {"VI": {"r_crystal": 0.62, "remark": "", "spin": "", "r_ionic": 0.48}, "IV": {"r_crystal": 0.54, "remark": "", "spin": "", "r_ionic": 0.4}}}, "Po": {"4": {"VI": {"r_crystal": 1.08, "remark": "R", "spin": "", "r_ionic": 0.94}, "VIII": {"r_crystal": 1.22, "remark": "R", "spin": "", "r_ionic": 1.08}}, "6": {"VI": {"r_crystal": 0.81, "remark": "A", "spin": "", "r_ionic": 0.67}}}, "Pm": {"3": {"VI": {"r_crystal": 1.11, "remark": "R", "spin": "", "r_ionic": 0.97}, "VIII": {"r_crystal": 1.233, "remark": "R", "spin": "", "r_ionic": 1.093}, "IX": {"r_crystal": 1.284, "remark": "R", "spin": "", "r_ionic": 1.144}}}, "Ho": {"3": {"VI": {"r_crystal": 1.041, "remark": "R", "spin": "", "r_ionic": 0.901}, "VIII": {"r_crystal": 1.155, "remark": "R", "spin": "", "r_ionic": 1.015}, "X": {"r_crystal": 1.26, "remark": "", "spin": "", "r_ionic": 1.12}, "IX": {"r_crystal": 1.212, "remark": "R", "spin": "", "r_ionic": 1.072}}}, "Hf": {"4": {"VI": {"r_crystal": 0.85, "remark": "R", "spin": "", "r_ionic": 0.71}, "VII": {"r_crystal": 0.9, "remark": "", "spin": "", "r_ionic": 0.76}, "VIII": {"r_crystal": 0.97, "remark": "", "spin": "", "r_ionic": 0.83}, "IV": {"r_crystal": 0.72, "remark": "R", "spin": "", "r_ionic": 0.58}}}, "Hg": {"1": {"VI": {"r_crystal": 1.33, "remark": "", "spin": "", "r_ionic": 1.19}, "III": {"r_crystal": 1.11, "remark": "", "spin": "", "r_ionic": 0.97}}, "2": {"II": {"r_crystal": 0.83, "remark": "", "spin": "", "r_ionic": 0.69}, "VI": {"r_crystal": 1.16, "remark": "", "spin": "", "r_ionic": 1.02}, "VIII": {"r_crystal": 1.28, "remark": "R", "spin": "", "r_ionic": 1.14}, "IV": {"r_crystal": 1.1, "remark": "", "spin": "", "r_ionic": 0.96}}}, "Mg": {"2": {"VI": {"r_crystal": 0.86, "remark": "*", "spin": "", "r_ionic": 0.72}, "V": {"r_crystal": 0.8, "remark": "", "spin": "", "r_ionic": 0.66}, "VIII": {"r_crystal": 1.03, "remark": "C", "spin": "", "r_ionic": 0.89}, "IV": {"r_crystal": 0.71, "remark": "", "spin": "", "r_ionic": 0.57}}}, "K": {"1": {"IX": {"r_crystal": 1.69, "remark": "", "spin": "", "r_ionic": 1.55}, "VI": {"r_crystal": 1.52, "remark": "", "spin": "", "r_ionic": 1.38}, "VII": {"r_crystal": 1.6, "remark": "", "spin": "", "r_ionic": 1.46}, "IV": {"r_crystal": 1.51, "remark": "", "spin": "", "r_ionic": 1.37}, "VIII": {"r_crystal": 1.65, "remark": "", "spin": "", "r_ionic": 1.51}, "XII": {"r_crystal": 1.78, "remark": "", "spin": "", "r_ionic": 1.64}, "X": {"r_crystal": 1.73, "remark": "", "spin": "", "r_ionic": 1.59}}}, "Mn": {"3": {"": {"r_crystal": 0.72, "remark": "R", "spin": "Low Spin", "r_ionic": 0.58}, "VI": {"r_crystal": 0.785, "remark": "R*", "spin": "High Spin", "r_ionic": 0.645}, "V": {"r_crystal": 0.72, "remark": "", "spin": "", "r_ionic": 0.58}}, "2": {"": {"r_crystal": 0.97, "remark": "R*", "spin": "High Spin", "r_ionic": 0.83}, "VI": {"r_crystal": 0.81, "remark": "E", "spin": "Low Spin", "r_ionic": 0.67}, "VII": {"r_crystal": 1.04, "remark": "C", "spin": "High Spin", "r_ionic": 0.9}, "IV": {"r_crystal": 0.8, "remark": "", "spin": "High Spin", "r_ionic": 0.66}, "VIII": {"r_crystal": 1.1, "remark": "R", "spin": "", "r_ionic": 0.96}, "V": {"r_crystal": 0.89, "remark": "C", "spin": "High Spin", "r_ionic": 0.75}}, "5": {"IV": {"r_crystal": 0.47, "remark": "R", "spin": "", "r_ionic": 0.33}}, "4": {"VI": {"r_crystal": 0.67, "remark": "R*", "spin": "", "r_ionic": 0.53}, "IV": {"r_crystal": 0.53, "remark": "R", "spin": "", "r_ionic": 0.39}}, "7": {"VI": {"r_crystal": 0.6, "remark": "A", "spin": "", "r_ionic": 0.46}, "IV": {"r_crystal": 0.39, "remark": "", "spin": "", "r_ionic": 0.25}}, "6": {"IV": {"r_crystal": 0.395, "remark": "", "spin": "", "r_ionic": 0.255}}}, "O": {"-2": {"II": {"r_crystal": 1.21, "remark": "", "spin": "", "r_ionic": 1.35}, "VI": {"r_crystal": 1.26, "remark": "", "spin": "", "r_ionic": 1.4}, "III": {"r_crystal": 1.22, "remark": "", "spin": "", "r_ionic": 1.36}, "VIII": {"r_crystal": 1.28, "remark": "", "spin": "", "r_ionic": 1.42}, "IV": {"r_crystal": 1.24, "remark": "", "spin": "", "r_ionic": 1.38}}}, "S": {"6": {"VI": {"r_crystal": 0.43, "remark": "C", "spin": "", "r_ionic": 0.29}, "IV": {"r_crystal": 0.26, "remark": "*", "spin": "", "r_ionic": 0.12}}, "4": {"VI": {"r_crystal": 0.51, "remark": "A", "spin": "", "r_ionic": 0.37}}, "-2": {"VI": {"r_crystal": 1.7, "remark": "P", "spin": "", "r_ionic": 1.84}}}, "W": {"5": {"VI": {"r_crystal": 0.76, "remark": "R", "spin": "", "r_ionic": 0.62}}, "4": {"VI": {"r_crystal": 0.8, "remark": "RM", "spin": "", "r_ionic": 0.66}}, "6": {"VI": {"r_crystal": 0.74, "remark": "*", "spin": "", "r_ionic": 0.6}, "V": {"r_crystal": 0.65, "remark": "", "spin": "", "r_ionic": 0.51}, "IV": {"r_crystal": 0.56, "remark": "*", "spin": "", "r_ionic": 0.42}}}, "Zn": {"2": {"VI": {"r_crystal": 0.88, "remark": "R*", "spin": "", "r_ionic": 0.74}, "V": {"r_crystal": 0.82, "remark": "*", "spin": "", "r_ionic": 0.68}, "VIII": {"r_crystal": 1.04, "remark": "C", "spin": "", "r_ionic": 0.9}, "IV": {"r_crystal": 0.74, "remark": "*", "spin": "", "r_ionic": 0.6}}}, "Eu": {"3": {"VI": {"r_crystal": 1.087, "remark": "R", "spin": "", "r_ionic": 0.947}, "VII": {"r_crystal": 1.15, "remark": "", "spin": "", "r_ionic": 1.01}, "VIII": {"r_crystal": 1.206, "remark": "R", "spin": "", "r_ionic": 1.066}, "IX": {"r_crystal": 1.26, "remark": "R", "spin": "", "r_ionic": 1.12}}, "2": {"VI": {"r_crystal": 1.31, "remark": "", "spin": "", "r_ionic": 1.17}, "VII": {"r_crystal": 1.34, "remark": "", "spin": "", "r_ionic": 1.2}, "VIII": {"r_crystal": 1.39, "remark": "", "spin": "", "r_ionic": 1.25}, "X": {"r_crystal": 1.49, "remark": "", "spin": "", "r_ionic": 1.35}, "IX": {"r_crystal": 1.44, "remark": "", "spin": "", "r_ionic": 1.3}}}, "Zr": {"4": {"IX": {"r_crystal": 1.03, "remark": "", "spin": "", "r_ionic": 0.89}, "VI": {"r_crystal": 0.86, "remark": "R*", "spin": "", "r_ionic": 0.72}, "VII": {"r_crystal": 0.92, "remark": "*", "spin": "", "r_ionic": 0.78}, "IV": {"r_crystal": 0.73, "remark": "R", "spin": "", "r_ionic": 0.59}, "VIII": {"r_crystal": 0.98, "remark": "*", "spin": "", "r_ionic": 0.84}, "V": {"r_crystal": 0.8, "remark": "C", "spin": "", "r_ionic": 0.66}}}, "Er": {"3": {"VI": {"r_crystal": 1.03, "remark": "R", "spin": "", "r_ionic": 0.89}, "VII": {"r_crystal": 1.085, "remark": "", "spin": "", "r_ionic": 0.945}, "VIII": {"r_crystal": 1.144, "remark": "R", "spin": "", "r_ionic": 1.004}, "IX": {"r_crystal": 1.202, "remark": "R", "spin": "", "r_ionic": 1.062}}}, "Ni": {"3": {"": {"r_crystal": 0.74, "remark": "E", "spin": "High Spin", "r_ionic": 0.6}, "VI": {"r_crystal": 0.7, "remark": "R*", "spin": "Low Spin", "r_ionic": 0.56}}, "2": {"IVSQ": {"r_crystal": 0.63, "remark": "", "spin": "", "r_ionic": 0.49}, "VI": {"r_crystal": 0.83, "remark": "R*", "spin": "", "r_ionic": 0.69}, "V": {"r_crystal": 0.77, "remark": "E", "spin": "", "r_ionic": 0.63}, "IV": {"r_crystal": 0.69, "remark": "", "spin": "", "r_ionic": 0.55}}, "4": {"VI": {"r_crystal": 0.62, "remark": "R", "spin": "Low Spin", "r_ionic": 0.48}}}, "No": {"2": {"VI": {"r_crystal": 1.24, "remark": "E", "spin": "", "r_ionic": 1.1}}}, "Na": {"1": {"IX": {"r_crystal": 1.38, "remark": "C", "spin": "", "r_ionic": 1.24}, "VI": {"r_crystal": 1.16, "remark": "", "spin": "", "r_ionic": 1.02}, "VII": {"r_crystal": 1.26, "remark": "", "spin": "", "r_ionic": 1.12}, "IV": {"r_crystal": 1.13, "remark": "", "spin": "", "r_ionic": 0.99}, "VIII": {"r_crystal": 1.32, "remark": "", "spin": "", "r_ionic": 1.18}, "XII": {"r_crystal": 1.53, "remark": "", "spin": "", "r_ionic": 1.39}, "V": {"r_crystal": 1.14, "remark": "", "spin": "", "r_ionic": 1}}}, "Nb": {"3": {"VI": {"r_crystal": 0.86, "remark": "", "spin": "", "r_ionic": 0.72}}, "5": {"VI": {"r_crystal": 0.78, "remark": "", "spin": "", "r_ionic": 0.64}, "VII": {"r_crystal": 0.83, "remark": "C", "spin": "", "r_ionic": 0.69}, "VIII": {"r_crystal": 0.88, "remark": "", "spin": "", "r_ionic": 0.74}, "IV": {"r_crystal": 0.62, "remark": "C", "spin": "", "r_ionic": 0.48}}, "4": {"VI": {"r_crystal": 0.82, "remark": "RE", "spin": "", "r_ionic": 0.68}, "VIII": {"r_crystal": 0.93, "remark": "", "spin": "", "r_ionic": 0.79}}}, "Nd": {"3": {"VI": {"r_crystal": 1.123, "remark": "R", "spin": "", "r_ionic": 0.983}, "VIII": {"r_crystal": 1.249, "remark": "R*", "spin": "", "r_ionic": 1.109}, "XII": {"r_crystal": 1.41, "remark": "E", "spin": "", "r_ionic": 1.27}, "IX": {"r_crystal": 1.303, "remark": "R", "spin": "", "r_ionic": 1.163}}, "2": {"IX": {"r_crystal": 1.49, "remark": "", "spin": "", "r_ionic": 1.35}, "VIII": {"r_crystal": 1.43, "remark": "", "spin": "", "r_ionic": 1.29}}}, "Np": {"3": {"VI": {"r_crystal": 1.15, "remark": "R", "spin": "", "r_ionic": 1.01}}, "2": {"VI": {"r_crystal": 1.24, "remark": "", "spin": "", "r_ionic": 1.1}}, "5": {"VI": {"r_crystal": 0.89, "remark": "", "spin": "", "r_ionic": 0.75}}, "4": {"VI": {"r_crystal": 1.01, "remark": "R", "spin": "", "r_ionic": 0.87}, "VIII": {"r_crystal": 1.12, "remark": "R", "spin": "", "r_ionic": 0.98}}, "7": {"VI": {"r_crystal": 0.85, "remark": "A", "spin": "", "r_ionic": 0.71}}, "6": {"VI": {"r_crystal": 0.86, "remark": "R", "spin": "", "r_ionic": 0.72}}}, "Fr": {"1": {"VI": {"r_crystal": 1.94, "remark": "A", "spin": "", "r_ionic": 1.8}}}, "Fe": {"3": {"": {"r_crystal": 0.785, "remark": "R*", "spin": "High Spin", "r_ionic": 0.645}, "VI": {"r_crystal": 0.69, "remark": "R", "spin": "Low Spin", "r_ionic": 0.55}, "V": {"r_crystal": 0.72, "remark": "", "spin": "", "r_ionic": 0.58}, "VIII": {"r_crystal": 0.92, "remark": "", "spin": "High Spin", "r_ionic": 0.78}, "IV": {"r_crystal": 0.63, "remark": "*", "spin": "High Spin", "r_ionic": 0.49}}, "2": {"": {"r_crystal": 0.92, "remark": "R*", "spin": "High Spin", "r_ionic": 0.78}, "IVSQ": {"r_crystal": 0.78, "remark": "", "spin": "High Spin", "r_ionic": 0.64}, "VI": {"r_crystal": 0.75, "remark": "E", "spin": "Low Spin", "r_ionic": 0.61}, "VIII": {"r_crystal": 1.06, "remark": "C", "spin": "High Spin", "r_ionic": 0.92}, "IV": {"r_crystal": 0.77, "remark": "", "spin": "High Spin", "r_ionic": 0.63}}, "4": {"VI": {"r_crystal": 0.725, "remark": "R", "spin": "", "r_ionic": 0.585}}, "6": {"IV": {"r_crystal": 0.39, "remark": "R", "spin": "", "r_ionic": 0.25}}}, "B": {"3": {"VI": {"r_crystal": 0.41, "remark": "C", "spin": "", "r_ionic": 0.27}, "III": {"r_crystal": 0.15, "remark": "*", "spin": "", "r_ionic": 0.01}, "IV": {"r_crystal": 0.25, "remark": "*", "spin": "", "r_ionic": 0.11}}}, "F": {"-1": {"II": {"r_crystal": 1.145, "remark": "", "spin": "", "r_ionic": 1.285}, "VI": {"r_crystal": 1.19, "remark": "", "spin": "", "r_ionic": 1.33}, "III": {"r_crystal": 1.16, "remark": "", "spin": "", "r_ionic": 1.3}, "IV": {"r_crystal": 1.17, "remark": "", "spin": "", "r_ionic": 1.31}}, "7": {"VI": {"r_crystal": 0.22, "remark": "A", "spin": "", "r_ionic": 0.08}}}, "Sr": {"2": {"IX": {"r_crystal": 1.45, "remark": "", "spin": "", "r_ionic": 1.31}, "VI": {"r_crystal": 1.32, "remark": "", "spin": "", "r_ionic": 1.18}, "VII": {"r_crystal": 1.35, "remark": "", "spin": "", "r_ionic": 1.21}, "VIII": {"r_crystal": 1.4, "remark": "", "spin": "", "r_ionic": 1.26}, "XII": {"r_crystal": 1.58, "remark": "C", "spin": "", "r_ionic": 1.44}, "X": {"r_crystal": 1.5, "remark": "C", "spin": "", "r_ionic": 1.36}}}, "N": {"3": {"VI": {"r_crystal": 0.3, "remark": "A", "spin": "", "r_ionic": 0.16}}, "5": {"VI": {"r_crystal": 0.27, "remark": "A", "spin": "", "r_ionic": 0.13}, "III": {"r_crystal": 0.044, "remark": "", "spin": "", "r_ionic": -0.104}}, "-3": {"IV": {"r_crystal": 1.32, "remark": "", "spin": "", "r_ionic": 1.46}}}, "Si": {"4": {"VI": {"r_crystal": 0.54, "remark": "R*", "spin": "", "r_ionic": 0.4}, "IV": {"r_crystal": 0.4, "remark": "*", "spin": "", "r_ionic": 0.26}}}, "Sn": {"4": {"VI": {"r_crystal": 0.83, "remark": "R*", "spin": "", "r_ionic": 0.69}, "V": {"r_crystal": 0.76, "remark": "C", "spin": "", "r_ionic": 0.62}, "VIII": {"r_crystal": 0.95, "remark": "C", "spin": "", "r_ionic": 0.81}, "VII": {"r_crystal": 0.89, "remark": "", "spin": "", "r_ionic": 0.75}, "IV": {"r_crystal": 0.69, "remark": "R", "spin": "", "r_ionic": 0.55}}}, "Sm": {"3": {"VI": {"r_crystal": 1.098, "remark": "R", "spin": "", "r_ionic": 0.958}, "VII": {"r_crystal": 1.16, "remark": "E", "spin": "", "r_ionic": 1.02}, "VIII": {"r_crystal": 1.219, "remark": "R", "spin": "", "r_ionic": 1.079}, "XII": {"r_crystal": 1.38, "remark": "C", "spin": "", "r_ionic": 1.24}, "IX": {"r_crystal": 1.272, "remark": "R", "spin": "", "r_ionic": 1.132}}, "2": {"IX": {"r_crystal": 1.46, "remark": "", "spin": "", "r_ionic": 1.32}, "VII": {"r_crystal": 1.36, "remark": "", "spin": "", "r_ionic": 1.22}, "VIII": {"r_crystal": 1.41, "remark": "", "spin": "", "r_ionic": 1.27}}}, "V": {"3": {"VI": {"r_crystal": 0.78, "remark": "R*", "spin": "", "r_ionic": 0.64}}, "2": {"VI": {"r_crystal": 0.93, "remark": "", "spin": "", "r_ionic": 0.79}}, "5": {"VI": {"r_crystal": 0.68, "remark": "", "spin": "", "r_ionic": 0.54}, "V": {"r_crystal": 0.6, "remark": "*", "spin": "", "r_ionic": 0.46}, "IV": {"r_crystal": 0.495, "remark": "R*", "spin": "", "r_ionic": 0.355}}, "4": {"VI": {"r_crystal": 0.72, "remark": "R*", "spin": "", "r_ionic": 0.58}, "VIII": {"r_crystal": 0.86, "remark": "E", "spin": "", "r_ionic": 0.72}, "V": {"r_crystal": 0.67, "remark": "", "spin": "", "r_ionic": 0.53}}}, "Sc": {"3": {"VI": {"r_crystal": 0.885, "remark": "R*", "spin": "", "r_ionic": 0.745}, "VIII": {"r_crystal": 1.01, "remark": "R*", "spin": "", "r_ionic": 0.87}}}, "Sb": {"3": {"IVPY": {"r_crystal": 0.9, "remark": "", "spin": "", "r_ionic": 0.76}, "VI": {"r_crystal": 0.9, "remark": "A", "spin": "", "r_ionic": 0.76}, "V": {"r_crystal": 0.94, "remark": "", "spin": "", "r_ionic": 0.8}}, "5": {"VI": {"r_crystal": 0.74, "remark": "*", "spin": "", "r_ionic": 0.6}}}, "Se": {"6": {"VI": {"r_crystal": 0.56, "remark": "C", "spin": "", "r_ionic": 0.42}, "IV": {"r_crystal": 0.42, "remark": "*", "spin": "", "r_ionic": 0.28}}, "4": {"VI": {"r_crystal": 0.64, "remark": "A", "spin": "", "r_ionic": 0.5}}, "-2": {"VI": {"r_crystal": 1.84, "remark": "P", "spin": "", "r_ionic": 1.98}}}, "Co": {"3": {"": {"r_crystal": 0.685, "remark": "R*", "spin": "Low Spin", "r_ionic": 0.545}, "VI": {"r_crystal": 0.75, "remark": "", "spin": "High Spin", "r_ionic": 0.61}}, "2": {"": {"r_crystal": 0.885, "remark": "R*", "spin": "High Spin", "r_ionic": 0.745}, "VI": {"r_crystal": 0.79, "remark": "R", "spin": "Low Spin", "r_ionic": 0.65}, "V": {"r_crystal": 0.81, "remark": "C", "spin": "", "r_ionic": 0.67}, "VIII": {"r_crystal": 1.04, "remark": "", "spin": "", "r_ionic": 0.9}, "IV": {"r_crystal": 0.72, "remark": "", "spin": "High Spin", "r_ionic": 0.58}}, "4": {"VI": {"r_crystal": 0.67, "remark": "R", "spin": "High Spin", "r_ionic": 0.53}, "IV": {"r_crystal": 0.54, "remark": "", "spin": "", "r_ionic": 0.4}}}, "Cm": {"3": {"VI": {"r_crystal": 1.11, "remark": "R", "spin": "", "r_ionic": 0.97}}, "4": {"VI": {"r_crystal": 0.99, "remark": "R", "spin": "", "r_ionic": 0.85}, "VIII": {"r_crystal": 1.09, "remark": "R", "spin": "", "r_ionic": 0.95}}}, "Cl": {"5": {"IIIPY": {"r_crystal": 0.26, "remark": "", "spin": "", "r_ionic": 0.12}}, "-1": {"VI": {"r_crystal": 1.67, "remark": "P", "spin": "", "r_ionic": 1.81}}, "7": {"VI": {"r_crystal": 0.41, "remark": "A", "spin": "", "r_ionic": 0.27}, "IV": {"r_crystal": 0.22, "remark": "*", "spin": "", "r_ionic": 0.08}}}, "Ca": {"2": {"IX": {"r_crystal": 1.32, "remark": "", "spin": "", "r_ionic": 1.18}, "VI": {"r_crystal": 1.14, "remark": "", "spin": "", "r_ionic": 1}, "VII": {"r_crystal": 1.2, "remark": "*", "spin": "", "r_ionic": 1.06}, "VIII": {"r_crystal": 1.26, "remark": "*", "spin": "", "r_ionic": 1.12}, "XII": {"r_crystal": 1.48, "remark": "C", "spin": "", "r_ionic": 1.34}, "X": {"r_crystal": 1.37, "remark": "C", "spin": "", "r_ionic": 1.23}}}, "Cf": {"3": {"VI": {"r_crystal": 1.09, "remark": "R", "spin": "", "r_ionic": 0.95}}, "4": {"VI": {"r_crystal": 0.961, "remark": "R", "spin": "", "r_ionic": 0.821}, "VIII": {"r_crystal": 1.06, "remark": "", "spin": "", "r_ionic": 0.92}}}, "Ce": {"3": {"IX": {"r_crystal": 1.336, "remark": "R", "spin": "", "r_ionic": 1.196}, "VI": {"r_crystal": 1.15, "remark": "R", "spin": "", "r_ionic": 1.01}, "VII": {"r_crystal": 1.21, "remark": "E", "spin": "", "r_ionic": 1.07}, "VIII": {"r_crystal": 1.283, "remark": "R", "spin": "", "r_ionic": 1.143}, "XII": {"r_crystal": 1.48, "remark": "C", "spin": "", "r_ionic": 1.34}, "X": {"r_crystal": 1.39, "remark": "", "spin": "", "r_ionic": 1.25}}, "4": {"VI": {"r_crystal": 1.01, "remark": "R", "spin": "", "r_ionic": 0.87}, "VIII": {"r_crystal": 1.11, "remark": "R", "spin": "", "r_ionic": 0.97}, "XII": {"r_crystal": 1.28, "remark": "", "spin": "", "r_ionic": 1.14}, "X": {"r_crystal": 1.21, "remark": "", "spin": "", "r_ionic": 1.07}}}, "Cd": {"2": {"VII": {"r_crystal": 1.17, "remark": "C", "spin": "", "r_ionic": 1.03}, "VI": {"r_crystal": 1.09, "remark": "", "spin": "", "r_ionic": 0.95}, "V": {"r_crystal": 1.01, "remark": "", "spin": "", "r_ionic": 0.87}, "IV": {"r_crystal": 0.92, "remark": "", "spin": "", "r_ionic": 0.78}, "VIII": {"r_crystal": 1.24, "remark": "C", "spin": "", "r_ionic": 1.1}, "XII": {"r_crystal": 1.45, "remark": "", "spin": "", "r_ionic": 1.31}}}, "Tm": {"3": {"VI": {"r_crystal": 1.02, "remark": "R", "spin": "", "r_ionic": 0.88}, "VIII": {"r_crystal": 1.134, "remark": "R", "spin": "", "r_ionic": 0.994}, "IX": {"r_crystal": 1.192, "remark": "R", "spin": "", "r_ionic": 1.052}}, "2": {"VI": {"r_crystal": 1.17, "remark": "", "spin": "", "r_ionic": 1.03}, "VII": {"r_crystal": 1.23, "remark": "", "spin": "", "r_ionic": 1.09}}}, "Cs": {"1": {"IX": {"r_crystal": 1.92, "remark": "", "spin": "", "r_ionic": 1.78}, "XI": {"r_crystal": 1.99, "remark": "", "spin": "", "r_ionic": 1.85}, "VI": {"r_crystal": 1.81, "remark": "", "spin": "", "r_ionic": 1.67}, "VIII": {"r_crystal": 1.88, "remark": "", "spin": "", "r_ionic": 1.74}, "XII": {"r_crystal": 2.02, "remark": "", "spin": "", "r_ionic": 1.88}, "X": {"r_crystal": 1.95, "remark": "", "spin": "", "r_ionic": 1.81}}}, "Cr": {"3": {"VI": {"r_crystal": 0.755, "remark": "R*", "spin": "", "r_ionic": 0.615}}, "2": {"": {"r_crystal": 0.94, "remark": "R*", "spin": "High Spin", "r_ionic": 0.8}, "VI": {"r_crystal": 0.87, "remark": "E", "spin": "Low Spin", "r_ionic": 0.73}}, "5": {"VI": {"r_crystal": 0.63, "remark": "ER", "spin": "", "r_ionic": 0.49}, "VIII": {"r_crystal": 0.71, "remark": "", "spin": "", "r_ionic": 0.57}, "IV": {"r_crystal": 0.485, "remark": "R", "spin": "", "r_ionic": 0.345}}, "4": {"VI": {"r_crystal": 0.69, "remark": "R", "spin": "", "r_ionic": 0.55}, "IV": {"r_crystal": 0.55, "remark": "", "spin": "", "r_ionic": 0.41}}, "6": {"VI": {"r_crystal": 0.58, "remark": "C", "spin": "", "r_ionic": 0.44}, "IV": {"r_crystal": 0.4, "remark": "", "spin": "", "r_ionic": 0.26}}}, "Cu": {"1": {"II": {"r_crystal": 0.6, "remark": "", "spin": "", "r_ionic": 0.46}, "VI": {"r_crystal": 0.91, "remark": "E", "spin": "", "r_ionic": 0.77}, "IV": {"r_crystal": 0.74, "remark": "E", "spin": "", "r_ionic": 0.6}}, "3": {"VI": {"r_crystal": 0.68, "remark": "", "spin": "Low Spin", "r_ionic": 0.54}}, "2": {"IVSQ": {"r_crystal": 0.71, "remark": "*", "spin": "", "r_ionic": 0.57}, "VI": {"r_crystal": 0.87, "remark": "", "spin": "", "r_ionic": 0.73}, "V": {"r_crystal": 0.79, "remark": "*", "spin": "", "r_ionic": 0.65}, "IV": {"r_crystal": 0.71, "remark": "", "spin": "", "r_ionic": 0.57}}}, "La": {"3": {"IX": {"r_crystal": 1.356, "remark": "R", "spin": "", "r_ionic": 1.216}, "VI": {"r_crystal": 1.172, "remark": "R", "spin": "", "r_ionic": 1.032}, "VII": {"r_crystal": 1.24, "remark": "", "spin": "", "r_ionic": 1.1}, "VIII": {"r_crystal": 1.3, "remark": "R", "spin": "", "r_ionic": 1.16}, "XII": {"r_crystal": 1.5, "remark": "C", "spin": "", "r_ionic": 1.36}, "X": {"r_crystal": 1.41, "remark": "", "spin": "", "r_ionic": 1.27}}}, "Li": {"1": {"VI": {"r_crystal": 0.9, "remark": "*", "spin": "", "r_ionic": 0.76}, "VIII": {"r_crystal": 1.06, "remark": "C", "spin": "", "r_ionic": 0.92}, "IV": {"r_crystal": 0.73, "remark": "*", "spin": "", "r_ionic": 0.59}}}, "Tl": {"1": {"VI": {"r_crystal": 1.64, "remark": "R", "spin": "", "r_ionic": 1.5}, "VIII": {"r_crystal": 1.73, "remark": "R", "spin": "", "r_ionic": 1.59}, "XII": {"r_crystal": 1.84, "remark": "RE", "spin": "", "r_ionic": 1.7}}, "3": {"VI": {"r_crystal": 1.025, "remark": "R", "spin": "", "r_ionic": 0.885}, "VIII": {"r_crystal": 1.12, "remark": "C", "spin": "", "r_ionic": 0.98}, "IV": {"r_crystal": 0.89, "remark": "", "spin": "", "r_ionic": 0.75}}}, "Lu": {"3": {"VI": {"r_crystal": 1.001, "remark": "R", "spin": "", "r_ionic": 0.861}, "VIII": {"r_crystal": 1.117, "remark": "R", "spin": "", "r_ionic": 0.977}, "IX": {"r_crystal": 1.172, "remark": "R", "spin": "", "r_ionic": 1.032}}}, "Th": {"4": {"IX": {"r_crystal": 1.23, "remark": "*", "spin": "", "r_ionic": 1.09}, "XI": {"r_crystal": 1.32, "remark": "C", "spin": "", "r_ionic": 1.18}, "VI": {"r_crystal": 1.08, "remark": "C", "spin": "", "r_ionic": 0.94}, "VIII": {"r_crystal": 1.19, "remark": "RC", "spin": "", "r_ionic": 1.05}, "XII": {"r_crystal": 1.35, "remark": "C", "spin": "", "r_ionic": 1.21}, "X": {"r_crystal": 1.27, "remark": "E", "spin": "", "r_ionic": 1.13}}}, "Ti": {"3": {"VI": {"r_crystal": 0.81, "remark": "R*", "spin": "", "r_ionic": 0.67}}, "2": {"VI": {"r_crystal": 1, "remark": "E", "spin": "", "r_ionic": 0.86}}, "4": {"VI": {"r_crystal": 0.745, "remark": "R*", "spin": "", "r_ionic": 0.605}, "V": {"r_crystal": 0.65, "remark": "C", "spin": "", "r_ionic": 0.51}, "VIII": {"r_crystal": 0.88, "remark": "C", "spin": "", "r_ionic": 0.74}, "IV": {"r_crystal": 0.56, "remark": "C", "spin": "", "r_ionic": 0.42}}}, "Te": {"6": {"VI": {"r_crystal": 0.7, "remark": "*", "spin": "", "r_ionic": 0.56}, "IV": {"r_crystal": 0.57, "remark": "C", "spin": "", "r_ionic": 0.43}}, "4": {"VI": {"r_crystal": 1.11, "remark": "", "spin": "", "r_ionic": 0.97}, "III": {"r_crystal": 0.66, "remark": "", "spin": "", "r_ionic": 0.52}, "IV": {"r_crystal": 0.8, "remark": "", "spin": "", "r_ionic": 0.66}}, "-2": {"VI": {"r_crystal": 2.07, "remark": "P", "spin": "", "r_ionic": 2.21}}}, "Tb": {"3": {"VI": {"r_crystal": 1.063, "remark": "R", "spin": "", "r_ionic": 0.923}, "VII": {"r_crystal": 1.12, "remark": "E", "spin": "", "r_ionic": 0.98}, "VIII": {"r_crystal": 1.18, "remark": "R", "spin": "", "r_ionic": 1.04}, "IX": {"r_crystal": 1.235, "remark": "R", "spin": "", "r_ionic": 1.095}}, "4": {"VI": {"r_crystal": 0.9, "remark": "R", "spin": "", "r_ionic": 0.76}, "VIII": {"r_crystal": 1.02, "remark": "", "spin": "", "r_ionic": 0.88}}}, "Tc": {"5": {"VI": {"r_crystal": 0.74, "remark": "ER", "spin": "", "r_ionic": 0.6}}, "4": {"VI": {"r_crystal": 0.785, "remark": "RM", "spin": "", "r_ionic": 0.645}}, "7": {"VI": {"r_crystal": 0.7, "remark": "A", "spin": "", "r_ionic": 0.56}, "IV": {"r_crystal": 0.51, "remark": "", "spin": "", "r_ionic": 0.37}}}, "Ta": {"3": {"VI": {"r_crystal": 0.86, "remark": "E", "spin": "", "r_ionic": 0.72}}, "5": {"VI": {"r_crystal": 0.78, "remark": "", "spin": "", "r_ionic": 0.64}, "VII": {"r_crystal": 0.83, "remark": "", "spin": "", "r_ionic": 0.69}, "VIII": {"r_crystal": 0.88, "remark": "", "spin": "", "r_ionic": 0.74}}, "4": {"VI": {"r_crystal": 0.82, "remark": "E", "spin": "", "r_ionic": 0.68}}}, "Yb": {"3": {"VI": {"r_crystal": 1.008, "remark": "R*", "spin": "", "r_ionic": 0.868}, "VII": {"r_crystal": 1.065, "remark": "E", "spin": "", "r_ionic": 0.925}, "VIII": {"r_crystal": 1.125, "remark": "R", "spin": "", "r_ionic": 0.985}, "IX": {"r_crystal": 1.182, "remark": "R", "spin": "", "r_ionic": 1.042}}, "2": {"VI": {"r_crystal": 1.16, "remark": "", "spin": "", "r_ionic": 1.02}, "VII": {"r_crystal": 1.22, "remark": "E", "spin": "", "r_ionic": 1.08}, "VIII": {"r_crystal": 1.28, "remark": "", "spin": "", "r_ionic": 1.14}}}, "Dy": {"3": {"VI": {"r_crystal": 1.052, "remark": "R", "spin": "", "r_ionic": 0.912}, "VII": {"r_crystal": 1.11, "remark": "", "spin": "", "r_ionic": 0.97}, "VIII": {"r_crystal": 1.167, "remark": "R", "spin": "", "r_ionic": 1.027}, "IX": {"r_crystal": 1.223, "remark": "R", "spin": "", "r_ionic": 1.083}}, "2": {"VI": {"r_crystal": 1.21, "remark": "", "spin": "", "r_ionic": 1.07}, "VII": {"r_crystal": 1.27, "remark": "", "spin": "", "r_ionic": 1.13}, "VIII": {"r_crystal": 1.33, "remark": "", "spin": "", "r_ionic": 1.19}}}, "I": {"5": {"VI": {"r_crystal": 1.09, "remark": "", "spin": "", "r_ionic": 0.95}, "IIIPY": {"r_crystal": 0.58, "remark": "*", "spin": "", "r_ionic": 0.44}}, "-1": {"VI": {"r_crystal": 2.06, "remark": "A", "spin": "", "r_ionic": 2.2}}, "7": {"VI": {"r_crystal": 0.67, "remark": "", "spin": "", "r_ionic": 0.53}, "IV": {"r_crystal": 0.56, "remark": "", "spin": "", "r_ionic": 0.42}}}, "U": {"3": {"VI": {"r_crystal": 1.165, "remark": "R", "spin": "", "r_ionic": 1.025}}, "5": {"VI": {"r_crystal": 0.9, "remark": "", "spin": "", "r_ionic": 0.76}, "VII": {"r_crystal": 0.98, "remark": "E", "spin": "", "r_ionic": 0.84}}, "4": {"VI": {"r_crystal": 1.03, "remark": "", "spin": "", "r_ionic": 0.89}, "VII": {"r_crystal": 1.09, "remark": "E", "spin": "", "r_ionic": 0.95}, "VIII": {"r_crystal": 1.14, "remark": "R*", "spin": "", "r_ionic": 1}, "XII": {"r_crystal": 1.31, "remark": "E", "spin": "", "r_ionic": 1.17}, "IX": {"r_crystal": 1.19, "remark": "", "spin": "", "r_ionic": 1.05}}, "6": {"II": {"r_crystal": 0.59, "remark": "", "spin": "", "r_ionic": 0.45}, "VI": {"r_crystal": 0.87, "remark": "*", "spin": "", "r_ionic": 0.73}, "VII": {"r_crystal": 0.95, "remark": "E", "spin": "", "r_ionic": 0.81}, "VIII": {"r_crystal": 1, "remark": "", "spin": "", "r_ionic": 0.86}, "IV": {"r_crystal": 0.66, "remark": "", "spin": "", "r_ionic": 0.52}}}, "Y": {"3": {"VI": {"r_crystal": 1.04, "remark": "R*", "spin": "", "r_ionic": 0.9}, "VII": {"r_crystal": 1.1, "remark": "", "spin": "", "r_ionic": 0.96}, "VIII": {"r_crystal": 1.159, "remark": "R*", "spin": "", "r_ionic": 1.019}, "IX": {"r_crystal": 1.215, "remark": "R", "spin": "", "r_ionic": 1.075}}}, "Ac": {"3": {"VI": {"r_crystal": 1.26, "remark": "R", "spin": "", "r_ionic": 1.12}}}, "Ag": {"1": {"VII": {"r_crystal": 1.36, "remark": "", "spin": "", "r_ionic": 1.22}, "IVSQ": {"r_crystal": 1.16, "remark": "", "spin": "", "r_ionic": 1.02}, "V": {"r_crystal": 1.23, "remark": "C", "spin": "", "r_ionic": 1.09}, "IV": {"r_crystal": 1.14, "remark": "C", "spin": "", "r_ionic": 1}, "II": {"r_crystal": 0.81, "remark": "", "spin": "", "r_ionic": 0.67}, "VIII": {"r_crystal": 1.42, "remark": "", "spin": "", "r_ionic": 1.28}, "VI": {"r_crystal": 1.29, "remark": "C", "spin": "", "r_ionic": 1.15}}, "3": {"IVSQ": {"r_crystal": 0.81, "remark": "", "spin": "", "r_ionic": 0.67}, "VI": {"r_crystal": 0.89, "remark": "R", "spin": "", "r_ionic": 0.75}}, "2": {"IVSQ": {"r_crystal": 0.93, "remark": "", "spin": "", "r_ionic": 0.79}, "VI": {"r_crystal": 1.08, "remark": "", "spin": "", "r_ionic": 0.94}}}, "Ir": {"3": {"VI": {"r_crystal": 0.82, "remark": "E", "spin": "", "r_ionic": 0.68}}, "5": {"VI": {"r_crystal": 0.71, "remark": "EM", "spin": "", "r_ionic": 0.57}}, "4": {"VI": {"r_crystal": 0.765, "remark": "R", "spin": "", "r_ionic": 0.625}}}, "Am": {"3": {"VI": {"r_crystal": 1.115, "remark": "R", "spin": "", "r_ionic": 0.975}, "VIII": {"r_crystal": 1.23, "remark": "", "spin": "", "r_ionic": 1.09}}, "2": {"IX": {"r_crystal": 1.45, "remark": "", "spin": "", "r_ionic": 1.31}, "VII": {"r_crystal": 1.35, "remark": "", "spin": "", "r_ionic": 1.21}, "VIII": {"r_crystal": 1.4, "remark": "", "spin": "", "r_ionic": 1.26}}, "4": {"VI": {"r_crystal": 0.99, "remark": "R", "spin": "", "r_ionic": 0.85}, "VIII": {"r_crystal": 1.09, "remark": "", "spin": "", "r_ionic": 0.95}}}, "Al": {"3": {"VI": {"r_crystal": 0.675, "remark": "R*", "spin": "", "r_ionic": 0.535}, "V": {"r_crystal": 0.62, "remark": "", "spin": "", "r_ionic": 0.48}, "IV": {"r_crystal": 0.53, "remark": "*", "spin": "", "r_ionic": 0.39}}}, "As": {"3": {"VI": {"r_crystal": 0.72, "remark": "A", "spin": "", "r_ionic": 0.58}}, "5": {"VI": {"r_crystal": 0.6, "remark": "C*", "spin": "", "r_ionic": 0.46}, "IV": {"r_crystal": 0.475, "remark": "R*", "spin": "", "r_ionic": 0.335}}}, "Au": {"1": {"VI": {"r_crystal": 1.51, "remark": "A", "spin": "", "r_ionic": 1.37}}, "3": {"IVSQ": {"r_crystal": 0.82, "remark": "", "spin": "", "r_ionic": 0.68}, "VI": {"r_crystal": 0.99, "remark": "A", "spin": "", "r_ionic": 0.85}}, "5": {"VI": {"r_crystal": 0.71, "remark": "", "spin": "", "r_ionic": 0.57}}}, "At": {"7": {"VI": {"r_crystal": 0.76, "remark": "A", "spin": "", "r_ionic": 0.62}}}, "In": {"3": {"VI": {"r_crystal": 0.94, "remark": "R*", "spin": "", "r_ionic": 0.8}, "VIII": {"r_crystal": 1.06, "remark": "RC", "spin": "", "r_ionic": 0.92}, "IV": {"r_crystal": 0.76, "remark": "", "spin": "", "r_ionic": 0.62}}}, "Mo": {"3": {"VI": {"r_crystal": 0.83, "remark": "E", "spin": "", "r_ionic": 0.69}}, "5": {"VI": {"r_crystal": 0.75, "remark": "R", "spin": "", "r_ionic": 0.61}, "IV": {"r_crystal": 0.6, "remark": "R", "spin": "", "r_ionic": 0.46}}, "4": {"VI": {"r_crystal": 0.79, "remark": "RM", "spin": "", "r_ionic": 0.65}}, "6": {"VI": {"r_crystal": 0.73, "remark": "R*", "spin": "", "r_ionic": 0.59}, "V": {"r_crystal": 0.64, "remark": "", "spin": "", "r_ionic": 0.5}, "VII": {"r_crystal": 0.87, "remark": "", "spin": "", "r_ionic": 0.73}, "IV": {"r_crystal": 0.55, "remark": "R*", "spin": "", "r_ionic": 0.41}}}} -------------------------------------------------------------------------------- /bvlain/core.py: -------------------------------------------------------------------------------- 1 | """ Lain - main class of BVlain library. """ 2 | 3 | import os 4 | import re 5 | import sys 6 | import json 7 | import pickle 8 | import itertools 9 | import numpy as np 10 | import pandas as pd 11 | from joblib import Parallel, delayed 12 | from scipy.spatial import cKDTree 13 | from scipy.ndimage import measurements, generate_binary_structure 14 | from ase.neighborlist import neighbor_list 15 | from ase.io import read, cube 16 | from ase.build import make_supercell 17 | from ase.data import atomic_numbers 18 | from pymatgen.analysis.bond_valence import BVAnalyzer 19 | from pymatgen.io.ase import AseAtomsAdaptor 20 | from .potentials import BVSEPotential 21 | from .data.covalent_radii import get_covalent_radii 22 | 23 | 24 | 25 | class Lain: 26 | """ 27 | The class is used to perform BVSE calculations and related tasks. 28 | 29 | Parameters 30 | ---------- 31 | 32 | verbose: boolean, True by default 33 | Will print progress steps if True 34 | """ 35 | 36 | def __init__(self, verbose = True): 37 | 38 | self.verbose = verbose 39 | self.params_path = self._resource_path('data') 40 | self.cation_file = os.path.join(self.params_path, 'cation.pkl') 41 | self.anion_file = os.path.join(self.params_path, 'anion.pkl') 42 | self.quantum_file = os.path.join(self.params_path, 'quantum_n.pkl') 43 | self.radii_file = os.path.join(self.params_path, 'shannon-radii.json') 44 | 45 | 46 | 47 | def read_structure(self, st, oxi_check = True, forbidden_species = ['O-', 'P3-']): 48 | 49 | """ 50 | Read structure from pymatgen's Structure. 51 | Note: Works only with ordered structures 52 | 53 | Parameters 54 | ---------- 55 | 56 | st: pymatgen's Structure object 57 | Should be ordered 58 | 59 | oxi_check: boolean, False by default) 60 | If true will try to assign oxi states by pymategen's BVAnalyzer 61 | 62 | forbidden_species: list of str, ['O-', 'P3-'] by default 63 | list of forbidden ions to be checked during structure decoration 64 | used when oxi_check is True 65 | 66 | Returns 67 | ------- 68 | pymatgen's Structure object 69 | stores ase.atoms in self.atoms_copy 70 | 71 | """ 72 | 73 | self.st = st 74 | if oxi_check: 75 | bva = BVAnalyzer(forbidden_species = forbidden_species) 76 | self.st = bva.get_oxi_state_decorated_structure(self.st) 77 | self.atoms_copy = AseAtomsAdaptor.get_atoms(self.st) 78 | self.cell = self.atoms_copy.cell 79 | return self.st 80 | 81 | 82 | 83 | def read_atoms(self, atoms, oxi_check = True, forbidden_species = ['O-', 'P3-']): 84 | 85 | """ 86 | Read ase' atoms object 87 | Note: Works only with ordered structures 88 | 89 | Parameters 90 | ---------- 91 | 92 | atoms: ase's Atoms object 93 | Should be ordered 94 | 95 | oxi_check: boolean, False by default) 96 | If true will try to assign oxi states by pymategen's BVAnalyzer 97 | 98 | forbidden_species: list of str, ['O-', 'P3-'] by default 99 | list of forbidden ions to be checked during structure decoration 100 | used when oxi_check is True 101 | 102 | Returns 103 | ------- 104 | ase's Atoms object 105 | stores ase.atoms in self.atoms_copy 106 | 107 | """ 108 | st = AseAtomsAdaptor().get_structure(atoms) 109 | self.read_structure(st, oxi_check=oxi_check, forbidden_species=forbidden_species) 110 | return self.atoms_copy 111 | 112 | 113 | 114 | def read_file(self, file, oxi_check = True, forbidden_species = ['O-', 'P3-']): 115 | """ 116 | Structure reader. Possible formats are .cif, POSCAR. 117 | It is a bit modified pymatgen's function Structure.from_file. 118 | Note: Works only with ordered structures 119 | 120 | Parameters 121 | ---------- 122 | 123 | file: str 124 | pathway to CIF or POSCAR 125 | 126 | oxi_check: boolean, False by default 127 | If true will try to assign oxi states by pymategen's BVAnalyzer 128 | 129 | forbidden_species: list of str, ['O-', 'P3-'] by default 130 | list of forbidden ions to be checked during structure decoration 131 | used when oxi_check is True 132 | 133 | 134 | Returns 135 | ------- 136 | ase's Atoms object 137 | stores ase.atoms in self.atoms_copy 138 | """ 139 | 140 | atoms = read(file) 141 | return self.read_atoms(atoms, oxi_check=oxi_check, forbidden_species=forbidden_species) 142 | 143 | 144 | 145 | def _mesh(self, resolution = 0.1, shift = [0, 0, 0]): 146 | 147 | """ 148 | This method creates grid of equidistant points in 3D 149 | with respect to the input resolution. 150 | 151 | Parameters 152 | ---------- 153 | 154 | resolution: float, 0.2 by default 155 | spacing between points (in Angstroms) 156 | Note: Number of points ~(lattice_parameter/resolution)^3 157 | 158 | shift: array [x, y, z] 159 | Used when invoked from self.bvse_distribution function 160 | 161 | Returns 162 | ------- 163 | mesh_: np.array 164 | meshgrid 165 | 166 | """ 167 | 168 | a, b, c, _, _, _ = self.cell.cellpar() 169 | nx, ny, nz = int(a // resolution), int(b // resolution), int(c // resolution) 170 | x = np.linspace(0, 1, nx) + shift[0] 171 | y = np.linspace(0, 1, ny) + shift[1] 172 | z = np.linspace(0, 1, nz) + shift[2] 173 | mesh_ = np.stack(np.meshgrid(x, y, z, indexing='ij'), axis=-1).reshape(-1, 3) 174 | self.mesh_ = mesh_ 175 | self.shift = shift 176 | self.size = [nx, ny, nz] 177 | return mesh_ 178 | 179 | 180 | 181 | def _scale_cell(self, cell, r_cut): 182 | """ 183 | 184 | Scaling of the unit cell for the search of neighbors 185 | 186 | Parameters 187 | ---------- 188 | 189 | r_cut: float 190 | cutoff distance for interaction between tracer ion and framework 191 | 192 | cell: ase.atoms.cell 193 | Unit cell parameters 194 | 195 | Returns 196 | ------- 197 | scale: np.array (3, 3) 198 | Matrix of the unit cell transformation 199 | 200 | """ 201 | # a, b, c, angle(b,c), angle(a,c), angle(a,b) 202 | a, b, c, alpha, beta, gamma = cell.cellpar(radians = True) 203 | scale_a = 2*np.ceil(r_cut/min(a*np.sin(gamma), a*np.sin(beta))) + 1 204 | scale_b = 2*np.ceil(r_cut/min(b*np.sin(gamma), b*np.sin(beta))) + 1 205 | scale_c = 2*np.ceil(r_cut/min(c*np.sin(beta), c*np.sin(beta))) + 1 206 | scale = np.vstack([[scale_a, 0, 0], [0, scale_b, 0], [0, 0, scale_c]]) 207 | return scale 208 | 209 | 210 | 211 | def _get_params(self, mobile_ion = None, use_softbv_covalent_radii = False): 212 | 213 | """ 214 | 215 | Collect parameters required for the calculations 216 | 217 | Parameters 218 | ---------- 219 | mobile_ion: str, 220 | ion, e.g. Li1+, F1- 221 | 222 | use_softbv_covalent_radii: boolean, False by default 223 | use ASE or softBV covalent radii data 224 | """ 225 | 226 | with open(self.quantum_file, 'rb') as f: 227 | quantum_number = pickle.load(f) 228 | self.num_mi, self.q_mi = self._decompose(mobile_ion) 229 | self.framework = self.atoms_copy.copy()[self.atoms_copy.numbers != self.num_mi] 230 | self.atoms = self.framework 231 | self.n_mi = quantum_number[self.num_mi] 232 | self.rc_mi = get_covalent_radii(self.num_mi, self.q_mi if use_softbv_covalent_radii else None) 233 | numbers, oxi_states = self.atoms.numbers, self.atoms.arrays['oxi_states'] 234 | rc = np.array([get_covalent_radii(num, q if use_softbv_covalent_radii else None) for num, q in zip(numbers, oxi_states)]) 235 | self.atoms.set_array('r_c', rc) 236 | self.atoms.set_array('n', np.array([quantum_number[num] for num in self.atoms.numbers])) 237 | charges = self.atoms.get_array('oxi_states') 238 | r_min = list() 239 | alpha = list() 240 | d0 = list() 241 | 242 | if self.q_mi > 0: 243 | with open(self.cation_file, 'rb') as f: 244 | data = pickle.load(f) 245 | data = data[self.num_mi][self.q_mi] 246 | try: 247 | for num, charge in zip(self.atoms.numbers, charges): 248 | if charge < 0: 249 | params = data[num][charge] 250 | r_min.append(params['r_min']) 251 | alpha.append(params['alpha']) 252 | d0.append(params['d0']) 253 | else: 254 | r_min.append(np.nan) 255 | alpha.append(np.nan) 256 | d0.append(np.nan) 257 | except KeyError: 258 | print('Oops. No BVSE data for a given combination of oxidation states.') 259 | raise 260 | else: 261 | with open(self.anion_file, 'rb') as f: 262 | data = pickle.load(f) 263 | data = data[self.num_mi][self.q_mi] 264 | try: 265 | for num, charge in zip(self.atoms.numbers, charges): 266 | if charge > 0: 267 | params = data[num][charge] 268 | r_min.append(params['r_min']) 269 | alpha.append(params['alpha']) 270 | d0.append(params['d0']) 271 | else: 272 | r_min.append(np.nan) 273 | alpha.append(np.nan) 274 | d0.append(np.nan) 275 | except KeyError: 276 | print('Oops. No BVSE data for a given combination of oxidation states.') 277 | raise 278 | 279 | r_min = np.hstack(r_min) 280 | alpha = np.hstack(alpha) 281 | d0 = np.hstack(d0) 282 | self.atoms.set_array('r_min', r_min) 283 | self.atoms.set_array('alpha', alpha) 284 | self.atoms.set_array('d0', d0) 285 | 286 | 287 | 288 | def _get_ionic_radius(self, symbol, charge, table): 289 | """ 290 | Get Shannon radius of ion. 291 | Note: radius is averaged over all possible coordination numbers 292 | 293 | 294 | Parameters 295 | ---------- 296 | symbol: str, 297 | atomic symbol, e.g. Li, F 298 | charge: int, 299 | oxidation state of an ion 300 | table: dict, 301 | data read from json file shannon-radii.json 302 | see: https://github.com/prtkm/ionic-radii 303 | 304 | Returns 305 | ---------- 306 | radii: float 307 | average ionic radii for the provided ion 308 | 309 | """ 310 | 311 | d = table[symbol][str(charge)] 312 | radii = [] 313 | for CN in d.keys(): 314 | radii.append(d[CN]['r_ionic']) 315 | return np.array(radii).mean() 316 | 317 | 318 | 319 | def _get_params_voids(self, mobile_ion = None, ionic = True): 320 | 321 | """ 322 | Collect parameters required for the calculations 323 | 324 | Parameters 325 | ---------- 326 | mobile_ion: str, 327 | ion, e.g. Li1+, F1- 328 | 329 | """ 330 | file = self.radii_file 331 | with open(file) as f: 332 | radii_data = f.read() 333 | table = json.loads(radii_data) 334 | 335 | self.num_mi, self.q_mi = self._decompose(mobile_ion) 336 | self.framework = self.atoms_copy.copy()[self.atoms_copy.numbers != self.num_mi] 337 | self.atoms = self.framework 338 | if ionic: 339 | self.ri_mi = self._get_ionic_radius(self.element_mi, self.q_mi, table) 340 | charges = np.array(self.atoms.get_array('oxi_states'), dtype = int) 341 | r_i = [self._get_ionic_radius(s, c, table) for s,c in zip(self.atoms.symbols, charges)] 342 | self.atoms.set_array('r_i', np.array(r_i)) 343 | 344 | 345 | 346 | def _ionic_dist(self, R, r_i): 347 | 348 | """ Calculate distances between mobile ion and 349 | framework's ions considering them hard spheres 350 | Note: radius of a mobile ion is 0 351 | 352 | 353 | Parameters 354 | ---------- 355 | R: np.array of floats 356 | distance between mobile ion and framework ions' centers 357 | 358 | r_i: np.array of floats 359 | ionic radii of framework ions 360 | 361 | Returns 362 | ---------- 363 | dists: np.array 364 | distances between mesh points and framework ions 365 | considering their ionic radii 366 | """ 367 | 368 | dists = R - r_i 369 | return dists 370 | 371 | 372 | 373 | def void_distribution(self, mobile_ion = None, r_cut = 10.0, 374 | resolution = 0.2, k = 2, ionic = True): 375 | 376 | """ 377 | Calculate void space distribution for a given mobile ion. 378 | Note! It is a vectorized method. Works fast, but memory expensive. 379 | Never ever set resolution parameter lower then 0.05. 380 | 381 | 382 | Parameters 383 | ---------- 384 | 385 | mobile_ion: str 386 | ion, e.g. 'Li1+', 'F-' 387 | 388 | resolution: float, 0.2 by default 389 | distance between grid points 390 | 391 | r_cut: float, 10.0 by default 392 | maximum distances for neighbor search 393 | Note: do not set the parameter < minimum mobile ion to framework distance 394 | 395 | k: int, 2 by default 396 | maximum number of neighbours (used for KDTree search of neighbors) 397 | adjusting this number should not effect the final result. used for tests. 398 | 399 | Returns 400 | ---------- 401 | 402 | void_data: np.array 403 | void distribution 404 | """ 405 | 406 | self.resolution = resolution 407 | 408 | if self.verbose: 409 | print('getting void distribution...') 410 | 411 | self._get_params_voids(mobile_ion, ionic = ionic) 412 | _, distances, ids, numbers = self._neighbors(r_cut = r_cut, 413 | resolution = resolution, 414 | k = k) 415 | if ionic: 416 | r_i = np.take(self._get_array('r_i'), ids, axis = -1) 417 | else: 418 | r_i = np.zeros(ids.shape) 419 | min_dists = np.nan_to_num(self._ionic_dist(distances, r_i), 420 | copy = False, 421 | nan = 1000.0).min(axis = 1) 422 | #self.void_dist = np.where(min_dists > 0, min_dists, 0) 423 | self.void_dist = min_dists 424 | self.void_data = self.void_dist.reshape(self.size) 425 | 426 | if self.verbose: 427 | print('distribution is ready\n') 428 | 429 | return self.void_data 430 | 431 | 432 | 433 | def _percolation_radius(self, dim): 434 | 435 | """ Get percolation radius for a given dimensionality of percolation 436 | 437 | Parameters 438 | ---------- 439 | 440 | dim: int 441 | dimensionality of percolation (from 1 to 27) 442 | 443 | Returns 444 | ---------- 445 | percolation_radius: float 446 | percolation energy or np.inf if no percolation found 447 | """ 448 | 449 | data = np.where(self.void_data > 0, self.void_data, 0) 450 | emax = data.max() 451 | emin = 0 452 | radii = 0 453 | while (emax - emin) > 0.1: 454 | probe = (emin + emax) / 2 455 | labels, features = self._connected_components(data, probe, task = 'void') 456 | if len(features) > 0: 457 | d = self._percolation_dimension(labels, features) 458 | if d >= dim: 459 | emin = probe 460 | radii = round(emin,4) 461 | else: 462 | emax = probe 463 | else: 464 | emax = probe 465 | return radii 466 | 467 | 468 | 469 | def _decompose(self, mobile_ion): 470 | 471 | """ Decompose input string into chemical element and oxidation state 472 | 473 | Parameters 474 | ---------- 475 | mobile_ion: str, 476 | ion, e.g. Li1+, F1- 477 | 478 | 479 | Returns 480 | ---------- 481 | tuple(atomic_number, oxidation_state) 482 | 483 | """ 484 | 485 | element = re.sub('\d', '', mobile_ion).replace("+","").replace("-","") 486 | oxi_state = re.sub('\D', '', mobile_ion) 487 | 488 | if '-' in mobile_ion: 489 | sign = -1 490 | else: 491 | sign = 1 492 | if len(oxi_state) > 0: 493 | if sign > 0: 494 | oxi_state = float(oxi_state) 495 | else: 496 | oxi_state = -float(oxi_state) 497 | else: 498 | oxi_state = sign 499 | 500 | if self.verbose: 501 | print(f'\tcollecting force field parameters...', 502 | f'{element} | charge: {oxi_state}') 503 | 504 | self.mi_atom = atomic_numbers[element] 505 | self.mi_charge = int(oxi_state) 506 | self.element_mi = element 507 | return atomic_numbers[element], int(oxi_state) 508 | 509 | 510 | 511 | def _cartesian_sites(self, mesh): 512 | 513 | """ Helper function""" 514 | 515 | sites = self.cell.cartesian_positions(mesh) 516 | self.sites = sites 517 | return sites 518 | 519 | 520 | 521 | def _neighbors(self, r_cut = 10.0, resolution = 0.1, k = 100): # modify considering kdtree bug! 522 | 523 | """ 524 | Search of the neighbors using scipy's cKDTree 525 | Parameters 526 | ---------- 527 | 528 | r_cut: float 529 | cutoff radius of tracer ion - framework interaction 530 | 531 | resolution: float 532 | distance between grid points (in Angstroms) 533 | 534 | k: int 535 | maximum number of neighbors 536 | 537 | Returns 538 | ---------- 539 | 540 | tuple of neigbors parameters 541 | 542 | """ 543 | 544 | if self.verbose: 545 | print('\tcollecting neighbors...') 546 | 547 | a, b, c, _, _, _ = self.cell.cellpar() 548 | scale = self._scale_cell(self.atoms.cell, r_cut = r_cut) 549 | shift = [np.median(np.arange(0, scale[0,0])), 550 | np.median(np.arange(0, scale[1,1])), 551 | np.median(np.arange(0, scale[2,2])), 552 | ] 553 | supercell = make_supercell(self.atoms, scale) 554 | self.supercell = supercell 555 | 556 | sites = self._cartesian_sites(self._mesh(resolution = resolution, 557 | shift = shift)) 558 | self.sites = sites 559 | KDTree = cKDTree(supercell.positions) 560 | distances, indexes = KDTree.query(sites, 561 | workers=-1, 562 | k=k, 563 | distance_upper_bound = r_cut) 564 | return sites, distances, indexes, supercell.numbers 565 | 566 | 567 | 568 | def _get_array(self, name): 569 | """ Helper function""" 570 | arr = self.supercell.get_array(name) 571 | arr = np.concatenate([arr, [np.nan]]) # np.nan is added to deal with kDTree upper bound 572 | return arr 573 | 574 | 575 | 576 | def bvse_distribution(self, mobile_ion = None, r_cut = 10, 577 | resolution = 0.2, k = 100, f = 0.74, use_softbv_covalent_radii = False): 578 | 579 | """ 580 | Calculate BVSE distribution for a given mobile ion. 581 | Note! It is a vectorized method. Works fast, but memory expensive. 582 | Never ever set resolution parameter lower then 0.05. 583 | 584 | 585 | Parameters 586 | ---------- 587 | 588 | mobile_ion: str 589 | ion, e.g. 'Li1+', 'F-' 590 | 591 | resolution: float, 0.2 by default 592 | distance between grid points 593 | 594 | r_cut: float, 10.0 by default 595 | maximum distances for mobile ion - framework interaction 596 | 597 | k: int, 100 by default 598 | maximum number of neighbours (used for KDTree search of neighbors) 599 | 600 | f: float, 0.74 by default 601 | screening factor 602 | 603 | use_softbv_covalent_radii: boolean, False by default 604 | use ASE or softBV covalent radii data 605 | 606 | Returns 607 | ---------- 608 | 609 | bvse_data: np.array 610 | BVSE distribution 611 | """ 612 | self.k = k 613 | self.r_cut = r_cut 614 | self.resolution = resolution 615 | if self.verbose: 616 | print('getting BVSE distribution...') 617 | 618 | self._get_params(mobile_ion, use_softbv_covalent_radii = use_softbv_covalent_radii) 619 | _, distances, ids, numbers = self._neighbors(r_cut = r_cut, 620 | resolution = resolution, 621 | k = k) 622 | r_min = np.take(self._get_array('r_min'), ids, axis = -1) 623 | alpha = np.take(self._get_array('alpha'), ids, axis = -1) 624 | r_c = np.take(self._get_array('r_c'), ids, axis = -1) 625 | d0 = np.take(self._get_array('d0'), ids, axis = -1) 626 | q = np.take(self._get_array('oxi_states'), ids, axis = -1) 627 | q = np.where(q * self.q_mi > 0, q, 0) 628 | n = np.take(self._get_array('n'), ids, axis = -1) 629 | 630 | morse = np.nan_to_num(BVSEPotential.Morse(distances, r_min, d0, alpha), 631 | copy = False, 632 | nan = 0.0).sum(axis = 1) 633 | 634 | coulomb = np.nan_to_num(BVSEPotential.Coulomb(distances, 635 | self.q_mi, q, 636 | self.rc_mi, r_c, 637 | self.n_mi, n, f = f), 638 | copy = False, 639 | nan = 0.0).sum(axis = 1) 640 | energy = morse + coulomb 641 | self.distribution = energy 642 | self.data = energy.reshape(self.size) 643 | if self.verbose: 644 | print('distribution is ready\n') 645 | return self.data 646 | 647 | 648 | 649 | def _cross_boundary(self, coords, data_shape): 650 | 651 | """ 652 | Check if connected component crosses the boundary of unit cell 653 | 654 | Parameters 655 | ---------- 656 | 657 | coords: np.array 658 | coordinates of points in connected component 659 | 660 | data_shape: list 661 | shape of the mesh constructed over supercell 662 | 663 | Returns 664 | ---------- 665 | 666 | d: int 667 | number of unit cells within a supercell that contains connected component 668 | """ 669 | 670 | probe = coords[0, :] 671 | cell_location = np.floor(probe / data_shape) 672 | translations = np.array(list(itertools.product([0, 1], 673 | [0, 1], 674 | [0, 1]))) 675 | translations = translations - cell_location 676 | test = probe + translations * data_shape 677 | d = np.argwhere(abs(coords[:, None] - test).sum(axis = 2) == 0).shape[0] 678 | return d 679 | 680 | 681 | 682 | def _connected_components(self, data, tr, task = 'bvse'): 683 | 684 | """ 685 | Find connected components 686 | 687 | Parameters 688 | ---------- 689 | 690 | data: np.array 691 | BVSE distribution data 692 | 693 | tr: float 694 | energy threshold to find components 695 | 696 | task: str, either "bvse" or "void" 697 | select type of calculation 698 | 699 | Returns 700 | ---------- 701 | 702 | labels, features: np.array, number of components 703 | labels are data points colored to features values 704 | """ 705 | 706 | n = 2 707 | lx, ly, lz = data.shape 708 | superdata = np.zeros((n * lx, n * ly, n * lz)) 709 | for i in range(n): 710 | for j in range(n): 711 | for k in range(n): 712 | superdata[i*lx:(i+1)*lx, j*ly:(j+1)*ly, k*lz:(k+1)*lz] = data 713 | 714 | region = superdata - superdata.min() 715 | structure = generate_binary_structure(3,3) 716 | if task == 'bvse': 717 | labels, features = measurements.label(region < tr, structure = structure) 718 | else: 719 | labels, features = measurements.label(region > tr, structure = structure) 720 | labels_with_pbc = self._apply_pbc(labels) 721 | return labels_with_pbc, np.unique(labels_with_pbc) # labels, features 722 | 723 | 724 | 725 | def _apply_pbc(self, labels): 726 | 727 | """ 728 | Apply periodic boundary conditions to the NxMxL np.array of labeled points. 729 | 730 | Parameters 731 | ---------- 732 | 733 | labels: np.array of NxMxL size 734 | array of labeles (connected components) 735 | 736 | Returns 737 | ---------- 738 | 739 | labels, features: np.array of NxMxL size and np.array of its unique labels 740 | the array returned implies pbc conditions 741 | 742 | """ 743 | 744 | faces_left = [labels[-1, :, :], 745 | labels[:, -1, :], 746 | labels[:, :, -1] 747 | ] 748 | faces_right = [labels[0, :, :], 749 | labels[:, 0, :], 750 | labels[:, :, 0] 751 | ] 752 | for f1, f2 in zip(faces_left, faces_right): 753 | for s in np.unique(f1): 754 | if s == 0: 755 | continue 756 | else: 757 | connect = np.unique(f2[f1 == s]) 758 | for c in connect: 759 | if c == 0: 760 | continue 761 | else: 762 | labels[labels == c] = s 763 | return labels 764 | 765 | 766 | 767 | def _percolation_dimension_old(self, labels, features): 768 | 769 | """ 770 | Check percolation dimensionality 771 | 772 | Old version. Does not work here but used for tests with elder version. 773 | 774 | Parameters 775 | ---------- 776 | 777 | labels: np.array 778 | label from _connected_components method 779 | 780 | features: np.array 781 | label from _connected_components method 782 | 783 | Returns 784 | ---------- 785 | d: dimensionality of percolation 786 | Note: can be from 1 to 27, which is the number of neighboring unit cells within 3x3x3 supercell 787 | """ 788 | 789 | if len(features) < 1: 790 | d = 0 791 | else: 792 | ds = [] 793 | for feature in features: 794 | if feature == 0: 795 | continue 796 | else: 797 | coords = np.argwhere(labels == feature) 798 | ds.append(self._cross_boundary(coords, np.array(labels.shape)/3)) 799 | d = max(ds) 800 | return d 801 | 802 | 803 | 804 | def _percolation_dimension(self, labels, features): 805 | 806 | """ 807 | Check percolation dimensionality 808 | 809 | Parameters 810 | ---------- 811 | 812 | labels: np.array 813 | label from _connected_components method 814 | 815 | features: np.array 816 | label from _connected_components method 817 | 818 | Returns 819 | ---------- 820 | d: dimensionality of percolation 821 | Note: can be from 2 to 8, which is the number of neighboring unit cells within 3x3x3 supercell 822 | """ 823 | 824 | if len(features) < 1: 825 | d = 0 826 | else: 827 | d = max(Parallel(n_jobs=self.n_jobs, 828 | backend = self.backend)(delayed(self._percolation_dimension_parallel)(feature, labels) for feature in features)) 829 | return d 830 | 831 | 832 | 833 | def _percolation_dimension_parallel(self, feature, labels): 834 | 835 | if feature == 0: 836 | d = 0 837 | else: 838 | coords = np.argwhere(labels == feature) 839 | d = self._cross_boundary(coords, np.array(labels.shape)/2) 840 | return d 841 | 842 | 843 | 844 | def _percolation_energy(self, dim, encut = 10.0): 845 | 846 | """ 847 | Get percolation energy fofr a given dimensionality of percolation 848 | 849 | Parameters 850 | ---------- 851 | 852 | dim: int 853 | dimensionality of percolation. 2 -> 1D, 4 -> 2D, 8 - 3D percolation 854 | 855 | encut: float, 10.0 by default 856 | stop criterion for the search of percolation energy 857 | 858 | Returns 859 | ---------- 860 | barrier: float 861 | percolation energy or np.inf if no percolation found 862 | """ 863 | 864 | data = self.data.reshape(self.size) 865 | data = data - data.min() 866 | emin = data.min() 867 | emax = emin + encut 868 | count = 0 869 | barrier = np.inf 870 | while (emax - emin) > 0.01: 871 | count = count + 1 872 | probe = (emin + emax) / 2 873 | labels, features = self._connected_components(data, probe) 874 | if len(features) > 0: 875 | d = self._percolation_dimension(labels, features) 876 | if d >= dim: 877 | emax = probe 878 | barrier = round(emax,4) 879 | else: 880 | emin = probe 881 | else: 882 | emin = probe 883 | return barrier 884 | 885 | 886 | 887 | def percolation_barriers(self, encut = 10.0, n_jobs = 1, backend = 'threading'): 888 | 889 | """ 890 | Find percolation energy and dimensionality of a migration network. 891 | 892 | Parameters 893 | ---------- 894 | 895 | encut: float, 5.0 by default 896 | cutoff energy above which barriers supposed to be np.inf 897 | 898 | n_jobs: int, 1 by default 899 | number of jobs to run for percolation energy search 900 | 901 | backend: str, 'threading' by default 902 | see joblib's documentations for more details 903 | 904 | Returns 905 | ---------- 906 | 907 | energies: dict 908 | infromation about percolation {'E_1D': float, 'E_2D': float, 'E_3D': float} 909 | 910 | """ 911 | 912 | self.n_jobs = n_jobs 913 | self.backend = backend 914 | 915 | energies = {} 916 | for i, dim in enumerate([2, 4, 8]): 917 | 918 | energy = self._percolation_energy(encut = encut, dim = dim) 919 | energies.update({f'E_{i+1}D': energy}) 920 | 921 | return energies 922 | 923 | 924 | 925 | def percolation_radii(self, n_jobs = 1, backend = 'threading'): 926 | 927 | """ 928 | Find the largest percolation radius of the free sphere 929 | w.r.t. the dimensionality of a migration network. 930 | 931 | Parameters 932 | ---------- 933 | 934 | n_jobs: int, 1 by default 935 | number of jobs to run for percolation energy search 936 | 937 | backend: str, 'threading' by default 938 | see joblib's documentations for more details 939 | 940 | Returns 941 | ---------- 942 | 943 | energies: dict 944 | infromation about percolation {'r_1D': float, 'r_2D': float, 'r_3D': float} 945 | 946 | """ 947 | self.n_jobs = n_jobs 948 | self.backend = backend 949 | 950 | radii = {} 951 | for i, dim in enumerate([2, 4, 8]): 952 | 953 | r = self._percolation_radius(dim = dim) 954 | radii.update({f'r_{i+1}D': r}) 955 | 956 | return radii 957 | 958 | 959 | 960 | def write_cube(self, filename, task = 'bvse'): 961 | 962 | """ 963 | Write .cube file containing structural and BVSE data. 964 | Note! Run it after self.bvse_distribution method 965 | 966 | Parameters 967 | ---------- 968 | 969 | filename: str 970 | file name to write .cube 971 | task: str, "bvse" by default 972 | which data to write, allowed values are "void" and "bvse" 973 | """ 974 | 975 | if task == 'bvse': 976 | data = self.data 977 | else: 978 | data = self.void_data 979 | nx, ny, nz = data.shape 980 | with open(f'{filename}.cube', 'w') as f: 981 | cube.write_cube(f, self.atoms_copy, data = data[:nx-1, :ny-1, :nz-1]) 982 | 983 | 984 | 985 | def write_grd(self, filename, task = 'bvse'): 986 | 987 | """ 988 | Write BVSE distribution volumetric file for VESTA 3.0. 989 | Note! Run it after self.bvse_distribution method 990 | 991 | Parameters 992 | ---------- 993 | 994 | filename: str 995 | file name to write .grd 996 | task: str, "bvse" by default 997 | which data to write, allowed values are "void" and "bvse" 998 | """ 999 | 1000 | if task == 'bvse': 1001 | data = self.data.reshape(self.size) 1002 | else: 1003 | data = self.void_data 1004 | voxels = data.shape[0] - 1, data.shape[1] - 1, data.shape[2] - 1 1005 | cellpars = self.cell.cellpar() 1006 | with open(f'{filename}.grd' , 'w') as report: 1007 | comment = '# BVSE data made with bvlain package: https://github.com/dembart/BVlain' 1008 | report.write(comment + '\n') 1009 | report.write(''.join(str(p) + ' ' for p in cellpars).strip() + '\n') 1010 | report.write(''.join(str(v) + ' ' for v in voxels).strip() + '\n') 1011 | for i in range(voxels[0]): 1012 | for j in range(voxels[1]): 1013 | for k in range(voxels[2]): 1014 | val = data[i, j, k] 1015 | report.write(str(val) + '\n') 1016 | 1017 | 1018 | 1019 | def mismatch(self, r_cut = 3.0): 1020 | 1021 | """ 1022 | Calculate bond valence sum mismatch for each site. 1023 | 1024 | Parameters 1025 | ---------- 1026 | 1027 | r_cut: float, 3.0 by default 1028 | cutoff radius for nearest neighbors 1029 | 1030 | Returns 1031 | ---------- 1032 | pd.DataFrame 1033 | structure data and misamtches 1034 | """ 1035 | 1036 | with open(self.cation_file, 'rb') as f: 1037 | data_cation = pickle.load(f) 1038 | 1039 | with open(self.anion_file, 'rb') as f: 1040 | data_anion = pickle.load(f) 1041 | 1042 | atoms = self.atoms_copy 1043 | centers, neighbors, distances = neighbor_list('ijd', atoms, r_cut) 1044 | 1045 | 1046 | mismatch = [] 1047 | bvs_list = [] 1048 | for i, n in enumerate(atoms.numbers): 1049 | 1050 | ids = np.argwhere(centers == i).ravel() 1051 | env = neighbors[ids] 1052 | r = distances[ids] 1053 | q1 = atoms.get_array('oxi_states')[i] 1054 | n_env = atoms.numbers[env] 1055 | q2 = atoms.get_array('oxi_states')[env] 1056 | alpha = np.zeros(q2.shape) 1057 | r0 = np.zeros(q2.shape) 1058 | 1059 | if q1 > 0: 1060 | q1q2 = np.where(q1*q2 < 0, 1, 0) 1061 | for index in np.argwhere(q1q2 == 1).ravel(): 1062 | alpha[index] = data_cation[n][q1][n_env[index]][q2[index]]['alpha'] 1063 | r0[index] = data_cation[n][q1][n_env[index]][q2[index]]['r0'] 1064 | bvs = np.exp(alpha * (r0 - r)) * q1q2 1065 | 1066 | if q1 < 0: 1067 | q1q2 = np.where(q1*q2 < 0, 1, 0) 1068 | for index in np.argwhere(q1q2 == 1).ravel(): 1069 | alpha[index] = data_anion[n][q1][n_env[index]][q2[index]]['alpha'] 1070 | r0[index] = data_anion[n][q1][n_env[index]][q2[index]]['r0'] 1071 | bvs = np.exp(alpha * (r0 - r)) * q1q2 1072 | 1073 | bvs_list.append(bvs.sum()) 1074 | pos = np.round(atoms.get_scaled_positions(), 4) 1075 | mismatch.append(bvs.sum() - abs(q1)) 1076 | 1077 | df = pd.DataFrame(pos, columns = ['x/a', 'y/b', 'z/c']) 1078 | df['mismatch'] = mismatch 1079 | df['atom'] = atoms.get_chemical_symbols() 1080 | df['formal_charge'] = atoms.get_array('oxi_states') 1081 | df['bvs'] = bvs_list 1082 | return df[['atom', 'x/a', 'y/b', 'z/c', 'formal_charge', 'bvs', 'mismatch']] 1083 | 1084 | 1085 | 1086 | def _resource_path(self, relative_path): 1087 | """ Get absolute path to resource, works for dev and for PyInstaller """ 1088 | base_path = getattr(sys, '_MEIPASS', os.path.dirname(os.path.abspath(__file__))) 1089 | path = os.path.join(base_path, relative_path) 1090 | return path 1091 | --------------------------------------------------------------------------------