From 2439d46c0ae36f1ab92d426ec3262b180de4db18 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Sat, 17 Oct 2026 02:31:08 -0700 Subject: [PATCH 01/21] =?UTF-8?q?SOF-8085:=20periodic=20twisted=20bilayer?= =?UTF-8?q?=20h-BN=20at=207.34=C2=B0=20(Xian=20et=20al.=202019)=20?= =?UTF-8?q?=E2=80=94=20structure=20and=20flat-band=20simulation=20notebook?= =?UTF-8?q?s;=20ribbon=20notebook=20cites=20Nano=20Lett.=20and=20labels=20?= =?UTF-8?q?=CE=B1/=CE=B2=20as=20the=20paper?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- .../specific_examples/Introduction.ipynb | 1 + ..._commensurate_lattices_boron_nitride.ipynb | 250 +++++++ ...te_lattices_boron_nitride_SIMULATION.ipynb | 655 ++++++++++++++++++ ...er_twisted_nanoribbons_boron_nitride.ipynb | 4 +- 4 files changed, 908 insertions(+), 2 deletions(-) create mode 100644 other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb create mode 100644 other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb diff --git a/other/materials_designer/specific_examples/Introduction.ipynb b/other/materials_designer/specific_examples/Introduction.ipynb index 885b47f71..533ad19c4 100644 --- a/other/materials_designer/specific_examples/Introduction.ipynb +++ b/other/materials_designer/specific_examples/Introduction.ipynb @@ -30,6 +30,7 @@ "| `C-2D-INT-Z` | Interface ZSL | [Graphene/Ni Interface Film XY Position Optimization](optimization_interface_film_xy_position_graphene_nickel.ipynb) | [Gr/Ni(111) Registry and Work of Adhesion](optimization_interface_film_xy_position_graphene_nickel_SIMULATION.ipynb) | [[7]](#ref7) |\n", "| `C-2D-INT-T` | Interface Twisted | *To be added* | — | — |\n", "| `C-2D-INT-C` | Interface Commensurate Lattice | [Twisted Commensurate MoS₂ Bilayer](interface_bilayer_twisted_commensurate_lattices_molybdenum_disulfide.ipynb) | [Twisted MoS₂ Bilayer Band Structure](interface_bilayer_twisted_commensurate_lattices_molybdenum_disulfide_SIMULATION.ipynb) | [[8]](#ref8) |\n", + "| `C-2D-INT-C` | Interface Commensurate Lattice | [Twisted Commensurate h-BN Bilayer](interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb) | [Twisted h-BN Bilayer Flat Bands](interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb) | [[9]](#ref9) |\n", "| `C-2D-MLT` | Multi-Layer | *To be added* | — | — |\n", "| `C-0D-INT-R` | Nanoribbons Interface Rotation | [Twisted BN Nanoribbon Bilayer](interface_bilayer_twisted_nanoribbons_boron_nitride.ipynb) | *To be added* | [[9]](#ref9) |\n", "| `D-3D-AMO` | Amorphous | *To be added* | — | — |\n", diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb new file mode 100644 index 000000000..a1769b6f6 --- /dev/null +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb @@ -0,0 +1,250 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# Twisted bilayer Boron Nitride at 7.34° on a commensurate lattice.\n", + "\n", + "## 0. Introduction.\n", + "\n", + "This notebook demonstrates how to generate a twisted interface between two materials using commensurate lattices. The example uses hexagonal boron nitride (h-BN) as both the film and substrate materials and builds the periodic moiré cell the paper computes at 7.34° (244 atoms). The notebook uses the `create_interface_commensurate` function which first creates a slab from the material and then performs commensurate lattice matching to find valid supercells for the target twist angle. The algorithm searches for supercell matrices within specified size limits to achieve the target twist angle within tolerance. The generated interface is visualized and analyzed to determine the number of atoms and the interlayer distance.\n", + "\n", + "> **Lede Xian, Dante M. Kennes, Nicolas Tancogne-Dejean, Massimo Altarelli, and Angel Rubio**\n", + "> Multiflat Bands and Strong Correlations in Twisted Bilayer Boron Nitride: Doping-Induced Correlated Insulator and Superconductor. Nano Letters, 19, 4934. 2019.\n", + "> [https://doi.org/10.1021/acs.nanolett.9b00986](https://doi.org/10.1021/acs.nanolett.9b00986)\n", + "\n", + "The twisted h-BN bilayer is shown in the following Figure 1 from the article: configurations α (a) and β (b), and the width of the top valence flat bands against twist angle (g).\n", + "\n", + "\"Twisted" + ] + }, + { + "cell_type": "markdown", + "id": "1", + "metadata": {}, + "source": [ + "## 1. Prepare the Environment\n", + "### 1.1. Configurations from the article\n", + "\n", + "The twist angle and the interlayer distance below are the ones of the article's band-width series: flat layers,\n", + "3.23 Å apart, the optimized interlayer distance of the untwisted bilayer. The article's two configurations, α and β,\n", + "share one moiré cell and differ in twist by 60°: in α the B-over-B and N-over-N regions sit at different sites of the\n", + "cell, in β at the same site.\n", + "\n", + "The name below is how the [band structure notebook](interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb)\n", + "finds the material created here, so changing it means changing it there too." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], + "source": [ + "TARGET_TWIST_ANGLE = 60 + 7.34 # degrees; configuration α of Xian et al. 2019 Fig. 1a, 7.34 gives β\n", + "INTERFACE_DISTANCE = 3.23 # Å, the article's\n", + "MATERIAL_NAME = \"h-BN bilayer 7.34deg alpha d3.23\"" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "### 1.2. Set interface creation and search parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "VACUUM = 20.0 # Å of empty space above the top layer; paper: not stated\n", + "\n", + "# Search algorithm parameters\n", + "MAX_REPETITION = None # Maximum supercell matrix element value (None for automatic)\n", + "ANGLE_TOLERANCE = 0.5 # in degrees\n", + "RETURN_FIRST_MATCH = True # If True, returns first solution within tolerance\n", + "\n", + "# Visualization parameters\n", + "SHOW_INTERMEDIATE_STEPS = True\n", + "VISUALIZE_REPETITIONS = [3, 3, 1]" + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "### 1.3. Install packages\n", + "The step executes only in Pyodide environment. For other environments, the packages should be installed via `pip install` (see [README](../../README.ipynb))." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.packages import install_packages\n", + "\n", + "await install_packages(\"made|specific_examples\")" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "### 1.4. Get input material\n", + "We'll use the h-BN monolayer from Standata.\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.made.material import Material\n", + "from mat3ra.standata.materials import Materials\n", + "from mat3ra.notebooks_utils.ipython.entity.material.visualize import visualize_materials\n", + "\n", + "# paper: a = 2.512 Å; ours Standata's h-BN monolayer as is\n", + "material = Material.create(Materials.get_by_name_and_categories(\"BN\", \"2D\"))\n", + "print(f\"{material.name}: {material.basis.number_of_atoms} atoms, a = {material.lattice.a:.3f} Å\")\n", + "\n", + "if SHOW_INTERMEDIATE_STEPS:\n", + " visualize_materials(material, repetitions=VISUALIZE_REPETITIONS)\n", + " visualize_materials(material, repetitions=VISUALIZE_REPETITIONS, rotation=\"-90x\")" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "## 2. Generate the Twisted Interface" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.esse.models.core.reusable.axis_enum import AxisEnum\n", + "from mat3ra.made.tools.analyze.other import get_average_interlayer_distance\n", + "from mat3ra.made.tools.convert import to_ase\n", + "from mat3ra.made.tools.convert.interface_parts_enum import InterfacePartsEnum\n", + "from mat3ra.made.tools.helpers import create_interface_commensurate, create_supercell\n", + "\n", + "interface = create_interface_commensurate(\n", + " material=material,\n", + " target_angle=TARGET_TWIST_ANGLE,\n", + " angle_tolerance=ANGLE_TOLERANCE,\n", + " max_repetition_int=MAX_REPETITION,\n", + " return_first_match=RETURN_FIRST_MATCH,\n", + " direction=AxisEnum.z,\n", + " gap=INTERFACE_DISTANCE,\n", + " # the builder adds the gap above the top layer as well\n", + " vacuum=VACUUM - INTERFACE_DISTANCE,\n", + ")\n", + "# The symbolic K point of the band path assumes the 120° hexagonal cell; the builder returns the 60° one.\n", + "interface = create_supercell(interface, supercell_matrix=[[1, 0, 0], [-1, 1, 0], [0, 0, 1]])\n", + "interface.lattice.type = \"HEX\"\n", + "interface.name = MATERIAL_NAME\n", + "\n", + "interlayer_distance = get_average_interlayer_distance(\n", + " interface, InterfacePartsEnum.SUBSTRATE.value, InterfacePartsEnum.FILM.value)\n", + "print(f\"{interface.name}: {interface.basis.number_of_atoms} atoms ({to_ase(interface).get_chemical_formula()}), \"\n", + " f\"a = {interface.lattice.a:.3f} Å, gamma = {interface.lattice.gamma:.1f}°, \"\n", + " f\"interlayer distance {interlayer_distance:.3f} Å, target twist {TARGET_TWIST_ANGLE:.2f}°\")" + ] + }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "## 3. Preview the material" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "visualize_materials(interface, repetitions=VISUALIZE_REPETITIONS)\n", + "visualize_materials(interface, repetitions=VISUALIZE_REPETITIONS, rotation=\"-90x\")" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "## 4. Save the material\n", + "\n", + "The material is written to the `uploads` folder under its name, which is how the\n", + "[band structure notebook](interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb)\n", + "picks it up." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.io import download_content_to_file\n", + "from mat3ra.notebooks_utils.material import set_materials\n", + "\n", + "set_materials([interface])\n", + "download_content_to_file(interface.to_json(), f\"{interface.name}.json\")" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, + "source": [ + "## References\n", + "\n", + "[1] L. Xian, D. M. Kennes, N. Tancogne-Dejean, M. Altarelli and A. Rubio, \"Multiflat Bands and Strong Correlations in Twisted Bilayer Boron Nitride: Doping-Induced Correlated Insulator and Superconductor\", Nano Lett. 19, 4934 (2019). https://doi.org/10.1021/acs.nanolett.9b00986" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb new file mode 100644 index 000000000..c114705c4 --- /dev/null +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb @@ -0,0 +1,655 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# Flat Valence Bands of Twisted Bilayer h-BN\n", + "\n", + "> **Lede Xian, Dante M. Kennes, Nicolas Tancogne-Dejean, Massimo Altarelli, and Angel Rubio**\n", + "> **Multiflat Bands and Strong Correlations in Twisted Bilayer Boron Nitride: Doping-Induced Correlated Insulator and Superconductor**\n", + "> Nano Letters 19, 4934 (2019)\n", + "> [DOI: 10.1021/acs.nanolett.9b00986](https://doi.org/10.1021/acs.nanolett.9b00986)\n", + "\n", + "Calculate the band structure of the twisted h-BN bilayer created in the\n", + "[structure notebook](interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb), using Quantum ESPRESSO and the\n", + "band structure workflow from Standata, and read off the width of its top set of flat valence bands.\n", + "\n", + "The article's result is that twisting bilayer h-BN splits its top valence bands into isolated flat sets whose width\n", + "shrinks with the twist angle, from 101.4 meV at 7.34° to 1.6 meV at 2.64° (Fig. 1g).\n", + "\n", + "

Usage

\n", + "\n", + "1. Create the material in the [structure notebook](interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb), which saves it to the `uploads` folder under the name used in cell 1.2 below.\n", + "1. Set the material and the calculation parameters in cells 1.2 and 1.3 (or use the default values).\n", + "1. Click \"Run\" > \"Run All\" to run all cells.\n", + "1. Wait for the job to complete.\n", + "1. Scroll down to view the results; section 8 prints the comparison with the paper.\n", + "\n", + "## Summary\n", + "\n", + "1. Set up the environment and parameters: install packages (JupyterLite only) and configure the material, workflow, model, compute resources and job.\n", + "1. Authenticate and initialize API client: authenticate via browser, initialize the client, then select account and project.\n", + "1. Load the material by name from the `uploads` folder, print its provenance and save it to the platform.\n", + "1. Configure the workflow: select the application and the model, load the band structure workflow from Standata, and set the k-grid of the self-consistent run, the k-path of the bands and the cutoffs.\n", + "1. Configure compute: get the list of clusters and create a compute configuration.\n", + "1. Run the job, re-using a job that already ran under the same workflow name.\n", + "1. Retrieve results: the band structure, the width of the top valence flat bands and their separation from the bands below, and the bands near the valence-band top.\n", + "1. Compare with Xian et al. (2019)." + ] + }, + { + "cell_type": "markdown", + "id": "1", + "metadata": {}, + "source": [ + "## 1. Set up the environment and parameters\n", + "### 1.1. Install packages (JupyterLite)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.packages import install_packages\n", + "\n", + "await install_packages(\"made|api_examples\")" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "### 1.2. Set parameters and configurations for the workflow and jobs" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "from datetime import datetime\n", + "from mat3ra.ide.compute import QueueName\n", + "\n", + "ORGANIZATION_NAME = None # set to your organization name (full or partial); otherwise, your default one is used\n", + "FOLDER = \"./uploads\"\n", + "MATERIAL_NAME = \"h-BN bilayer 7.34deg alpha d3.23\" # as saved by the structure notebook\n", + "\n", + "WORKFLOW_SEARCH_TERM = \"band_structure.json\"\n", + "MY_WORKFLOW_NAME = \"Band Structure\"\n", + "APPLICATION_NAME = \"espresso\"\n", + "\n", + "CLUSTER_NAME = None # specify full or partial name i.e. \"cluster-001\" to select\n", + "QUEUE_NAME = QueueName.OR\n", + "PPN = 16 # OR allows 16 cores per job\n", + "TIME_LIMIT = \"04:00:00\"\n", + "\n", + "timestamp = datetime.now().strftime(\"%Y-%m-%d %H:%M\")\n", + "POLL_INTERVAL = 60 # seconds" + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "### 1.3. Set the DFT parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [ + "MODEL_SUBTYPE = \"lda\"\n", + "FUNCTIONAL = \"pz\"\n", + "PSEUDOPOTENTIAL_TYPE = \"us\" # GBRV\n", + "ECUTWFC = 40 # Ry\n", + "ECUTRHO = 200 # Ry; paper: VASP PAW, 400 eV\n", + "\n", + "KGRID = [1, 1, 1] # Γ only, as the paper's self-consistent run\n", + "# paper: Γ–K–M, number of points not stated; ours 7, evenly spaced (|ΓK| = 2|KM|)\n", + "KPATH = [\n", + " {\"point\": \"Γ\", \"steps\": 4},\n", + " {\"point\": \"K\", \"steps\": 2},\n", + " {\"point\": \"M\", \"steps\": 1},\n", + "]\n", + "MODEL_TAG = (f\"{FUNCTIONAL}-{PSEUDOPOTENTIAL_TYPE} {ECUTWFC}-{ECUTRHO}Ry k{KGRID[0]} \"\n", + " f\"p{sum(point['steps'] for point in KPATH)}\")\n", + "\n", + "SCF_UNIT = \"pw_scf\"\n", + "BANDS_UNIT = \"pw_bands\"\n", + "\n", + "PLOT_ENERGY_RANGE = (-0.5, 0.1) # eV, relative to the top of the flat bands" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "## 2. Authenticate and initialize API client\n", + "### 2.1. Authenticate\n", + "Authenticate in the browser and have credentials stored in environment variable \"OIDC_ACCESS_TOKEN\"." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.auth import authenticate\n", + "\n", + "await authenticate()" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "### 2.2. Initialize API client" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.api_client import APIClient\n", + "\n", + "client = APIClient.authenticate()\n", + "client" + ] + }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "### 2.3. Select account" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "client.list_accounts()" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "13", + "metadata": {}, + "outputs": [], + "source": [ + "selected_account = client.my_account\n", + "\n", + "if ORGANIZATION_NAME:\n", + " selected_account = client.get_account(name=ORGANIZATION_NAME)\n", + "\n", + "ACCOUNT_ID = selected_account.id\n", + "print(f\"✅ Selected account ID: {ACCOUNT_ID}, name: {selected_account.name}\")" + ] + }, + { + "cell_type": "markdown", + "id": "14", + "metadata": {}, + "source": [ + "### 2.4. Select project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "15", + "metadata": {}, + "outputs": [], + "source": [ + "projects = client.projects.list({\"isDefault\": True, \"owner._id\": ACCOUNT_ID})\n", + "project_id = projects[0][\"_id\"]\n", + "print(f\"✅ Using project: {projects[0]['name']} ({project_id})\")" + ] + }, + { + "cell_type": "markdown", + "id": "16", + "metadata": {}, + "source": [ + "## 3. Load the material\n", + "### 3.1. Load from the uploads folder and print provenance\n", + "\n", + "The structure, its geometry and its lattice type all come from the structure notebook; this one only loads it by\n", + "name." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "17", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.core.entity.material.api import load_material\n", + "\n", + "material = load_material(client, FOLDER, MATERIAL_NAME, ACCOUNT_ID)\n", + "print(f\"{material.name}: {material.basis.number_of_atoms} atoms, a = {material.lattice.a:.3f} Å, \"\n", + " f\"gamma = {material.lattice.gamma:.3f}°, lattice {material.lattice.type}\")" + ] + }, + { + "cell_type": "markdown", + "id": "18", + "metadata": {}, + "source": [ + "### 3.2. Preview the material" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "19", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.ipython.entity.material.visualize import visualize_materials\n", + "\n", + "visualize_materials(material, viewer=\"wave\")" + ] + }, + { + "cell_type": "markdown", + "id": "20", + "metadata": {}, + "source": [ + "### 3.3. Save the material to the platform" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "21", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.made.material import Material\n", + "from mat3ra.notebooks_utils.core.entity.material.api import get_or_create_material\n", + "\n", + "material.basis.set_labels_from_list([])\n", + "saved_material = Material.create(get_or_create_material(client, material, ACCOUNT_ID))" + ] + }, + { + "cell_type": "markdown", + "id": "22", + "metadata": {}, + "source": [ + "## 4. Configure the workflow\n", + "### 4.1. Select application and model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "23", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.standata.applications import ApplicationStandata\n", + "from mat3ra.standata.model_tree import ModelTreeStandata\n", + "from mat3ra.ade.application import Application\n", + "from mat3ra.mode import ModelFactory\n", + "\n", + "app_config = ApplicationStandata.get_by_name_first_match(APPLICATION_NAME)\n", + "app = Application(**app_config)\n", + "\n", + "model_config = ModelTreeStandata.get_model_by_parameters(type=\"dft\", subtype=MODEL_SUBTYPE, functional=FUNCTIONAL)\n", + "model_config[\"method\"] = {\"type\": \"pseudopotential\", \"subtype\": PSEUDOPOTENTIAL_TYPE}\n", + "model = ModelFactory.create(model_config)\n", + "print(f\"Using application: {app.name}, model: {MODEL_TAG}\")" + ] + }, + { + "cell_type": "markdown", + "id": "24", + "metadata": {}, + "source": [ + "### 4.2. Configure the workflow\n", + "\n", + "The self-consistent run on `KGRID`, then the bands along `KPATH`, both with the cutoffs of 1.3. The workflow is named\n", + "after the material and `MODEL_TAG`; section 6 finds a job that already ran by that name.\n", + "\n", + "The structure is not relaxed, as in the article's band-width series." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "25", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.standata.workflows import WorkflowStandata\n", + "from mat3ra.wode.workflows import Workflow\n", + "from mat3ra.wode.context.providers import PlanewaveCutoffsContextProvider, PointsGridDataProvider, \\\n", + " PointsPathDataProvider\n", + "\n", + "workflow_config = WorkflowStandata.filter_by_application(app.name).get_by_name_first_match(WORKFLOW_SEARCH_TERM)\n", + "workflow = Workflow.create(workflow_config)\n", + "workflow.name = f\"{MY_WORKFLOW_NAME} {MATERIAL_NAME} {MODEL_TAG}\"\n", + "subworkflow = workflow.subworkflows[0]\n", + "subworkflow.model = model\n", + "\n", + "cutoffs_context = PlanewaveCutoffsContextProvider(\n", + " wavefunction=ECUTWFC, density=ECUTRHO, isEdited=True).get_context_item_data()\n", + "grid_context = PointsGridDataProvider(material=material, dimensions=KGRID, isEdited=True).get_context_item_data()\n", + "path_context = PointsPathDataProvider(path=KPATH, isEdited=True).get_context_item_data()\n", + "\n", + "for unit_name, contexts in [(SCF_UNIT, [grid_context, cutoffs_context]),\n", + " (BANDS_UNIT, [path_context, cutoffs_context])]:\n", + " unit = subworkflow.get_unit_by_name(name=unit_name)\n", + " for context in contexts:\n", + " unit.add_context(context)\n", + " subworkflow.set_unit(unit)\n", + "print(workflow.name)" + ] + }, + { + "cell_type": "markdown", + "id": "26", + "metadata": {}, + "source": [ + "### 4.3. Preview the workflow" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "27", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.ipython.entity.workflow.visualize import visualize_workflow\n", + "\n", + "visualize_workflow(workflow)" + ] + }, + { + "cell_type": "markdown", + "id": "28", + "metadata": {}, + "source": [ + "### 4.4. Save the workflow to the collection" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "29", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.core.entity.workflow.api import get_or_create_workflow\n", + "\n", + "saved_workflow = Workflow.create(get_or_create_workflow(client, workflow, ACCOUNT_ID))\n", + "print(f\"{MATERIAL_NAME}: workflow {saved_workflow.id}\")" + ] + }, + { + "cell_type": "markdown", + "id": "30", + "metadata": {}, + "source": [ + "## 5. Create the compute configuration\n", + "### 5.1. Get list of clusters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "31", + "metadata": {}, + "outputs": [], + "source": [ + "clusters = client.clusters.list()\n", + "print(f\"Available clusters: {[c['hostname'] for c in clusters]}\")" + ] + }, + { + "cell_type": "markdown", + "id": "32", + "metadata": {}, + "source": [ + "### 5.2. Create the compute configuration for the job" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "33", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.ide.compute import Compute\n", + "\n", + "if CLUSTER_NAME:\n", + " cluster = next((c for c in clusters if CLUSTER_NAME in c[\"hostname\"]), None)\n", + " if cluster is None:\n", + " raise ValueError(f\"Cluster '{CLUSTER_NAME}' not found. Available: {[c['hostname'] for c in clusters]}\")\n", + "else:\n", + " cluster = clusters[0]\n", + "compute = Compute(cluster=cluster, queue=QUEUE_NAME, ppn=PPN, timeLimit=TIME_LIMIT)\n", + "print(f\"Using cluster: {compute.cluster.hostname}, queue: {QUEUE_NAME}, ppn: {PPN}, \"\n", + " f\"time limit: {TIME_LIMIT}\")" + ] + }, + { + "cell_type": "markdown", + "id": "34", + "metadata": {}, + "source": [ + "## 6. Run the job\n", + "\n", + "The job is found by its material and its workflow name, which carries the model tag, and re-used if it exists;\n", + "otherwise it is created and submitted." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "35", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.core.entity.job.api import find_job_for_material\n", + "from mat3ra.notebooks_utils.job import create_job\n", + "from mat3ra.notebooks_utils.api.job import submit_jobs, wait_for_jobs_to_finish_async\n", + "\n", + "job = find_job_for_material(\n", + " client, saved_material.id, workflow.name, ACCOUNT_ID, statuses=(\"submitted\", \"queued\", \"active\", \"finished\"),\n", + ")\n", + "if job is None:\n", + " job = create_job(\n", + " api_client=client, materials=[saved_material], workflow=workflow, project_id=project_id,\n", + " owner_id=ACCOUNT_ID, compute=compute.to_dict(), prefix=f\"{workflow.name} {timestamp}\",\n", + " )\n", + " submit_jobs(client.jobs, [job[\"_id\"]])\n", + " print(f\"✅ Submitted job {job['_id']}\")\n", + "else:\n", + " print(f\"♻️ Reusing job {job['_id']}\")\n", + "job_id = job[\"_id\"]\n", + "await wait_for_jobs_to_finish_async(client.jobs, [job_id], poll_interval=POLL_INTERVAL)" + ] + }, + { + "cell_type": "markdown", + "id": "36", + "metadata": {}, + "source": [ + "## 7. Retrieve the results\n", + "### 7.1. Band structure\n", + "\n", + "The path is Γ–K–M of the moiré cell, as in the article; the bands of the two layers are folded onto its small\n", + "Brillouin zone." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "37", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.core.entity.property.api import get_properties_for_job\n", + "from mat3ra.notebooks_utils.ipython.entity.property.visualize import visualize_properties\n", + "\n", + "band_structure = get_properties_for_job(client, job_id, property_name=\"band_structure\")[0]\n", + "visualize_properties(band_structure, title=f\"Band Structure: {MATERIAL_NAME}\",\n", + " extra_config={\"material\": material.to_dict()})" + ] + }, + { + "cell_type": "markdown", + "id": "38", + "metadata": {}, + "source": [ + "### 7.2. Top valence flat bands\n", + "\n", + "The flat set starts at the highest occupied band and takes in each band below whose maximum along the path reaches\n", + "the set's minimum. Its width is the spread of the set over the points of `KPATH`, and its separation is the distance\n", + "from the set's minimum down to the maximum of the next band. The article does not say whether its width is taken along\n", + "the path or over the whole Brillouin zone." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "39", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "\n", + "NUMBER_OF_OCCUPIED_BANDS = 2 * material.basis.number_of_atoms # 8 valence electrons per B–N pair: B 3, N 5\n", + "\n", + "bands = np.array(band_structure[\"yDataSeries\"]) # band × path point, eV\n", + "flat_set_bottom = NUMBER_OF_OCCUPIED_BANDS - 1\n", + "while bands[flat_set_bottom - 1].max() >= bands[flat_set_bottom:NUMBER_OF_OCCUPIED_BANDS].min():\n", + " flat_set_bottom -= 1\n", + "flat_set = bands[flat_set_bottom:NUMBER_OF_OCCUPIED_BANDS]\n", + "flat_set_top = flat_set.max()\n", + "flat_band_width = 1000 * (flat_set_top - flat_set.min())\n", + "flat_band_separation = 1000 * (flat_set.min() - bands[flat_set_bottom - 1].max())" + ] + }, + { + "cell_type": "markdown", + "id": "40", + "metadata": {}, + "source": [ + "### 7.3. Bands near the valence-band top (Fig. 1f of the paper)\n", + "\n", + "Energies relative to the top of the flat set, which is drawn in red." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "41", + "metadata": {}, + "outputs": [], + "source": [ + "from matplotlib import pyplot as plt\n", + "from mat3ra.notebooks_utils.plot import display_matplotlib_figure\n", + "\n", + "vertex_indices = np.cumsum([0] + [point[\"steps\"] for point in KPATH[:-1]])\n", + "figure, axes = plt.subplots()\n", + "axes.plot((bands - flat_set_top).T, color=\"black\", marker=\".\")\n", + "axes.plot((flat_set - flat_set_top).T, color=\"red\", marker=\".\")\n", + "axes.set_xticks(vertex_indices, [point[\"point\"] for point in KPATH])\n", + "axes.set_ylim(*PLOT_ENERGY_RANGE)\n", + "axes.set_ylabel(\"E − E(top of the flat bands) (eV)\")\n", + "axes.set_title(f\"Bands near the valence-band top: {MATERIAL_NAME}\")\n", + "display_matplotlib_figure(figure)" + ] + }, + { + "cell_type": "markdown", + "id": "42", + "metadata": {}, + "source": [ + "## 8. Compare with Xian et al. (2019)\n", + "\n", + "The article's width at 7.34° beside ours; the article gives no separation at this angle.\n", + "\n", + "Settings that differ from the article's: GBRV ultrasoft pseudopotentials at 40/200 Ry against VASP PAW at 400 eV, and\n", + "Standata's lattice constant of 2.509 Å against 2.512 Å." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "43", + "metadata": {}, + "outputs": [], + "source": [ + "XIAN_2019_FLAT_BAND_WIDTH = 101.4 # meV, 7.34°, text p. 4936 and Fig. 1g\n", + "\n", + "print(f\"Top valence flat-band width along Γ–K–M: {flat_band_width:.1f} meV · \"\n", + " f\"Xian et al. 2019: {XIAN_2019_FLAT_BAND_WIDTH} meV\")\n", + "print(f\"Separation from the bands below: {flat_band_separation:.1f} meV\")" + ] + }, + { + "cell_type": "markdown", + "id": "44", + "metadata": {}, + "source": [ + "## References\n", + "\n", + "[1] L. Xian, D. M. Kennes, N. Tancogne-Dejean, M. Altarelli and A. Rubio, \"Multiflat Bands and Strong Correlations in Twisted Bilayer Boron Nitride: Doping-Induced Correlated Insulator and Superconductor\", Nano Lett. 19, 4934 (2019). https://doi.org/10.1021/acs.nanolett.9b00986\n", + "\n", + "[2] K. F. Garrity, J. W. Bennett, K. M. Rabe and D. Vanderbilt, \"Pseudopotentials for high-throughput DFT calculations\", Comput. Mater. Sci. 81, 446 (2014). https://doi.org/10.1016/j.commatsci.2013.08.053" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "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.2" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_nanoribbons_boron_nitride.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_nanoribbons_boron_nitride.ipynb index a34081ed7..a9c46fd11 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_nanoribbons_boron_nitride.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_nanoribbons_boron_nitride.ipynb @@ -13,7 +13,7 @@ "\n", "> **Lede Xian, Dante M. Kennes, Nicolas Tancogne-Dejean, Massimo Altarelli, and Angel Rubio**,\n", "> \"Multiflat Bands and Strong Correlations in Twisted Bilayer Boron Nitride: Doping-Induced Correlated Insulator and Superconductor\"\n", - "> Phys. Rev. Lett. 125, 086402 – Published 20 August 2020\n", + "> Nano Lett. 19, 4934–4940 (2019)\n", "> [DOI: 10.1021/acs.nanolett.9b00986](https://pubs.acs.org/doi/10.1021/acs.nanolett.9b00986)\n", "\n", "We will reproduce the structure shown in Figure 1(a,b) of the paper, which shows a twisted bilayer h-BN with specific stacking regions.\n", @@ -22,7 +22,7 @@ "1. Hexagonal boron nitride bilayer structure\n", "2. Twisted configurations with 2 specific twist angles\n", "\n", - "The image shows the twisted bilayer h-BN structure with a twist angle of 2.64° (a) and 62.64° (b).\n", + "The image shows the twisted bilayer h-BN structure with a twist angle of 62.64° (a, configuration α) and 2.64° (b, configuration β).\n", "\n", "\"Twisted" ] From a8534a9b5a4dab7ee5cd720be0ba37e4f0fff14b Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Sat, 17 Oct 2026 02:48:06 -0700 Subject: [PATCH 02/21] =?UTF-8?q?SOF-8085:=20review=20-=20flat-set=20band?= =?UTF-8?q?=20count=20beside=20the=20width,=20no=20Fig.=201f=20in=20the=20?= =?UTF-8?q?7.34=C2=B0=20plot=20heading,=20made=20pinned=20to=20the=20searc?= =?UTF-8?q?h=20fix,=20structure=20build=20on=20the=20helper's=20defaults?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The structure notebook drops angle_tolerance, max_repetition_int, return_first_match and direction: with the helper's defaults the 67.34° cell is identical (244 atoms, same coordinates and lattice, alpha by registry). mat3ra-made is pinned to made fe1eee45 (feature/SOF-8085) until the search fix is released. Co-Authored-By: Claude Opus 5.5 --- ...twisted_commensurate_lattices_boron_nitride.ipynb | 12 +----------- ...mensurate_lattices_boron_nitride_SIMULATION.ipynb | 9 ++++----- pyproject.toml | 2 +- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb index a1769b6f6..4491a1def 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb @@ -54,7 +54,7 @@ "id": "3", "metadata": {}, "source": [ - "### 1.2. Set interface creation and search parameters" + "### 1.2. Set interface creation and visualization parameters" ] }, { @@ -66,11 +66,6 @@ "source": [ "VACUUM = 20.0 # Å of empty space above the top layer; paper: not stated\n", "\n", - "# Search algorithm parameters\n", - "MAX_REPETITION = None # Maximum supercell matrix element value (None for automatic)\n", - "ANGLE_TOLERANCE = 0.5 # in degrees\n", - "RETURN_FIRST_MATCH = True # If True, returns first solution within tolerance\n", - "\n", "# Visualization parameters\n", "SHOW_INTERMEDIATE_STEPS = True\n", "VISUALIZE_REPETITIONS = [3, 3, 1]" @@ -141,7 +136,6 @@ "metadata": {}, "outputs": [], "source": [ - "from mat3ra.esse.models.core.reusable.axis_enum import AxisEnum\n", "from mat3ra.made.tools.analyze.other import get_average_interlayer_distance\n", "from mat3ra.made.tools.convert import to_ase\n", "from mat3ra.made.tools.convert.interface_parts_enum import InterfacePartsEnum\n", @@ -150,10 +144,6 @@ "interface = create_interface_commensurate(\n", " material=material,\n", " target_angle=TARGET_TWIST_ANGLE,\n", - " angle_tolerance=ANGLE_TOLERANCE,\n", - " max_repetition_int=MAX_REPETITION,\n", - " return_first_match=RETURN_FIRST_MATCH,\n", - " direction=AxisEnum.z,\n", " gap=INTERFACE_DISTANCE,\n", " # the builder adds the gap above the top layer as well\n", " vacuum=VACUUM - INTERFACE_DISTANCE,\n", diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb index c114705c4..ff24988ae 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb @@ -548,7 +548,7 @@ "source": [ "import numpy as np\n", "\n", - "NUMBER_OF_OCCUPIED_BANDS = 2 * material.basis.number_of_atoms # 8 valence electrons per B–N pair: B 3, N 5\n", + "NUMBER_OF_OCCUPIED_BANDS = 2 * material.basis.number_of_atoms # GBRV valence electrons: B 3, N 5\n", "\n", "bands = np.array(band_structure[\"yDataSeries\"]) # band × path point, eV\n", "flat_set_bottom = NUMBER_OF_OCCUPIED_BANDS - 1\n", @@ -565,9 +565,9 @@ "id": "40", "metadata": {}, "source": [ - "### 7.3. Bands near the valence-band top (Fig. 1f of the paper)\n", + "### 7.3. Bands near the valence-band top\n", "\n", - "Energies relative to the top of the flat set, which is drawn in red." + "Energies relative to the top of the flat set." ] }, { @@ -583,7 +583,6 @@ "vertex_indices = np.cumsum([0] + [point[\"steps\"] for point in KPATH[:-1]])\n", "figure, axes = plt.subplots()\n", "axes.plot((bands - flat_set_top).T, color=\"black\", marker=\".\")\n", - "axes.plot((flat_set - flat_set_top).T, color=\"red\", marker=\".\")\n", "axes.set_xticks(vertex_indices, [point[\"point\"] for point in KPATH])\n", "axes.set_ylim(*PLOT_ENERGY_RANGE)\n", "axes.set_ylabel(\"E − E(top of the flat bands) (eV)\")\n", @@ -613,7 +612,7 @@ "source": [ "XIAN_2019_FLAT_BAND_WIDTH = 101.4 # meV, 7.34°, text p. 4936 and Fig. 1g\n", "\n", - "print(f\"Top valence flat-band width along Γ–K–M: {flat_band_width:.1f} meV · \"\n", + "print(f\"Top valence flat set ({len(flat_set)} bands), width along Γ–K–M: {flat_band_width:.1f} meV · \"\n", " f\"Xian et al. 2019: {XIAN_2019_FLAT_BAND_WIDTH} meV\")\n", "print(f\"Separation from the bands below: {flat_band_separation:.1f} meV\")" ] diff --git a/pyproject.toml b/pyproject.toml index 2840c8d43..b73125b1d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made", + "mat3ra-made @ git+https://github.com/mat3ra/made.git@fe1eee459ef5518d7eefc99f106afbd4f27427f3", # made feature/SOF-8085; unpin on release "mat3ra-periodic-table" ] workflows = [ From 066dd58c35a0df1474e7f4d88e553045e1af80c2 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Sat, 17 Oct 2026 02:58:03 -0700 Subject: [PATCH 03/21] SOF-8085: review - structure notebook intro describes the search the builder now runs on its defaults Co-Authored-By: Claude Opus 5.5 --- ...ce_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb index 4491a1def..eb1ff731b 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb @@ -9,7 +9,7 @@ "\n", "## 0. Introduction.\n", "\n", - "This notebook demonstrates how to generate a twisted interface between two materials using commensurate lattices. The example uses hexagonal boron nitride (h-BN) as both the film and substrate materials and builds the periodic moiré cell the paper computes at 7.34° (244 atoms). The notebook uses the `create_interface_commensurate` function which first creates a slab from the material and then performs commensurate lattice matching to find valid supercells for the target twist angle. The algorithm searches for supercell matrices within specified size limits to achieve the target twist angle within tolerance. The generated interface is visualized and analyzed to determine the number of atoms and the interlayer distance.\n", + "This notebook demonstrates how to generate a twisted interface between two materials using commensurate lattices. The example uses hexagonal boron nitride (h-BN) as both the film and substrate materials and builds the periodic moiré cell the paper computes at 7.34° (244 atoms). The notebook uses the `create_interface_commensurate` function which first creates a slab from the material and then performs commensurate lattice matching to find valid supercells for the target twist angle. The algorithm searches for the supercell matrices that give the target twist angle. The generated interface is visualized and analyzed to determine the number of atoms and the interlayer distance.\n", "\n", "> **Lede Xian, Dante M. Kennes, Nicolas Tancogne-Dejean, Massimo Altarelli, and Angel Rubio**\n", "> Multiflat Bands and Strong Correlations in Twisted Bilayer Boron Nitride: Doping-Induced Correlated Insulator and Superconductor. Nano Letters, 19, 4934. 2019.\n", From a605d70d1c487a44c872fee772786d1c21b2ed38 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 23 Oct 2026 13:21:12 -0700 Subject: [PATCH 04/21] =?UTF-8?q?SOF-8085:=20structure=20notebook=20builds?= =?UTF-8?q?=20configurations=20=CE=B1=20and=20=CE=B2=20at=207.34=C2=B0,=20?= =?UTF-8?q?the=20paper's=206.01,=205.08=20and=203.89=C2=B0=20as=20commente?= =?UTF-8?q?d=20entries?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- ..._commensurate_lattices_boron_nitride.ipynb | 79 +++++++++++-------- 1 file changed, 47 insertions(+), 32 deletions(-) diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb index eb1ff731b..1589790b2 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb @@ -9,7 +9,7 @@ "\n", "## 0. Introduction.\n", "\n", - "This notebook demonstrates how to generate a twisted interface between two materials using commensurate lattices. The example uses hexagonal boron nitride (h-BN) as both the film and substrate materials and builds the periodic moiré cell the paper computes at 7.34° (244 atoms). The notebook uses the `create_interface_commensurate` function which first creates a slab from the material and then performs commensurate lattice matching to find valid supercells for the target twist angle. The algorithm searches for the supercell matrices that give the target twist angle. The generated interface is visualized and analyzed to determine the number of atoms and the interlayer distance.\n", + "This notebook demonstrates how to generate a twisted interface between two materials using commensurate lattices. The example uses hexagonal boron nitride (h-BN) as both the film and substrate materials and builds the periodic moiré cells of configurations α and β that the paper computes, at 7.34° (244 atoms) by default. The notebook uses the `create_interface_commensurate` function which first creates a slab from the material and then performs commensurate lattice matching to find valid supercells for the target twist angle. The algorithm searches for the supercell matrices that give the target twist angle. The generated interfaces are visualized and analyzed to determine the number of atoms and the interlayer distance.\n", "\n", "> **Lede Xian, Dante M. Kennes, Nicolas Tancogne-Dejean, Massimo Altarelli, and Angel Rubio**\n", "> Multiflat Bands and Strong Correlations in Twisted Bilayer Boron Nitride: Doping-Induced Correlated Insulator and Superconductor. Nano Letters, 19, 4934. 2019.\n", @@ -28,13 +28,13 @@ "## 1. Prepare the Environment\n", "### 1.1. Configurations from the article\n", "\n", - "The twist angle and the interlayer distance below are the ones of the article's band-width series: flat layers,\n", + "The twist angles and the interlayer distance below are the ones of the article's band-width series: flat layers,\n", "3.23 Å apart, the optimized interlayer distance of the untwisted bilayer. The article's two configurations, α and β,\n", "share one moiré cell and differ in twist by 60°: in α the B-over-B and N-over-N regions sit at different sites of the\n", "cell, in β at the same site.\n", "\n", - "The name below is how the [band structure notebook](interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb)\n", - "finds the material created here, so changing it means changing it there too." + "The names below are how the [band structure notebook](interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb)\n", + "finds the materials created here, so changing one means changing it there too." ] }, { @@ -44,9 +44,20 @@ "metadata": {}, "outputs": [], "source": [ - "TARGET_TWIST_ANGLE = 60 + 7.34 # degrees; configuration α of Xian et al. 2019 Fig. 1a, 7.34 gives β\n", - "INTERFACE_DISTANCE = 3.23 # Å, the article's\n", - "MATERIAL_NAME = \"h-BN bilayer 7.34deg alpha d3.23\"" + "# Uncomment a line to build that configuration as well: α is twisted by 60° + θ, β by θ. The angles are those of\n", + "# Xian et al. 2019 Fig. 1g; smaller angles have larger cells (6.01°: 364 atoms, 5.08°: 508, 3.89°: 868) and build\n", + "# slower.\n", + "INTERFACE_PARAMETERS = [\n", + " {\"name\": \"h-BN bilayer 7.34deg alpha d3.23\", \"angle\": 60 + 7.34},\n", + " {\"name\": \"h-BN bilayer 7.34deg beta d3.23\", \"angle\": 7.34},\n", + " # {\"name\": \"h-BN bilayer 6.01deg alpha d3.23\", \"angle\": 60 + 6.01},\n", + " # {\"name\": \"h-BN bilayer 6.01deg beta d3.23\", \"angle\": 6.01},\n", + " # {\"name\": \"h-BN bilayer 5.08deg alpha d3.23\", \"angle\": 60 + 5.08},\n", + " # {\"name\": \"h-BN bilayer 5.08deg beta d3.23\", \"angle\": 5.08},\n", + " # {\"name\": \"h-BN bilayer 3.89deg alpha d3.23\", \"angle\": 60 + 3.89},\n", + " # {\"name\": \"h-BN bilayer 3.89deg beta d3.23\", \"angle\": 3.89},\n", + "]\n", + "INTERFACE_DISTANCE = 3.23 # Å, the article's" ] }, { @@ -126,7 +137,7 @@ "id": "9", "metadata": {}, "source": [ - "## 2. Generate the Twisted Interface" + "## 2. Generate the Twisted Interfaces" ] }, { @@ -141,23 +152,26 @@ "from mat3ra.made.tools.convert.interface_parts_enum import InterfacePartsEnum\n", "from mat3ra.made.tools.helpers import create_interface_commensurate, create_supercell\n", "\n", - "interface = create_interface_commensurate(\n", - " material=material,\n", - " target_angle=TARGET_TWIST_ANGLE,\n", - " gap=INTERFACE_DISTANCE,\n", - " # the builder adds the gap above the top layer as well\n", - " vacuum=VACUUM - INTERFACE_DISTANCE,\n", - ")\n", - "# The symbolic K point of the band path assumes the 120° hexagonal cell; the builder returns the 60° one.\n", - "interface = create_supercell(interface, supercell_matrix=[[1, 0, 0], [-1, 1, 0], [0, 0, 1]])\n", - "interface.lattice.type = \"HEX\"\n", - "interface.name = MATERIAL_NAME\n", - "\n", - "interlayer_distance = get_average_interlayer_distance(\n", - " interface, InterfacePartsEnum.SUBSTRATE.value, InterfacePartsEnum.FILM.value)\n", - "print(f\"{interface.name}: {interface.basis.number_of_atoms} atoms ({to_ase(interface).get_chemical_formula()}), \"\n", - " f\"a = {interface.lattice.a:.3f} Å, gamma = {interface.lattice.gamma:.1f}°, \"\n", - " f\"interlayer distance {interlayer_distance:.3f} Å, target twist {TARGET_TWIST_ANGLE:.2f}°\")" + "interfaces = []\n", + "for parameters in INTERFACE_PARAMETERS:\n", + " interface = create_interface_commensurate(\n", + " material=material,\n", + " target_angle=parameters[\"angle\"],\n", + " gap=INTERFACE_DISTANCE,\n", + " # the builder adds the gap above the top layer as well\n", + " vacuum=VACUUM - INTERFACE_DISTANCE,\n", + " )\n", + " # The symbolic K point of the band path assumes the 120° hexagonal cell; the builder returns the 60° one.\n", + " interface = create_supercell(interface, supercell_matrix=[[1, 0, 0], [-1, 1, 0], [0, 0, 1]])\n", + " interface.lattice.type = \"HEX\"\n", + " interface.name = parameters[\"name\"]\n", + " interfaces.append(interface)\n", + "\n", + " interlayer_distance = get_average_interlayer_distance(\n", + " interface, InterfacePartsEnum.SUBSTRATE.value, InterfacePartsEnum.FILM.value)\n", + " print(f\"{interface.name}: {interface.basis.number_of_atoms} atoms ({to_ase(interface).get_chemical_formula()}), \"\n", + " f\"a = {interface.lattice.a:.3f} Å, gamma = {interface.lattice.gamma:.1f}°, \"\n", + " f\"interlayer distance {interlayer_distance:.3f} Å, target twist {parameters['angle']:.2f}°\")" ] }, { @@ -165,7 +179,7 @@ "id": "11", "metadata": {}, "source": [ - "## 3. Preview the material" + "## 3. Preview the materials" ] }, { @@ -175,8 +189,8 @@ "metadata": {}, "outputs": [], "source": [ - "visualize_materials(interface, repetitions=VISUALIZE_REPETITIONS)\n", - "visualize_materials(interface, repetitions=VISUALIZE_REPETITIONS, rotation=\"-90x\")" + "visualize_materials(interfaces, repetitions=VISUALIZE_REPETITIONS)\n", + "visualize_materials(interfaces, repetitions=VISUALIZE_REPETITIONS, rotation=\"-90x\")" ] }, { @@ -184,9 +198,9 @@ "id": "13", "metadata": {}, "source": [ - "## 4. Save the material\n", + "## 4. Save the materials\n", "\n", - "The material is written to the `uploads` folder under its name, which is how the\n", + "Each material is written to the `uploads` folder under its name, which is how the\n", "[band structure notebook](interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb)\n", "picks it up." ] @@ -201,8 +215,9 @@ "from mat3ra.notebooks_utils.io import download_content_to_file\n", "from mat3ra.notebooks_utils.material import set_materials\n", "\n", - "set_materials([interface])\n", - "download_content_to_file(interface.to_json(), f\"{interface.name}.json\")" + "set_materials(interfaces)\n", + "for interface in interfaces:\n", + " download_content_to_file(interface.to_json(), f\"{interface.name}.json\")" ] }, { From e9cebd43d84e8e94356eeec57d52bc842ba4aa9f Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 23 Oct 2026 13:21:13 -0700 Subject: [PATCH 05/21] =?UTF-8?q?SOF-8085:=20simulation=20notebook=20takes?= =?UTF-8?q?=20a=20list=20of=20materials,=20each=20with=20the=20paper's=20f?= =?UTF-8?q?lat-band=20width;=20=CE=B1=20at=207.34=C2=B0=20by=20default?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- ...te_lattices_boron_nitride_SIMULATION.ipynb | 197 ++++++++++-------- 1 file changed, 115 insertions(+), 82 deletions(-) diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb index ff24988ae..292285213 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb @@ -12,29 +12,29 @@ "> Nano Letters 19, 4934 (2019)\n", "> [DOI: 10.1021/acs.nanolett.9b00986](https://doi.org/10.1021/acs.nanolett.9b00986)\n", "\n", - "Calculate the band structure of the twisted h-BN bilayer created in the\n", + "Calculate the band structure of the twisted h-BN bilayers created in the\n", "[structure notebook](interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb), using Quantum ESPRESSO and the\n", - "band structure workflow from Standata, and read off the width of its top set of flat valence bands.\n", + "band structure workflow from Standata, and read off the width of their top set of flat valence bands.\n", "\n", "The article's result is that twisting bilayer h-BN splits its top valence bands into isolated flat sets whose width\n", "shrinks with the twist angle, from 101.4 meV at 7.34° to 1.6 meV at 2.64° (Fig. 1g).\n", "\n", "

Usage

\n", "\n", - "1. Create the material in the [structure notebook](interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb), which saves it to the `uploads` folder under the name used in cell 1.2 below.\n", - "1. Set the material and the calculation parameters in cells 1.2 and 1.3 (or use the default values).\n", + "1. Create the materials in the [structure notebook](interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb), which saves them to the `uploads` folder under the names used in cell 1.2 below.\n", + "1. Set the materials and the calculation parameters in cells 1.2 and 1.3 (or use the default values).\n", "1. Click \"Run\" > \"Run All\" to run all cells.\n", - "1. Wait for the job to complete.\n", + "1. Wait for the jobs to complete.\n", "1. Scroll down to view the results; section 8 prints the comparison with the paper.\n", "\n", "## Summary\n", "\n", - "1. Set up the environment and parameters: install packages (JupyterLite only) and configure the material, workflow, model, compute resources and job.\n", + "1. Set up the environment and parameters: install packages (JupyterLite only) and configure the materials, workflow, model, compute resources and jobs.\n", "1. Authenticate and initialize API client: authenticate via browser, initialize the client, then select account and project.\n", - "1. Load the material by name from the `uploads` folder, print its provenance and save it to the platform.\n", + "1. Load the materials by name from the `uploads` folder, print their provenance and save them to the platform.\n", "1. Configure the workflow: select the application and the model, load the band structure workflow from Standata, and set the k-grid of the self-consistent run, the k-path of the bands and the cutoffs.\n", "1. Configure compute: get the list of clusters and create a compute configuration.\n", - "1. Run the job, re-using a job that already ran under the same workflow name.\n", + "1. Run one job per material, one after another, re-using a job that already ran under the same workflow name.\n", "1. Retrieve results: the band structure, the width of the top valence flat bands and their separation from the bands below, and the bands near the valence-band top.\n", "1. Compare with Xian et al. (2019)." ] @@ -80,7 +80,19 @@ "\n", "ORGANIZATION_NAME = None # set to your organization name (full or partial); otherwise, your default one is used\n", "FOLDER = \"./uploads\"\n", - "MATERIAL_NAME = \"h-BN bilayer 7.34deg alpha d3.23\" # as saved by the structure notebook\n", + "# Names as saved by the structure notebook, each with the width of its top valence flat set in Xian et al. 2019\n", + "# (meV; 7.34°: text p. 4936; 6.01, 5.08 and 3.89°: read off Fig. 1g). One job per material: 7.34° takes about 3 h on\n", + "# queue OR with 16 cores; 5.08° and smaller exceed one 4 h single-node job.\n", + "MATERIALS = {\n", + " \"h-BN bilayer 7.34deg alpha d3.23\": {\"paper_flat_band_width\": 101.4},\n", + " # \"h-BN bilayer 7.34deg beta d3.23\": {\"paper_flat_band_width\": 101.4},\n", + " # \"h-BN bilayer 6.01deg alpha d3.23\": {\"paper_flat_band_width\": 54.9},\n", + " # \"h-BN bilayer 6.01deg beta d3.23\": {\"paper_flat_band_width\": 54.9},\n", + " # \"h-BN bilayer 5.08deg alpha d3.23\": {\"paper_flat_band_width\": 31.6},\n", + " # \"h-BN bilayer 5.08deg beta d3.23\": {\"paper_flat_band_width\": 31.6},\n", + " # \"h-BN bilayer 3.89deg alpha d3.23\": {\"paper_flat_band_width\": 11.7},\n", + " # \"h-BN bilayer 3.89deg beta d3.23\": {\"paper_flat_band_width\": 11.7},\n", + "}\n", "\n", "WORKFLOW_SEARCH_TERM = \"band_structure.json\"\n", "MY_WORKFLOW_NAME = \"Band Structure\"\n", @@ -234,11 +246,11 @@ "id": "16", "metadata": {}, "source": [ - "## 3. Load the material\n", + "## 3. Load the materials\n", "### 3.1. Load from the uploads folder and print provenance\n", "\n", - "The structure, its geometry and its lattice type all come from the structure notebook; this one only loads it by\n", - "name." + "The structures, their geometry and their lattice type all come from the structure notebook; this one only loads them\n", + "by name." ] }, { @@ -250,9 +262,12 @@ "source": [ "from mat3ra.notebooks_utils.core.entity.material.api import load_material\n", "\n", - "material = load_material(client, FOLDER, MATERIAL_NAME, ACCOUNT_ID)\n", - "print(f\"{material.name}: {material.basis.number_of_atoms} atoms, a = {material.lattice.a:.3f} Å, \"\n", - " f\"gamma = {material.lattice.gamma:.3f}°, lattice {material.lattice.type}\")" + "materials = {}\n", + "for name in MATERIALS:\n", + " material = load_material(client, FOLDER, name, ACCOUNT_ID)\n", + " materials[name] = material\n", + " print(f\"{name}: {material.basis.number_of_atoms} atoms, a = {material.lattice.a:.3f} Å, \"\n", + " f\"gamma = {material.lattice.gamma:.3f}°, lattice {material.lattice.type}\")" ] }, { @@ -260,7 +275,7 @@ "id": "18", "metadata": {}, "source": [ - "### 3.2. Preview the material" + "### 3.2. Preview the materials" ] }, { @@ -272,7 +287,8 @@ "source": [ "from mat3ra.notebooks_utils.ipython.entity.material.visualize import visualize_materials\n", "\n", - "visualize_materials(material, viewer=\"wave\")" + "visualize_materials([{\"material\": material, \"title\": name} for name, material in materials.items()],\n", + " viewer=\"wave\")" ] }, { @@ -280,7 +296,7 @@ "id": "20", "metadata": {}, "source": [ - "### 3.3. Save the material to the platform" + "### 3.3. Save the materials to the platform" ] }, { @@ -293,8 +309,10 @@ "from mat3ra.made.material import Material\n", "from mat3ra.notebooks_utils.core.entity.material.api import get_or_create_material\n", "\n", - "material.basis.set_labels_from_list([])\n", - "saved_material = Material.create(get_or_create_material(client, material, ACCOUNT_ID))" + "saved_materials = {}\n", + "for name, material in materials.items():\n", + " material.basis.set_labels_from_list([])\n", + " saved_materials[name] = Material.create(get_or_create_material(client, material, ACCOUNT_ID))" ] }, { @@ -334,8 +352,8 @@ "source": [ "### 4.2. Configure the workflow\n", "\n", - "The self-consistent run on `KGRID`, then the bands along `KPATH`, both with the cutoffs of 1.3. The workflow is named\n", - "after the material and `MODEL_TAG`; section 6 finds a job that already ran by that name.\n", + "One workflow per material: the self-consistent run on `KGRID`, then the bands along `KPATH`, both with the cutoffs of\n", + "1.3. Each workflow is named after its material and `MODEL_TAG`; section 6 finds a job that already ran by that name.\n", "\n", "The structure is not relaxed, as in the article's band-width series." ] @@ -352,24 +370,29 @@ "from mat3ra.wode.context.providers import PlanewaveCutoffsContextProvider, PointsGridDataProvider, \\\n", " PointsPathDataProvider\n", "\n", - "workflow_config = WorkflowStandata.filter_by_application(app.name).get_by_name_first_match(WORKFLOW_SEARCH_TERM)\n", - "workflow = Workflow.create(workflow_config)\n", - "workflow.name = f\"{MY_WORKFLOW_NAME} {MATERIAL_NAME} {MODEL_TAG}\"\n", - "subworkflow = workflow.subworkflows[0]\n", - "subworkflow.model = model\n", + "from copy import deepcopy\n", "\n", + "workflow_config = WorkflowStandata.filter_by_application(app.name).get_by_name_first_match(WORKFLOW_SEARCH_TERM)\n", "cutoffs_context = PlanewaveCutoffsContextProvider(\n", " wavefunction=ECUTWFC, density=ECUTRHO, isEdited=True).get_context_item_data()\n", - "grid_context = PointsGridDataProvider(material=material, dimensions=KGRID, isEdited=True).get_context_item_data()\n", "path_context = PointsPathDataProvider(path=KPATH, isEdited=True).get_context_item_data()\n", "\n", - "for unit_name, contexts in [(SCF_UNIT, [grid_context, cutoffs_context]),\n", - " (BANDS_UNIT, [path_context, cutoffs_context])]:\n", - " unit = subworkflow.get_unit_by_name(name=unit_name)\n", - " for context in contexts:\n", - " unit.add_context(context)\n", - " subworkflow.set_unit(unit)\n", - "print(workflow.name)" + "workflows = {}\n", + "for name, material in materials.items():\n", + " workflow = Workflow.create(deepcopy(workflow_config))\n", + " workflow.name = f\"{MY_WORKFLOW_NAME} {name} {MODEL_TAG}\"\n", + " subworkflow = workflow.subworkflows[0]\n", + " subworkflow.model = model\n", + " grid_context = PointsGridDataProvider(material=material, dimensions=KGRID, isEdited=True).get_context_item_data()\n", + "\n", + " for unit_name, contexts in [(SCF_UNIT, [grid_context, cutoffs_context]),\n", + " (BANDS_UNIT, [path_context, cutoffs_context])]:\n", + " unit = subworkflow.get_unit_by_name(name=unit_name)\n", + " for context in contexts:\n", + " unit.add_context(context)\n", + " subworkflow.set_unit(unit)\n", + " workflows[name] = workflow\n", + " print(workflow.name)" ] }, { @@ -389,7 +412,7 @@ "source": [ "from mat3ra.notebooks_utils.ipython.entity.workflow.visualize import visualize_workflow\n", "\n", - "visualize_workflow(workflow)" + "visualize_workflow(next(iter(workflows.values())))" ] }, { @@ -397,7 +420,7 @@ "id": "28", "metadata": {}, "source": [ - "### 4.4. Save the workflow to the collection" + "### 4.4. Save the workflows to the collection" ] }, { @@ -409,8 +432,9 @@ "source": [ "from mat3ra.notebooks_utils.core.entity.workflow.api import get_or_create_workflow\n", "\n", - "saved_workflow = Workflow.create(get_or_create_workflow(client, workflow, ACCOUNT_ID))\n", - "print(f\"{MATERIAL_NAME}: workflow {saved_workflow.id}\")" + "for name, workflow in workflows.items():\n", + " saved = Workflow.create(get_or_create_workflow(client, workflow, ACCOUNT_ID))\n", + " print(f\"{name}: workflow {saved.id}\")" ] }, { @@ -438,7 +462,7 @@ "id": "32", "metadata": {}, "source": [ - "### 5.2. Create the compute configuration for the job" + "### 5.2. Create the compute configuration for the jobs" ] }, { @@ -466,10 +490,10 @@ "id": "34", "metadata": {}, "source": [ - "## 6. Run the job\n", + "## 6. Run the jobs one at a time\n", "\n", - "The job is found by its material and its workflow name, which carries the model tag, and re-used if it exists;\n", - "otherwise it is created and submitted." + "A job is found by its material and its workflow name, which carries the model tag, and re-used if it exists;\n", + "otherwise it is created and submitted. The jobs run one after another." ] }, { @@ -483,20 +507,23 @@ "from mat3ra.notebooks_utils.job import create_job\n", "from mat3ra.notebooks_utils.api.job import submit_jobs, wait_for_jobs_to_finish_async\n", "\n", - "job = find_job_for_material(\n", - " client, saved_material.id, workflow.name, ACCOUNT_ID, statuses=(\"submitted\", \"queued\", \"active\", \"finished\"),\n", - ")\n", - "if job is None:\n", - " job = create_job(\n", - " api_client=client, materials=[saved_material], workflow=workflow, project_id=project_id,\n", - " owner_id=ACCOUNT_ID, compute=compute.to_dict(), prefix=f\"{workflow.name} {timestamp}\",\n", + "job_ids = {}\n", + "for name, workflow in workflows.items():\n", + " job = find_job_for_material(\n", + " client, saved_materials[name].id, workflow.name, ACCOUNT_ID,\n", + " statuses=(\"submitted\", \"queued\", \"active\", \"finished\"),\n", " )\n", - " submit_jobs(client.jobs, [job[\"_id\"]])\n", - " print(f\"✅ Submitted job {job['_id']}\")\n", - "else:\n", - " print(f\"♻️ Reusing job {job['_id']}\")\n", - "job_id = job[\"_id\"]\n", - "await wait_for_jobs_to_finish_async(client.jobs, [job_id], poll_interval=POLL_INTERVAL)" + " if job is None:\n", + " job = create_job(\n", + " api_client=client, materials=[saved_materials[name]], workflow=workflow, project_id=project_id,\n", + " owner_id=ACCOUNT_ID, compute=compute.to_dict(), prefix=f\"{workflow.name} {timestamp}\",\n", + " )\n", + " submit_jobs(client.jobs, [job[\"_id\"]])\n", + " print(f\"✅ {name}: submitted job {job['_id']}\")\n", + " else:\n", + " print(f\"♻️ {name}: reusing job {job['_id']}\")\n", + " await wait_for_jobs_to_finish_async(client.jobs, [job[\"_id\"]], poll_interval=POLL_INTERVAL)\n", + " job_ids[name] = job[\"_id\"]" ] }, { @@ -521,9 +548,11 @@ "from mat3ra.notebooks_utils.core.entity.property.api import get_properties_for_job\n", "from mat3ra.notebooks_utils.ipython.entity.property.visualize import visualize_properties\n", "\n", - "band_structure = get_properties_for_job(client, job_id, property_name=\"band_structure\")[0]\n", - "visualize_properties(band_structure, title=f\"Band Structure: {MATERIAL_NAME}\",\n", - " extra_config={\"material\": material.to_dict()})" + "band_structures = {}\n", + "for name, job_id in job_ids.items():\n", + " band_structures[name] = get_properties_for_job(client, job_id, property_name=\"band_structure\")[0]\n", + " visualize_properties(band_structures[name], title=f\"Band Structure: {name}\",\n", + " extra_config={\"material\": materials[name].to_dict()})" ] }, { @@ -548,16 +577,20 @@ "source": [ "import numpy as np\n", "\n", - "NUMBER_OF_OCCUPIED_BANDS = 2 * material.basis.number_of_atoms # GBRV valence electrons: B 3, N 5\n", - "\n", - "bands = np.array(band_structure[\"yDataSeries\"]) # band × path point, eV\n", - "flat_set_bottom = NUMBER_OF_OCCUPIED_BANDS - 1\n", - "while bands[flat_set_bottom - 1].max() >= bands[flat_set_bottom:NUMBER_OF_OCCUPIED_BANDS].min():\n", - " flat_set_bottom -= 1\n", - "flat_set = bands[flat_set_bottom:NUMBER_OF_OCCUPIED_BANDS]\n", - "flat_set_top = flat_set.max()\n", - "flat_band_width = 1000 * (flat_set_top - flat_set.min())\n", - "flat_band_separation = 1000 * (flat_set.min() - bands[flat_set_bottom - 1].max())" + "flat_bands = {}\n", + "for name, band_structure in band_structures.items():\n", + " number_of_occupied_bands = 2 * materials[name].basis.number_of_atoms # GBRV valence electrons: B 3, N 5\n", + " bands = np.array(band_structure[\"yDataSeries\"]) # band × path point, eV\n", + " flat_set_bottom = number_of_occupied_bands - 1\n", + " while bands[flat_set_bottom - 1].max() >= bands[flat_set_bottom:number_of_occupied_bands].min():\n", + " flat_set_bottom -= 1\n", + " flat_set = bands[flat_set_bottom:number_of_occupied_bands]\n", + " flat_bands[name] = {\n", + " \"bands\": bands,\n", + " \"flat_set\": flat_set,\n", + " \"width\": 1000 * (flat_set.max() - flat_set.min()),\n", + " \"separation\": 1000 * (flat_set.min() - bands[flat_set_bottom - 1].max()),\n", + " }" ] }, { @@ -581,13 +614,14 @@ "from mat3ra.notebooks_utils.plot import display_matplotlib_figure\n", "\n", "vertex_indices = np.cumsum([0] + [point[\"steps\"] for point in KPATH[:-1]])\n", - "figure, axes = plt.subplots()\n", - "axes.plot((bands - flat_set_top).T, color=\"black\", marker=\".\")\n", - "axes.set_xticks(vertex_indices, [point[\"point\"] for point in KPATH])\n", - "axes.set_ylim(*PLOT_ENERGY_RANGE)\n", - "axes.set_ylabel(\"E − E(top of the flat bands) (eV)\")\n", - "axes.set_title(f\"Bands near the valence-band top: {MATERIAL_NAME}\")\n", - "display_matplotlib_figure(figure)" + "for name, result in flat_bands.items():\n", + " figure, axes = plt.subplots()\n", + " axes.plot((result[\"bands\"] - result[\"flat_set\"].max()).T, color=\"black\", marker=\".\")\n", + " axes.set_xticks(vertex_indices, [point[\"point\"] for point in KPATH])\n", + " axes.set_ylim(*PLOT_ENERGY_RANGE)\n", + " axes.set_ylabel(\"E − E(top of the flat bands) (eV)\")\n", + " axes.set_title(f\"Bands near the valence-band top: {name}\")\n", + " display_matplotlib_figure(figure)" ] }, { @@ -597,7 +631,7 @@ "source": [ "## 8. Compare with Xian et al. (2019)\n", "\n", - "The article's width at 7.34° beside ours; the article gives no separation at this angle.\n", + "The article's width for each material, set in `MATERIALS`, beside ours; the article gives no separation.\n", "\n", "Settings that differ from the article's: GBRV ultrasoft pseudopotentials at 40/200 Ry against VASP PAW at 400 eV, and\n", "Standata's lattice constant of 2.509 Å against 2.512 Å." @@ -610,11 +644,10 @@ "metadata": {}, "outputs": [], "source": [ - "XIAN_2019_FLAT_BAND_WIDTH = 101.4 # meV, 7.34°, text p. 4936 and Fig. 1g\n", - "\n", - "print(f\"Top valence flat set ({len(flat_set)} bands), width along Γ–K–M: {flat_band_width:.1f} meV · \"\n", - " f\"Xian et al. 2019: {XIAN_2019_FLAT_BAND_WIDTH} meV\")\n", - "print(f\"Separation from the bands below: {flat_band_separation:.1f} meV\")" + "for name, result in flat_bands.items():\n", + " print(f\"{name}: top valence flat set ({len(result['flat_set'])} bands), width along Γ–K–M: \"\n", + " f\"{result['width']:.1f} meV · Xian et al. 2019: {MATERIALS[name]['paper_flat_band_width']} meV\")\n", + " print(f\"{name}: separation from the bands below: {result['separation']:.1f} meV\")" ] }, { From 687e3514766cb93fb61b59c7c721744052b4c42c Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 23 Oct 2026 13:26:08 -0700 Subject: [PATCH 06/21] SOF-8085: simulation notebook's materials comment carries no run timing Co-Authored-By: Claude Opus 5.5 --- ...isted_commensurate_lattices_boron_nitride_SIMULATION.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb index 292285213..8d3c4b145 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb @@ -81,8 +81,8 @@ "ORGANIZATION_NAME = None # set to your organization name (full or partial); otherwise, your default one is used\n", "FOLDER = \"./uploads\"\n", "# Names as saved by the structure notebook, each with the width of its top valence flat set in Xian et al. 2019\n", - "# (meV; 7.34°: text p. 4936; 6.01, 5.08 and 3.89°: read off Fig. 1g). One job per material: 7.34° takes about 3 h on\n", - "# queue OR with 16 cores; 5.08° and smaller exceed one 4 h single-node job.\n", + "# (meV; 7.34°: text p. 4936; 6.01, 5.08 and 3.89°: read off Fig. 1g). One job per material; 5.08° and smaller exceed\n", + "# one 4 h single-node job.\n", "MATERIALS = {\n", " \"h-BN bilayer 7.34deg alpha d3.23\": {\"paper_flat_band_width\": 101.4},\n", " # \"h-BN bilayer 7.34deg beta d3.23\": {\"paper_flat_band_width\": 101.4},\n", From 29f30e3d95d6abf38af5526c750c0f950c0895a7 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 23 Oct 2026 13:34:32 -0700 Subject: [PATCH 07/21] =?UTF-8?q?SOF-8085:=20review=20-=20=CE=B1=20and=20?= =?UTF-8?q?=CE=B2=20previews=20titled=20by=20name;=20paper=20widths=20name?= =?UTF-8?q?=20no=20configuration,=20every=20angle=20below=207.34=C2=B0=20e?= =?UTF-8?q?xceeds=20one=204=20h=20single-node=20job?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- ...bilayer_twisted_commensurate_lattices_boron_nitride.ipynb | 5 +++-- ...sted_commensurate_lattices_boron_nitride_SIMULATION.ipynb | 4 ++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb index 1589790b2..0982b37fc 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb @@ -189,8 +189,9 @@ "metadata": {}, "outputs": [], "source": [ - "visualize_materials(interfaces, repetitions=VISUALIZE_REPETITIONS)\n", - "visualize_materials(interfaces, repetitions=VISUALIZE_REPETITIONS, rotation=\"-90x\")" + "titled_interfaces = [{\"material\": interface, \"title\": interface.name} for interface in interfaces]\n", + "visualize_materials(titled_interfaces, repetitions=VISUALIZE_REPETITIONS)\n", + "visualize_materials(titled_interfaces, repetitions=VISUALIZE_REPETITIONS, rotation=\"-90x\")" ] }, { diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb index 8d3c4b145..f11ee69d6 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb @@ -81,8 +81,8 @@ "ORGANIZATION_NAME = None # set to your organization name (full or partial); otherwise, your default one is used\n", "FOLDER = \"./uploads\"\n", "# Names as saved by the structure notebook, each with the width of its top valence flat set in Xian et al. 2019\n", - "# (meV; 7.34°: text p. 4936; 6.01, 5.08 and 3.89°: read off Fig. 1g). One job per material; 5.08° and smaller exceed\n", - "# one 4 h single-node job.\n", + "# (meV, configuration not stated; 7.34°: text p. 4936; 6.01, 5.08 and 3.89°: read off Fig. 1g). One job per material;\n", + "# every angle below 7.34° exceeds one 4 h single-node job.\n", "MATERIALS = {\n", " \"h-BN bilayer 7.34deg alpha d3.23\": {\"paper_flat_band_width\": 101.4},\n", " # \"h-BN bilayer 7.34deg beta d3.23\": {\"paper_flat_band_width\": 101.4},\n", From 5c0ea1bfdc33ae8a3eb672c6df21ca94a4b08ea2 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 23 Oct 2026 17:10:38 -0700 Subject: [PATCH 08/21] =?UTF-8?q?SOF-8085:=202.64=C2=B0=20=CE=B1=20and=20?= =?UTF-8?q?=CE=B2=20as=20commented=20entries=20in=20both=20notebooks;=20ma?= =?UTF-8?q?de=20pinned=20to=20the=20coincidence-lattice=20search?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- ...ilayer_twisted_commensurate_lattices_boron_nitride.ipynb | 5 +++-- ...ted_commensurate_lattices_boron_nitride_SIMULATION.ipynb | 6 ++++-- pyproject.toml | 2 +- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb index 0982b37fc..ef3daffa9 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb @@ -45,8 +45,7 @@ "outputs": [], "source": [ "# Uncomment a line to build that configuration as well: α is twisted by 60° + θ, β by θ. The angles are those of\n", - "# Xian et al. 2019 Fig. 1g; smaller angles have larger cells (6.01°: 364 atoms, 5.08°: 508, 3.89°: 868) and build\n", - "# slower.\n", + "# Xian et al. 2019 Fig. 1g; smaller angles have larger cells (6.01°: 364 atoms, 5.08°: 508, 3.89°: 868, 2.64°: 1876).\n", "INTERFACE_PARAMETERS = [\n", " {\"name\": \"h-BN bilayer 7.34deg alpha d3.23\", \"angle\": 60 + 7.34},\n", " {\"name\": \"h-BN bilayer 7.34deg beta d3.23\", \"angle\": 7.34},\n", @@ -56,6 +55,8 @@ " # {\"name\": \"h-BN bilayer 5.08deg beta d3.23\", \"angle\": 5.08},\n", " # {\"name\": \"h-BN bilayer 3.89deg alpha d3.23\", \"angle\": 60 + 3.89},\n", " # {\"name\": \"h-BN bilayer 3.89deg beta d3.23\", \"angle\": 3.89},\n", + " # {\"name\": \"h-BN bilayer 2.64deg alpha d3.23\", \"angle\": 60 + 2.64},\n", + " # {\"name\": \"h-BN bilayer 2.64deg beta d3.23\", \"angle\": 2.64},\n", "]\n", "INTERFACE_DISTANCE = 3.23 # Å, the article's" ] diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb index f11ee69d6..f53d9a1b8 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb @@ -81,8 +81,8 @@ "ORGANIZATION_NAME = None # set to your organization name (full or partial); otherwise, your default one is used\n", "FOLDER = \"./uploads\"\n", "# Names as saved by the structure notebook, each with the width of its top valence flat set in Xian et al. 2019\n", - "# (meV, configuration not stated; 7.34°: text p. 4936; 6.01, 5.08 and 3.89°: read off Fig. 1g). One job per material;\n", - "# every angle below 7.34° exceeds one 4 h single-node job.\n", + "# (meV, configuration not stated; 7.34° and 2.64°: text p. 4936; 6.01, 5.08 and 3.89°: read off Fig. 1g). One job per\n", + "# material; every angle below 7.34° exceeds one 4 h single-node job.\n", "MATERIALS = {\n", " \"h-BN bilayer 7.34deg alpha d3.23\": {\"paper_flat_band_width\": 101.4},\n", " # \"h-BN bilayer 7.34deg beta d3.23\": {\"paper_flat_band_width\": 101.4},\n", @@ -92,6 +92,8 @@ " # \"h-BN bilayer 5.08deg beta d3.23\": {\"paper_flat_band_width\": 31.6},\n", " # \"h-BN bilayer 3.89deg alpha d3.23\": {\"paper_flat_band_width\": 11.7},\n", " # \"h-BN bilayer 3.89deg beta d3.23\": {\"paper_flat_band_width\": 11.7},\n", + " # \"h-BN bilayer 2.64deg alpha d3.23\": {\"paper_flat_band_width\": 1.6},\n", + " # \"h-BN bilayer 2.64deg beta d3.23\": {\"paper_flat_band_width\": 1.6},\n", "}\n", "\n", "WORKFLOW_SEARCH_TERM = \"band_structure.json\"\n", diff --git a/pyproject.toml b/pyproject.toml index b73125b1d..f512165fb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made @ git+https://github.com/mat3ra/made.git@fe1eee459ef5518d7eefc99f106afbd4f27427f3", # made feature/SOF-8085; unpin on release + "mat3ra-made @ git+https://github.com/mat3ra/made.git@2bb6bad9c551b445f6659b51f0506bf57329a1d4", # made feature/SOF-8085; unpin on release "mat3ra-periodic-table" ] workflows = [ From 519f94dc5277902f45703bca9eca8c8a4a68e01c Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 23 Oct 2026 17:20:54 -0700 Subject: [PATCH 09/21] SOF-8085: made pinned to ed20fa13 Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f512165fb..56f86abd8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made @ git+https://github.com/mat3ra/made.git@2bb6bad9c551b445f6659b51f0506bf57329a1d4", # made feature/SOF-8085; unpin on release + "mat3ra-made @ git+https://github.com/mat3ra/made.git@ed20fa13086a404f76437cf39a47466e1d198612", # made feature/SOF-8085; unpin on release "mat3ra-periodic-table" ] workflows = [ From 628ef2407faf68979476efae7ecd32015677b62b Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 23 Oct 2026 18:25:12 -0700 Subject: [PATCH 10/21] SOF-8085: pin made to the readable coincidence-lattice search (30df3002); unpin on release Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 56f86abd8..ab54e3954 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made @ git+https://github.com/mat3ra/made.git@ed20fa13086a404f76437cf39a47466e1d198612", # made feature/SOF-8085; unpin on release + "mat3ra-made @ git+https://github.com/mat3ra/made.git@30df3002e80beb2958675fc2969d7fa47a54a5f6", # made feature/SOF-8085; unpin on release "mat3ra-periodic-table" ] workflows = [ From 068b47c915665fc57cc5517154627d48ace694e9 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 23 Oct 2026 20:00:02 -0700 Subject: [PATCH 11/21] SOF-8085: the h-BN monolayer (Fig. 1d) saved and computed beside the bilayers; k-grid per material, band gap beside the paper's 4.7 eV Co-Authored-By: Claude Opus 5.5 --- ..._commensurate_lattices_boron_nitride.ipynb | 3 +- ...te_lattices_boron_nitride_SIMULATION.ipynb | 79 +++++++++++-------- 2 files changed, 49 insertions(+), 33 deletions(-) diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb index ef3daffa9..02dee87f2 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb @@ -217,7 +217,8 @@ "from mat3ra.notebooks_utils.io import download_content_to_file\n", "from mat3ra.notebooks_utils.material import set_materials\n", "\n", - "set_materials(interfaces)\n", + "material.name = \"h-BN monolayer\"\n", + "set_materials([*interfaces, material])\n", "for interface in interfaces:\n", " download_content_to_file(interface.to_json(), f\"{interface.name}.json\")" ] diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb index f53d9a1b8..be3fddf83 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb @@ -12,9 +12,10 @@ "> Nano Letters 19, 4934 (2019)\n", "> [DOI: 10.1021/acs.nanolett.9b00986](https://doi.org/10.1021/acs.nanolett.9b00986)\n", "\n", - "Calculate the band structure of the twisted h-BN bilayers created in the\n", + "Calculate the band structures of the h-BN monolayer and the twisted h-BN bilayers created in the\n", "[structure notebook](interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb), using Quantum ESPRESSO and the\n", - "band structure workflow from Standata, and read off the width of their top set of flat valence bands.\n", + "band structure workflow from Standata, read off the band gap of the monolayer (Fig. 1d) and the width of the top set\n", + "of flat valence bands of the bilayers.\n", "\n", "The article's result is that twisting bilayer h-BN splits its top valence bands into isolated flat sets whose width\n", "shrinks with the twist angle, from 101.4 meV at 7.34° to 1.6 meV at 2.64° (Fig. 1g).\n", @@ -35,7 +36,7 @@ "1. Configure the workflow: select the application and the model, load the band structure workflow from Standata, and set the k-grid of the self-consistent run, the k-path of the bands and the cutoffs.\n", "1. Configure compute: get the list of clusters and create a compute configuration.\n", "1. Run one job per material, one after another, re-using a job that already ran under the same workflow name.\n", - "1. Retrieve results: the band structure, the width of the top valence flat bands and their separation from the bands below, and the bands near the valence-band top.\n", + "1. Retrieve results: the band structures, the width of the top valence flat bands and their separation from the bands below, the bands near the valence-band top, and the band gap of the monolayer.\n", "1. Compare with Xian et al. (2019)." ] }, @@ -80,20 +81,23 @@ "\n", "ORGANIZATION_NAME = None # set to your organization name (full or partial); otherwise, your default one is used\n", "FOLDER = \"./uploads\"\n", - "# Names as saved by the structure notebook, each with the width of its top valence flat set in Xian et al. 2019\n", - "# (meV, configuration not stated; 7.34° and 2.64°: text p. 4936; 6.01, 5.08 and 3.89°: read off Fig. 1g). One job per\n", - "# material; every angle below 7.34° exceeds one 4 h single-node job.\n", + "# Names as saved by the structure notebook, each with the k-grid of its self-consistent run and the paper's value:\n", + "# the monolayer's LDA band gap (eV, SI p. 10) or the width of the bilayer's top valence flat set (meV, configuration\n", + "# not stated; 7.34° and 2.64°: text p. 4936; 6.01, 5.08 and 3.89°: read off Fig. 1g). The twisted cells use the paper's\n", + "# Γ-only self-consistent run. One job per material; every angle below 7.34° exceeds one 4 h single-node job.\n", "MATERIALS = {\n", - " \"h-BN bilayer 7.34deg alpha d3.23\": {\"paper_flat_band_width\": 101.4},\n", - " # \"h-BN bilayer 7.34deg beta d3.23\": {\"paper_flat_band_width\": 101.4},\n", - " # \"h-BN bilayer 6.01deg alpha d3.23\": {\"paper_flat_band_width\": 54.9},\n", - " # \"h-BN bilayer 6.01deg beta d3.23\": {\"paper_flat_band_width\": 54.9},\n", - " # \"h-BN bilayer 5.08deg alpha d3.23\": {\"paper_flat_band_width\": 31.6},\n", - " # \"h-BN bilayer 5.08deg beta d3.23\": {\"paper_flat_band_width\": 31.6},\n", - " # \"h-BN bilayer 3.89deg alpha d3.23\": {\"paper_flat_band_width\": 11.7},\n", - " # \"h-BN bilayer 3.89deg beta d3.23\": {\"paper_flat_band_width\": 11.7},\n", - " # \"h-BN bilayer 2.64deg alpha d3.23\": {\"paper_flat_band_width\": 1.6},\n", - " # \"h-BN bilayer 2.64deg beta d3.23\": {\"paper_flat_band_width\": 1.6},\n", + " # paper: k-grid not stated; ours a multiple of 3, which keeps K on the mesh\n", + " \"h-BN monolayer\": {\"kgrid\": [12, 12, 1], \"paper_band_gap\": 4.7},\n", + " \"h-BN bilayer 7.34deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 101.4},\n", + " # \"h-BN bilayer 7.34deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 101.4},\n", + " # \"h-BN bilayer 6.01deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 54.9},\n", + " # \"h-BN bilayer 6.01deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 54.9},\n", + " # \"h-BN bilayer 5.08deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 31.6},\n", + " # \"h-BN bilayer 5.08deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 31.6},\n", + " # \"h-BN bilayer 3.89deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 11.7},\n", + " # \"h-BN bilayer 3.89deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 11.7},\n", + " # \"h-BN bilayer 2.64deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 1.6},\n", + " # \"h-BN bilayer 2.64deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 1.6},\n", "}\n", "\n", "WORKFLOW_SEARCH_TERM = \"band_structure.json\"\n", @@ -130,15 +134,14 @@ "ECUTWFC = 40 # Ry\n", "ECUTRHO = 200 # Ry; paper: VASP PAW, 400 eV\n", "\n", - "KGRID = [1, 1, 1] # Γ only, as the paper's self-consistent run\n", "# paper: Γ–K–M, number of points not stated; ours 7, evenly spaced (|ΓK| = 2|KM|)\n", "KPATH = [\n", " {\"point\": \"Γ\", \"steps\": 4},\n", " {\"point\": \"K\", \"steps\": 2},\n", " {\"point\": \"M\", \"steps\": 1},\n", "]\n", - "MODEL_TAG = (f\"{FUNCTIONAL}-{PSEUDOPOTENTIAL_TYPE} {ECUTWFC}-{ECUTRHO}Ry k{KGRID[0]} \"\n", - " f\"p{sum(point['steps'] for point in KPATH)}\")\n", + "MODEL_TAG = f\"{FUNCTIONAL}-{PSEUDOPOTENTIAL_TYPE} {ECUTWFC}-{ECUTRHO}Ry\"\n", + "PATH_TAG = f\"p{sum(point['steps'] for point in KPATH)}\"\n", "\n", "SCF_UNIT = \"pw_scf\"\n", "BANDS_UNIT = \"pw_bands\"\n", @@ -354,8 +357,9 @@ "source": [ "### 4.2. Configure the workflow\n", "\n", - "One workflow per material: the self-consistent run on `KGRID`, then the bands along `KPATH`, both with the cutoffs of\n", - "1.3. Each workflow is named after its material and `MODEL_TAG`; section 6 finds a job that already ran by that name.\n", + "One workflow per material: the self-consistent run on the k-grid set alongside its name in 1.2, then the bands along\n", + "`KPATH`, both with the cutoffs of 1.3. Each workflow is named after its material, `MODEL_TAG`, its k-grid and\n", + "`PATH_TAG`; section 6 finds a job that already ran by that name.\n", "\n", "The structure is not relaxed, as in the article's band-width series." ] @@ -382,10 +386,11 @@ "workflows = {}\n", "for name, material in materials.items():\n", " workflow = Workflow.create(deepcopy(workflow_config))\n", - " workflow.name = f\"{MY_WORKFLOW_NAME} {name} {MODEL_TAG}\"\n", + " workflow.name = f\"{MY_WORKFLOW_NAME} {name} {MODEL_TAG} k{MATERIALS[name]['kgrid'][0]} {PATH_TAG}\"\n", " subworkflow = workflow.subworkflows[0]\n", " subworkflow.model = model\n", - " grid_context = PointsGridDataProvider(material=material, dimensions=KGRID, isEdited=True).get_context_item_data()\n", + " grid_context = PointsGridDataProvider(material=material, dimensions=MATERIALS[name][\"kgrid\"],\n", + " isEdited=True).get_context_item_data()\n", "\n", " for unit_name, contexts in [(SCF_UNIT, [grid_context, cutoffs_context]),\n", " (BANDS_UNIT, [path_context, cutoffs_context])]:\n", @@ -562,7 +567,7 @@ "id": "38", "metadata": {}, "source": [ - "### 7.2. Top valence flat bands\n", + "### 7.2. Top valence flat bands of the bilayers\n", "\n", "The flat set starts at the highest occupied band and takes in each band below whose maximum along the path reaches\n", "the set's minimum. Its width is the spread of the set over the points of `KPATH`, and its separation is the distance\n", @@ -579,14 +584,18 @@ "source": [ "import numpy as np\n", "\n", + "bands_by_material = {name: np.array(band_structure[\"yDataSeries\"]) # band × path point, eV\n", + " for name, band_structure in band_structures.items()}\n", + "# GBRV valence electrons: B 3, N 5\n", + "number_of_occupied_bands = {name: 2 * material.basis.number_of_atoms for name, material in materials.items()}\n", + "\n", "flat_bands = {}\n", - "for name, band_structure in band_structures.items():\n", - " number_of_occupied_bands = 2 * materials[name].basis.number_of_atoms # GBRV valence electrons: B 3, N 5\n", - " bands = np.array(band_structure[\"yDataSeries\"]) # band × path point, eV\n", - " flat_set_bottom = number_of_occupied_bands - 1\n", - " while bands[flat_set_bottom - 1].max() >= bands[flat_set_bottom:number_of_occupied_bands].min():\n", + "for name in [name for name, settings in MATERIALS.items() if \"paper_flat_band_width\" in settings]:\n", + " bands, occupied = bands_by_material[name], number_of_occupied_bands[name]\n", + " flat_set_bottom = occupied - 1\n", + " while bands[flat_set_bottom - 1].max() >= bands[flat_set_bottom:occupied].min():\n", " flat_set_bottom -= 1\n", - " flat_set = bands[flat_set_bottom:number_of_occupied_bands]\n", + " flat_set = bands[flat_set_bottom:occupied]\n", " flat_bands[name] = {\n", " \"bands\": bands,\n", " \"flat_set\": flat_set,\n", @@ -633,7 +642,8 @@ "source": [ "## 8. Compare with Xian et al. (2019)\n", "\n", - "The article's width for each material, set in `MATERIALS`, beside ours; the article gives no separation.\n", + "The article's values, set in `MATERIALS`, beside ours: the width of the flat set for the bilayers (the article gives no\n", + "separation), and the band gap over the points of `KPATH` for the monolayer.\n", "\n", "Settings that differ from the article's: GBRV ultrasoft pseudopotentials at 40/200 Ry against VASP PAW at 400 eV, and\n", "Standata's lattice constant of 2.509 Å against 2.512 Å." @@ -649,7 +659,12 @@ "for name, result in flat_bands.items():\n", " print(f\"{name}: top valence flat set ({len(result['flat_set'])} bands), width along Γ–K–M: \"\n", " f\"{result['width']:.1f} meV · Xian et al. 2019: {MATERIALS[name]['paper_flat_band_width']} meV\")\n", - " print(f\"{name}: separation from the bands below: {result['separation']:.1f} meV\")" + " print(f\"{name}: separation from the bands below: {result['separation']:.1f} meV\")\n", + "\n", + "for name in [name for name, settings in MATERIALS.items() if \"paper_band_gap\" in settings]:\n", + " bands, occupied = bands_by_material[name], number_of_occupied_bands[name]\n", + " band_gap = bands[occupied].min() - bands[occupied - 1].max()\n", + " print(f\"{name}: band gap along Γ–K–M: {band_gap:.2f} eV · Xian et al. 2019: {MATERIALS[name]['paper_band_gap']} eV\")" ] }, { From ac9e0f9442759560a6e0ebf4d21262cd253b8473 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 23 Oct 2026 20:43:51 -0700 Subject: [PATCH 12/21] =?UTF-8?q?SOF-8085:=20the=20monolayer's=20bands=20o?= =?UTF-8?q?n=20a=20denser=20=CE=93=E2=80=93K=E2=80=93M=20path=20(61=20poin?= =?UTF-8?q?ts);=20the=20twisted=20cells=20keep=207?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- ...ate_lattices_boron_nitride_SIMULATION.ipynb | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb index be3fddf83..135083321 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb @@ -140,8 +140,14 @@ " {\"point\": \"K\", \"steps\": 2},\n", " {\"point\": \"M\", \"steps\": 1},\n", "]\n", + "# paper Fig. 1d: Γ–K–M, number of points not stated; ours 61, evenly spaced\n", + "KPATH_MONOLAYER = [\n", + " {\"point\": \"Γ\", \"steps\": 40},\n", + " {\"point\": \"K\", \"steps\": 20},\n", + " {\"point\": \"M\", \"steps\": 1},\n", + "]\n", + "KPATHS = {\"h-BN monolayer\": KPATH_MONOLAYER} # every other material: KPATH\n", "MODEL_TAG = f\"{FUNCTIONAL}-{PSEUDOPOTENTIAL_TYPE} {ECUTWFC}-{ECUTRHO}Ry\"\n", - "PATH_TAG = f\"p{sum(point['steps'] for point in KPATH)}\"\n", "\n", "SCF_UNIT = \"pw_scf\"\n", "BANDS_UNIT = \"pw_bands\"\n", @@ -358,8 +364,8 @@ "### 4.2. Configure the workflow\n", "\n", "One workflow per material: the self-consistent run on the k-grid set alongside its name in 1.2, then the bands along\n", - "`KPATH`, both with the cutoffs of 1.3. Each workflow is named after its material, `MODEL_TAG`, its k-grid and\n", - "`PATH_TAG`; section 6 finds a job that already ran by that name.\n", + "its path in `KPATHS` (otherwise `KPATH`), both with the cutoffs of 1.3. Each workflow is named after its material,\n", + "`MODEL_TAG`, its k-grid and the number of points on its path; section 6 finds a job that already ran by that name.\n", "\n", "The structure is not relaxed, as in the article's band-width series." ] @@ -381,16 +387,18 @@ "workflow_config = WorkflowStandata.filter_by_application(app.name).get_by_name_first_match(WORKFLOW_SEARCH_TERM)\n", "cutoffs_context = PlanewaveCutoffsContextProvider(\n", " wavefunction=ECUTWFC, density=ECUTRHO, isEdited=True).get_context_item_data()\n", - "path_context = PointsPathDataProvider(path=KPATH, isEdited=True).get_context_item_data()\n", "\n", "workflows = {}\n", "for name, material in materials.items():\n", " workflow = Workflow.create(deepcopy(workflow_config))\n", - " workflow.name = f\"{MY_WORKFLOW_NAME} {name} {MODEL_TAG} k{MATERIALS[name]['kgrid'][0]} {PATH_TAG}\"\n", + " kpath = KPATHS.get(name, KPATH)\n", + " workflow.name = (f\"{MY_WORKFLOW_NAME} {name} {MODEL_TAG} k{MATERIALS[name]['kgrid'][0]} \"\n", + " f\"p{sum(point['steps'] for point in kpath)}\")\n", " subworkflow = workflow.subworkflows[0]\n", " subworkflow.model = model\n", " grid_context = PointsGridDataProvider(material=material, dimensions=MATERIALS[name][\"kgrid\"],\n", " isEdited=True).get_context_item_data()\n", + " path_context = PointsPathDataProvider(path=kpath, isEdited=True).get_context_item_data()\n", "\n", " for unit_name, contexts in [(SCF_UNIT, [grid_context, cutoffs_context]),\n", " (BANDS_UNIT, [path_context, cutoffs_context])]:\n", From 7f229651696622b311077fc11e16a0d2dd695191 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Sun, 25 Oct 2026 15:41:30 -0700 Subject: [PATCH 13/21] SOF-8085: review - each material carries its own band path beside its k-grid; the monolayer's name is a parameter and is downloaded with the bilayers; markdown describes each cell's own path Co-Authored-By: Claude Opus 5.5 --- ..._commensurate_lattices_boron_nitride.ipynb | 12 ++-- ...te_lattices_boron_nitride_SIMULATION.ipynb | 72 +++++++++---------- 2 files changed, 43 insertions(+), 41 deletions(-) diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb index 02dee87f2..82ea7ef7b 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb @@ -58,7 +58,8 @@ " # {\"name\": \"h-BN bilayer 2.64deg alpha d3.23\", \"angle\": 60 + 2.64},\n", " # {\"name\": \"h-BN bilayer 2.64deg beta d3.23\", \"angle\": 2.64},\n", "]\n", - "INTERFACE_DISTANCE = 3.23 # Å, the article's" + "INTERFACE_DISTANCE = 3.23 # Å, the article's\n", + "MONOLAYER_NAME = \"h-BN monolayer\" # the Standata monolayer, saved as is (Fig. 1d)" ] }, { @@ -217,10 +218,11 @@ "from mat3ra.notebooks_utils.io import download_content_to_file\n", "from mat3ra.notebooks_utils.material import set_materials\n", "\n", - "material.name = \"h-BN monolayer\"\n", - "set_materials([*interfaces, material])\n", - "for interface in interfaces:\n", - " download_content_to_file(interface.to_json(), f\"{interface.name}.json\")" + "material.name = MONOLAYER_NAME\n", + "materials_to_save = [*interfaces, material]\n", + "set_materials(materials_to_save)\n", + "for material_to_save in materials_to_save:\n", + " download_content_to_file(material_to_save.to_json(), f\"{material_to_save.name}.json\")" ] }, { diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb index 135083321..f492a9a22 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride_SIMULATION.ipynb @@ -81,23 +81,36 @@ "\n", "ORGANIZATION_NAME = None # set to your organization name (full or partial); otherwise, your default one is used\n", "FOLDER = \"./uploads\"\n", - "# Names as saved by the structure notebook, each with the k-grid of its self-consistent run and the paper's value:\n", - "# the monolayer's LDA band gap (eV, SI p. 10) or the width of the bilayer's top valence flat set (meV, configuration\n", - "# not stated; 7.34° and 2.64°: text p. 4936; 6.01, 5.08 and 3.89°: read off Fig. 1g). The twisted cells use the paper's\n", - "# Γ-only self-consistent run. One job per material; every angle below 7.34° exceeds one 4 h single-node job.\n", + "# paper: Γ–K–M, number of points not stated; ours evenly spaced (|ΓK| = 2|KM|), 7 points for the moiré cells\n", + "KPATH = [\n", + " {\"point\": \"Γ\", \"steps\": 4},\n", + " {\"point\": \"K\", \"steps\": 2},\n", + " {\"point\": \"M\", \"steps\": 1},\n", + "]\n", + "# paper Fig. 1d: Γ–K–M, number of points not stated; ours 61, evenly spaced\n", + "KPATH_MONOLAYER = [\n", + " {\"point\": \"Γ\", \"steps\": 40},\n", + " {\"point\": \"K\", \"steps\": 20},\n", + " {\"point\": \"M\", \"steps\": 1},\n", + "]\n", + "# Names as saved by the structure notebook, each with the k-grid of its self-consistent run, the path of its bands and\n", + "# the paper's value: the monolayer's LDA band gap (eV, SI p. 10) or the width of the bilayer's top valence flat set\n", + "# (meV, configuration not stated; 7.34° and 2.64°: text p. 4936; 6.01, 5.08 and 3.89°: read off Fig. 1g). The twisted\n", + "# cells use the paper's Γ-only self-consistent run. One job per material; every angle below 7.34° exceeds one 4 h\n", + "# single-node job.\n", "MATERIALS = {\n", " # paper: k-grid not stated; ours a multiple of 3, which keeps K on the mesh\n", - " \"h-BN monolayer\": {\"kgrid\": [12, 12, 1], \"paper_band_gap\": 4.7},\n", - " \"h-BN bilayer 7.34deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 101.4},\n", - " # \"h-BN bilayer 7.34deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 101.4},\n", - " # \"h-BN bilayer 6.01deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 54.9},\n", - " # \"h-BN bilayer 6.01deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 54.9},\n", - " # \"h-BN bilayer 5.08deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 31.6},\n", - " # \"h-BN bilayer 5.08deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 31.6},\n", - " # \"h-BN bilayer 3.89deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 11.7},\n", - " # \"h-BN bilayer 3.89deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 11.7},\n", - " # \"h-BN bilayer 2.64deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 1.6},\n", - " # \"h-BN bilayer 2.64deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"paper_flat_band_width\": 1.6},\n", + " \"h-BN monolayer\": {\"kgrid\": [12, 12, 1], \"kpath\": KPATH_MONOLAYER, \"paper_band_gap\": 4.7},\n", + " \"h-BN bilayer 7.34deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"kpath\": KPATH, \"paper_flat_band_width\": 101.4},\n", + " # \"h-BN bilayer 7.34deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"kpath\": KPATH, \"paper_flat_band_width\": 101.4},\n", + " # \"h-BN bilayer 6.01deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"kpath\": KPATH, \"paper_flat_band_width\": 54.9},\n", + " # \"h-BN bilayer 6.01deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"kpath\": KPATH, \"paper_flat_band_width\": 54.9},\n", + " # \"h-BN bilayer 5.08deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"kpath\": KPATH, \"paper_flat_band_width\": 31.6},\n", + " # \"h-BN bilayer 5.08deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"kpath\": KPATH, \"paper_flat_band_width\": 31.6},\n", + " # \"h-BN bilayer 3.89deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"kpath\": KPATH, \"paper_flat_band_width\": 11.7},\n", + " # \"h-BN bilayer 3.89deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"kpath\": KPATH, \"paper_flat_band_width\": 11.7},\n", + " # \"h-BN bilayer 2.64deg alpha d3.23\": {\"kgrid\": [1, 1, 1], \"kpath\": KPATH, \"paper_flat_band_width\": 1.6},\n", + " # \"h-BN bilayer 2.64deg beta d3.23\": {\"kgrid\": [1, 1, 1], \"kpath\": KPATH, \"paper_flat_band_width\": 1.6},\n", "}\n", "\n", "WORKFLOW_SEARCH_TERM = \"band_structure.json\"\n", @@ -134,19 +147,6 @@ "ECUTWFC = 40 # Ry\n", "ECUTRHO = 200 # Ry; paper: VASP PAW, 400 eV\n", "\n", - "# paper: Γ–K–M, number of points not stated; ours 7, evenly spaced (|ΓK| = 2|KM|)\n", - "KPATH = [\n", - " {\"point\": \"Γ\", \"steps\": 4},\n", - " {\"point\": \"K\", \"steps\": 2},\n", - " {\"point\": \"M\", \"steps\": 1},\n", - "]\n", - "# paper Fig. 1d: Γ–K–M, number of points not stated; ours 61, evenly spaced\n", - "KPATH_MONOLAYER = [\n", - " {\"point\": \"Γ\", \"steps\": 40},\n", - " {\"point\": \"K\", \"steps\": 20},\n", - " {\"point\": \"M\", \"steps\": 1},\n", - "]\n", - "KPATHS = {\"h-BN monolayer\": KPATH_MONOLAYER} # every other material: KPATH\n", "MODEL_TAG = f\"{FUNCTIONAL}-{PSEUDOPOTENTIAL_TYPE} {ECUTWFC}-{ECUTRHO}Ry\"\n", "\n", "SCF_UNIT = \"pw_scf\"\n", @@ -364,8 +364,8 @@ "### 4.2. Configure the workflow\n", "\n", "One workflow per material: the self-consistent run on the k-grid set alongside its name in 1.2, then the bands along\n", - "its path in `KPATHS` (otherwise `KPATH`), both with the cutoffs of 1.3. Each workflow is named after its material,\n", - "`MODEL_TAG`, its k-grid and the number of points on its path; section 6 finds a job that already ran by that name.\n", + "the path set beside it, both with the cutoffs of 1.3. Each workflow is named after its material, `MODEL_TAG`, its\n", + "k-grid and the number of points on its path; section 6 finds a job that already ran by that name.\n", "\n", "The structure is not relaxed, as in the article's band-width series." ] @@ -391,7 +391,7 @@ "workflows = {}\n", "for name, material in materials.items():\n", " workflow = Workflow.create(deepcopy(workflow_config))\n", - " kpath = KPATHS.get(name, KPATH)\n", + " kpath = MATERIALS[name][\"kpath\"]\n", " workflow.name = (f\"{MY_WORKFLOW_NAME} {name} {MODEL_TAG} k{MATERIALS[name]['kgrid'][0]} \"\n", " f\"p{sum(point['steps'] for point in kpath)}\")\n", " subworkflow = workflow.subworkflows[0]\n", @@ -549,8 +549,8 @@ "## 7. Retrieve the results\n", "### 7.1. Band structure\n", "\n", - "The path is Γ–K–M of the moiré cell, as in the article; the bands of the two layers are folded onto its small\n", - "Brillouin zone." + "The path is Γ–K–M of each cell, as in the article: the monolayer's own Brillouin zone, and for the moiré cells their\n", + "small zone, onto which the bands of the two layers are folded." ] }, { @@ -632,11 +632,11 @@ "from matplotlib import pyplot as plt\n", "from mat3ra.notebooks_utils.plot import display_matplotlib_figure\n", "\n", - "vertex_indices = np.cumsum([0] + [point[\"steps\"] for point in KPATH[:-1]])\n", "for name, result in flat_bands.items():\n", + " kpath = MATERIALS[name][\"kpath\"]\n", " figure, axes = plt.subplots()\n", " axes.plot((result[\"bands\"] - result[\"flat_set\"].max()).T, color=\"black\", marker=\".\")\n", - " axes.set_xticks(vertex_indices, [point[\"point\"] for point in KPATH])\n", + " axes.set_xticks(np.cumsum([0] + [point[\"steps\"] for point in kpath[:-1]]), [point[\"point\"] for point in kpath])\n", " axes.set_ylim(*PLOT_ENERGY_RANGE)\n", " axes.set_ylabel(\"E − E(top of the flat bands) (eV)\")\n", " axes.set_title(f\"Bands near the valence-band top: {name}\")\n", @@ -651,7 +651,7 @@ "## 8. Compare with Xian et al. (2019)\n", "\n", "The article's values, set in `MATERIALS`, beside ours: the width of the flat set for the bilayers (the article gives no\n", - "separation), and the band gap over the points of `KPATH` for the monolayer.\n", + "separation), and the band gap over the points of its path for the monolayer.\n", "\n", "Settings that differ from the article's: GBRV ultrasoft pseudopotentials at 40/200 Ry against VASP PAW at 400 eV, and\n", "Standata's lattice constant of 2.509 Å against 2.512 Å." From dda8a5418399263a30b99ba03e2d3e12285a35a7 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 29 Oct 2026 13:12:45 -0700 Subject: [PATCH 14/21] SOF-8085: pin made to 3ae2f1ce (docstrings); unpin on release Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ab54e3954..597e82138 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made @ git+https://github.com/mat3ra/made.git@30df3002e80beb2958675fc2969d7fa47a54a5f6", # made feature/SOF-8085; unpin on release + "mat3ra-made @ git+https://github.com/mat3ra/made.git@3ae2f1cea403eddd9d7c66e3d45a919f28aa6acc", # made feature/SOF-8085; unpin on release "mat3ra-periodic-table" ] workflows = [ From 96852dfc2188cf711fac37d0b1b4f7a33c91cea0 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 29 Oct 2026 13:27:31 -0700 Subject: [PATCH 15/21] SOF-8085: pin made to 10689847 (docstring linter); unpin on release Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 597e82138..70a00f887 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made @ git+https://github.com/mat3ra/made.git@3ae2f1cea403eddd9d7c66e3d45a919f28aa6acc", # made feature/SOF-8085; unpin on release + "mat3ra-made @ git+https://github.com/mat3ra/made.git@1068984728363a2ab8f108c830269ddc83c33e47", # made feature/SOF-8085; unpin on release "mat3ra-periodic-table" ] workflows = [ From ca07057f76c2333a7dd8da42396ae4f408ba4627 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 30 Oct 2026 13:48:13 -0700 Subject: [PATCH 16/21] SOF-8085: pin made to 8ac39d4f (direct names); unpin on release Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 70a00f887..ae9fa0237 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made @ git+https://github.com/mat3ra/made.git@1068984728363a2ab8f108c830269ddc83c33e47", # made feature/SOF-8085; unpin on release + "mat3ra-made @ git+https://github.com/mat3ra/made.git@8ac39d4fd8e3eef20906f8e680a1b2f05bc24003", # made feature/SOF-8085; unpin on release "mat3ra-periodic-table" ] workflows = [ From b23f1f61a181ba1f336008bea25ac7e2c297da4a Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 30 Oct 2026 18:42:19 -0700 Subject: [PATCH 17/21] SOF-8085: pin made to 26c6f8f2 (readability); unpin on release Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index ae9fa0237..764e7d7f9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made @ git+https://github.com/mat3ra/made.git@8ac39d4fd8e3eef20906f8e680a1b2f05bc24003", # made feature/SOF-8085; unpin on release + "mat3ra-made @ git+https://github.com/mat3ra/made.git@26c6f8f230d2adb41adadd1fb6ae6a04d531ecf5", # made feature/SOF-8085; unpin on release "mat3ra-periodic-table" ] workflows = [ From 0bbab10bf6194642c42a0380c45cd117bad96257 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Mon, 2 Nov 2026 13:04:45 -0800 Subject: [PATCH 18/21] =?UTF-8?q?SOF-8085:=20the=20builder=20returns=20the?= =?UTF-8?q?=20120=C2=B0=20cell,=20so=20the=20structure=20notebook=20drops?= =?UTF-8?q?=20its=20re-set;=20made=20pinned=20to=20b1964646?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Claude Opus 5.5 --- ...bilayer_twisted_commensurate_lattices_boron_nitride.ipynb | 5 ++--- pyproject.toml | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb index 82ea7ef7b..1b9547df3 100644 --- a/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb +++ b/other/materials_designer/specific_examples/interface_bilayer_twisted_commensurate_lattices_boron_nitride.ipynb @@ -152,7 +152,7 @@ "from mat3ra.made.tools.analyze.other import get_average_interlayer_distance\n", "from mat3ra.made.tools.convert import to_ase\n", "from mat3ra.made.tools.convert.interface_parts_enum import InterfacePartsEnum\n", - "from mat3ra.made.tools.helpers import create_interface_commensurate, create_supercell\n", + "from mat3ra.made.tools.helpers import create_interface_commensurate\n", "\n", "interfaces = []\n", "for parameters in INTERFACE_PARAMETERS:\n", @@ -163,8 +163,7 @@ " # the builder adds the gap above the top layer as well\n", " vacuum=VACUUM - INTERFACE_DISTANCE,\n", " )\n", - " # The symbolic K point of the band path assumes the 120° hexagonal cell; the builder returns the 60° one.\n", - " interface = create_supercell(interface, supercell_matrix=[[1, 0, 0], [-1, 1, 0], [0, 0, 1]])\n", + " # Naming the hexagonal lattice is what lets the symbolic K point of the band path resolve.\n", " interface.lattice.type = \"HEX\"\n", " interface.name = parameters[\"name\"]\n", " interfaces.append(interface)\n", diff --git a/pyproject.toml b/pyproject.toml index 764e7d7f9..8a9b424cd 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made @ git+https://github.com/mat3ra/made.git@26c6f8f230d2adb41adadd1fb6ae6a04d531ecf5", # made feature/SOF-8085; unpin on release + "mat3ra-made @ git+https://github.com/mat3ra/made.git@b1964646207fd59bd2c36d928cb96d2d60f50e8c", # made feature/SOF-8085; unpin on release "mat3ra-periodic-table" ] workflows = [ From 67c2940d4c13878ae59c262a72de3e62cf01ee86 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Mon, 2 Nov 2026 18:41:43 -0800 Subject: [PATCH 19/21] SOF-8085: pin made to 0801160e (one size limit); unpin on release Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 8a9b424cd..a69e00a63 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made @ git+https://github.com/mat3ra/made.git@b1964646207fd59bd2c36d928cb96d2d60f50e8c", # made feature/SOF-8085; unpin on release + "mat3ra-made @ git+https://github.com/mat3ra/made.git@0801160e52a5375b6d401dc23de9af23a167d1be", # made feature/SOF-8085; unpin on release "mat3ra-periodic-table" ] workflows = [ From 43c553d6779f3b0091e41d0ea106f399e770223b Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Mon, 2 Nov 2026 18:57:26 -0800 Subject: [PATCH 20/21] SOF-8085: pin made to 702ca7cf; unpin on release Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index a69e00a63..d2d7b6710 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made @ git+https://github.com/mat3ra/made.git@0801160e52a5375b6d401dc23de9af23a167d1be", # made feature/SOF-8085; unpin on release + "mat3ra-made @ git+https://github.com/mat3ra/made.git@702ca7cf9a5a0d4b396b95bffad4599824e74abc", # made feature/SOF-8085; unpin on release "mat3ra-periodic-table" ] workflows = [ From bcbc25ea3d5fde24fe32753353266e3919b2cf8e Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Mon, 2 Nov 2026 20:17:40 -0800 Subject: [PATCH 21/21] SOF-8085: unpin mat3ra-made (made #302 merged) Co-Authored-By: Claude Opus 5.5 --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index d2d7b6710..2840c8d43 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -36,7 +36,7 @@ materials = [ "mat3ra-notebooks-utils[utils_standata]", "pymatgen==2024.4.13", "pymatgen-analysis-defects<=2024.4.23", - "mat3ra-made @ git+https://github.com/mat3ra/made.git@702ca7cf9a5a0d4b396b95bffad4599824e74abc", # made feature/SOF-8085; unpin on release + "mat3ra-made", "mat3ra-periodic-table" ] workflows = [