diff --git a/README.md b/README.md index 58c482a8..6580420c 100644 --- a/README.md +++ b/README.md @@ -6,6 +6,7 @@ Below, we list the contents of this repository, in roughly the order that a user | Folder | Notebook | Description | | ------------------|-----------------------------------------| ----------- | + | [Examples/System](examples/system/) | [Get Authentication Params](examples/system/get_authentication_params.ipynb) | Demonstrates how to programatically find your user ID and access token, which is to [authenticate](https://docs.mat3ra.com/rest-api/authentication/) for many portions of the Mat3ra API. | [Examples/Workflow](examples/workflow/) | [Get Workflows](examples/workflow/get_workflows.ipynb) | Walks through how to [query](https://docs.mat3ra.com/rest-api/query-structure/) the Mat3ra API to programatically search for workflows. In this example, we search for workflows that calculate the total energy of a material. | [Examples/Workflow](examples/workflow/) | [Quantum Espresso Workflow and Job](examples/workflow/qe_scf_calculation.ipynb) | Create Quantum Espresso workflow starting from QE input file; create and submit job; after the job is finished, download output file, and finally perform postprocessing analysis. diff --git a/other/materials_designer/BN.json b/other/materials_designer/BN.json new file mode 100644 index 00000000..133be860 --- /dev/null +++ b/other/materials_designer/BN.json @@ -0,0 +1 @@ +{"lattice":{"a":2.508995,"b":2.508995,"c":7.71,"alpha":90,"beta":90,"gamma":120,"units":{"length":"angstrom","angle":"degree"},"type":"HEX","vectors":{"a":[2.508995,0,0],"b":[-1.254498,2.172854,0],"c":[0,0,7.71],"alat":1,"units":"angstrom"}},"basis":{"elements":[{"id":0,"value":"B"},{"id":1,"value":"N"}],"coordinates":[{"id":0,"value":[0,0,0]},{"id":1,"value":[0.333333,0.666667,0]}],"units":"crystal","cell":[[2.50899515,0,1.5363164397618668e-16],[-1.2544975749999998,2.1728535378719482,1.5363164397618668e-16],[0,0,7.71]],"constraints":[]},"name":"h-BN (mp-984)","isNonPeriodic":false,"external":{"id":"mp-984","source":"materials project","doi":"10.17188/1281942","url":"https://next-gen.materialsproject.org/materials/mp-984/","origin":true}} \ No newline at end of file diff --git a/other/materials_designer/Gr.json b/other/materials_designer/Gr.json new file mode 100644 index 00000000..7fa97ba9 --- /dev/null +++ b/other/materials_designer/Gr.json @@ -0,0 +1 @@ +{"lattice":{"a":2.467291,"b":2.467291,"c":20,"alpha":90,"beta":90,"gamma":120,"units":{"length":"angstrom","angle":"degree"},"type":"HEX","vectors":{"a":[2.467291,0,0],"b":[-1.233645,2.136737,0],"c":[0,0,20],"alat":1,"units":"angstrom"}},"basis":{"elements":[{"id":0,"value":"C"},{"id":1,"value":"C"}],"coordinates":[{"id":0,"value":[0,0,0]},{"id":1,"value":[0.333333,0.666667,0]}],"units":"crystal","cell":[[2.467291,0,1.5107800128575361e-16],[-1.2336454999999997,2.1367366845287115,1.5107800128575361e-16],[0,0,20]],"constraints":[]},"name":"Graphene (mp-1040425)","isNonPeriodic":false,"external":{"id":"mp-1040425","source":"materials project","doi":"10.17188/1405723","url":"https://next-gen.materialsproject.org/materials/mp-1040425/","origin":true},"isUpdated":true} \ No newline at end of file diff --git a/other/materials_designer/Ni.json b/other/materials_designer/Ni.json new file mode 100644 index 00000000..ade14823 --- /dev/null +++ b/other/materials_designer/Ni.json @@ -0,0 +1 @@ +{"name":"Ni (mp-23)","basis":{"elements":[{"id":0,"value":"Ni"}],"coordinates":[{"id":0,"value":[0,0,0]}],"units":"crystal","cell":[[2.130422493309719,0,1.2300000000000002],[0.7101408311032398,2.008581589082206,1.2300000000000002],[0,0,2.46]],"constraints":[{"id":0,"value":[true,true,true]}]},"lattice":{"a":2.46,"b":2.46,"c":2.46,"alpha":60,"beta":60,"gamma":60,"units":{"length":"angstrom","angle":"degree"},"type":"FCC","vectors":{"a":[2.130422,0,1.23],"b":[0.7101408,2.008582,1.23],"c":[0,0,2.46],"alat":1,"units":"angstrom"}},"isNonPeriodic":false,"external":{"id":"mp-224","source":"materials project","doi":"10.17188/1199153","url":"https://next-gen.materialsproject.org/materials/mp-23/","origin":true},"isUpdated":true} \ No newline at end of file diff --git a/other/materials_designer/calculator_pickle.py b/other/materials_designer/calculator_pickle.py new file mode 100644 index 00000000..36ab649d --- /dev/null +++ b/other/materials_designer/calculator_pickle.py @@ -0,0 +1,15 @@ +import matgl +from matgl.ext.ase import M3GNetCalculator +from matgl.ext.ase import M3GNetCalculator + +import cloudpickle + +pot = matgl.load_model("M3GNet-MP-2021.2.8-PES") + +# Save the calculator to pickle for use in the Pyodide environment +calculator = M3GNetCalculator(pot) +print(calculator) + +with open("m3gnet_calculator_3.11_32.pkl", "wb") as f: + cloudpickle.dump(calculator, f, protocol=3) + \ No newline at end of file diff --git a/other/materials_designer/create_interface_with_relaxation_alignn.ipynb b/other/materials_designer/create_interface_with_relaxation_alignn.ipynb new file mode 100644 index 00000000..a3d68efa --- /dev/null +++ b/other/materials_designer/create_interface_with_relaxation_alignn.ipynb @@ -0,0 +1,2165 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Create an interface between two materials with minimal strain\n", + "\n", + "Use Zur and McGill superlattices matching [algorithm](https://doi.org/10.1063/1.3330840) to create interfaces between two materials using the Pymatgen [implementation](https://pymatgen.org/pymatgen.analysis.interfaces.html#pymatgen.analysis.interfaces.zsl).\n", + "\n", + "

Usage

\n", + "\n", + "0. Make sure to select Input Materials\n", + "1. Execute \"Run first: ...\" cell below to load Input Materials into the current kernel\n", + "2. Set Input Parameters (e.g. `MILLER_INDICES`, `THICKNESS`, `MAX_AREA`) below or use the default values\n", + "3. Click \"Run\" > \"Run All\" to run all cells\n", + "4. Wait for the run to complete (depending on the area, it can take 1-2 min or more). Scroll down to view cell results.\n", + "5. Review the strain plot and modify its parameters as needed\n", + "\n", + "## Methodology\n", + "\n", + "The following happens in the script below:\n", + "\n", + "1. Create slabs for each input material. The materials data is passed in from and back to the web application according to this description (TBA).\n", + " We assume that two input materials are either in bulk form (e.g. Ni crystal) or layered (e.g. graphene). \n", + " \n", + " We construct the interface along the Z-axis. The material corresponding to the bottom of the interface is referred to as the \"**substrate**\", and the top - as the \"**layer**\". \n", + "\n", + "2. Perform strain matching on the slabs to extract the supercell dimensions. The algorithm has a set of parameters, such as the maximum area considered, that can be configured by editing the cells below.\n", + "\n", + "3. When the strain matching is finished, the interface with the lowest strain (and the smallest number of atoms) is selected. We create the corresponding supercells and place them at a specified distance from each other (note no shift is performed currently).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Run first: load input materials in current kernel

\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:02.172653Z", + "start_time": "2024-02-23T06:54:02.117478Z" + } + }, + "outputs": [], + "source": [ + "import json\n", + "materials_in = []\n", + "for file in [\"Ni.json\", \"Gr.json\"]:\n", + " with open(file, \"r\") as f:\n", + " data = f.read()\n", + " materials_in.append(json.loads(data))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Set Input Parameters\n", + "\n", + "### 1.1. Select Substrate and Layer from Input Materials" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:02.183063Z", + "start_time": "2024-02-23T06:54:02.177507Z" + } + }, + "outputs": [], + "source": [ + "SUBSTRATE_PARAMETERS = {\n", + " \"MATERIAL_INDEX\": 0, # the index of the material in the materials_in list\n", + " \"MILLER_INDICES\": (1, 1, 1), # the miller indices of the interfacial plane\n", + " \"THICKNESS\": 3, # in layers\n", + "}\n", + "\n", + "LAYER_PARAMETERS = {\n", + " \"MATERIAL_INDEX\": 1, # the index of the material in the materials_in list\n", + " \"MILLER_INDICES\": (0, 0, 1), # the miller indices of the interfacial plane\n", + " \"THICKNESS\": 1, # in layers\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.2. Set Interface Parameters\n", + "\n", + "The distance between layer and substrate and maximum area to consider when matching.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:02.194678Z", + "start_time": "2024-02-23T06:54:02.185489Z" + } + }, + "outputs": [], + "source": [ + "INTERFACE_PARAMETERS = {\n", + " \"DISTANCE_Z\": 3.0, # in Angstroms\n", + " \"MAX_AREA\": 50, # in Angstroms^2\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.3. Set Algorithm Parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:02.195298Z", + "start_time": "2024-02-23T06:54:02.190351Z" + } + }, + "outputs": [], + "source": [ + "ZSL_PARAMETERS = {\n", + " \"MAX_AREA\": INTERFACE_PARAMETERS[\"MAX_AREA\"], # The area to consider in Angstrom^2\n", + " \"MAX_AREA_TOL\": 0.09, # The area within this tolerance is considered equal\n", + " \"MAX_LENGTH_TOL\": 0.03, # supercell lattice vectors lengths within this tolerance are considered equal\n", + " \"MAX_ANGLE_TOL\": 0.01, # supercell lattice angles within this tolerance are considered equal\n", + " \"STRAIN_TOL\": 10e-6, # strains within this tolerance are considered equal\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Install Packages" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:04.004961Z", + "start_time": "2024-02-23T06:54:02.198579Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Python 3.11.7\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Package Version\n", + "-------------------------- -----------------\n", + "accelerate 0.27.2\n", + "aiohttp 3.9.3\n", + "aiosignal 1.3.1\n", + "alignn 2024.2.4\n", + "anyio 4.3.0\n", + "appnope 0.1.4\n", + "argon2-cffi 23.1.0\n", + "argon2-cffi-bindings 21.2.0\n", + "arrow 1.3.0\n", + "ase 3.22.1\n", + "asttokens 2.4.1\n", + "async-lru 2.0.4\n", + "attrs 23.2.0\n", + "Babel 2.14.0\n", + "beautifulsoup4 4.12.3\n", + "bleach 6.1.0\n", + "certifi 2024.2.2\n", + "cffi 1.16.0\n", + "charset-normalizer 3.3.2\n", + "click 8.1.7\n", + "colorama 0.4.6\n", + "comm 0.2.1\n", + "contourpy 1.2.0\n", + "cycler 0.12.1\n", + "debugpy 1.8.1\n", + "decorator 5.1.1\n", + "defusedxml 0.7.1\n", + "dgl 2.0.0\n", + "executing 2.0.1\n", + "fastjsonschema 2.19.1\n", + "filelock 3.13.1\n", + "flake8 7.0.0\n", + "fonttools 4.49.0\n", + "fqdn 1.5.1\n", + "frozenlist 1.4.1\n", + "fsspec 2024.2.0\n", + "future 1.0.0\n", + "ghp-import 2.1.0\n", + "h11 0.14.0\n", + "httpcore 1.0.4\n", + "httpx 0.27.0\n", + "huggingface-hub 0.20.3\n", + "idna 3.6\n", + "install 1.3.5\n", + "ipykernel 6.29.2\n", + "ipython 8.22.1\n", + "ipywidgets 8.1.2\n", + "isoduration 20.11.0\n", + "jarvis-tools 2023.12.12\n", + "jedi 0.19.1\n", + "Jinja2 3.1.3\n", + "joblib 1.3.2\n", + "json5 0.9.17\n", + "jsonpointer 2.4\n", + "jsonschema 4.21.1\n", + "jsonschema-specifications 2023.12.1\n", + "jupyter_client 8.6.0\n", + "jupyter_core 5.7.1\n", + "jupyter-events 0.9.0\n", + "jupyter-lsp 2.2.2\n", + "jupyter_server 2.12.5\n", + "jupyter_server_terminals 0.5.2\n", + "jupyterlab 4.1.2\n", + "jupyterlab_pygments 0.3.0\n", + "jupyterlab_server 2.25.3\n", + "jupyterlab_widgets 3.0.10\n", + "kiwisolver 1.4.5\n", + "latexcodec 2.0.1\n", + "lightning-utilities 0.10.1\n", + "Markdown 3.5.2\n", + "MarkupSafe 2.1.5\n", + "matgl 0.9.2\n", + "matplotlib 3.8.3\n", + "matplotlib-inline 0.1.6\n", + "mccabe 0.7.0\n", + "mergedeep 1.3.4\n", + "mistune 3.0.2\n", + "mkdocs 1.5.3\n", + "mkdocs-material 9.5.10\n", + "mkdocs-material-extensions 1.3.1\n", + "monty 2024.2.2\n", + "mpmath 1.3.0\n", + "multidict 6.0.5\n", + "nbclient 0.9.0\n", + "nbconvert 7.16.1\n", + "nbformat 5.9.2\n", + "nest-asyncio 1.6.0\n", + "networkx 3.2.1\n", + "nglview 3.1.1\n", + "notebook 7.1.0\n", + "notebook_shim 0.2.4\n", + "numpy 1.26.4\n", + "overrides 7.7.0\n", + "packaging 23.2\n", + "paginate 0.5.6\n", + "palettable 3.3.3\n", + "pandas 2.2.1\n", + "pandocfilters 1.5.1\n", + "parso 0.8.3\n", + "pathspec 0.12.1\n", + "pexpect 4.9.0\n", + "pillow 10.2.0\n", + "pip 23.3.1\n", + "platformdirs 4.2.0\n", + "plotly 5.19.0\n", + "prometheus_client 0.20.0\n", + "prompt-toolkit 3.0.43\n", + "psutil 5.9.8\n", + "ptyprocess 0.7.0\n", + "pure-eval 0.2.2\n", + "pybtex 0.24.0\n", + "pycodestyle 2.11.1\n", + "pycparser 2.21\n", + "pydantic 1.8.1\n", + "pydocstyle 6.3.0\n", + "pyflakes 3.2.0\n", + "Pygments 2.17.2\n", + "pymatgen 2024.2.8\n", + "pymdown-extensions 10.7\n", + "pyparsing 2.4.7\n", + "PyQt5 5.15.10\n", + "PyQt5-Qt5 5.15.12\n", + "PyQt5-sip 12.13.0\n", + "python-dateutil 2.8.2\n", + "python-json-logger 2.0.7\n", + "pytorch-ignite 0.5.0.dev20240223\n", + "pytorch-lightning 2.2.0.post0\n", + "pytz 2024.1\n", + "PyYAML 6.0.1\n", + "pyyaml_env_tag 0.1\n", + "pyzmq 25.1.2\n", + "referencing 0.33.0\n", + "regex 2023.12.25\n", + "requests 2.31.0\n", + "rfc3339-validator 0.1.4\n", + "rfc3986-validator 0.1.1\n", + "rpds-py 0.18.0\n", + "ruamel.yaml 0.18.6\n", + "ruamel.yaml.clib 0.2.8\n", + "safetensors 0.4.2\n", + "scikit-learn 1.4.1.post1\n", + "scipy 1.12.0\n", + "Send2Trash 1.8.2\n", + "setuptools 69.0.2\n", + "six 1.16.0\n", + "sniffio 1.3.0\n", + "snowballstemmer 2.2.0\n", + "soupsieve 2.5\n", + "spglib 2.0.2\n", + "stack-data 0.6.3\n", + "sympy 1.12\n", + "tabulate 0.9.0\n", + "tenacity 8.2.3\n", + "terminado 0.18.0\n", + "threadpoolctl 3.3.0\n", + "tinycss2 1.2.1\n", + "toolz 0.12.1\n", + "torch 2.0.0\n", + "torchdata 0.7.1\n", + "torchmetrics 1.3.1\n", + "tornado 6.4\n", + "tqdm 4.66.2\n", + "traitlets 5.14.1\n", + "types-python-dateutil 2.8.19.20240106\n", + "typing_extensions 4.9.0\n", + "tzdata 2024.1\n", + "uncertainties 3.1.7\n", + "uri-template 1.3.0\n", + "urllib3 2.2.1\n", + "watchdog 4.0.0\n", + "wcwidth 0.2.13\n", + "webcolors 1.13\n", + "webencodings 0.5.1\n", + "websocket-client 1.7.0\n", + "widgetsnbextension 4.0.10\n", + "xmltodict 0.13.0\n", + "yarl 1.9.4\n", + "\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m A new release of pip is available: \u001b[0m\u001b[31;49m23.3.1\u001b[0m\u001b[39;49m -> \u001b[0m\u001b[32;49m24.0\u001b[0m\n", + "\u001b[1m[\u001b[0m\u001b[34;49mnotice\u001b[0m\u001b[1;39;49m]\u001b[0m\u001b[39;49m To update, run: \u001b[0m\u001b[32;49mpip install --upgrade pip\u001b[0m\n" + ] + } + ], + "source": [ + "!python --version\n", + "!pip list\n", + "# !pip install pymatgen==2024.2.8 ase==3.22.1 nbformat==5.9.2 ipykernel==6.29.2 matgl==0.9.2 nglview==3.1.1 alignn==2024.2.4 pip install PyQt5==5.15.10" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Create interfaces\n", + "\n", + "### 3.1. Extract Interfaces and Terminations\n", + "\n", + "Extract all possible layer/substrate supercell combinations within the maximum area including different terminations." + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:09.335794Z", + "start_time": "2024-02-23T06:54:04.013364Z" + }, + "tags": [], + "trusted": true + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Full Formula (Ni1)\n", + "Reduced Formula: Ni\n", + "abc : 2.460000 2.460000 2.460000\n", + "angles: 60.000004 59.999994 60.000003\n", + "pbc : True True True\n", + "Sites (1)\n", + " # SP a b c\n", + "--- ---- --- --- ---\n", + " 0 Ni 0 0 0 \n", + "\n", + "Full Formula (C2)\n", + "Reduced Formula: C\n", + "abc : 2.467291 2.467291 20.000000\n", + "angles: 90.000000 90.000000 119.999986\n", + "pbc : True True True\n", + "Sites (2)\n", + " # SP a b c\n", + "--- ---- -------- -------- ---\n", + " 0 C 0 0 0\n", + " 1 C 0.333333 0.666667 0 \n", + "\n", + "Creating interfaces...\n" + ] + } + ], + "source": [ + "from src.pymatgen_coherent_interface_builder import CoherentInterfaceBuilder, ZSLGenerator\n", + "from src.utils import to_pymatgen\n", + "\n", + "if \"materials_in\" in globals():\n", + " pymatgen_materials = [to_pymatgen(item) for item in materials_in]\n", + "for material in pymatgen_materials:\n", + " print(material, \"\\n\")\n", + "\n", + "\n", + "def create_interfaces(settings):\n", + " print(\"Creating interfaces...\")\n", + " zsl = ZSLGenerator(\n", + " max_area_ratio_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_AREA_TOL\"],\n", + " max_area=settings[\"ZSL_PARAMETERS\"][\"MAX_AREA\"],\n", + " max_length_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_LENGTH_TOL\"],\n", + " max_angle_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_ANGLE_TOL\"],\n", + " )\n", + "\n", + " cib = CoherentInterfaceBuilder(\n", + " substrate_structure=pymatgen_materials[settings[\"SUBSTRATE_PARAMETERS\"][\"MATERIAL_INDEX\"]],\n", + " film_structure=pymatgen_materials[settings[\"LAYER_PARAMETERS\"][\"MATERIAL_INDEX\"]],\n", + " substrate_miller=settings[\"SUBSTRATE_PARAMETERS\"][\"MILLER_INDICES\"],\n", + " film_miller=settings[\"LAYER_PARAMETERS\"][\"MILLER_INDICES\"],\n", + " zslgen=zsl,\n", + " strain_tol=settings[\"ZSL_PARAMETERS\"][\"STRAIN_TOL\"],\n", + " )\n", + "\n", + " # Find terminations\n", + " cib._find_terminations()\n", + " terminations = cib.terminations\n", + "\n", + " # Create interfaces for each termination\n", + " interfaces = {}\n", + " for termination in terminations:\n", + " interfaces[termination] = []\n", + " for interface in cib.get_interfaces(\n", + " termination,\n", + " gap=settings[\"INTERFACE_PARAMETERS\"][\"DISTANCE_Z\"],\n", + " film_thickness=settings[\"LAYER_PARAMETERS\"][\"THICKNESS\"],\n", + " substrate_thickness=settings[\"SUBSTRATE_PARAMETERS\"][\"THICKNESS\"],\n", + " in_layers=True,\n", + " ):\n", + " # Wrap atoms to unit cell\n", + " interface[\"interface\"].make_supercell((1,1,1), to_unit_cell=True)\n", + " interfaces[termination].append(interface)\n", + " return interfaces, terminations\n", + "\n", + "\n", + "interfaces, terminations = create_interfaces(\n", + " settings={\n", + " \"SUBSTRATE_PARAMETERS\": SUBSTRATE_PARAMETERS,\n", + " \"LAYER_PARAMETERS\": LAYER_PARAMETERS,\n", + " \"ZSL_PARAMETERS\": ZSL_PARAMETERS,\n", + " \"INTERFACE_PARAMETERS\": INTERFACE_PARAMETERS,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3.2. Print out the interfaces and terminations" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:09.342541Z", + "start_time": "2024-02-23T06:54:09.337841Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 1 terminations\n", + "Found 233 interfaces for ('C_P6/mmm_2', 'Ni_R-3m_1') termination\n" + ] + } + ], + "source": [ + "print(f'Found {len(terminations)} terminations')\n", + "for termination in terminations:\n", + " print(f\"Found {len(interfaces[termination])} interfaces for\", termination, \"termination\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Sort interfaces by strain\n", + "\n", + "### 4.1. Sort all interfaces" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:09.349850Z", + "start_time": "2024-02-23T06:54:09.344766Z" + } + }, + "outputs": [], + "source": [ + "# Could be \"strain\", \"von_mises_strain\", \"mean_abs_strain\"\n", + "strain_mode = \"mean_abs_strain\"\n", + "\n", + "# Sort interfaces by the specified strain mode and number of sites\n", + "def sort_interfaces(interfaces, terminations):\n", + " sorted_interfaces = {}\n", + " for termination in terminations:\n", + " sorted_interfaces[termination] = sorted(\n", + " interfaces[termination], key=lambda x: (x[strain_mode], x[\"interface\"].num_sites)\n", + " )\n", + " return sorted_interfaces\n", + "\n", + "\n", + "sorted_interfaces = sort_interfaces(interfaces, terminations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.2. Print out interfaces with lowest strain for each termination" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:09.352241Z", + "start_time": "2024-02-23T06:54:09.349349Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Interface with lowest strain for termination ('C_P6/mmm_2', 'Ni_R-3m_1') (index 0):\n", + " strain: 0.06600000000000002 %\n", + " number of atoms: 5\n" + ] + } + ], + "source": [ + "for termination in terminations:\n", + " print(f\"Interface with lowest strain for termination {termination} (index 0):\")\n", + " first_interface = interfaces[termination][0]\n", + " print(\" strain:\", first_interface[strain_mode] * 100, \"%\")\n", + " print(\" number of atoms:\", first_interface[\"interface\"].num_sites)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Plot the results\n", + "\n", + "Plot the number of atoms vs strain. Adjust the parameters as needed.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:09.692367Z", + "start_time": "2024-02-23T06:54:09.362250Z" + } + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "config": { + "plotlyServerURL": "https://plot.ly" + }, + "data": [ + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 0", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 0
Strain: 0.07%
Atoms: 5" + ], + "type": "scatter", + "x": [ + 0.06600000000000002 + ], + "y": [ + 5 + ] + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 1-9", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 1-9
Strain: 0.07%
Atoms: 10" + ], + "type": "scatter", + "x": [ + 0.06600000000000002 + ], + "y": [ + 10 + ] + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 10-19", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 10-19
Strain: 0.07%
Atoms: 15" + ], + "type": "scatter", + "x": [ + 0.06600000000000002 + ], + "y": [ + 15 + ] + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 20-38", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 20-38
Strain: 0.07%
Atoms: 20" + ], + "type": "scatter", + "x": [ + 0.06600000000000002 + ], + "y": [ + 20 + ] + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 39-56", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 39-56
Strain: 0.07%
Atoms: 25" + ], + "type": "scatter", + "x": [ + 0.06600000000000002 + ], + "y": [ + 25 + ] + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 57-110", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 57-110
Strain: 0.07%
Atoms: 30" + ], + "type": "scatter", + "x": [ + 0.06600000000000002 + ], + "y": [ + 30 + ] + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 111-132", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 111-132
Strain: 0.07%
Atoms: 35" + ], + "type": "scatter", + "x": [ + 0.06600000000000002 + ], + "y": [ + 35 + ] + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 133-177", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 133-177
Strain: 0.07%
Atoms: 40" + ], + "type": "scatter", + "x": [ + 0.06600000000000002 + ], + "y": [ + 40 + ] + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 178-232", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 178-232
Strain: 0.07%
Atoms: 45" + ], + "type": "scatter", + "x": [ + 0.06600000000000002 + ], + "y": [ + 45 + ] + } + ], + "layout": { + "height": 600, + "hovermode": "closest", + "legend": { + "title": { + "text": "Interfaces Index Range" + } + }, + "template": { + "data": { + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "choropleth": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "choropleth" + } + ], + "contour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "contour" + } + ], + "contourcarpet": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "contourcarpet" + } + ], + "heatmap": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmap" + } + ], + "heatmapgl": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "heatmapgl" + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "histogram2d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2d" + } + ], + "histogram2dcontour": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "histogram2dcontour" + } + ], + "mesh3d": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "type": "mesh3d" + } + ], + "parcoords": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "parcoords" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "scatter3d": [ + { + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatter3d" + } + ], + "scattercarpet": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattercarpet" + } + ], + "scattergeo": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergeo" + } + ], + "scattergl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattergl" + } + ], + "scattermapbox": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scattermapbox" + } + ], + "scatterpolar": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolar" + } + ], + "scatterpolargl": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterpolargl" + } + ], + "scatterternary": [ + { + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "type": "scatterternary" + } + ], + "surface": [ + { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "type": "surface" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ] + }, + "layout": { + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "autotypenumbers": "strict", + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ], + "sequential": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1, + "#f0f921" + ] + ] + }, + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "geo": { + "bgcolor": "white", + "lakecolor": "white", + "landcolor": "#E5ECF6", + "showlakes": true, + "showland": true, + "subunitcolor": "white" + }, + "hoverlabel": { + "align": "left" + }, + "hovermode": "closest", + "mapbox": { + "style": "light" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "gridwidth": 2, + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white" + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "ternary": { + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "bgcolor": "#E5ECF6", + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "title": { + "x": 0.05 + }, + "xaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + }, + "yaxis": { + "automargin": true, + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "zerolinewidth": 2 + } + } + }, + "xaxis": { + "title": { + "text": "Strain (%)" + }, + "type": "log" + }, + "yaxis": { + "title": { + "text": "Number of atoms" + }, + "type": "log" + } + } + } + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Termination 0: ('C_P6/mmm_2', 'Ni_R-3m_1')\n" + ] + } + ], + "source": [ + "import plotly.graph_objs as go\n", + "from collections import defaultdict\n", + "\n", + "PLOT_SETTINGS = {\n", + " \"HEIGHT\": 600,\n", + " \"X_SCALE\": \"log\", # or linear\n", + " \"Y_SCALE\": \"log\", # or linear\n", + "}\n", + "\n", + "\n", + "def plot_strain_vs_atoms(sorted_interfaces, terminations, settings):\n", + " # Create a mapping from termination to its index\n", + " termination_to_index = {termination: i for i, termination in enumerate(terminations)}\n", + "\n", + " grouped_interfaces = defaultdict(list)\n", + " for termination, interfaces in sorted_interfaces.items():\n", + " for index, interface_data in enumerate(interfaces):\n", + " strain_percentage = interface_data[\"mean_abs_strain\"] * 100\n", + " num_sites = interface_data[\"interface\"].num_sites\n", + " key = (strain_percentage, num_sites)\n", + " grouped_interfaces[key].append((index, termination))\n", + "\n", + " data = []\n", + " for (strain, num_sites), indices_and_terminations in grouped_interfaces.items():\n", + " termination_indices = defaultdict(list)\n", + " for index, termination in indices_and_terminations:\n", + " termination_indices[termination].append(index)\n", + " all_indices = [index for indices in termination_indices.values() for index in indices]\n", + " index_range = f\"{min(all_indices)}-{max(all_indices)}\" if len(all_indices) > 1 else str(min(all_indices))\n", + "\n", + " hover_text = \"
-----
\".join(\n", + " f\"Termination: {termination}
Termination index: {termination_to_index[termination]}
Interfaces Index Range: {index_range}
Strain: {strain:.2f}%
Atoms: {num_sites}\"\n", + " for termination, indices in termination_indices.items()\n", + " )\n", + " trace = go.Scatter(\n", + " x=[strain],\n", + " y=[num_sites],\n", + " text=[hover_text],\n", + " mode=\"markers\",\n", + " hoverinfo=\"text\",\n", + " name=f\"Indices: {index_range}\",\n", + " )\n", + " data.append(trace)\n", + "\n", + " layout = go.Layout(\n", + " xaxis=dict(title=\"Strain (%)\", type=settings[\"X_SCALE\"]),\n", + " yaxis=dict(title=\"Number of atoms\", type=settings[\"Y_SCALE\"]),\n", + " hovermode=\"closest\",\n", + " height=settings[\"HEIGHT\"],\n", + " legend_title_text=\"Interfaces Index Range\",\n", + " )\n", + " fig = go.Figure(data=data, layout=layout)\n", + " fig.show()\n", + "\n", + "\n", + "\n", + "plot_strain_vs_atoms(sorted_interfaces, terminations, PLOT_SETTINGS)\n", + "\n", + "for i, termination in enumerate(terminations):\n", + " print(f\"Termination {i}:\", termination)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Select the interface to relax\n", + "\n", + "### 6.1. Select the interface with the desired termination and strain\n", + "\n", + "The data in `sorted_interfaces` now contains an object with the following structure:\n", + "\n", + "```json\n", + "{\n", + " \"('C_P6/mmm_2', 'Si_R-3m_1')\": [\n", + " { ...interface for ('C_P6/mmm_2', 'Si_R-3m_1') at index 0...},\n", + " { ...interface for ('C_P6/mmm_2', 'Si_R-3m_1') at index 1...},\n", + " ...\n", + " ],\n", + " \"\": [\n", + " { ...interface for 'termination at index 1' at index 0...},\n", + " { ...interface for 'termination at index 1' at index 1...},\n", + " ...\n", + " ]\n", + "}\n", + "```\n", + "\n", + "Select the index for termination first, and for it - the index in the list of corresponding interfaces sorted by strain (index 0 has minimum strain)." + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:09.693236Z", + "start_time": "2024-02-23T06:54:09.688382Z" + } + }, + "outputs": [], + "source": [ + "termination_index = 0\n", + "interface_index = 0\n", + "\n", + "termination = terminations[termination_index]\n", + "\n", + "interface = sorted_interfaces[termination][interface_index][\"interface\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Apply relaxation\n", + "### 7.1. Apply relaxation to the selected interface" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:55:22.364557Z", + "start_time": "2024-02-23T06:55:11.082886Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "dir_path /Users/vb/code/mat3ra/api-examples/.venv-3.11/lib/python3.11/site-packages/alignn/ff/alignnff_wt10\n", + "model_path /Users/vb/code/mat3ra/api-examples/.venv-3.11/lib/python3.11/site-packages/alignn/ff/alignnff_wt10\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "ecd2719341094c3daf2bfc1fb837544a", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "FigureWidget({\n", + " 'data': [{'mode': 'lines+markers',\n", + " 'name': 'Energy',\n", + " 'type': 'scatter',\n", + " 'uid': 'c770d60f-b401-459d-adda-da6789b57e20',\n", + " 'x': [],\n", + " 'y': []}],\n", + " 'layout': {'template': '...',\n", + " 'title': {'text': 'Real-time Optimization Progress'},\n", + " 'xaxis': {'anchor': 'y', 'domain': [0.0, 1.0], 'title': {'text': 'Step'}},\n", + " 'yaxis': {'anchor': 'x', 'domain': [0.0, 1.0], 'title': {'text': 'Energy (eV)'}}}\n", + "})" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Step Time Energy fmax\n", + "BFGS: 0 09:15:13 -17.939891 0.1364\n", + "Step: 0, Energy: -17.9399 eV\n", + "BFGS: 1 09:15:14 -17.944651 0.1350\n", + "Step: 1, Energy: -17.9447 eV\n", + "BFGS: 2 09:15:14 -18.104429 0.0183\n", + "Step: 2, Energy: -18.1044 eV\n", + "BFGS: 3 09:15:14 -18.104575 0.0183\n", + "Step: 3, Energy: -18.1046 eV\n", + "BFGS: 4 09:15:15 -18.104699 0.0182\n", + "Step: 4, Energy: -18.1047 eV\n", + "BFGS: 5 09:15:15 -18.104762 0.0182\n", + "Step: 5, Energy: -18.1048 eV\n", + "BFGS: 6 09:15:15 -18.105327 0.0178\n", + "Step: 6, Energy: -18.1053 eV\n", + "Original structure:\n", + " Ni C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143268 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni C \n", + " 3 2\n", + "Cartesian\n", + " 1.2300003829518742 0.7101417146926911 0.0000000000000001\n", + " 0.0000010237800151 0.0000011496383034 2.0085815523361399\n", + " 2.4600007659037484 1.4202834293853821 4.0171631046722771\n", + " 0.0000000000000000 0.0000000000000000 7.0171631046722744\n", + " 1.2299984704321629 0.7101402381262073 7.0171631046722753\n", + "\n", + "\n", + "Relaxed structure:\n", + " Ni C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143268 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni C \n", + " 3 2\n", + "Cartesian\n", + " 1.2300027025647622 0.7101431378908720 0.1948863120965003\n", + " 0.0000122416025937 0.0000077319999213 1.8379527731385130\n", + " 2.4657495023575300 1.4236022556285031 4.0614048789710475\n", + " -0.0108452190571857 -0.0062635946350369 6.9907350485416675\n", + " 1.2221636434393375 0.7056186683932514 6.9790081204315761\n", + "\n", + "The final energy is -18.105 eV.\n" + ] + } + ], + "source": [ + "import plotly.graph_objs as go\n", + "from IPython.display import display\n", + "from plotly.subplots import make_subplots\n", + "from src.utils import poscar_to_ase, ase_to_poscar, ase_to_pymatgen, pymatgen_to_ase\n", + "from ase.optimize import BFGS\n", + "from alignn.ff.ff import AlignnAtomwiseCalculator as Calculator, default_path\n", + "\n", + "model_path = default_path()\n", + "calc = Calculator(path=model_path)\n", + "\n", + "# relax the interface\n", + "ase_interface = poscar_to_ase(interface.to(fmt=\"poscar\"))\n", + "ase_interface.set_calculator(calc)\n", + "\n", + "dyn = BFGS(ase_interface)\n", + "\n", + "# Initialize empty lists to store steps and energies\n", + "steps = []\n", + "energies = []\n", + "\n", + "# Create a plotly figure widget\n", + "fig = make_subplots(rows=1, cols=1, specs=[[{\"type\": \"scatter\"}]])\n", + "scatter = go.Scatter(x=[], y=[], mode='lines+markers', name='Energy')\n", + "fig.add_trace(scatter)\n", + "fig.update_layout(title_text='Real-time Optimization Progress', xaxis_title='Step', yaxis_title='Energy (eV)')\n", + "\n", + "# Display figure widget\n", + "f = go.FigureWidget(fig)\n", + "display(f)\n", + "\n", + "# Define a callback function to update the plot at each step\n", + "def plotly_callback():\n", + " step = dyn.nsteps\n", + " energy = ase_interface.get_total_energy()\n", + "\n", + " # Add the new step and energy to the lists\n", + " steps.append(step)\n", + " energies.append(energy)\n", + "\n", + " print(f\"Step: {step}, Energy: {energy:.4f} eV\")\n", + "\n", + " # Update the figure with the new data\n", + " with f.batch_update():\n", + " f.data[0].x = steps\n", + " f.data[0].y = energies\n", + "\n", + "\n", + "\n", + "dyn.attach(plotly_callback, interval=1)\n", + "dyn.run(fmax=0.018)\n", + "\n", + "# extract results\n", + "ase_original_interface = pymatgen_to_ase(interface)\n", + "ase_final_interface = ase_interface\n", + "relaxed_energy = ase_interface.get_total_energy()\n", + "\n", + "# print out the final relaxed structure and energy\n", + "print('Original structure:\\n', ase_to_poscar(ase_original_interface))\n", + "print('\\nRelaxed structure:\\n', ase_to_poscar(ase_final_interface))\n", + "print(f\"The final energy is {float(relaxed_energy):.3f} eV.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.2. View structure before and after relaxation" + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:16.486110Z", + "start_time": "2024-02-23T06:54:16.296274Z" + } + }, + "outputs": [ + { + "data": { + "text/html": [ + "
\n", + "
\n", + "

Ni3C2 - original

\n", + " \"original\"\n", + "
\n", + " \n", + "
\n", + "

Ni3C2 - relaxed

\n", + " \"relaxed\"\n", + "
\n", + "
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import base64\n", + "from ase.io import write\n", + "from ase.build import make_supercell\n", + "from IPython.display import HTML\n", + "import io\n", + "\n", + "def visualize_material_base64(material, title: str, rotation: str = '0x', number_of_repetitions: int = 3):\n", + " \"\"\"\n", + " Returns an HTML string with a Base64-encoded image for visualization,\n", + " including the name of the file, positioned horizontally.\n", + " \"\"\"\n", + " # Set the number of unit cell repetition for the structure\n", + " n = number_of_repetitions\n", + " material_repeat = make_supercell(material, [[n,0,0],[0,n,0],[0,0,1]])\n", + " text = f\"{material.symbols} - {title}\"\n", + "\n", + " # Write image to a buffer to display in HTML\n", + " buf = io.BytesIO()\n", + " write(buf, material_repeat, format='png', rotation=rotation)\n", + " buf.seek(0)\n", + " img_str = base64.b64encode(buf.read()).decode('utf-8')\n", + " html_str = f'''\n", + "
\n", + "

{text}

\n", + " \"{title}\"\n", + "
\n", + " '''\n", + " return html_str\n", + "\n", + "html_original = visualize_material_base64(ase_original_interface, \"original\", \"-90x\")\n", + "html_relaxed = visualize_material_base64(ase_final_interface, \"relaxed\", \"-90x\")\n", + "\n", + "# Display the interfaces before and after relaxation\n", + "html_content = f'
{html_original}{html_relaxed}
'\n", + "display(HTML(html_content))\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.3. Calculate energy energy using matgl M3GNet" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:57:56.887702Z", + "start_time": "2024-02-23T06:57:56.631462Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5.240839288055053\n", + "5\n", + "3\n", + "2\n", + "Relaxed interface energy: -18.1053 eV\n", + "Original Substrate energy: -2.6920 eV\n", + "Original Layer energy: -15.4182 eV\n", + "Original Delta: 0.0049 eV\n", + "Original Delta per area: 0.0009 eV/Ang^2\n", + "Relaxed Substrate energy: -2.6684 eV\n", + "Relaxed Layer energy: -15.4182 eV\n", + "Relaxed Delta: -0.0187 eV\n", + "Relaxed Delta per area: -0.0036 eV/Ang^2\n", + "Effective relaxed Delta per area: -0.9862 eV/Ang^2\n", + "Ni C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143268 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni C \n", + " 3 2\n", + "Cartesian\n", + " 1.2300027025647622 0.7101431378908720 0.1948863120965003\n", + " 0.0000122416025937 0.0000077319999213 1.8379527731385130\n", + " 2.4657495023575300 1.4236022556285031 4.0614048789710475\n", + " -0.0108452190571857 -0.0062635946350369 6.9907350485416675\n", + " 1.2221636434393375 0.7056186683932514 6.9790081204315761\n", + "\n", + "Ni \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143268 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni \n", + " 3\n", + "Cartesian\n", + " 1.2300027025647622 0.7101431378908720 0.1948863120965003\n", + " 0.0000122416025937 0.0000077319999213 1.8379527731385130\n", + " 2.4657495023575300 1.4236022556285031 4.0614048789710475\n", + "\n", + " C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143268 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " C \n", + " 2\n", + "Cartesian\n", + " -0.0108452190571857 -0.0062635946350369 6.9907350485416675\n", + " 1.2221636434393375 0.7056186683932514 6.9790081204315761\n", + "\n", + "Ni \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143268 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni \n", + " 3\n", + "Cartesian\n", + " 1.2300003829518742 0.7101417146926911 0.0000000000000001\n", + " 0.0000010237800151 0.0000011496383034 2.0085815523361399\n", + " 2.4600007659037484 1.4202834293853821 4.0171631046722771\n", + "\n", + " C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143268 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " C \n", + " 2\n", + "Cartesian\n", + " 0.0000000000000000 0.0000000000000000 7.0171631046722744\n", + " 1.2299984704321629 0.7101402381262073 7.0171631046722753\n", + "\n" + ] + } + ], + "source": [ + "nickel_relaxed_interface = ase_final_interface.copy()\n", + "graphene_relaxed_interface = ase_final_interface.copy()\n", + "nickel_original_interface = ase_original_interface.copy()\n", + "graphene_original_interface = ase_original_interface.copy()\n", + "\n", + "del nickel_relaxed_interface[[atom.index for atom in nickel_relaxed_interface if atom.symbol != 'Ni']]\n", + "del graphene_relaxed_interface[[atom.index for atom in graphene_relaxed_interface if atom.symbol != 'C']]\n", + "del nickel_original_interface[[atom.index for atom in nickel_original_interface if atom.symbol != 'Ni']]\n", + "del graphene_original_interface[[atom.index for atom in graphene_original_interface if atom.symbol != 'C']]\n", + "\n", + "#set EMT calculator\n", + "nickel_relaxed_interface.set_calculator(calc)\n", + "graphene_relaxed_interface.set_calculator(calc)\n", + "nickel_original_interface.set_calculator(calc)\n", + "graphene_original_interface.set_calculator(calc)\n", + "\n", + "original_substrate_energy = nickel_original_interface.get_total_energy()\n", + "original_layer_energy = graphene_original_interface.get_total_energy()\n", + "relaxed_substrate_energy = nickel_relaxed_interface.get_total_energy()\n", + "relaxed_layer_energy = graphene_relaxed_interface.get_total_energy()\n", + "\n", + "delta_original = relaxed_energy - original_substrate_energy - original_layer_energy\n", + "delta_relaxed = relaxed_energy - relaxed_substrate_energy - relaxed_layer_energy\n", + "\n", + "# calculate area of interface\n", + "area = ase_original_interface.get_volume() / ase_original_interface.cell[2, 2]\n", + "print(area)\n", + "\n", + "effective_delta_relaxed = (relaxed_energy * ase_final_interface.get_global_number_of_atoms() -\n", + " nickel_relaxed_interface.get_global_number_of_atoms() * relaxed_substrate_energy -\n", + " graphene_relaxed_interface.get_global_number_of_atoms() * relaxed_layer_energy)/(2 * area * ase_final_interface.get_global_number_of_atoms())\n", + "print(ase_final_interface.get_global_number_of_atoms())\n", + "print(nickel_relaxed_interface.get_global_number_of_atoms())\n", + "print(graphene_relaxed_interface.get_global_number_of_atoms())\n", + "# print(f\"Original interface energy: {ase_original_interface.get_total_energy():.4f} eV\")\n", + "print(f\"Relaxed interface energy: {relaxed_energy:.4f} eV\")\n", + "print(f\"Original Substrate energy: {original_substrate_energy:.4f} eV\")\n", + "print(f\"Original Layer energy: {original_layer_energy:.4f} eV\")\n", + "print(f\"Original Delta: {delta_original:.4f} eV\")\n", + "print(f\"Original Delta per area: {delta_original / area:.4f} eV/Ang^2\")\n", + "print(f\"Relaxed Substrate energy: {relaxed_substrate_energy:.4f} eV\")\n", + "print(f\"Relaxed Layer energy: {relaxed_layer_energy:.4f} eV\")\n", + "print(f\"Relaxed Delta: {delta_relaxed:.4f} eV\")\n", + "print(f\"Relaxed Delta per area: {delta_relaxed / area:.4f} eV/Ang^2\")\n", + "print(f\"Effective relaxed Delta per area: {effective_delta_relaxed:.4f} eV/Ang^2\")\n", + "\n", + "\n", + "print(ase_to_poscar(ase_final_interface))\n", + "print(ase_to_poscar(nickel_relaxed_interface))\n", + "print(ase_to_poscar(graphene_relaxed_interface))\n", + "print(ase_to_poscar(nickel_original_interface))\n", + "print(ase_to_poscar(graphene_original_interface))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "start_time": "2024-02-23T06:54:17.113780Z" + } + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:54:17.124980Z", + "start_time": "2024-02-23T06:54:17.116350Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [] + }, + { + "cell_type": "markdown", + "metadata": { + "collapsed": false + }, + "source": [ + "## References\n", + "\n", + "[1] ASE alignn calculator relaxation example: https://github.com/usnistgov/alignn?tab=readme-ov-file#alignnff \n", + "[2] Plotly 3D molecular visualization: https://dash.plotly.com/dash-bio/molecule3dviewer" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.7" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": {}, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/other/materials_designer/create_interface_with_relaxation_ase_emt.ipynb b/other/materials_designer/create_interface_with_relaxation_ase_emt.ipynb new file mode 100644 index 00000000..eb4dd729 --- /dev/null +++ b/other/materials_designer/create_interface_with_relaxation_ase_emt.ipynb @@ -0,0 +1,1906 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Create an interface between two materials with minimal strain\n", + "\n", + "Use Zur and McGill superlattices matching [algorithm](https://doi.org/10.1063/1.3330840) to create interfaces between two materials using the Pymatgen [implementation](https://pymatgen.org/pymatgen.analysis.interfaces.html#pymatgen.analysis.interfaces.zsl).\n", + "\n", + "

Usage

\n", + "\n", + "0. Make sure to select Input Materials\n", + "1. Execute \"Run first: ...\" cell below to load Input Materials into the current kernel\n", + "2. Set Input Parameters (e.g. `MILLER_INDICES`, `THICKNESS`, `MAX_AREA`) below or use the default values\n", + "3. Click \"Run\" > \"Run All\" to run all cells\n", + "4. Wait for the run to complete (depending on the area, it can take 1-2 min or more). Scroll down to view cell results.\n", + "5. Review the strain plot and modify its parameters as needed\n", + "\n", + "## Methodology\n", + "\n", + "The following happens in the script below:\n", + "\n", + "1. Create slabs for each input material. The materials data is passed in from and back to the web application according to this description (TBA).\n", + " We assume that two input materials are either in bulk form (e.g. Ni crystal) or layered (e.g. graphene). \n", + " \n", + " We construct the interface along the Z-axis. The material corresponding to the bottom of the interface is referred to as the \"**substrate**\", and the top - as the \"**layer**\". \n", + "\n", + "2. Perform strain matching on the slabs to extract the supercell dimensions. The algorithm has a set of parameters, such as the maximum area considered, that can be configured by editing the cells below.\n", + "\n", + "3. When the strain matching is finished, the interface with the lowest strain (and the smallest number of atoms) is selected. We create the corresponding supercells and place them at a specified distance from each other (note no shift is performed currently).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Run first: load input materials in current kernel

\n" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:32.139897Z", + "start_time": "2024-02-23T06:59:32.011540Z" + } + }, + "outputs": [], + "source": [ + "import json\n", + "materials_in = []\n", + "for file in [\"Ni.json\", \"Gr.json\"]:\n", + " with open(file, \"r\") as f:\n", + " data = f.read()\n", + " materials_in.append(json.loads(data))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Set Input Parameters\n", + "\n", + "### 1.1. Select Substrate and Layer from Input Materials" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:32.182902Z", + "start_time": "2024-02-23T06:59:32.143075Z" + } + }, + "outputs": [], + "source": [ + "SUBSTRATE_PARAMETERS = {\n", + " \"MATERIAL_INDEX\": 0, # the index of the material in the materials_in list\n", + " \"MILLER_INDICES\": (1, 1, 1), # the miller indices of the interfacial plane\n", + " \"THICKNESS\": 3, # in layers\n", + "}\n", + "\n", + "LAYER_PARAMETERS = {\n", + " \"MATERIAL_INDEX\": 1, # the index of the material in the materials_in list\n", + " \"MILLER_INDICES\": (0, 0, 1), # the miller indices of the interfacial plane\n", + " \"THICKNESS\": 1, # in layers\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.2. Set Interface Parameters\n", + "\n", + "The distance between layer and substrate and maximum area to consider when matching.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 26, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:32.260407Z", + "start_time": "2024-02-23T06:59:32.186142Z" + } + }, + "outputs": [], + "source": [ + "INTERFACE_PARAMETERS = {\n", + " \"DISTANCE_Z\": 3.0, # in Angstroms\n", + " \"MAX_AREA\": 50, # in Angstroms^2\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.3. Set Algorithm Parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 27, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:32.325278Z", + "start_time": "2024-02-23T06:59:32.251721Z" + } + }, + "outputs": [], + "source": [ + "ZSL_PARAMETERS = {\n", + " \"MAX_AREA\": INTERFACE_PARAMETERS[\"MAX_AREA\"], # The area to consider in Angstrom^2\n", + " \"MAX_AREA_TOL\": 0.09, # The area within this tolerance is considered equal\n", + " \"MAX_LENGTH_TOL\": 0.03, # supercell lattice vectors lengths within this tolerance are considered equal\n", + " \"MAX_ANGLE_TOL\": 0.01, # supercell lattice angles within this tolerance are considered equal\n", + " \"STRAIN_TOL\": 10e-6, # strains within this tolerance are considered equal\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Install Packages" + ] + }, + { + "cell_type": "code", + "execution_count": 28, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:32.377580Z", + "start_time": "2024-02-23T06:59:32.318494Z" + } + }, + "outputs": [], + "source": [ + "# from jupyterlite.utils import install_packages\n", + "\n", + "# await install_packages(\"create_interface_with_min_strain_zsl.ipynb\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Create interfaces\n", + "\n", + "### 3.1. Extract Interfaces and Terminations\n", + "\n", + "Extract all possible layer/substrate supercell combinations within the maximum area including different terminations." + ] + }, + { + "cell_type": "code", + "execution_count": 29, + "metadata": { + "tags": [], + "trusted": true, + "ExecuteTime": { + "end_time": "2024-02-23T06:59:34.530093Z", + "start_time": "2024-02-23T06:59:32.371609Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Full Formula (Ni1)\n", + "Reduced Formula: Ni\n", + "abc : 2.460000 2.460000 2.460000\n", + "angles: 60.000004 59.999994 60.000003\n", + "pbc : True True True\n", + "Sites (1)\n", + " # SP a b c\n", + "--- ---- --- --- ---\n", + " 0 Ni 0 0 0 \n", + "\n", + "Full Formula (C2)\n", + "Reduced Formula: C\n", + "abc : 2.467291 2.467291 20.000000\n", + "angles: 90.000000 90.000000 119.999986\n", + "pbc : True True True\n", + "Sites (2)\n", + " # SP a b c\n", + "--- ---- -------- -------- ---\n", + " 0 C 0 0 0\n", + " 1 C 0.333333 0.666667 0 \n", + "\n", + "Creating interfaces...\n" + ] + } + ], + "source": [ + "from src.pymatgen_coherent_interface_builder import CoherentInterfaceBuilder, ZSLGenerator\n", + "from src.utils import to_pymatgen\n", + "\n", + "if \"materials_in\" in globals():\n", + " pymatgen_materials = [to_pymatgen(item) for item in materials_in]\n", + "for material in pymatgen_materials:\n", + " print(material, \"\\n\")\n", + "\n", + "\n", + "def create_interfaces(settings):\n", + " print(\"Creating interfaces...\")\n", + " zsl = ZSLGenerator(\n", + " max_area_ratio_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_AREA_TOL\"],\n", + " max_area=settings[\"ZSL_PARAMETERS\"][\"MAX_AREA\"],\n", + " max_length_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_LENGTH_TOL\"],\n", + " max_angle_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_ANGLE_TOL\"],\n", + " )\n", + "\n", + " cib = CoherentInterfaceBuilder(\n", + " substrate_structure=pymatgen_materials[settings[\"SUBSTRATE_PARAMETERS\"][\"MATERIAL_INDEX\"]],\n", + " film_structure=pymatgen_materials[settings[\"LAYER_PARAMETERS\"][\"MATERIAL_INDEX\"]],\n", + " substrate_miller=settings[\"SUBSTRATE_PARAMETERS\"][\"MILLER_INDICES\"],\n", + " film_miller=settings[\"LAYER_PARAMETERS\"][\"MILLER_INDICES\"],\n", + " zslgen=zsl,\n", + " strain_tol=settings[\"ZSL_PARAMETERS\"][\"STRAIN_TOL\"],\n", + " )\n", + "\n", + " # Find terminations\n", + " cib._find_terminations()\n", + " terminations = cib.terminations\n", + "\n", + " # Create interfaces for each termination\n", + " interfaces = {}\n", + " for termination in terminations:\n", + " interfaces[termination] = []\n", + " for interface in cib.get_interfaces(\n", + " termination,\n", + " gap=settings[\"INTERFACE_PARAMETERS\"][\"DISTANCE_Z\"],\n", + " film_thickness=settings[\"LAYER_PARAMETERS\"][\"THICKNESS\"],\n", + " substrate_thickness=settings[\"SUBSTRATE_PARAMETERS\"][\"THICKNESS\"],\n", + " in_layers=True,\n", + " ):\n", + " # Wrap atoms to unit cell\n", + " interface[\"interface\"].make_supercell((1,1,1), to_unit_cell=True)\n", + " interfaces[termination].append(interface)\n", + " return interfaces, terminations\n", + "\n", + "\n", + "interfaces, terminations = create_interfaces(\n", + " settings={\n", + " \"SUBSTRATE_PARAMETERS\": SUBSTRATE_PARAMETERS,\n", + " \"LAYER_PARAMETERS\": LAYER_PARAMETERS,\n", + " \"ZSL_PARAMETERS\": ZSL_PARAMETERS,\n", + " \"INTERFACE_PARAMETERS\": INTERFACE_PARAMETERS,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3.2. Print out the interfaces and terminations" + ] + }, + { + "cell_type": "code", + "execution_count": 30, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:34.539509Z", + "start_time": "2024-02-23T06:59:34.533076Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 1 terminations\n", + "Found 233 interfaces for ('C_P6/mmm_2', 'Ni_R-3m_1') termination\n" + ] + } + ], + "source": [ + "print(f'Found {len(terminations)} terminations')\n", + "for termination in terminations:\n", + " print(f\"Found {len(interfaces[termination])} interfaces for\", termination, \"termination\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Sort interfaces by strain\n", + "\n", + "### 4.1. Sort all interfaces" + ] + }, + { + "cell_type": "code", + "execution_count": 31, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:34.552722Z", + "start_time": "2024-02-23T06:59:34.549963Z" + } + }, + "outputs": [], + "source": [ + "# Could be \"strain\", \"von_mises_strain\", \"mean_abs_strain\"\n", + "strain_mode = \"mean_abs_strain\"\n", + "\n", + "# Sort interfaces by the specified strain mode and number of sites\n", + "def sort_interfaces(interfaces, terminations):\n", + " sorted_interfaces = {}\n", + " for termination in terminations:\n", + " sorted_interfaces[termination] = sorted(\n", + " interfaces[termination], key=lambda x: (x[strain_mode], x[\"interface\"].num_sites)\n", + " )\n", + " return sorted_interfaces\n", + "\n", + "\n", + "sorted_interfaces = sort_interfaces(interfaces, terminations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.2. Print out interfaces with lowest strain for each termination" + ] + }, + { + "cell_type": "code", + "execution_count": 32, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:34.603677Z", + "start_time": "2024-02-23T06:59:34.556662Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Interface with lowest strain for termination ('C_P6/mmm_2', 'Ni_R-3m_1') (index 0):\n", + " strain: 0.06600000000000002 %\n", + " number of atoms: 5\n" + ] + } + ], + "source": [ + "for termination in terminations:\n", + " print(f\"Interface with lowest strain for termination {termination} (index 0):\")\n", + " first_interface = interfaces[termination][0]\n", + " print(\" strain:\", first_interface[strain_mode] * 100, \"%\")\n", + " print(\" number of atoms:\", first_interface[\"interface\"].num_sites)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Plot the results\n", + "\n", + "Plot the number of atoms vs strain. Adjust the parameters as needed.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 33, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:34.605359Z", + "start_time": "2024-02-23T06:59:34.573908Z" + } + }, + "outputs": [ + { + "data": { + "application/vnd.plotly.v1+json": { + "data": [ + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 0", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 0
Strain: 0.07%
Atoms: 5" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 5 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 1-9", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 1-9
Strain: 0.07%
Atoms: 10" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 10 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 10-19", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 10-19
Strain: 0.07%
Atoms: 15" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 15 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 20-38", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 20-38
Strain: 0.07%
Atoms: 20" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 20 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 39-56", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 39-56
Strain: 0.07%
Atoms: 25" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 25 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 57-110", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 57-110
Strain: 0.07%
Atoms: 30" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 30 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 111-132", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 111-132
Strain: 0.07%
Atoms: 35" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 35 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 133-177", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 133-177
Strain: 0.07%
Atoms: 40" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 40 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 178-232", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 178-232
Strain: 0.07%
Atoms: 45" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 45 + ], + "type": "scatter" + } + ], + "layout": { + "height": 600, + "hovermode": "closest", + "legend": { + "title": { + "text": "Interfaces Index Range" + } + }, + "xaxis": { + "title": { + "text": "Strain (%)" + }, + "type": "log" + }, + "yaxis": { + "title": { + "text": "Number of atoms" + }, + "type": "log" + }, + "template": { + "data": { + "histogram2dcontour": [ + { + "type": "histogram2dcontour", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "choropleth": [ + { + "type": "choropleth", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "histogram2d": [ + { + "type": "histogram2d", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "heatmap": [ + { + "type": "heatmap", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "heatmapgl": [ + { + "type": "heatmapgl", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "contourcarpet": [ + { + "type": "contourcarpet", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "contour": [ + { + "type": "contour", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "surface": [ + { + "type": "surface", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "mesh3d": [ + { + "type": "mesh3d", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "scatter": [ + { + "fillpattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + }, + "type": "scatter" + } + ], + "parcoords": [ + { + "type": "parcoords", + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterpolargl": [ + { + "type": "scatterpolargl", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "bar": [ + { + "error_x": { + "color": "#2a3f5f" + }, + "error_y": { + "color": "#2a3f5f" + }, + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "scattergeo": [ + { + "type": "scattergeo", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterpolar": [ + { + "type": "scatterpolar", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "scattergl": [ + { + "type": "scattergl", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatter3d": [ + { + "type": "scatter3d", + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scattermapbox": [ + { + "type": "scattermapbox", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterternary": [ + { + "type": "scatterternary", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scattercarpet": [ + { + "type": "scattercarpet", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "baxis": { + "endlinecolor": "#2a3f5f", + "gridcolor": "white", + "linecolor": "white", + "minorgridcolor": "white", + "startlinecolor": "#2a3f5f" + }, + "type": "carpet" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#EBF0F8" + }, + "line": { + "color": "white" + } + }, + "header": { + "fill": { + "color": "#C8D4E3" + }, + "line": { + "color": "white" + } + }, + "type": "table" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "#E5ECF6", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ] + }, + "layout": { + "autotypenumbers": "strict", + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#2a3f5f" + }, + "hovermode": "closest", + "hoverlabel": { + "align": "left" + }, + "paper_bgcolor": "white", + "plot_bgcolor": "#E5ECF6", + "polar": { + "bgcolor": "#E5ECF6", + "angularaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "radialaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "ternary": { + "bgcolor": "#E5ECF6", + "aaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "baxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + }, + "caxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "" + } + }, + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ] + }, + "xaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "automargin": true, + "zerolinewidth": 2 + }, + "yaxis": { + "gridcolor": "white", + "linecolor": "white", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "white", + "automargin": true, + "zerolinewidth": 2 + }, + "scene": { + "xaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white", + "gridwidth": 2 + }, + "yaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white", + "gridwidth": 2 + }, + "zaxis": { + "backgroundcolor": "#E5ECF6", + "gridcolor": "white", + "linecolor": "white", + "showbackground": true, + "ticks": "", + "zerolinecolor": "white", + "gridwidth": 2 + } + }, + "shapedefaults": { + "line": { + "color": "#2a3f5f" + } + }, + "annotationdefaults": { + "arrowcolor": "#2a3f5f", + "arrowhead": 0, + "arrowwidth": 1 + }, + "geo": { + "bgcolor": "white", + "landcolor": "#E5ECF6", + "subunitcolor": "white", + "showland": true, + "showlakes": true, + "lakecolor": "white" + }, + "title": { + "x": 0.05 + }, + "mapbox": { + "style": "light" + } + } + } + }, + "config": { + "plotlyServerURL": "https://plot.ly" + } + }, + "text/html": "
" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Termination 0: ('C_P6/mmm_2', 'Ni_R-3m_1')\n" + ] + } + ], + "source": [ + "import plotly.graph_objs as go\n", + "from collections import defaultdict\n", + "\n", + "PLOT_SETTINGS = {\n", + " \"HEIGHT\": 600,\n", + " \"X_SCALE\": \"log\", # or linear\n", + " \"Y_SCALE\": \"log\", # or linear\n", + "}\n", + "\n", + "\n", + "def plot_strain_vs_atoms(sorted_interfaces, terminations, settings):\n", + " # Create a mapping from termination to its index\n", + " termination_to_index = {termination: i for i, termination in enumerate(terminations)}\n", + "\n", + " grouped_interfaces = defaultdict(list)\n", + " for termination, interfaces in sorted_interfaces.items():\n", + " for index, interface_data in enumerate(interfaces):\n", + " strain_percentage = interface_data[\"mean_abs_strain\"] * 100\n", + " num_sites = interface_data[\"interface\"].num_sites\n", + " key = (strain_percentage, num_sites)\n", + " grouped_interfaces[key].append((index, termination))\n", + " \n", + " data = []\n", + " for (strain, num_sites), indices_and_terminations in grouped_interfaces.items():\n", + " termination_indices = defaultdict(list)\n", + " for index, termination in indices_and_terminations:\n", + " termination_indices[termination].append(index)\n", + " all_indices = [index for indices in termination_indices.values() for index in indices]\n", + " index_range = f\"{min(all_indices)}-{max(all_indices)}\" if len(all_indices) > 1 else str(min(all_indices))\n", + " \n", + " hover_text = \"
-----
\".join(\n", + " f\"Termination: {termination}
Termination index: {termination_to_index[termination]}
Interfaces Index Range: {index_range}
Strain: {strain:.2f}%
Atoms: {num_sites}\"\n", + " for termination, indices in termination_indices.items()\n", + " )\n", + " trace = go.Scatter(\n", + " x=[strain],\n", + " y=[num_sites],\n", + " text=[hover_text],\n", + " mode=\"markers\",\n", + " hoverinfo=\"text\",\n", + " name=f\"Indices: {index_range}\",\n", + " )\n", + " data.append(trace)\n", + "\n", + " layout = go.Layout(\n", + " xaxis=dict(title=\"Strain (%)\", type=settings[\"X_SCALE\"]),\n", + " yaxis=dict(title=\"Number of atoms\", type=settings[\"Y_SCALE\"]),\n", + " hovermode=\"closest\",\n", + " height=settings[\"HEIGHT\"],\n", + " legend_title_text=\"Interfaces Index Range\",\n", + " )\n", + " fig = go.Figure(data=data, layout=layout)\n", + " fig.show()\n", + "\n", + "\n", + "\n", + "plot_strain_vs_atoms(sorted_interfaces, terminations, PLOT_SETTINGS)\n", + "\n", + "for i, termination in enumerate(terminations):\n", + " print(f\"Termination {i}:\", termination)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Select the interface to relax\n", + "\n", + "### 6.1. Select the interface with the desired termination and strain\n", + "\n", + "The data in `sorted_interfaces` now contains an object with the following structure:\n", + "\n", + "```json\n", + "{\n", + " \"('C_P6/mmm_2', 'Si_R-3m_1')\": [\n", + " { ...interface for ('C_P6/mmm_2', 'Si_R-3m_1') at index 0...},\n", + " { ...interface for ('C_P6/mmm_2', 'Si_R-3m_1') at index 1...},\n", + " ...\n", + " ],\n", + " \"\": [\n", + " { ...interface for 'termination at index 1' at index 0...},\n", + " { ...interface for 'termination at index 1' at index 1...},\n", + " ...\n", + " ]\n", + "}\n", + "```\n", + "\n", + "Select the index for termination first, and for it - the index in the list of corresponding interfaces sorted by strain (index 0 has minimum strain)." + ] + }, + { + "cell_type": "code", + "execution_count": 34, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:34.606026Z", + "start_time": "2024-02-23T06:59:34.582078Z" + } + }, + "outputs": [], + "source": [ + "termination_index = 0\n", + "interface_index = 0\n", + "\n", + "termination = terminations[termination_index]\n", + "\n", + "interface = sorted_interfaces[termination][interface_index][\"interface\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Apply relaxation\n", + "### 7.1. Apply relaxation to the selected interface" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:34.870087Z", + "start_time": "2024-02-23T06:59:34.592671Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + " Step Time Energy fmax\n", + "BFGS: 0 22:59:34 1.423498 0.2830\n", + "BFGS: 1 22:59:34 1.422027 0.2575\n", + "BFGS: 2 22:59:34 1.410513 0.2052\n", + "BFGS: 3 22:59:34 1.408686 0.2119\n", + "BFGS: 4 22:59:34 1.404357 0.2224\n", + "BFGS: 5 22:59:34 1.396633 0.3918\n", + "BFGS: 6 22:59:34 1.359630 0.7796\n", + "BFGS: 7 22:59:34 1.248944 1.0053\n", + "BFGS: 8 22:59:34 1.171894 1.0624\n", + "BFGS: 9 22:59:34 1.142866 1.0505\n", + "BFGS: 10 22:59:34 1.095750 1.0480\n", + "BFGS: 11 22:59:34 0.909481 1.0819\n", + "BFGS: 12 22:59:34 0.845958 1.4513\n", + "BFGS: 13 22:59:34 0.759011 0.9676\n", + "BFGS: 14 22:59:34 0.731432 0.3462\n", + "BFGS: 15 22:59:34 0.723573 0.1376\n", + "BFGS: 16 22:59:34 0.722363 0.0433\n", + "BFGS: 17 22:59:34 0.722235 0.0062\n", + "Original structure:\n", + " Ni C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni C \n", + " 3 2\n", + "Cartesian\n", + " 1.2300003829518735 0.7101417146926911 0.0000000000000001\n", + " 0.0000010237800144 0.0000011496383034 2.0085815523361399\n", + " 2.4600007659037471 1.4202834293853821 4.0171631046722771\n", + " 0.0000000000000000 0.0000000000000000 7.0171631046722780\n", + " 1.2299984704321631 0.7101402381262073 7.0171631046722780\n", + "\n", + "\n", + "Relaxed structure:\n", + " Ni C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni C \n", + " 3 2\n", + "Cartesian\n", + " 1.2300031015085946 0.7101461929515854 0.5260421300230792\n", + " 0.0000006922939747 0.0000006009098648 2.5465564275909114\n", + " 2.4599985522195529 1.4202799717570684 4.5673026420532636\n", + " -0.0000007808382405 -0.0000007432361958 6.2106684704714068\n", + " 1.2299990778839116 0.7101405094602526 6.2095011962143465\n", + "\n", + "The final energy is 0.722 eV.\n" + ] + } + ], + "source": [ + "# Per https://github.com/materialsvirtuallab/matgl/blob/main/examples/Relaxations%20and%20Simulations%20using%20the%20M3GNet%20Universal%20Potential.ipynb\n", + "from src.utils import poscar_to_ase, ase_to_poscar, ase_to_pymatgen, pymatgen_to_ase\n", + "from ase.optimize import BFGS\n", + "from ase.calculators.emt import EMT\n", + "\n", + "# relax the interface\n", + "ase_interface = poscar_to_ase(interface.to(fmt=\"poscar\"))\n", + "ase_interface.set_calculator(EMT())\n", + "dyn = BFGS(ase_interface)\n", + "dyn.run(fmax=0.01)\n", + "\n", + "# extract results\n", + "ase_original_interface = pymatgen_to_ase(interface)\n", + "ase_final_interface = ase_interface\n", + "relaxed_energy = ase_interface.get_total_energy()\n", + "\n", + "# print out the final relaxed structure and energy\n", + "print('Original structure:\\n', ase_to_poscar(ase_original_interface))\n", + "print('\\nRelaxed structure:\\n', ase_to_poscar(ase_final_interface))\n", + "print(f\"The final energy is {float(relaxed_energy):.3f} eV.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.2. View structure before and after relaxation" + ] + }, + { + "cell_type": "code", + "execution_count": 39, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T07:00:03.504373Z", + "start_time": "2024-02-23T07:00:02.936170Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "", + "text/html": "
\n
\n

Ni3C2 - original

\n \"original\"\n
\n \n
\n

Ni3C2 - relaxed

\n \"relaxed\"\n
\n
" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import base64\n", + "from ase.io import write\n", + "from ase.build import make_supercell\n", + "from IPython.display import HTML\n", + "import io\n", + "\n", + "def visualize_material_base64(material, title: str, rotation: str = '0x', number_of_repetitions: int = 3):\n", + " \"\"\"\n", + " Returns an HTML string with a Base64-encoded image for visualization,\n", + " including the name of the file, positioned horizontally.\n", + " \"\"\"\n", + " # Set the number of unit cell repetition for the structure\n", + " n = number_of_repetitions\n", + " material_repeat = make_supercell(material, [[n,0,0],[0,n,0],[0,0,1]])\n", + " text = f\"{material.symbols} - {title}\"\n", + " \n", + " # Write image to a buffer to display in HTML\n", + " buf = io.BytesIO()\n", + " write(buf, material_repeat, format='png', rotation=rotation)\n", + " buf.seek(0)\n", + " img_str = base64.b64encode(buf.read()).decode('utf-8')\n", + " html_str = f'''\n", + "
\n", + "

{text}

\n", + " \"{title}\"\n", + "
\n", + " '''\n", + " return html_str\n", + "\n", + "html_original = visualize_material_base64(ase_original_interface, \"original\", \"-90x\")\n", + "html_relaxed = visualize_material_base64(ase_final_interface, \"relaxed\", \"-90x\")\n", + "\n", + "# Display the interfaces before and after relaxation\n", + "html_content = f'
{html_original}{html_relaxed}
'\n", + "display(HTML(html_content))\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.3. Calculate energy energy using ASE EMT" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:34.937042Z", + "start_time": "2024-02-23T06:59:34.870485Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5.240839288055053\n", + "5\n", + "3\n", + "2\n", + "Relaxed interface energy: 0.7222 eV\n", + "Original Substrate energy: 1.0828 eV\n", + "Original Layer energy: 0.4296 eV\n", + "Original Delta: -0.7901 eV\n", + "Original Delta per area: -0.1508 eV/Ang^2\n", + "Relaxed Substrate energy: 1.0817 eV\n", + "Relaxed Layer energy: 0.4296 eV\n", + "Relaxed Delta: -0.7890 eV\n", + "Relaxed Delta per area: -0.1506 eV/Ang^2\n", + "Effective relaxed Delta per area: -0.0094 eV/Ang^2\n", + "Ni C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni C \n", + " 3 2\n", + "Cartesian\n", + " 1.2300031015085946 0.7101461929515854 0.5260421300230792\n", + " 0.0000006922939747 0.0000006009098648 2.5465564275909114\n", + " 2.4599985522195529 1.4202799717570684 4.5673026420532636\n", + " -0.0000007808382405 -0.0000007432361958 6.2106684704714068\n", + " 1.2299990778839116 0.7101405094602526 6.2095011962143465\n", + "\n", + "Ni \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni \n", + " 3\n", + "Cartesian\n", + " 1.2300031015085946 0.7101461929515854 0.5260421300230792\n", + " 0.0000006922939747 0.0000006009098648 2.5465564275909114\n", + " 2.4599985522195529 1.4202799717570684 4.5673026420532636\n", + "\n", + " C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " C \n", + " 2\n", + "Cartesian\n", + " -0.0000007808382405 -0.0000007432361958 6.2106684704714068\n", + " 1.2299990778839116 0.7101405094602526 6.2095011962143465\n", + "\n", + "Ni \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni \n", + " 3\n", + "Cartesian\n", + " 1.2300003829518735 0.7101417146926911 0.0000000000000001\n", + " 0.0000010237800144 0.0000011496383034 2.0085815523361399\n", + " 2.4600007659037471 1.4202834293853821 4.0171631046722771\n", + "\n", + " C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " C \n", + " 2\n", + "Cartesian\n", + " 0.0000000000000000 0.0000000000000000 7.0171631046722780\n", + " 1.2299984704321631 0.7101402381262073 7.0171631046722780\n" + ] + } + ], + "source": [ + "from ase import Atoms\n", + "nickel_relaxed_interface = ase_final_interface.copy()\n", + "graphene_relaxed_interface = ase_final_interface.copy()\n", + "nickel_original_interface = ase_original_interface.copy()\n", + "graphene_original_interface = ase_original_interface.copy()\n", + "\n", + "del nickel_relaxed_interface[[atom.index for atom in nickel_relaxed_interface if atom.symbol != 'Ni']]\n", + "del graphene_relaxed_interface[[atom.index for atom in graphene_relaxed_interface if atom.symbol != 'C']]\n", + "del nickel_original_interface[[atom.index for atom in nickel_original_interface if atom.symbol != 'Ni']]\n", + "del graphene_original_interface[[atom.index for atom in graphene_original_interface if atom.symbol != 'C']]\n", + "\n", + "#set EMT calculator\n", + "nickel_relaxed_interface.set_calculator(EMT())\n", + "graphene_relaxed_interface.set_calculator(EMT())\n", + "nickel_original_interface.set_calculator(EMT())\n", + "graphene_original_interface.set_calculator(EMT())\n", + "\n", + "original_substrate_energy = nickel_original_interface.get_total_energy()\n", + "original_layer_energy = graphene_original_interface.get_total_energy()\n", + "relaxed_substrate_energy = nickel_relaxed_interface.get_total_energy()\n", + "relaxed_layer_energy = graphene_relaxed_interface.get_total_energy()\n", + "\n", + "delta_original = relaxed_energy - original_substrate_energy - original_layer_energy\n", + "delta_relaxed = relaxed_energy - relaxed_substrate_energy - relaxed_layer_energy\n", + "\n", + "# calculate area of interface\n", + "area = ase_original_interface.get_volume() / ase_original_interface.cell[2, 2]\n", + "print(area)\n", + "\n", + "effective_delta_relaxed = (relaxed_energy * ase_final_interface.get_global_number_of_atoms() -\n", + " nickel_relaxed_interface.get_global_number_of_atoms() * relaxed_substrate_energy -\n", + " graphene_relaxed_interface.get_global_number_of_atoms() * relaxed_layer_energy)/(2 * area * ase_final_interface.get_global_number_of_atoms())\n", + "print(ase_final_interface.get_global_number_of_atoms())\n", + "print(nickel_relaxed_interface.get_global_number_of_atoms())\n", + "print(graphene_relaxed_interface.get_global_number_of_atoms())\n", + "# print(f\"Original interface energy: {ase_original_interface.get_total_energy():.4f} eV\")\n", + "print(f\"Relaxed interface energy: {relaxed_energy:.4f} eV\")\n", + "print(f\"Original Substrate energy: {original_substrate_energy:.4f} eV\")\n", + "print(f\"Original Layer energy: {original_layer_energy:.4f} eV\")\n", + "print(f\"Original Delta: {delta_original:.4f} eV\")\n", + "print(f\"Original Delta per area: {delta_original / area:.4f} eV/Ang^2\")\n", + "print(f\"Relaxed Substrate energy: {relaxed_substrate_energy:.4f} eV\")\n", + "print(f\"Relaxed Layer energy: {relaxed_layer_energy:.4f} eV\")\n", + "print(f\"Relaxed Delta: {delta_relaxed:.4f} eV\")\n", + "print(f\"Relaxed Delta per area: {delta_relaxed / area:.4f} eV/Ang^2\")\n", + "print(f\"Effective relaxed Delta per area: {effective_delta_relaxed:.4f} eV/Ang^2\")\n", + "\n", + "\n", + "print(ase_to_poscar(ase_final_interface))\n", + "print(ase_to_poscar(nickel_relaxed_interface))\n", + "print(ase_to_poscar(graphene_relaxed_interface))\n", + "print(ase_to_poscar(nickel_original_interface))\n", + "print(ase_to_poscar(graphene_original_interface))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. Pass relaxed interface to Materials Designer" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:34.994260Z", + "start_time": "2024-02-23T06:59:34.937542Z" + } + }, + "outputs": [ + { + "ename": "ImportError", + "evalue": "This module intended to be used in a Pyodide environment. Please install packages yourself using pip.", + "output_type": "error", + "traceback": [ + "\u001B[0;31m---------------------------------------------------------------------------\u001B[0m", + "\u001B[0;31mModuleNotFoundError\u001B[0m Traceback (most recent call last)", + "File \u001B[0;32m~/code/GREEN/api-examples/other/materials_designer/jupyterlite/utils.py:6\u001B[0m\n\u001B[1;32m 5\u001B[0m \u001B[38;5;28;01mtry\u001B[39;00m:\n\u001B[0;32m----> 6\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mmicropip\u001B[39;00m\n\u001B[1;32m 7\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mImportError\u001B[39;00m:\n", + "\u001B[0;31mModuleNotFoundError\u001B[0m: No module named 'micropip'", + "\nDuring handling of the above exception, another exception occurred:\n", + "\u001B[0;31mImportError\u001B[0m Traceback (most recent call last)", + "Cell \u001B[0;32mIn[38], line 1\u001B[0m\n\u001B[0;32m----> 1\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01mjupyterlite\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mutils\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m set_data\n\u001B[1;32m 2\u001B[0m \u001B[38;5;28;01mfrom\u001B[39;00m \u001B[38;5;21;01msrc\u001B[39;00m\u001B[38;5;21;01m.\u001B[39;00m\u001B[38;5;21;01mutils\u001B[39;00m \u001B[38;5;28;01mimport\u001B[39;00m from_pymatgen\n\u001B[1;32m 4\u001B[0m esse_interface \u001B[38;5;241m=\u001B[39m from_pymatgen(ase_to_pymatgen(ase_final_interface))\n", + "File \u001B[0;32m~/code/GREEN/api-examples/other/materials_designer/jupyterlite/utils.py:8\u001B[0m\n\u001B[1;32m 6\u001B[0m \u001B[38;5;28;01mimport\u001B[39;00m \u001B[38;5;21;01mmicropip\u001B[39;00m\n\u001B[1;32m 7\u001B[0m \u001B[38;5;28;01mexcept\u001B[39;00m \u001B[38;5;167;01mImportError\u001B[39;00m:\n\u001B[0;32m----> 8\u001B[0m \u001B[38;5;28;01mraise\u001B[39;00m \u001B[38;5;167;01mImportError\u001B[39;00m(\n\u001B[1;32m 9\u001B[0m \u001B[38;5;124m\"\u001B[39m\u001B[38;5;124mThis module intended to be used in a Pyodide environment. Please install packages yourself using pip.\u001B[39m\u001B[38;5;124m\"\u001B[39m\n\u001B[1;32m 10\u001B[0m )\n\u001B[1;32m 12\u001B[0m \u001B[38;5;28;01masync\u001B[39;00m \u001B[38;5;28;01mdef\u001B[39;00m \u001B[38;5;21minstall_package\u001B[39m(pkg, verbose\u001B[38;5;241m=\u001B[39m\u001B[38;5;28;01mTrue\u001B[39;00m):\n\u001B[1;32m 13\u001B[0m \u001B[38;5;250m \u001B[39m\u001B[38;5;124;03m\"\"\"\u001B[39;00m\n\u001B[1;32m 14\u001B[0m \u001B[38;5;124;03m Installs a package in a Pyodide environment.\u001B[39;00m\n\u001B[1;32m 15\u001B[0m \u001B[38;5;124;03m Args:\u001B[39;00m\n\u001B[0;32m (...)\u001B[0m\n\u001B[1;32m 20\u001B[0m \u001B[38;5;124;03m None\u001B[39;00m\n\u001B[1;32m 21\u001B[0m \u001B[38;5;124;03m \"\"\"\u001B[39;00m\n", + "\u001B[0;31mImportError\u001B[0m: This module intended to be used in a Pyodide environment. Please install packages yourself using pip." + ] + } + ], + "source": [ + "from jupyterlite.utils import set_data\n", + "from src.utils import from_pymatgen\n", + "\n", + "esse_interface = from_pymatgen(ase_to_pymatgen(ase_final_interface))\n", + "set_data(\"materials\", [esse_interface] )" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:59:35.003262Z", + "start_time": "2024-02-23T06:59:34.998238Z" + } + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": {}, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/other/materials_designer/create_interface_with_relaxation_ase_lj.ipynb b/other/materials_designer/create_interface_with_relaxation_ase_lj.ipynb new file mode 100644 index 00000000..11e06637 --- /dev/null +++ b/other/materials_designer/create_interface_with_relaxation_ase_lj.ipynb @@ -0,0 +1,581 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Create an interface between two materials with minimal strain\n", + "\n", + "Use Zur and McGill superlattices matching [algorithm](https://doi.org/10.1063/1.3330840) to create interfaces between two materials using the Pymatgen [implementation](https://pymatgen.org/pymatgen.analysis.interfaces.html#pymatgen.analysis.interfaces.zsl).\n", + "\n", + "

Usage

\n", + "\n", + "0. Make sure to select Input Materials\n", + "1. Execute \"Run first: ...\" cell below to load Input Materials into the current kernel\n", + "2. Set Input Parameters (e.g. `MILLER_INDICES`, `THICKNESS`, `MAX_AREA`) below or use the default values\n", + "3. Click \"Run\" > \"Run All\" to run all cells\n", + "4. Wait for the run to complete (depending on the area, it can take 1-2 min or more). Scroll down to view cell results.\n", + "5. Review the strain plot and modify its parameters as needed\n", + "\n", + "## Methodology\n", + "\n", + "The following happens in the script below:\n", + "\n", + "1. Create slabs for each input material. The materials data is passed in from and back to the web application according to this description (TBA).\n", + " We assume that two input materials are either in bulk form (e.g. Ni crystal) or layered (e.g. graphene). \n", + " \n", + " We construct the interface along the Z-axis. The material corresponding to the bottom of the interface is referred to as the \"**substrate**\", and the top - as the \"**layer**\". \n", + "\n", + "2. Perform strain matching on the slabs to extract the supercell dimensions. The algorithm has a set of parameters, such as the maximum area considered, that can be configured by editing the cells below.\n", + "\n", + "3. When the strain matching is finished, the interface with the lowest strain (and the smallest number of atoms) is selected. We create the corresponding supercells and place them at a specified distance from each other (note no shift is performed currently).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Run first: load input materials in current kernel

\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "materials_in = []\n", + "for file in [\"Ni.json\", \"Gr.json\"]:\n", + " with open(file, \"r\") as f:\n", + " data = f.read()\n", + " materials_in.append(json.loads(data))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Set Input Parameters\n", + "\n", + "### 1.1. Select Substrate and Layer from Input Materials" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "SUBSTRATE_PARAMETERS = {\n", + " \"MATERIAL_INDEX\": 0, # the index of the material in the materials_in list\n", + " \"MILLER_INDICES\": (1, 1, 2), # the miller indices of the interfacial plane\n", + " \"THICKNESS\": 3, # in layers\n", + "}\n", + "\n", + "LAYER_PARAMETERS = {\n", + " \"MATERIAL_INDEX\": 1, # the index of the material in the materials_in list\n", + " \"MILLER_INDICES\": (0, 0, 1), # the miller indices of the interfacial plane\n", + " \"THICKNESS\": 1, # in layers\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.2. Set Interface Parameters\n", + "\n", + "The distance between layer and substrate and maximum area to consider when matching.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "INTERFACE_PARAMETERS = {\n", + " \"DISTANCE_Z\": 3.0, # in Angstroms\n", + " \"MAX_AREA\": 50, # in Angstroms^2\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.3. Set Algorithm Parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ZSL_PARAMETERS = {\n", + " \"MAX_AREA\": INTERFACE_PARAMETERS[\"MAX_AREA\"], # The area to consider in Angstrom^2\n", + " \"MAX_AREA_TOL\": 0.09, # The area within this tolerance is considered equal\n", + " \"MAX_LENGTH_TOL\": 0.03, # supercell lattice vectors lengths within this tolerance are considered equal\n", + " \"MAX_ANGLE_TOL\": 0.01, # supercell lattice angles within this tolerance are considered equal\n", + " \"STRAIN_TOL\": 10e-6, # strains within this tolerance are considered equal\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Install Packages" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from jupyterlite.utils import install_packages\n", + "\n", + "await install_packages(\"create_interface_with_min_strain_zsl.ipynb\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Create interfaces\n", + "\n", + "### 3.1. Extract Interfaces and Terminations\n", + "\n", + "Extract all possible layer/substrate supercell combinations within the maximum area including different terminations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": { + "tags": [], + "trusted": true + }, + "outputs": [], + "source": [ + "from src.pymatgen_coherent_interface_builder import CoherentInterfaceBuilder, ZSLGenerator\n", + "from src.utils import to_pymatgen\n", + "\n", + "if \"materials_in\" in globals():\n", + " pymatgen_materials = [to_pymatgen(item) for item in materials_in]\n", + "for material in pymatgen_materials:\n", + " print(material, \"\\n\")\n", + "\n", + "\n", + "def create_interfaces(settings):\n", + " print(\"Creating interfaces...\")\n", + " zsl = ZSLGenerator(\n", + " max_area_ratio_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_AREA_TOL\"],\n", + " max_area=settings[\"ZSL_PARAMETERS\"][\"MAX_AREA\"],\n", + " max_length_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_LENGTH_TOL\"],\n", + " max_angle_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_ANGLE_TOL\"],\n", + " )\n", + "\n", + " cib = CoherentInterfaceBuilder(\n", + " substrate_structure=pymatgen_materials[settings[\"SUBSTRATE_PARAMETERS\"][\"MATERIAL_INDEX\"]],\n", + " film_structure=pymatgen_materials[settings[\"LAYER_PARAMETERS\"][\"MATERIAL_INDEX\"]],\n", + " substrate_miller=settings[\"SUBSTRATE_PARAMETERS\"][\"MILLER_INDICES\"],\n", + " film_miller=settings[\"LAYER_PARAMETERS\"][\"MILLER_INDICES\"],\n", + " zslgen=zsl,\n", + " strain_tol=settings[\"ZSL_PARAMETERS\"][\"STRAIN_TOL\"],\n", + " )\n", + "\n", + " # Find terminations\n", + " cib._find_terminations()\n", + " terminations = cib.terminations\n", + "\n", + " # Create interfaces for each termination\n", + " interfaces = {}\n", + " for termination in terminations:\n", + " interfaces[termination] = []\n", + " for interface in cib.get_interfaces(\n", + " termination,\n", + " gap=settings[\"INTERFACE_PARAMETERS\"][\"DISTANCE_Z\"],\n", + " film_thickness=settings[\"LAYER_PARAMETERS\"][\"THICKNESS\"],\n", + " substrate_thickness=settings[\"SUBSTRATE_PARAMETERS\"][\"THICKNESS\"],\n", + " in_layers=True,\n", + " ):\n", + " # Wrap atoms to unit cell\n", + " interface[\"interface\"].make_supercell((1,1,1), to_unit_cell=True)\n", + " interfaces[termination].append(interface)\n", + " return interfaces, terminations\n", + "\n", + "\n", + "interfaces, terminations = create_interfaces(\n", + " settings={\n", + " \"SUBSTRATE_PARAMETERS\": SUBSTRATE_PARAMETERS,\n", + " \"LAYER_PARAMETERS\": LAYER_PARAMETERS,\n", + " \"ZSL_PARAMETERS\": ZSL_PARAMETERS,\n", + " \"INTERFACE_PARAMETERS\": INTERFACE_PARAMETERS,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3.2. Print out the interfaces and terminations" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(f'Found {len(terminations)} terminations')\n", + "for termination in terminations:\n", + " print(f\"Found {len(interfaces[termination])} interfaces for\", termination, \"termination\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Sort interfaces by strain\n", + "\n", + "### 4.1. Sort all interfaces" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Could be \"strain\", \"von_mises_strain\", \"mean_abs_strain\"\n", + "strain_mode = \"mean_abs_strain\"\n", + "\n", + "# Sort interfaces by the specified strain mode and number of sites\n", + "def sort_interfaces(interfaces, terminations):\n", + " sorted_interfaces = {}\n", + " for termination in terminations:\n", + " sorted_interfaces[termination] = sorted(\n", + " interfaces[termination], key=lambda x: (x[strain_mode], x[\"interface\"].num_sites)\n", + " )\n", + " return sorted_interfaces\n", + "\n", + "\n", + "sorted_interfaces = sort_interfaces(interfaces, terminations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.2. Print out interfaces with lowest strain for each termination" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for termination in terminations:\n", + " print(f\"Interface with lowest strain for termination {termination} (index 0):\")\n", + " first_interface = interfaces[termination][0]\n", + " print(\" strain:\", first_interface[strain_mode] * 100, \"%\")\n", + " print(\" number of atoms:\", first_interface[\"interface\"].num_sites)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Plot the results\n", + "\n", + "Plot the number of atoms vs strain. Adjust the parameters as needed.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import plotly.graph_objs as go\n", + "from collections import defaultdict\n", + "\n", + "PLOT_SETTINGS = {\n", + " \"HEIGHT\": 600,\n", + " \"X_SCALE\": \"log\", # or linear\n", + " \"Y_SCALE\": \"log\", # or linear\n", + "}\n", + "\n", + "\n", + "def plot_strain_vs_atoms(sorted_interfaces, terminations, settings):\n", + " # Create a mapping from termination to its index\n", + " termination_to_index = {termination: i for i, termination in enumerate(terminations)}\n", + "\n", + " grouped_interfaces = defaultdict(list)\n", + " for termination, interfaces in sorted_interfaces.items():\n", + " for index, interface_data in enumerate(interfaces):\n", + " strain_percentage = interface_data[\"mean_abs_strain\"] * 100\n", + " num_sites = interface_data[\"interface\"].num_sites\n", + " key = (strain_percentage, num_sites)\n", + " grouped_interfaces[key].append((index, termination))\n", + " \n", + " data = []\n", + " for (strain, num_sites), indices_and_terminations in grouped_interfaces.items():\n", + " termination_indices = defaultdict(list)\n", + " for index, termination in indices_and_terminations:\n", + " termination_indices[termination].append(index)\n", + " all_indices = [index for indices in termination_indices.values() for index in indices]\n", + " index_range = f\"{min(all_indices)}-{max(all_indices)}\" if len(all_indices) > 1 else str(min(all_indices))\n", + " \n", + " hover_text = \"
-----
\".join(\n", + " f\"Termination: {termination}
Termination index: {termination_to_index[termination]}
Interfaces Index Range: {index_range}
Strain: {strain:.2f}%
Atoms: {num_sites}\"\n", + " for termination, indices in termination_indices.items()\n", + " )\n", + " trace = go.Scatter(\n", + " x=[strain],\n", + " y=[num_sites],\n", + " text=[hover_text],\n", + " mode=\"markers\",\n", + " hoverinfo=\"text\",\n", + " name=f\"Indices: {index_range}\",\n", + " )\n", + " data.append(trace)\n", + "\n", + " layout = go.Layout(\n", + " xaxis=dict(title=\"Strain (%)\", type=settings[\"X_SCALE\"]),\n", + " yaxis=dict(title=\"Number of atoms\", type=settings[\"Y_SCALE\"]),\n", + " hovermode=\"closest\",\n", + " height=settings[\"HEIGHT\"],\n", + " legend_title_text=\"Interfaces Index Range\",\n", + " )\n", + " fig = go.Figure(data=data, layout=layout)\n", + " fig.show()\n", + "\n", + "\n", + "\n", + "plot_strain_vs_atoms(sorted_interfaces, terminations, PLOT_SETTINGS)\n", + "\n", + "for i, termination in enumerate(terminations):\n", + " print(f\"Termination {i}:\", termination)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Select the interface to relax\n", + "\n", + "### 6.1. Select the interface with the desired termination and strain\n", + "\n", + "The data in `sorted_interfaces` now contains an object with the following structure:\n", + "\n", + "```json\n", + "{\n", + " \"('C_P6/mmm_2', 'Si_R-3m_1')\": [\n", + " { ...interface for ('C_P6/mmm_2', 'Si_R-3m_1') at index 0...},\n", + " { ...interface for ('C_P6/mmm_2', 'Si_R-3m_1') at index 1...},\n", + " ...\n", + " ],\n", + " \"\": [\n", + " { ...interface for 'termination at index 1' at index 0...},\n", + " { ...interface for 'termination at index 1' at index 1...},\n", + " ...\n", + " ]\n", + "}\n", + "```\n", + "\n", + "Select the index for termination first, and for it - the index in the list of corresponding interfaces sorted by strain (index 0 has minimum strain)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "termination_index = 0\n", + "interface_index = 0\n", + "\n", + "termination = terminations[termination_index]\n", + "\n", + "interface = sorted_interfaces[termination][interface_index][\"interface\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Apply relaxation\n", + "### 7.1. Apply relaxation to the selected interface" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "# Per https://github.com/materialsvirtuallab/matgl/blob/main/examples/Relaxations%20and%20Simulations%20using%20the%20M3GNet%20Universal%20Potential.ipynb\n", + "from src.utils import poscar_to_ase, ase_to_poscar, ase_to_pymatgen, pymatgen_to_ase\n", + "from ase.optimize import BFGS\n", + "from ase.calculators.lj import LennardJones as LJ\n", + "\n", + "# relax the interface\n", + "ase_interface = poscar_to_ase(interface.to(fmt=\"poscar\"))\n", + "ase_interface.set_calculator(LJ())\n", + "dyn = BFGS(ase_interface)\n", + "dyn.run(fmax=0.01)\n", + "\n", + "# extract results\n", + "ase_original_interface = pymatgen_to_ase(interface)\n", + "ase_relaxed_interface = ase_interface\n", + "relaxed_energy = ase_interface.get_total_energy()\n", + "\n", + "# print out the final relaxed structure and energy\n", + "print('Original structure:\\n', ase_to_poscar(ase_original_interface))\n", + "print('\\nRelaxed structure:\\n', ase_to_poscar(ase_relaxed_interface))\n", + "print(f\"The final energy is {float(relaxed_energy):.3f} eV.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.2. View structure before and after relaxation" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ase.visualize import view\n", + "\n", + "# view(ase_original_interface, viewer=\"x3d\")\n", + "# view(ase_relaxed_interface, viewer=\"x3d\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.3. Calculate energy energy using ASE LJ" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ase import Atoms\n", + "nickel_relaxed_interface = ase_relaxed_interface.copy()\n", + "graphene_relaxed_interface = ase_relaxed_interface.copy()\n", + "nickel_original_interface = ase_original_interface.copy()\n", + "graphene_original_interface = ase_original_interface.copy()\n", + "\n", + "del nickel_relaxed_interface[[atom.index for atom in nickel_relaxed_interface if atom.symbol != 'Ni']]\n", + "del graphene_relaxed_interface[[atom.index for atom in graphene_relaxed_interface if atom.symbol != 'C']]\n", + "del nickel_original_interface[[atom.index for atom in nickel_original_interface if atom.symbol != 'Ni']]\n", + "del graphene_original_interface[[atom.index for atom in graphene_original_interface if atom.symbol != 'C']]\n", + "\n", + "#set LJ calculator\n", + "nickel_relaxed_interface.set_calculator(LJ())\n", + "graphene_relaxed_interface.set_calculator(LJ())\n", + "nickel_original_interface.set_calculator(LJ())\n", + "graphene_original_interface.set_calculator(LJ())\n", + "\n", + "original_substrate_energy = nickel_original_interface.get_total_energy()\n", + "original_layer_energy = graphene_original_interface.get_total_energy()\n", + "relaxed_substrate_energy = nickel_relaxed_interface.get_total_energy()\n", + "relaxed_layer_energy = graphene_relaxed_interface.get_total_energy()\n", + "\n", + "delta_original = relaxed_energy - original_substrate_energy - original_layer_energy\n", + "delta_relaxed = relaxed_energy - relaxed_substrate_energy - relaxed_layer_energy\n", + "\n", + "# calculate area of interface\n", + "area = ase_original_interface.get_volume() / ase_original_interface.cell[2, 2]\n", + "print('Interface area:', area, 'Ang^2')\n", + "print()\n", + "effective_delta_relaxed = (relaxed_energy*ase_relaxed_interface.get_global_number_of_atoms() - \n", + " nickel_relaxed_interface.get_global_number_of_atoms()*relaxed_substrate_energy - \n", + " graphene_relaxed_interface.get_global_number_of_atoms()*relaxed_layer_energy)/(2*area*ase_relaxed_interface.get_global_number_of_atoms())\n", + "\n", + "print(f\"Relaxed interface energy: {relaxed_energy:.4f} eV\")\n", + "print(f\"Original Substrate energy: {original_substrate_energy:.4f} eV\")\n", + "print(f\"Original Layer energy: {original_layer_energy:.4f} eV\")\n", + "print(f\"Original Delta: {delta_original:.4f} eV\")\n", + "print(f\"Original Delta per area: {delta_original / area:.4f} eV/Ang^2\")\n", + "print()\n", + "\n", + "print(f\"Relaxed Substrate energy: {relaxed_substrate_energy:.4f} eV\")\n", + "print(f\"Relaxed Layer energy: {relaxed_layer_energy:.4f} eV\")\n", + "print(f\"Relaxed Delta: {delta_relaxed:.4f} eV\")\n", + "print(f\"Relaxed Delta per area: {delta_relaxed / area:.4f} eV/Ang^2\")\n", + "print(f\"Effective relaxed Delta per area: {effective_delta_relaxed:.4f} eV/Ang^2\")\n", + "print()\n", + "\n", + "print(ase_to_poscar(ase_relaxed_interface))\n", + "print(ase_to_poscar(nickel_relaxed_interface))\n", + "print(ase_to_poscar(graphene_relaxed_interface))\n", + "print(ase_to_poscar(nickel_original_interface))\n", + "print(ase_to_poscar(graphene_original_interface))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 8. Pass relaxed interface to Materials Designer" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from jupyterlite.utils import set_data\n", + "from src.utils import from_pymatgen\n", + "\n", + "esse_interface = from_pymatgen(ase_to_pymatgen(ase_relaxed_interface))\n", + "set_data(\"materials\", [esse_interface] )" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": {}, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/other/materials_designer/create_interface_with_relaxation_matgl_m3gnet.ipynb b/other/materials_designer/create_interface_with_relaxation_matgl_m3gnet.ipynb new file mode 100644 index 00000000..83b7291e --- /dev/null +++ b/other/materials_designer/create_interface_with_relaxation_matgl_m3gnet.ipynb @@ -0,0 +1,2100 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Create an interface between two materials with minimal strain\n", + "\n", + "Use Zur and McGill superlattices matching [algorithm](https://doi.org/10.1063/1.3330840) to create interfaces between two materials using the Pymatgen [implementation](https://pymatgen.org/pymatgen.analysis.interfaces.html#pymatgen.analysis.interfaces.zsl).\n", + "\n", + "

Usage

\n", + "\n", + "0. Make sure to select Input Materials\n", + "1. Execute \"Run first: ...\" cell below to load Input Materials into the current kernel\n", + "2. Set Input Parameters (e.g. `MILLER_INDICES`, `THICKNESS`, `MAX_AREA`) below or use the default values\n", + "3. Click \"Run\" > \"Run All\" to run all cells\n", + "4. Wait for the run to complete (depending on the area, it can take 1-2 min or more). Scroll down to view cell results.\n", + "5. Review the strain plot and modify its parameters as needed\n", + "\n", + "## Methodology\n", + "\n", + "The following happens in the script below:\n", + "\n", + "1. Create slabs for each input material. The materials data is passed in from and back to the web application according to this description (TBA).\n", + " We assume that two input materials are either in bulk form (e.g. Ni crystal) or layered (e.g. graphene). \n", + " \n", + " We construct the interface along the Z-axis. The material corresponding to the bottom of the interface is referred to as the \"**substrate**\", and the top - as the \"**layer**\". \n", + "\n", + "2. Perform strain matching on the slabs to extract the supercell dimensions. The algorithm has a set of parameters, such as the maximum area considered, that can be configured by editing the cells below.\n", + "\n", + "3. When the strain matching is finished, the interface with the lowest strain (and the smallest number of atoms) is selected. We create the corresponding supercells and place them at a specified distance from each other (note no shift is performed currently).\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "

Run first: load input materials in current kernel

\n" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:46:32.336033Z", + "start_time": "2024-02-23T06:46:32.328297Z" + } + }, + "outputs": [], + "source": [ + "import json\n", + "materials_in = []\n", + "for file in [\"Ni.json\", \"Gr.json\"]:\n", + " with open(file, \"r\") as f:\n", + " data = f.read()\n", + " materials_in.append(json.loads(data))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Set Input Parameters\n", + "\n", + "### 1.1. Select Substrate and Layer from Input Materials" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:46:32.344401Z", + "start_time": "2024-02-23T06:46:32.337621Z" + } + }, + "outputs": [], + "source": [ + "SUBSTRATE_PARAMETERS = {\n", + " \"MATERIAL_INDEX\": 0, # the index of the material in the materials_in list\n", + " \"MILLER_INDICES\": (1, 1, 1), # the miller indices of the interfacial plane\n", + " \"THICKNESS\": 3, # in layers\n", + "}\n", + "\n", + "LAYER_PARAMETERS = {\n", + " \"MATERIAL_INDEX\": 1, # the index of the material in the materials_in list\n", + " \"MILLER_INDICES\": (0, 0, 1), # the miller indices of the interfacial plane\n", + " \"THICKNESS\": 1, # in layers\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.2. Set Interface Parameters\n", + "\n", + "The distance between layer and substrate and maximum area to consider when matching.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:46:32.345092Z", + "start_time": "2024-02-23T06:46:32.341171Z" + } + }, + "outputs": [], + "source": [ + "INTERFACE_PARAMETERS = {\n", + " \"DISTANCE_Z\": 3.0, # in Angstroms\n", + " \"MAX_AREA\": 50, # in Angstroms^2\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 1.3. Set Algorithm Parameters" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:46:32.352573Z", + "start_time": "2024-02-23T06:46:32.345998Z" + } + }, + "outputs": [], + "source": [ + "ZSL_PARAMETERS = {\n", + " \"MAX_AREA\": INTERFACE_PARAMETERS[\"MAX_AREA\"], # The area to consider in Angstrom^2\n", + " \"MAX_AREA_TOL\": 0.09, # The area within this tolerance is considered equal\n", + " \"MAX_LENGTH_TOL\": 0.03, # supercell lattice vectors lengths within this tolerance are considered equal\n", + " \"MAX_ANGLE_TOL\": 0.01, # supercell lattice angles within this tolerance are considered equal\n", + " \"STRAIN_TOL\": 10e-6, # strains within this tolerance are considered equal\n", + "}" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Install Packages" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:46:34.337926Z", + "start_time": "2024-02-23T06:46:32.350155Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Python 3.11.2\r\n", + "Package Version\r\n", + "-------------------------- -----------------\r\n", + "accelerate 0.27.2\r\n", + "aiohttp 3.9.3\r\n", + "aiosignal 1.3.1\r\n", + "alignn 2024.2.4\r\n", + "anyio 4.3.0\r\n", + "appnope 0.1.4\r\n", + "argon2-cffi 23.1.0\r\n", + "argon2-cffi-bindings 21.2.0\r\n", + "arrow 1.3.0\r\n", + "ase 3.22.1\r\n", + "asttokens 2.4.1\r\n", + "async-lru 2.0.4\r\n", + "attrs 23.2.0\r\n", + "Babel 2.14.0\r\n", + "beautifulsoup4 4.12.3\r\n", + "bleach 6.1.0\r\n", + "build 1.0.3\r\n", + "certifi 2024.2.2\r\n", + "cffi 1.16.0\r\n", + "cfgv 3.4.0\r\n", + "charset-normalizer 3.3.2\r\n", + "click 8.1.7\r\n", + "colorama 0.4.6\r\n", + "comm 0.2.1\r\n", + "contourpy 1.2.0\r\n", + "cycler 0.12.1\r\n", + "debugpy 1.8.1\r\n", + "decorator 5.1.1\r\n", + "defusedxml 0.7.1\r\n", + "dgl 2.0.0\r\n", + "distlib 0.3.8\r\n", + "executing 2.0.1\r\n", + "fastjsonschema 2.19.1\r\n", + "filelock 3.13.1\r\n", + "flake8 7.0.0\r\n", + "fonttools 4.49.0\r\n", + "fqdn 1.5.1\r\n", + "frozenlist 1.4.1\r\n", + "fsspec 2024.2.0\r\n", + "future 1.0.0\r\n", + "ghp-import 2.1.0\r\n", + "h11 0.14.0\r\n", + "httpcore 1.0.4\r\n", + "httpx 0.27.0\r\n", + "huggingface-hub 0.20.3\r\n", + "identify 2.5.35\r\n", + "idna 3.6\r\n", + "ipykernel 6.29.2\r\n", + "ipython 8.22.1\r\n", + "ipywidgets 8.1.2\r\n", + "isoduration 20.11.0\r\n", + "jarvis-tools 2023.12.12\r\n", + "jedi 0.19.1\r\n", + "Jinja2 3.1.3\r\n", + "joblib 1.3.2\r\n", + "json5 0.9.17\r\n", + "jsonpointer 2.4\r\n", + "jsonschema 4.21.1\r\n", + "jsonschema-specifications 2023.12.1\r\n", + "jupyter 1.0.0\r\n", + "jupyter_client 8.6.0\r\n", + "jupyter-console 6.6.3\r\n", + "jupyter_core 5.7.1\r\n", + "jupyter-events 0.9.0\r\n", + "jupyter-lsp 2.2.2\r\n", + "jupyter_server 2.12.5\r\n", + "jupyter_server_terminals 0.5.2\r\n", + "jupyterlab 4.1.2\r\n", + "jupyterlab_pygments 0.3.0\r\n", + "jupyterlab_server 2.25.3\r\n", + "jupyterlab_widgets 3.0.10\r\n", + "kiwisolver 1.4.5\r\n", + "latexcodec 2.0.1\r\n", + "lightning-utilities 0.10.1\r\n", + "Markdown 3.5.2\r\n", + "MarkupSafe 2.1.5\r\n", + "mat3ra-api-examples 0.1.0\r\n", + "matgl 0.9.2\r\n", + "matplotlib 3.8.3\r\n", + "matplotlib-inline 0.1.6\r\n", + "mccabe 0.7.0\r\n", + "mergedeep 1.3.4\r\n", + "mistune 3.0.2\r\n", + "mkdocs 1.5.3\r\n", + "mkdocs-material 9.5.10\r\n", + "mkdocs-material-extensions 1.3.1\r\n", + "monty 2024.2.2\r\n", + "mpmath 1.3.0\r\n", + "multidict 6.0.5\r\n", + "nbclient 0.9.0\r\n", + "nbconvert 7.16.1\r\n", + "nbformat 5.9.2\r\n", + "nest-asyncio 1.6.0\r\n", + "networkx 3.2.1\r\n", + "nglview 3.1.1\r\n", + "nodeenv 1.8.0\r\n", + "notebook 7.1.0\r\n", + "notebook_shim 0.2.4\r\n", + "numpy 1.26.4\r\n", + "overrides 7.7.0\r\n", + "packaging 23.2\r\n", + "paginate 0.5.6\r\n", + "palettable 3.3.3\r\n", + "pandas 2.2.0\r\n", + "pandocfilters 1.5.1\r\n", + "parso 0.8.3\r\n", + "pathspec 0.12.1\r\n", + "pexpect 4.9.0\r\n", + "pillow 10.2.0\r\n", + "pip 23.3.2\r\n", + "pip-tools 7.4.0\r\n", + "platformdirs 4.2.0\r\n", + "plotly 5.19.0\r\n", + "pre-commit 3.6.2\r\n", + "prometheus_client 0.20.0\r\n", + "prompt-toolkit 3.0.43\r\n", + "psutil 5.9.8\r\n", + "ptyprocess 0.7.0\r\n", + "pure-eval 0.2.2\r\n", + "pybtex 0.24.0\r\n", + "pycodestyle 2.11.1\r\n", + "pycparser 2.21\r\n", + "pydantic 1.8.1\r\n", + "pydocstyle 6.3.0\r\n", + "pyflakes 3.2.0\r\n", + "Pygments 2.17.2\r\n", + "pymatgen 2024.2.8\r\n", + "pymdown-extensions 10.7\r\n", + "pyparsing 2.4.7\r\n", + "pyproject_hooks 1.0.0\r\n", + "PyQt5 5.15.10\r\n", + "PyQt5-Qt5 5.15.12\r\n", + "PyQt5-sip 12.13.0\r\n", + "python-dateutil 2.8.2\r\n", + "python-json-logger 2.0.7\r\n", + "pytorch-ignite 0.5.0.dev20240223\r\n", + "pytorch-lightning 2.2.0.post0\r\n", + "pytz 2024.1\r\n", + "PyYAML 6.0.1\r\n", + "pyyaml_env_tag 0.1\r\n", + "pyzmq 25.1.2\r\n", + "qtconsole 5.5.1\r\n", + "QtPy 2.4.1\r\n", + "referencing 0.33.0\r\n", + "regex 2023.12.25\r\n", + "requests 2.31.0\r\n", + "rfc3339-validator 0.1.4\r\n", + "rfc3986-validator 0.1.1\r\n", + "rpds-py 0.18.0\r\n", + "ruamel.yaml 0.18.6\r\n", + "ruamel.yaml.clib 0.2.8\r\n", + "safetensors 0.4.2\r\n", + "scikit-learn 1.4.1.post1\r\n", + "scipy 1.12.0\r\n", + "Send2Trash 1.8.2\r\n", + "setuptools 69.0.3\r\n", + "six 1.16.0\r\n", + "sniffio 1.3.0\r\n", + "snowballstemmer 2.2.0\r\n", + "soupsieve 2.5\r\n", + "spglib 2.0.2\r\n", + "stack-data 0.6.3\r\n", + "sympy 1.12\r\n", + "tabulate 0.9.0\r\n", + "tenacity 8.2.3\r\n", + "terminado 0.18.0\r\n", + "threadpoolctl 3.3.0\r\n", + "tinycss2 1.2.1\r\n", + "toolz 0.12.1\r\n", + "torch 2.0.0\r\n", + "torchdata 0.7.1\r\n", + "torchmetrics 1.3.1\r\n", + "tornado 6.4\r\n", + "tqdm 4.66.2\r\n", + "traitlets 5.14.1\r\n", + "types-python-dateutil 2.8.19.20240106\r\n", + "typing_extensions 4.9.0\r\n", + "tzdata 2024.1\r\n", + "uncertainties 3.1.7\r\n", + "uri-template 1.3.0\r\n", + "urllib3 2.2.1\r\n", + "virtualenv 20.25.1\r\n", + "watchdog 4.0.0\r\n", + "wcwidth 0.2.13\r\n", + "webcolors 1.13\r\n", + "webencodings 0.5.1\r\n", + "websocket-client 1.7.0\r\n", + "wheel 0.42.0\r\n", + "widgetsnbextension 4.0.10\r\n", + "xmltodict 0.13.0\r\n", + "yarl 1.9.4\r\n", + "\r\n", + "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m A new release of pip is available: \u001B[0m\u001B[31;49m23.3.2\u001B[0m\u001B[39;49m -> \u001B[0m\u001B[32;49m24.0\u001B[0m\r\n", + "\u001B[1m[\u001B[0m\u001B[34;49mnotice\u001B[0m\u001B[1;39;49m]\u001B[0m\u001B[39;49m To update, run: \u001B[0m\u001B[32;49mpip install --upgrade pip\u001B[0m\r\n" + ] + } + ], + "source": [ + "!python --version\n", + "!pip list\n", + "#!pip install pymatgen==2024.2.8 ase==3.22.1 nbformat==5.9.2 ipykernel==6.29.2 matgl==0.9.2 nglview==3.1.1" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Create interfaces\n", + "\n", + "### 3.1. Extract Interfaces and Terminations\n", + "\n", + "Extract all possible layer/substrate supercell combinations within the maximum area including different terminations." + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": { + "tags": [], + "trusted": true, + "ExecuteTime": { + "end_time": "2024-02-23T06:46:40.318365Z", + "start_time": "2024-02-23T06:46:34.344521Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Full Formula (Ni1)\n", + "Reduced Formula: Ni\n", + "abc : 2.460000 2.460000 2.460000\n", + "angles: 60.000004 59.999994 60.000003\n", + "pbc : True True True\n", + "Sites (1)\n", + " # SP a b c\n", + "--- ---- --- --- ---\n", + " 0 Ni 0 0 0 \n", + "\n", + "Full Formula (C2)\n", + "Reduced Formula: C\n", + "abc : 2.467291 2.467291 20.000000\n", + "angles: 90.000000 90.000000 119.999986\n", + "pbc : True True True\n", + "Sites (2)\n", + " # SP a b c\n", + "--- ---- -------- -------- ---\n", + " 0 C 0 0 0\n", + " 1 C 0.333333 0.666667 0 \n", + "\n", + "Creating interfaces...\n" + ] + } + ], + "source": [ + "from src.pymatgen_coherent_interface_builder import CoherentInterfaceBuilder, ZSLGenerator\n", + "from src.utils import to_pymatgen\n", + "\n", + "if \"materials_in\" in globals():\n", + " pymatgen_materials = [to_pymatgen(item) for item in materials_in]\n", + "for material in pymatgen_materials:\n", + " print(material, \"\\n\")\n", + "\n", + "\n", + "def create_interfaces(settings):\n", + " print(\"Creating interfaces...\")\n", + " zsl = ZSLGenerator(\n", + " max_area_ratio_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_AREA_TOL\"],\n", + " max_area=settings[\"ZSL_PARAMETERS\"][\"MAX_AREA\"],\n", + " max_length_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_LENGTH_TOL\"],\n", + " max_angle_tol=settings[\"ZSL_PARAMETERS\"][\"MAX_ANGLE_TOL\"],\n", + " )\n", + "\n", + " cib = CoherentInterfaceBuilder(\n", + " substrate_structure=pymatgen_materials[settings[\"SUBSTRATE_PARAMETERS\"][\"MATERIAL_INDEX\"]],\n", + " film_structure=pymatgen_materials[settings[\"LAYER_PARAMETERS\"][\"MATERIAL_INDEX\"]],\n", + " substrate_miller=settings[\"SUBSTRATE_PARAMETERS\"][\"MILLER_INDICES\"],\n", + " film_miller=settings[\"LAYER_PARAMETERS\"][\"MILLER_INDICES\"],\n", + " zslgen=zsl,\n", + " strain_tol=settings[\"ZSL_PARAMETERS\"][\"STRAIN_TOL\"],\n", + " )\n", + "\n", + " # Find terminations\n", + " cib._find_terminations()\n", + " terminations = cib.terminations\n", + "\n", + " # Create interfaces for each termination\n", + " interfaces = {}\n", + " for termination in terminations:\n", + " interfaces[termination] = []\n", + " for interface in cib.get_interfaces(\n", + " termination,\n", + " gap=settings[\"INTERFACE_PARAMETERS\"][\"DISTANCE_Z\"],\n", + " film_thickness=settings[\"LAYER_PARAMETERS\"][\"THICKNESS\"],\n", + " substrate_thickness=settings[\"SUBSTRATE_PARAMETERS\"][\"THICKNESS\"],\n", + " in_layers=True,\n", + " ):\n", + " # Wrap atoms to unit cell\n", + " interface[\"interface\"].make_supercell((1,1,1), to_unit_cell=True)\n", + " interfaces[termination].append(interface)\n", + " return interfaces, terminations\n", + "\n", + "\n", + "interfaces, terminations = create_interfaces(\n", + " settings={\n", + " \"SUBSTRATE_PARAMETERS\": SUBSTRATE_PARAMETERS,\n", + " \"LAYER_PARAMETERS\": LAYER_PARAMETERS,\n", + " \"ZSL_PARAMETERS\": ZSL_PARAMETERS,\n", + " \"INTERFACE_PARAMETERS\": INTERFACE_PARAMETERS,\n", + " }\n", + ")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 3.2. Print out the interfaces and terminations" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:46:40.325949Z", + "start_time": "2024-02-23T06:46:40.320976Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Found 1 terminations\n", + "Found 233 interfaces for ('C_P6/mmm_2', 'Ni_R-3m_1') termination\n" + ] + } + ], + "source": [ + "print(f'Found {len(terminations)} terminations')\n", + "for termination in terminations:\n", + " print(f\"Found {len(interfaces[termination])} interfaces for\", termination, \"termination\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Sort interfaces by strain\n", + "\n", + "### 4.1. Sort all interfaces" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:46:40.333235Z", + "start_time": "2024-02-23T06:46:40.325006Z" + } + }, + "outputs": [], + "source": [ + "# Could be \"strain\", \"von_mises_strain\", \"mean_abs_strain\"\n", + "strain_mode = \"mean_abs_strain\"\n", + "\n", + "# Sort interfaces by the specified strain mode and number of sites\n", + "def sort_interfaces(interfaces, terminations):\n", + " sorted_interfaces = {}\n", + " for termination in terminations:\n", + " sorted_interfaces[termination] = sorted(\n", + " interfaces[termination], key=lambda x: (x[strain_mode], x[\"interface\"].num_sites)\n", + " )\n", + " return sorted_interfaces\n", + "\n", + "\n", + "sorted_interfaces = sort_interfaces(interfaces, terminations)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 4.2. Print out interfaces with lowest strain for each termination" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:46:40.340116Z", + "start_time": "2024-02-23T06:46:40.333147Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Interface with lowest strain for termination ('C_P6/mmm_2', 'Ni_R-3m_1') (index 0):\n", + " strain: 0.06600000000000002 %\n", + " number of atoms: 5\n" + ] + } + ], + "source": [ + "for termination in terminations:\n", + " print(f\"Interface with lowest strain for termination {termination} (index 0):\")\n", + " first_interface = interfaces[termination][0]\n", + " print(\" strain:\", first_interface[strain_mode] * 100, \"%\")\n", + " print(\" number of atoms:\", first_interface[\"interface\"].num_sites)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Plot the results\n", + "\n", + "Plot the number of atoms vs strain. Adjust the parameters as needed.\n" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:46:40.733358Z", + "start_time": "2024-02-23T06:46:40.345460Z" + } + }, + "outputs": [ + { + "data": { + "text/html": " \n " + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.plotly.v1+json": { + "data": [ + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 0", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 0
Strain: 0.07%
Atoms: 5" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 5 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 1-9", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 1-9
Strain: 0.07%
Atoms: 10" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 10 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 10-19", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 10-19
Strain: 0.07%
Atoms: 15" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 15 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 20-38", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 20-38
Strain: 0.07%
Atoms: 20" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 20 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 39-56", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 39-56
Strain: 0.07%
Atoms: 25" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 25 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 57-110", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 57-110
Strain: 0.07%
Atoms: 30" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 30 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 111-132", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 111-132
Strain: 0.07%
Atoms: 35" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 35 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 133-177", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 133-177
Strain: 0.07%
Atoms: 40" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 40 + ], + "type": "scatter" + }, + { + "hoverinfo": "text", + "mode": "markers", + "name": "Indices: 178-232", + "text": [ + "Termination: ('C_P6/mmm_2', 'Ni_R-3m_1')
Termination index: 0
Interfaces Index Range: 178-232
Strain: 0.07%
Atoms: 45" + ], + "x": [ + 0.06600000000000002 + ], + "y": [ + 45 + ], + "type": "scatter" + } + ], + "layout": { + "height": 600, + "hovermode": "closest", + "legend": { + "title": { + "text": "Interfaces Index Range" + } + }, + "xaxis": { + "title": { + "text": "Strain (%)" + }, + "type": "log" + }, + "yaxis": { + "title": { + "text": "Number of atoms" + }, + "type": "log" + }, + "template": { + "data": { + "histogram2dcontour": [ + { + "type": "histogram2dcontour", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "choropleth": [ + { + "type": "choropleth", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "histogram2d": [ + { + "type": "histogram2d", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "heatmap": [ + { + "type": "heatmap", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "heatmapgl": [ + { + "type": "heatmapgl", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "contourcarpet": [ + { + "type": "contourcarpet", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "contour": [ + { + "type": "contour", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "surface": [ + { + "type": "surface", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + }, + "colorscale": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ] + } + ], + "mesh3d": [ + { + "type": "mesh3d", + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + ], + "scatter": [ + { + "marker": { + "line": { + "color": "#283442" + } + }, + "type": "scatter" + } + ], + "parcoords": [ + { + "type": "parcoords", + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterpolargl": [ + { + "type": "scatterpolargl", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "bar": [ + { + "error_x": { + "color": "#f2f5fa" + }, + "error_y": { + "color": "#f2f5fa" + }, + "marker": { + "line": { + "color": "rgb(17,17,17)", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "bar" + } + ], + "scattergeo": [ + { + "type": "scattergeo", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterpolar": [ + { + "type": "scatterpolar", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "histogram": [ + { + "marker": { + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "histogram" + } + ], + "scattergl": [ + { + "marker": { + "line": { + "color": "#283442" + } + }, + "type": "scattergl" + } + ], + "scatter3d": [ + { + "type": "scatter3d", + "line": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scattermapbox": [ + { + "type": "scattermapbox", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scatterternary": [ + { + "type": "scatterternary", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "scattercarpet": [ + { + "type": "scattercarpet", + "marker": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + } + } + ], + "carpet": [ + { + "aaxis": { + "endlinecolor": "#A2B1C6", + "gridcolor": "#506784", + "linecolor": "#506784", + "minorgridcolor": "#506784", + "startlinecolor": "#A2B1C6" + }, + "baxis": { + "endlinecolor": "#A2B1C6", + "gridcolor": "#506784", + "linecolor": "#506784", + "minorgridcolor": "#506784", + "startlinecolor": "#A2B1C6" + }, + "type": "carpet" + } + ], + "table": [ + { + "cells": { + "fill": { + "color": "#506784" + }, + "line": { + "color": "rgb(17,17,17)" + } + }, + "header": { + "fill": { + "color": "#2a3f5f" + }, + "line": { + "color": "rgb(17,17,17)" + } + }, + "type": "table" + } + ], + "barpolar": [ + { + "marker": { + "line": { + "color": "rgb(17,17,17)", + "width": 0.5 + }, + "pattern": { + "fillmode": "overlay", + "size": 10, + "solidity": 0.2 + } + }, + "type": "barpolar" + } + ], + "pie": [ + { + "automargin": true, + "type": "pie" + } + ] + }, + "layout": { + "autotypenumbers": "strict", + "colorway": [ + "#636efa", + "#EF553B", + "#00cc96", + "#ab63fa", + "#FFA15A", + "#19d3f3", + "#FF6692", + "#B6E880", + "#FF97FF", + "#FECB52" + ], + "font": { + "color": "#f2f5fa" + }, + "hovermode": "closest", + "hoverlabel": { + "align": "left" + }, + "paper_bgcolor": "rgb(17,17,17)", + "plot_bgcolor": "rgb(17,17,17)", + "polar": { + "bgcolor": "rgb(17,17,17)", + "angularaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "radialaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + } + }, + "ternary": { + "bgcolor": "rgb(17,17,17)", + "aaxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "baxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + }, + "caxis": { + "gridcolor": "#506784", + "linecolor": "#506784", + "ticks": "" + } + }, + "coloraxis": { + "colorbar": { + "outlinewidth": 0, + "ticks": "" + } + }, + "colorscale": { + "sequential": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "sequentialminus": [ + [ + 0.0, + "#0d0887" + ], + [ + 0.1111111111111111, + "#46039f" + ], + [ + 0.2222222222222222, + "#7201a8" + ], + [ + 0.3333333333333333, + "#9c179e" + ], + [ + 0.4444444444444444, + "#bd3786" + ], + [ + 0.5555555555555556, + "#d8576b" + ], + [ + 0.6666666666666666, + "#ed7953" + ], + [ + 0.7777777777777778, + "#fb9f3a" + ], + [ + 0.8888888888888888, + "#fdca26" + ], + [ + 1.0, + "#f0f921" + ] + ], + "diverging": [ + [ + 0, + "#8e0152" + ], + [ + 0.1, + "#c51b7d" + ], + [ + 0.2, + "#de77ae" + ], + [ + 0.3, + "#f1b6da" + ], + [ + 0.4, + "#fde0ef" + ], + [ + 0.5, + "#f7f7f7" + ], + [ + 0.6, + "#e6f5d0" + ], + [ + 0.7, + "#b8e186" + ], + [ + 0.8, + "#7fbc41" + ], + [ + 0.9, + "#4d9221" + ], + [ + 1, + "#276419" + ] + ] + }, + "xaxis": { + "gridcolor": "#283442", + "linecolor": "#506784", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#283442", + "automargin": true, + "zerolinewidth": 2 + }, + "yaxis": { + "gridcolor": "#283442", + "linecolor": "#506784", + "ticks": "", + "title": { + "standoff": 15 + }, + "zerolinecolor": "#283442", + "automargin": true, + "zerolinewidth": 2 + }, + "scene": { + "xaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3", + "gridwidth": 2 + }, + "yaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3", + "gridwidth": 2 + }, + "zaxis": { + "backgroundcolor": "rgb(17,17,17)", + "gridcolor": "#506784", + "linecolor": "#506784", + "showbackground": true, + "ticks": "", + "zerolinecolor": "#C8D4E3", + "gridwidth": 2 + } + }, + "shapedefaults": { + "line": { + "color": "#f2f5fa" + } + }, + "annotationdefaults": { + "arrowcolor": "#f2f5fa", + "arrowhead": 0, + "arrowwidth": 1 + }, + "geo": { + "bgcolor": "rgb(17,17,17)", + "landcolor": "rgb(17,17,17)", + "subunitcolor": "#506784", + "showland": true, + "showlakes": true, + "lakecolor": "rgb(17,17,17)" + }, + "title": { + "x": 0.05 + }, + "updatemenudefaults": { + "bgcolor": "#506784", + "borderwidth": 0 + }, + "sliderdefaults": { + "bgcolor": "#C8D4E3", + "borderwidth": 1, + "bordercolor": "rgb(17,17,17)", + "tickwidth": 0 + }, + "mapbox": { + "style": "dark" + } + } + } + }, + "config": { + "plotlyServerURL": "https://plot.ly" + } + }, + "text/html": "
" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Termination 0: ('C_P6/mmm_2', 'Ni_R-3m_1')\n" + ] + } + ], + "source": [ + "import plotly.graph_objs as go\n", + "from collections import defaultdict\n", + "\n", + "PLOT_SETTINGS = {\n", + " \"HEIGHT\": 600,\n", + " \"X_SCALE\": \"log\", # or linear\n", + " \"Y_SCALE\": \"log\", # or linear\n", + "}\n", + "\n", + "\n", + "def plot_strain_vs_atoms(sorted_interfaces, terminations, settings):\n", + " # Create a mapping from termination to its index\n", + " termination_to_index = {termination: i for i, termination in enumerate(terminations)}\n", + "\n", + " grouped_interfaces = defaultdict(list)\n", + " for termination, interfaces in sorted_interfaces.items():\n", + " for index, interface_data in enumerate(interfaces):\n", + " strain_percentage = interface_data[\"mean_abs_strain\"] * 100\n", + " num_sites = interface_data[\"interface\"].num_sites\n", + " key = (strain_percentage, num_sites)\n", + " grouped_interfaces[key].append((index, termination))\n", + " \n", + " data = []\n", + " for (strain, num_sites), indices_and_terminations in grouped_interfaces.items():\n", + " termination_indices = defaultdict(list)\n", + " for index, termination in indices_and_terminations:\n", + " termination_indices[termination].append(index)\n", + " all_indices = [index for indices in termination_indices.values() for index in indices]\n", + " index_range = f\"{min(all_indices)}-{max(all_indices)}\" if len(all_indices) > 1 else str(min(all_indices))\n", + " \n", + " hover_text = \"
-----
\".join(\n", + " f\"Termination: {termination}
Termination index: {termination_to_index[termination]}
Interfaces Index Range: {index_range}
Strain: {strain:.2f}%
Atoms: {num_sites}\"\n", + " for termination, indices in termination_indices.items()\n", + " )\n", + " trace = go.Scatter(\n", + " x=[strain],\n", + " y=[num_sites],\n", + " text=[hover_text],\n", + " mode=\"markers\",\n", + " hoverinfo=\"text\",\n", + " name=f\"Indices: {index_range}\",\n", + " )\n", + " data.append(trace)\n", + "\n", + " layout = go.Layout(\n", + " xaxis=dict(title=\"Strain (%)\", type=settings[\"X_SCALE\"]),\n", + " yaxis=dict(title=\"Number of atoms\", type=settings[\"Y_SCALE\"]),\n", + " hovermode=\"closest\",\n", + " height=settings[\"HEIGHT\"],\n", + " legend_title_text=\"Interfaces Index Range\",\n", + " )\n", + " fig = go.Figure(data=data, layout=layout)\n", + " fig.show()\n", + "\n", + "\n", + "\n", + "plot_strain_vs_atoms(sorted_interfaces, terminations, PLOT_SETTINGS)\n", + "\n", + "for i, termination in enumerate(terminations):\n", + " print(f\"Termination {i}:\", termination)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Select the interface to relax\n", + "\n", + "### 6.1. Select the interface with the desired termination and strain\n", + "\n", + "The data in `sorted_interfaces` now contains an object with the following structure:\n", + "\n", + "```json\n", + "{\n", + " \"('C_P6/mmm_2', 'Si_R-3m_1')\": [\n", + " { ...interface for ('C_P6/mmm_2', 'Si_R-3m_1') at index 0...},\n", + " { ...interface for ('C_P6/mmm_2', 'Si_R-3m_1') at index 1...},\n", + " ...\n", + " ],\n", + " \"\": [\n", + " { ...interface for 'termination at index 1' at index 0...},\n", + " { ...interface for 'termination at index 1' at index 1...},\n", + " ...\n", + " ]\n", + "}\n", + "```\n", + "\n", + "Select the index for termination first, and for it - the index in the list of corresponding interfaces sorted by strain (index 0 has minimum strain)." + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:46:40.733819Z", + "start_time": "2024-02-23T06:46:40.727365Z" + } + }, + "outputs": [], + "source": [ + "termination_index = 0\n", + "interface_index = 0\n", + "\n", + "termination = terminations[termination_index]\n", + "\n", + "interface = sorted_interfaces[termination][interface_index][\"interface\"]" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 7. Apply relaxation\n", + "### 7.1. Apply relaxation to the selected interface" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T07:03:26.118896Z", + "start_time": "2024-02-23T07:03:22.015685Z" + } + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/mat3ra/code/GREEN/api-examples/.venv/lib/python3.11/site-packages/matgl/apps/pes.py:60: UserWarning:\n", + "\n", + "To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", + "\n", + "/Users/mat3ra/code/GREEN/api-examples/.venv/lib/python3.11/site-packages/matgl/apps/pes.py:66: UserWarning:\n", + "\n", + "To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", + "\n", + "/Users/mat3ra/code/GREEN/api-examples/.venv/lib/python3.11/site-packages/matgl/apps/pes.py:67: UserWarning:\n", + "\n", + "To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", + "\n", + "/Users/mat3ra/code/GREEN/api-examples/.venv/lib/python3.11/site-packages/matgl/layers/_basis.py:121: UserWarning:\n", + "\n", + "To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", + "\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Ni3 C2\n", + "1.0\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + "Ni C\n", + "3 2\n", + "direct\n", + " 0.3333334309041891 0.3333336930861107 0.0000000000000000 Ni\n", + " 0.0000001463562833 0.0000005396291662 0.0743446506413096 Ni\n", + " 0.6666668618083782 0.6666673861722214 0.1486893012826191 Ni\n", + " 0.0000000000000000 0.0000000000000000 0.2597298272022775 C\n", + " 0.3333330000000001 0.3333330000000000 0.2597298272022775 C\n", + "\n", + "Ni3 C2\n", + "1.0\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + "Ni C\n", + "3 2\n", + "direct\n", + " 0.3333340134487732 0.3333330807328738 -0.0170757790468935 Ni\n", + " 0.0000006233571625 0.0000010932091160 0.0579943255656671 Ni\n", + " 0.6666659312513874 0.6666678563754861 0.1329532574037621 Ni\n", + " -0.0000348881345262 -0.0000347332523320 0.2843109022203070 C\n", + " 0.3333679848948666 0.3333671611812928 0.2843109029243810 C\n", + "\n", + "The final energy is -34.621 eV.\n" + ] + } + ], + "source": [ + "# Per https://github.com/materialsvirtuallab/matgl/blob/main/examples/Relaxations%20and%20Simulations%20using%20the%20M3GNet%20Universal%20Potential.ipynb\n", + "from src.utils import pymatgen_to_ase\n", + "\n", + "import matgl\n", + "\n", + "from pymatgen.io.ase import AseAtomsAdaptor\n", + "from matgl.ext.ase import M3GNetCalculator, Relaxer\n", + "from matgl.apps.pes import Potential\n", + "ase_adaptor = AseAtomsAdaptor()\n", + "\n", + "pot = matgl.load_model(\"M3GNet-MP-2021.2.8-PES\")\n", + "Calculator = M3GNetCalculator(pot)\n", + "\n", + "def get_energy(structure, pot: Potential):\n", + " atoms = ase_adaptor.get_atoms(structure)\n", + " calc = M3GNetCalculator(pot)\n", + " atoms.set_calculator(calc)\n", + " return float(atoms.get_potential_energy())\n", + "\n", + "\n", + "relaxer = Relaxer(potential=pot, relax_cell=False)\n", + "relax_results = relaxer.relax(interface, fmax=0.01)\n", + "\n", + "# extract results\n", + "relaxed_interface = relax_results[\"final_structure\"]\n", + "relaxed_energy = relax_results[\"trajectory\"].energies[-1]\n", + "\n", + "ase_original_interface = pymatgen_to_ase(interface)\n", + "ase_final_interface = pymatgen_to_ase(relaxed_interface)\n", + "\n", + "# print out the final relaxed structure and energy\n", + "print(interface.to(fmt=\"poscar\"))\n", + "print(relaxed_interface.to(fmt=\"poscar\"))\n", + "\n", + "print(f\"The final energy is {float(relaxed_energy):.3f} eV.\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.2. View structure before and after relaxation" + ] + }, + { + "cell_type": "code", + "execution_count": 18, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T07:03:28.832592Z", + "start_time": "2024-02-23T07:03:28.627358Z" + } + }, + "outputs": [ + { + "data": { + "text/plain": "", + "text/html": "
\n
\n

Ni3C2 - original

\n \"original\"\n
\n \n
\n

Ni3C2 - relaxed

\n \"relaxed\"\n
\n
" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import base64\n", + "from ase.io import write\n", + "from ase.build import make_supercell\n", + "from IPython.display import HTML\n", + "import io\n", + "\n", + "def visualize_material_base64(material, title: str, rotation: str = '0x', number_of_repetitions: int = 3):\n", + " \"\"\"\n", + " Returns an HTML string with a Base64-encoded image for visualization,\n", + " including the name of the file, positioned horizontally.\n", + " \"\"\"\n", + " # Set the number of unit cell repetition for the structure\n", + " n = number_of_repetitions\n", + " material_repeat = make_supercell(material, [[n,0,0],[0,n,0],[0,0,1]])\n", + " text = f\"{material.symbols} - {title}\"\n", + " \n", + " # Write image to a buffer to display in HTML\n", + " buf = io.BytesIO()\n", + " write(buf, material_repeat, format='png', rotation=rotation)\n", + " buf.seek(0)\n", + " img_str = base64.b64encode(buf.read()).decode('utf-8')\n", + " html_str = f'''\n", + "
\n", + "

{text}

\n", + " \"{title}\"\n", + "
\n", + " '''\n", + " return html_str\n", + "\n", + "html_original = visualize_material_base64(ase_original_interface, \"original\", \"-90x\")\n", + "html_relaxed = visualize_material_base64(ase_final_interface, \"relaxed\", \"-90x\")\n", + "\n", + "# Display the interfaces before and after relaxation\n", + "html_content = f'
{html_original}{html_relaxed}
'\n", + "display(HTML(html_content))\n", + "\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "### 7.3. Calculate energy energy using matgl M3GNet" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T07:03:30.691565Z", + "start_time": "2024-02-23T07:03:30.534663Z" + } + }, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "5.240839288055053\n", + "5\n", + "3\n", + "2\n", + "Relaxed interface energy: -34.6208 eV\n", + "Original Substrate energy: -16.3230 eV\n", + "Original Layer energy: -18.2532 eV\n", + "Original Delta: -0.0446 eV\n", + "Original Delta per area: -0.0085 eV/Ang^2\n", + "Relaxed Substrate energy: -16.3256 eV\n", + "Relaxed Layer energy: -18.2532 eV\n", + "Relaxed Delta: -0.0420 eV\n", + "Relaxed Delta per area: -0.0080 eV/Ang^2\n", + "Effective relaxed Delta per area: -1.6719 eV/Ang^2\n", + "Ni C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni C \n", + " 3 2\n", + "Cartesian\n", + " 1.2300010628171087 0.7101404101213661 -0.4613391076492668\n", + " 0.0000028781050507 0.0000023289976749 1.5668421529530936\n", + " 2.4599990550837409 1.4202844311171587 3.5920198405749182\n", + " -0.0001285466800217 -0.0000739965142423 7.6812740177225667\n", + " 1.2301265514954720 0.7102130158872388 7.6812740367446484\n", + "\n", + "Ni \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni \n", + " 3\n", + "Cartesian\n", + " 1.2300010628171087 0.7101404101213661 -0.4613391076492668\n", + " 0.0000028781050507 0.0000023289976749 1.5668421529530936\n", + " 2.4599990550837409 1.4202844311171587 3.5920198405749182\n", + "\n", + " C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " C \n", + " 2\n", + "Cartesian\n", + " -0.0001285466800217 -0.0000739965142423 7.6812740177225667\n", + " 1.2301265514954720 0.7102130158872388 7.6812740367446484\n", + "\n", + "Ni \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " Ni \n", + " 3\n", + "Cartesian\n", + " 1.2300003829518735 0.7101417146926911 0.0000000000000001\n", + " 0.0000010237800144 0.0000011496383034 2.0085815523361399\n", + " 2.4600007659037471 1.4202834293853821 4.0171631046722771\n", + "\n", + " C \n", + " 1.0000000000000000\n", + " 2.4599995727812636 0.0000000000000000 0.0000000000000002\n", + " 1.2299995285143266 2.1304228448014668 0.0000000000000002\n", + " 0.0000000000000000 0.0000000000000000 27.0171631046722780\n", + " C \n", + " 2\n", + "Cartesian\n", + " 0.0000000000000000 0.0000000000000000 7.0171631046722780\n", + " 1.2299984704321631 0.7101402381262073 7.0171631046722780\n" + ] + } + ], + "source": [ + "from src.utils import ase_to_poscar\n", + "from ase import Atoms\n", + "nickel_relaxed_interface = ase_final_interface.copy()\n", + "graphene_relaxed_interface = ase_final_interface.copy()\n", + "nickel_original_interface = ase_original_interface.copy()\n", + "graphene_original_interface = ase_original_interface.copy()\n", + "\n", + "del nickel_relaxed_interface[[atom.index for atom in nickel_relaxed_interface if atom.symbol != 'Ni']]\n", + "del graphene_relaxed_interface[[atom.index for atom in graphene_relaxed_interface if atom.symbol != 'C']]\n", + "del nickel_original_interface[[atom.index for atom in nickel_original_interface if atom.symbol != 'Ni']]\n", + "del graphene_original_interface[[atom.index for atom in graphene_original_interface if atom.symbol != 'C']]\n", + "\n", + "#set EMT calculator\n", + "nickel_relaxed_interface.set_calculator(Calculator)\n", + "graphene_relaxed_interface.set_calculator(Calculator)\n", + "nickel_original_interface.set_calculator(Calculator)\n", + "graphene_original_interface.set_calculator(Calculator)\n", + "\n", + "original_substrate_energy = nickel_original_interface.get_total_energy()\n", + "original_layer_energy = graphene_original_interface.get_total_energy()\n", + "relaxed_substrate_energy = nickel_relaxed_interface.get_total_energy()\n", + "relaxed_layer_energy = graphene_relaxed_interface.get_total_energy()\n", + "\n", + "delta_original = relaxed_energy - original_substrate_energy - original_layer_energy\n", + "delta_relaxed = relaxed_energy - relaxed_substrate_energy - relaxed_layer_energy\n", + "\n", + "# calculate area of interface\n", + "area = ase_original_interface.get_volume() / ase_original_interface.cell[2, 2]\n", + "print(area)\n", + "\n", + "effective_delta_relaxed = (relaxed_energy * ase_final_interface.get_global_number_of_atoms() -\n", + " nickel_relaxed_interface.get_global_number_of_atoms() * relaxed_substrate_energy -\n", + " graphene_relaxed_interface.get_global_number_of_atoms() * relaxed_layer_energy)/(2 * area * ase_final_interface.get_global_number_of_atoms())\n", + "print(ase_final_interface.get_global_number_of_atoms())\n", + "print(nickel_relaxed_interface.get_global_number_of_atoms())\n", + "print(graphene_relaxed_interface.get_global_number_of_atoms())\n", + "# print(f\"Original interface energy: {ase_original_interface.get_total_energy():.4f} eV\")\n", + "print(f\"Relaxed interface energy: {relaxed_energy:.4f} eV\")\n", + "print(f\"Original Substrate energy: {original_substrate_energy:.4f} eV\")\n", + "print(f\"Original Layer energy: {original_layer_energy:.4f} eV\")\n", + "print(f\"Original Delta: {delta_original:.4f} eV\")\n", + "print(f\"Original Delta per area: {delta_original / area:.4f} eV/Ang^2\")\n", + "print(f\"Relaxed Substrate energy: {relaxed_substrate_energy:.4f} eV\")\n", + "print(f\"Relaxed Layer energy: {relaxed_layer_energy:.4f} eV\")\n", + "print(f\"Relaxed Delta: {delta_relaxed:.4f} eV\")\n", + "print(f\"Relaxed Delta per area: {delta_relaxed / area:.4f} eV/Ang^2\")\n", + "print(f\"Effective relaxed Delta per area: {effective_delta_relaxed:.4f} eV/Ang^2\")\n", + "\n", + "\n", + "print(ase_to_poscar(ase_final_interface))\n", + "print(ase_to_poscar(nickel_relaxed_interface))\n", + "print(ase_to_poscar(graphene_relaxed_interface))\n", + "print(ase_to_poscar(nickel_original_interface))\n", + "print(ase_to_poscar(graphene_original_interface))" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "metadata": { + "ExecuteTime": { + "end_time": "2024-02-23T06:46:46.857335Z", + "start_time": "2024-02-23T06:46:46.853894Z" + } + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10.12" + }, + "widgets": { + "application/vnd.jupyter.widget-state+json": { + "state": {}, + "version_major": 2, + "version_minor": 0 + } + } + }, + "nbformat": 4, + "nbformat_minor": 4 +} diff --git a/other/materials_designer/pickling.ipynb b/other/materials_designer/pickling.ipynb new file mode 100644 index 00000000..1d222be7 --- /dev/null +++ b/other/materials_designer/pickling.ipynb @@ -0,0 +1,127 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 3, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "b'ccopy_reg\\n_reconstructor\\np0\\n(ccloudpickle.cloudpickle\\n_make_skeleton_class\\np1\\n(c__builtin__\\ntype\\np2\\nVTest\\np3\\n(c__builtin__\\nobject\\np4\\ntp5\\n(dp6\\nV__module__\\np7\\nV__main__\\np8\\nsV9c9d2d434b1f404c97232f342818c56a\\np9\\nNtp10\\nRp11\\nccloudpickle.cloudpickle\\n_class_setstate\\np12\\ng11\\n((dp13\\ng7\\ng8\\nsV__init__\\np14\\nccloudpickle.cloudpickle\\n_make_function\\np15\\n(ccloudpickle.cloudpickle\\n_builtin_type\\np16\\n(VCodeType\\np17\\ntp18\\nRp19\\n(I1\\nI0\\nI0\\nI3\\nI1\\nI15\\nc_codecs\\nencode\\np20\\n(V\\x97\\\\u0000d\\\\u0000S\\\\u0000\\np21\\nVlatin1\\np22\\ntp23\\nRp24\\n(Ntp25\\n(t(Vself\\np26\\nVargs\\np27\\nVkwargs\\np28\\ntp29\\nV/var/folders/p2/dwnyx6w903d1s5rxs9br261m0000gn/T/ipykernel_9439/1462118015.py\\np30\\ng14\\nVTest.__init__\\np31\\nI3\\ng20\\n(V\\x80\\\\u0000\\xd8\\x08\\x0b\\x88\\x03\\np32\\ng22\\ntp33\\nRp34\\nc__builtin__\\nbytes\\np35\\n(tRp36\\n(t(ttp37\\nRp38\\n(dp39\\nV__package__\\np40\\nNsV__name__\\np41\\ng8\\nsNNNtp42\\nRp43\\nccloudpickle.cloudpickle\\n_function_setstate\\np44\\ng43\\n((dp45\\n(dp46\\ng41\\ng14\\nsV__qualname__\\np47\\ng31\\nsV__annotations__\\np48\\n(dp49\\nsV__kwdefaults__\\np50\\nNsV__defaults__\\np51\\nNsg7\\ng8\\nsV__doc__\\np52\\nNsV__closure__\\np53\\nNsV_cloudpickle_submodules\\np54\\n(lp55\\nsV__globals__\\np56\\n(dp57\\nstp58\\n\\x86R0sVget\\np59\\ng15\\n(g19\\n(I2\\nI0\\nI0\\nI2\\nI1\\nI3\\ng20\\n(V\\x97\\\\u0000|\\x01S\\\\u0000\\np60\\ng22\\ntp61\\nRp62\\ng25\\n(t(g26\\nVvalue\\np63\\ntp64\\ng30\\ng59\\nVTest.get\\np65\\nI5\\ng20\\n(V\\x80\\\\u0000\\xd8\\x0f\\x14\\x88\\x0c\\np66\\ng22\\ntp67\\nRp68\\ng36\\n(t(ttp69\\nRp70\\ng39\\nNNNtp71\\nRp72\\ng44\\ng72\\n((dp73\\n(dp74\\ng41\\ng59\\nsg47\\ng65\\nsg48\\n(dp75\\nsg50\\nNsg51\\n(I10\\ntp76\\nsg7\\ng8\\nsg52\\nNsg53\\nNsg54\\n(lp77\\nsg56\\n(dp78\\nstp79\\n\\x86R0sg52\\nNsV__slotnames__\\np80\\n(lp81\\ns(dp82\\ntp83\\n\\x86R0g4\\nNtp84\\nRp85\\n.'" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\u001b[0;31mSignature:\u001b[0m \u001b[0mpickle\u001b[0m\u001b[0;34m.\u001b[0m\u001b[0mdumps\u001b[0m\u001b[0;34m(\u001b[0m\u001b[0mobj\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mprotocol\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m,\u001b[0m \u001b[0mbuffer_callback\u001b[0m\u001b[0;34m=\u001b[0m\u001b[0;32mNone\u001b[0m\u001b[0;34m)\u001b[0m\u001b[0;34m\u001b[0m\u001b[0;34m\u001b[0m\u001b[0m\n", + "\u001b[0;31mDocstring:\u001b[0m\n", + "Serialize obj as a string of bytes allocated in memory\n", + "\n", + "protocol defaults to cloudpickle.DEFAULT_PROTOCOL which is an alias to\n", + "pickle.HIGHEST_PROTOCOL. This setting favors maximum communication\n", + "speed between processes running the same Python version.\n", + "\n", + "Set protocol=pickle.DEFAULT_PROTOCOL instead if you need to ensure\n", + "compatibility with older versions of Python (although this is not always\n", + "guaranteed to work because cloudpickle relies on some internal\n", + "implementation details that can change from one Python version to the\n", + "next).\n", + "\u001b[0;31mFile:\u001b[0m ~/code/green/api-examples/.venv-3.11/lib/python3.11/site-packages/cloudpickle/cloudpickle.py\n", + "\u001b[0;31mType:\u001b[0m function" + ] + } + ], + "source": [ + "import cloudpickle as pickle\n", + "\n", + "class Test:\n", + " def __init__(self, *args, **kwargs):\n", + " ...\n", + " def get(self, value=10):\n", + " return value\n", + "\n", + "test_obj = Test()\n", + "\n", + "with open(\"test-3.11.pkl\", \"wb\") as f:\n", + " pickle.dump(test_obj, f)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/Users/mat3ra/code/green/api-examples/.venv-3.11/lib/python3.11/site-packages/matgl/apps/pes.py:60: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", + " self.element_refs = AtomRef(property_offset=torch.tensor(element_refs, dtype=matgl.float_th))\n", + "/Users/mat3ra/code/green/api-examples/.venv-3.11/lib/python3.11/site-packages/matgl/apps/pes.py:66: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", + " self.register_buffer(\"data_mean\", torch.tensor(data_mean, dtype=matgl.float_th))\n", + "/Users/mat3ra/code/green/api-examples/.venv-3.11/lib/python3.11/site-packages/matgl/apps/pes.py:67: UserWarning: To copy construct from a tensor, it is recommended to use sourceTensor.clone().detach() or sourceTensor.clone().detach().requires_grad_(True), rather than torch.tensor(sourceTensor).\n", + " self.register_buffer(\"data_std\", torch.tensor(data_std, dtype=matgl.float_th))\n" + ] + } + ], + "source": [ + "import matgl\n", + "from matgl.ext.ase import M3GNetCalculator\n", + "from matgl.ext.ase import M3GNetCalculator\n", + "\n", + "import cloudpickle\n", + "\n", + "pot = matgl.load_model(\"M3GNet-MP-2021.2.8-PES\")\n", + "\n", + "# Save the calculator to pickle for use in the Pyodide environment\n", + "calculator = M3GNetCalculator(pot)\n", + "print(calculator)\n", + "\n", + "# with open(\"m3gnet_calculator_3.11_32.pkl\", \"wb\") as f:\n", + "# cloudpickle.dump(calculator, f, protocol=3)\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv-3.11", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.3" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/other/materials_designer/src/utils.py b/other/materials_designer/src/utils.py index 89b971f6..85d3da5a 100644 --- a/other/materials_designer/src/utils.py +++ b/other/materials_designer/src/utils.py @@ -104,3 +104,17 @@ def ase_to_poscar(atoms: ase_Atoms): output.close() return content + +def ase_to_pymatgen(atoms: ase_Atoms): + poscar = ase_to_poscar(atoms) + structure = Structure.from_str(poscar, fmt="poscar") + + return structure + +def pymatgen_to_ase(structure: Structure): + poscar = structure.to(fmt="poscar") + atoms = poscar_to_ase(poscar) + + return atoms + + diff --git a/other/materials_designer/test-cloud.pkl b/other/materials_designer/test-cloud.pkl new file mode 100644 index 00000000..b24f0e02 Binary files /dev/null and b/other/materials_designer/test-cloud.pkl differ