From 19beb469ebaef02f771966444ed220ddf18b79fe Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 8 Oct 2026 17:23:03 -0700 Subject: [PATCH 01/31] Build the paper's 458-atom TiN island cell with the Ti adatom at the sites of Fig. 6 The TiN island notebook now builds Sangiovanni et al.'s cell: a 5x5 island with Ti corners on a 12x12x3-atom TiN(001) slab with 15.3 A of vacuum (457 atoms), and saves it with a Ti adatom at the fourfold hollow a, atop the edge N (c) and atop the terrace N (i), each under a fixed name for the simulation notebook. Bulk TiN is looked up as mp-492, since "TiN" now matches tin in Standata. Co-Authored-By: Claude Opus 5.5 --- ...fect_surface_island_titanium_nitride.ipynb | 109 ++++++++++++++++-- 1 file changed, 97 insertions(+), 12 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb index 0cb6cf936..785fb5708 100644 --- a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb +++ b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb @@ -17,7 +17,7 @@ "\n", "![Fig 2.](https://github.com/Exabyte-io/documentation/raw/12617167278ae3523adc028583b21ea4e8ebd197/images/tutorials/materials/defects/defect-creation-surface-island-titanium-nitride/0.png)\n", "\n", - "In this notebook we will reproduce material from FIG. 2 a)\n" + "In this notebook we will reproduce the paper's 458-atom cell (Sec. II.A, Fig. 1b): a 5×5-atom island with Ti corners on a 12×12×3-atom TiN(001) slab with 15.3 Å of vacuum, with a Ti adatom at each of the sites a, c and i of Fig. 6. FIG. 2 above shows the larger 9×9-atom island.\n" ] }, { @@ -39,18 +39,30 @@ "source": [ "NUMBER_OF_ADDED_LAYERS = 0.5\n", "\n", + "# x and y minima one site apart put Ti atoms at the island corners\n", "SHAPE_PARAMETERS = {\n", " 'shape': 'box',\n", - " 'min_coordinate': [0.25, 0.2, 0],\n", - " 'max_coordinate': [0.65, 0.6, 1]\n", + " 'min_coordinate': [0.3233, 0.24, 0],\n", + " 'max_coordinate': [0.7233, 0.64, 1]\n", "}\n", "\n", + "# Thickness counts conventional layers of two (001) planes; the bottom plane is removed after the\n", + "# island is added, leaving the paper's three planes.\n", "SLAB_PARAMETERS = {\n", " \"miller_indices\": (0, 0, 1),\n", - " \"thickness\": 3,\n", - " \"vacuum\": 10.0,\n", + " \"thickness\": 2,\n", + " \"vacuum\": 15.3,\n", " \"USE_ORTHOGONAL_C\": True,\n", - " \"xy_supercell_matrix\": [[10, 0], [0, 10]]\n", + " \"xy_supercell_matrix\": [[6, 0], [0, 6]]\n", + "}\n", + "\n", + "ADATOM_ELEMENT = \"Ti\"\n", + "\n", + "ISLAND_MATERIAL_NAME = \"TiN(001) 12x12x3 island 5x5\"\n", + "ADATOM_MATERIAL_NAMES = {\n", + " \"a\": \"TiN(001) 12x12x3 island 5x5 + Ti a (FFH island)\",\n", + " \"c\": \"TiN(001) 12x12x3 island 5x5 + Ti c (atop-N edge)\",\n", + " \"i\": \"TiN(001) 12x12x3 island 5x5 + Ti i (atop-N terrace)\",\n", "}" ] }, @@ -94,7 +106,7 @@ "from mat3ra.made.material import Material\n", "from mat3ra.standata.materials import Materials\n", "\n", - "material = Material.create(Materials.get_by_name_first_match(\"TiN\"))" + "material = Material.create(Materials.get_by_name_first_match(\"mp-492\"))" ] }, { @@ -143,8 +155,12 @@ "metadata": {}, "outputs": [], "source": [ + "import numpy as np\n", + "from mat3ra.made.tools.analyze.other import get_atom_indices_by_layer\n", + "from mat3ra.made.tools.convert import to_ase\n", "from mat3ra.made.tools.entities.coordinate import BoxCoordinateCondition\n", "from mat3ra.made.tools.helpers import create_island\n", + "from mat3ra.made.tools.modify import filter_by_ids, remove_vacuum\n", "\n", "coordinate_condition = BoxCoordinateCondition(\n", " min_coordinate=SHAPE_PARAMETERS['min_coordinate'],\n", @@ -156,7 +172,22 @@ " condition=coordinate_condition,\n", " number_of_added_layers=NUMBER_OF_ADDED_LAYERS,\n", " use_cartesian_coordinates=False,\n", - ")" + ")\n", + "bottom_plane = get_atom_indices_by_layer(slab_with_island)[0]\n", + "slab_with_island = filter_by_ids(slab_with_island, ids=bottom_plane, invert=True, reset_ids=True)\n", + "slab_with_island = remove_vacuum(slab_with_island, fixed_padding=SLAB_PARAMETERS[\"vacuum\"])\n", + "slab_with_island.name = ISLAND_MATERIAL_NAME\n", + "\n", + "atoms = to_ase(slab_with_island)\n", + "symbols = np.array(atoms.get_chemical_symbols())\n", + "planes = get_atom_indices_by_layer(slab_with_island)\n", + "island, terrace = planes[-1], planes[-2]\n", + "island_x, island_y = atoms.positions[island, 0], atoms.positions[island, 1]\n", + "is_corner = ((np.isclose(island_x, island_x.min()) | np.isclose(island_x, island_x.max()))\n", + " & (np.isclose(island_y, island_y.min()) | np.isclose(island_y, island_y.max())))\n", + "print(f\"{slab_with_island.name}: {len(atoms)} atoms ({sum(symbols == 'Ti')} Ti, {sum(symbols == 'N')} N) \"\n", + " f\"in {len(planes)} planes, c = {atoms.cell[2, 2]:.3f} Å\")\n", + "print(f\"Island: {len(island)} atoms, corners {symbols[island][is_corner].tolist()}\")" ] }, { @@ -164,7 +195,16 @@ "id": "11", "metadata": {}, "source": [ - "## 3. Visualize the Result(s)" + "### 2.1. Add the Adatom at the Sites of Fig. 6\n", + "\n", + "The paper gives no coordinates for the sites; they follow from the lattice and are measured on the island\n", + "built above. Take an N atom of the island's edge row at the largest y (the edge N atoms are equivalent) and\n", + "the bulk site spacing d = a/2:\n", + "\n", + "- **a**, the fourfold hollow on the island next to the edge: (x_N + d/2, y_edge − d/2), d above the island plane;\n", + "- **c**, atop the edge N: (x_N, y_edge), d above the island plane;\n", + "- **i**, atop the terrace N in front of it, the epitaxial site that extends the island: (x_N, y_edge + d), d\n", + " above the terrace." ] }, { @@ -173,6 +213,51 @@ "id": "12", "metadata": {}, "outputs": [], + "source": [ + "from mat3ra.made.tools.helpers import create_defect_point_interstitial\n", + "\n", + "site_spacing = material.lattice.a / 2\n", + "edge_y = island_y.max()\n", + "edge_nitrogen_x = min(atoms.positions[index, 0] for index in island\n", + " if symbols[index] == \"N\" and np.isclose(atoms.positions[index, 1], edge_y))\n", + "island_z = atoms.positions[island, 2].mean()\n", + "terrace_z = atoms.positions[terrace, 2].mean()\n", + "\n", + "adatom_sites = {\n", + " \"a\": [edge_nitrogen_x + site_spacing / 2, edge_y - site_spacing / 2, island_z + site_spacing],\n", + " \"c\": [edge_nitrogen_x, edge_y, island_z + site_spacing],\n", + " \"i\": [edge_nitrogen_x, edge_y + site_spacing, terrace_z + site_spacing],\n", + "}\n", + "\n", + "materials_with_adatom = []\n", + "for site, coordinate in adatom_sites.items():\n", + " material_with_adatom = create_defect_point_interstitial(\n", + " slab_with_island, coordinate, ADATOM_ELEMENT, \"exact_coordinate\", use_cartesian_coordinates=True\n", + " )\n", + " material_with_adatom.name = ADATOM_MATERIAL_NAMES[site]\n", + " materials_with_adatom.append(material_with_adatom)\n", + "\n", + " atoms_with_adatom = to_ase(material_with_adatom)\n", + " adatom = len(atoms_with_adatom) - 1\n", + " distances = np.sort(atoms_with_adatom.get_distances(adatom, range(adatom), mic=True))[:3]\n", + " print(f\"{material_with_adatom.name}: {len(atoms_with_adatom)} atoms, \"\n", + " f\"adatom's three shortest distances {np.round(distances, 3)} Å\")" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "## 3. Visualize the Result(s)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], "source": [ "visualize_materials([{\"material\": slab, \"title\": \"Original material\", \"rotation\": \"-45x\"},\n", " {\"material\": slab_with_island,\n", @@ -183,7 +268,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "15", "metadata": {}, "source": [ "## 4. Pass data to the outside runtime" @@ -192,14 +277,14 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "16", "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(slab_with_island)\n", + "set_materials([slab_with_island, *materials_with_adatom])\n", "download_content_to_file(slab_with_island.to_json(), \"TiN_slab_with_island.json\")" ] } From 194ae2e98949b31da9393b0823373e771a57258a Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 8 Oct 2026 17:23:10 -0700 Subject: [PATCH 02/31] Add the MACE notebook for the Ti adatom descent energetics on the TiN island (Fig. 6) The new simulation notebook relaxes the island cell and the Ti adatom at a, c and i with MACE-MP-0 (large, D3), then prints the energies of c and i relative to a and the adsorption energy at a beside Sangiovanni et al.'s values with the deviation in percent, the island contraction and ripple, and Fig. 6 with the paper's curve. The Introduction links it in the D-2D-ISL row. Co-Authored-By: Claude Opus 5.5 --- .../specific_examples/Introduction.ipynb | 2 +- ...e_island_titanium_nitride_SIMULATION.ipynb | 427 ++++++++++++++++++ 2 files changed, 428 insertions(+), 1 deletion(-) create mode 100644 other/materials_designer/specific_examples/defect_surface_island_titanium_nitride_SIMULATION.ipynb diff --git a/other/materials_designer/specific_examples/Introduction.ipynb b/other/materials_designer/specific_examples/Introduction.ipynb index 898458bb1..31c6d9bf4 100644 --- a/other/materials_designer/specific_examples/Introduction.ipynb +++ b/other/materials_designer/specific_examples/Introduction.ipynb @@ -36,7 +36,7 @@ "| `D-2D-ADA` | Adatom | [Pt Adatom/Island on MoS₂](defect_point_adatom_island_molybdenum_disulfide_platinum.ipynb) | *To be added* | [[10]](#ref10) |\n", "| `D-2D-ADA` | Adatom | [Adatom on Graphene](defect_surface_adatom_graphene.ipynb) | *To be added* | [[11]](#ref11) |\n", "| `D-2D-GBP` | Grain Boundary Planar | [Grain Boundary in 3D FCC Cu](defect_planar_grain_boundary_3d_fcc_metals_copper.ipynb) | *To be added* | [[13]](#ref13) |\n", - "| `D-2D-ISL` | Island | [TiN Island on Surface](defect_surface_island_titanium_nitride.ipynb) | *To be added* | [[14]](#ref14) |\n", + "| `D-2D-ISL` | Island | [TiN Island on Surface](defect_surface_island_titanium_nitride.ipynb) | [Ti Adatom Descent on a 5x5 TiN Island (MACE)](defect_surface_island_titanium_nitride_SIMULATION.ipynb) | [[14]](#ref14) |\n", "| `D-2D-TER` | Terrace | [Step/Terrace on Pt Surface](defect_surface_step_platinum.ipynb) | *To be added* | [[15]](#ref15) |\n", "| `D-1D-GBL` | Grain Boundary Linear | [Grain Boundary in 2D BN](defect_planar_grain_boundary_2d_boron_nitride.ipynb) | *To be added* | [[12]](#ref12) |\n", "| `D-0D-DFP` | Defect Pair | [Defect Pair in GaN](defect_point_pair_gallium_nitride.ipynb) | [Mg_Ga-V_N Pair Formation Energy in GaN](defect_point_pair_gallium_nitride_SIMULATION.ipynb) | [[16]](#ref16) |\n", diff --git a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride_SIMULATION.ipynb new file mode 100644 index 000000000..b2a254791 --- /dev/null +++ b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride_SIMULATION.ipynb @@ -0,0 +1,427 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# Ti Adatom Descent on a 5×5 TiN Island (MACE)\n", + "\n", + "> **D. G. Sangiovanni, A. B. Mei, D. Edström, L. Hultman, V. Chirita, I. Petrov, and J. E. Greene**,\n", + "> \"Effects of surface vibrations on interlayer mass transport: Ab initio molecular dynamics investigation of Ti\n", + "> adatom descent pathways and rates from TiN/TiN(001) islands\", Physical Review B 97, 035406 (2018).\n", + "> [DOI: 10.1103/PhysRevB.97.035406](https://doi.org/10.1103/PhysRevB.97.035406)\n", + "\n", + "Relaxes a Ti adatom at three sites of the paper's Fig. 6 on the cell created in the\n", + "[structure notebook](defect_surface_island_titanium_nitride.ipynb): **a**, the fourfold hollow on the island\n", + "next to its edge; **c**, atop the edge N atom; **i**, atop the terrace N atom in front of the edge, the site\n", + "that extends the island. The energies of c and i relative to a, and the adsorption energy at a, are compared\n", + "with the paper's. The paper computed them with DFT (GGA); here every relaxation uses the\n", + "[MACE-MP-0](https://github.com/ACEsuit/mace) machine-learned force field with the D3 dispersion correction.\n", + "\n", + "The four relaxations are 458-atom MACE runs, meant to be executed natively; the notebook took 16 to 34 minutes on an Apple M1 Pro CPU in two runs.\n", + "\n", + "

Usage

\n", + "\n", + "1. Create the materials in the [structure notebook](defect_surface_island_titanium_nitride.ipynb), which saves the island cell and the three adatom cells to the `uploads` folder.\n", + "1. Set the material names and parameters in cells 1.2-1.3 (or use the defaults).\n", + "1. Click \"Run\" > \"Run All\" to run all cells.\n", + "1. Scroll down to view the results.\n", + "\n", + "## Summary\n", + "\n", + "1. Set up the environment and parameters: install packages (JupyterLite only), material names, force-field and relaxation parameters.\n", + "1. Load the materials by name from the `uploads` folder.\n", + "1. Build the MACE calculator.\n", + "1. Relax the island cell; measure the island contraction and the surface ripple.\n", + "1. Relax the adatom at a, c and i.\n", + "1. Compute the energy of an isolated Ti atom.\n", + "1. Compare with the paper: energies relative to a, the adsorption energy at a, and Fig. 6." + ] + }, + { + "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.calculators.mlff import get_mlff_install_profiles\n", + "from mat3ra.notebooks_utils.packages import install_packages\n", + "\n", + "await install_packages(get_mlff_install_profiles(\"mace\"))\n", + "\n", + "from mat3ra.notebooks_utils.pyodide.packages.patches import apply_all_patches\n", + "\n", + "apply_all_patches(\"mace\")" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "### 1.2. Material names" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4", + "metadata": {}, + "outputs": [], + "source": [ + "# Names saved by defect_surface_island_titanium_nitride.ipynb.\n", + "ISLAND_MATERIAL_NAME = \"TiN(001) 12x12x3 island 5x5\"\n", + "ADATOM_MATERIAL_NAMES = {\n", + " \"a\": \"TiN(001) 12x12x3 island 5x5 + Ti a (FFH island)\",\n", + " \"c\": \"TiN(001) 12x12x3 island 5x5 + Ti c (atop-N edge)\",\n", + " \"i\": \"TiN(001) 12x12x3 island 5x5 + Ti i (atop-N terrace)\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "### 1.3. Parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [ + "FOLDER = \"./uploads\"\n", + "\n", + "MACE_MODEL_FAMILY = \"MACE-MP-0\"\n", + "MACE_MODEL = \"large\"\n", + "MACE_DISPERSION = True\n", + "MACE_DEFAULT_DTYPE = \"float64\"\n", + "MACE_DEVICE = \"cpu\"\n", + "\n", + "FMAX = 0.02 # eV/Å, every atom free\n", + "MAX_STEPS = 1000\n", + "\n", + "ISOLATED_ATOM_BOX = 15.0 # Å, edge of the cubic box around the isolated Ti atom" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "## 2. Load the materials" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.material import load_materials_from_folder\n", + "\n", + "materials_by_name = {material.name: material for material in load_materials_from_folder(FOLDER)}\n", + "slab_with_island = materials_by_name[ISLAND_MATERIAL_NAME]\n", + "materials_with_adatom = {site: materials_by_name[name] for site, name in ADATOM_MATERIAL_NAMES.items()}\n", + "\n", + "for material in [slab_with_island, *materials_with_adatom.values()]:\n", + " print(f\"{material.name}: {material.basis.number_of_atoms} atoms\")" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "## 3. Build the MACE calculator" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "import importlib.util\n", + "\n", + "from mat3ra.notebooks_utils.calculators.mlff import create_mlff_calculator\n", + "\n", + "dispersion_available = importlib.util.find_spec(\"torch_dftd\") is not None\n", + "dispersion_active = MACE_DISPERSION and dispersion_available\n", + "if MACE_DISPERSION and not dispersion_available:\n", + " print(\"torch-dftd is not available here: MACE runs WITHOUT the D3 dispersion correction.\")\n", + "\n", + "calculator = create_mlff_calculator(\n", + " \"mace\",\n", + " {\n", + " \"family\": MACE_MODEL_FAMILY,\n", + " \"model\": MACE_MODEL,\n", + " \"dispersion\": dispersion_active,\n", + " \"default_dtype\": MACE_DEFAULT_DTYPE,\n", + " \"device\": MACE_DEVICE,\n", + " },\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "## 4. Relax the island cell\n", + "### 4.1. Relax\n", + "\n", + "Every atom is free, as in the paper's 0 K relaxations." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from mat3ra.made.tools.calculate import calculate_total_energy\n", + "from mat3ra.made.tools.convert import to_ase\n", + "from mat3ra.notebooks_utils.workflows.relaxation import relax_material\n", + "\n", + "slab_with_island_relaxed = relax_material(slab_with_island, calculator, fmax=FMAX, max_steps=MAX_STEPS)\n", + "energy_slab_with_island = calculate_total_energy(slab_with_island_relaxed, calculator)\n", + "print(f\"E(slab + island) = {energy_slab_with_island:.3f} eV\")" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "### 4.2. Island contraction and surface ripple\n", + "\n", + "The island's Ti–Ti spacing along its diagonals and Ti–N spacing along its medians, against the same spacings as\n", + "built on the bulk lattice; the ripple is the height of the N atoms above the Ti atoms in the exposed top plane of\n", + "the terrace (Fig. 2 of the paper)." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.made.tools.analyze.other import get_atom_indices_by_layer\n", + "\n", + "built, relaxed = to_ase(slab_with_island), to_ase(slab_with_island_relaxed)\n", + "symbols = np.array(built.get_chemical_symbols())\n", + "planes = get_atom_indices_by_layer(slab_with_island)\n", + "island, terrace = np.array(planes[-1]), np.array(planes[-2])\n", + "\n", + "island_x, island_y = built.positions[island, 0], built.positions[island, 1]\n", + "x_values = (island_x.min(), (island_x.min() + island_x.max()) / 2, island_x.max())\n", + "y_values = (island_y.min(), (island_y.min() + island_y.max()) / 2, island_y.max())\n", + "grid = {(column, row): island[np.argmin(np.hypot(island_x - x, island_y - y))]\n", + " for column, x in enumerate(x_values) for row, y in enumerate(y_values)}\n", + "island_rows = {\n", + " \"Ti–Ti along diagonals\": [(grid[0, 0], grid[2, 2]), (grid[0, 2], grid[2, 0])],\n", + " \"Ti–N along medians\": [(grid[0, 1], grid[2, 1]), (grid[1, 0], grid[1, 2])],\n", + "}\n", + "spacings_per_row = np.sqrt(len(island)) - 1\n", + "\n", + "island_contraction = {}\n", + "for label, pairs in island_rows.items():\n", + " as_built, after = (np.mean([atoms.get_distance(*pair) for pair in pairs]) / spacings_per_row\n", + " for atoms in (built, relaxed))\n", + " island_contraction[label] = 100 * (after / as_built - 1)\n", + " print(f\"{label}: {after:.3f} Å, {island_contraction[label]:+.1f} % against {as_built:.3f} Å as built\")\n", + "\n", + "island_xy = built.positions[island, :2]\n", + "exposed_terrace = [index for index in terrace\n", + " if not np.isclose(np.linalg.norm(island_xy - built.positions[index, :2], axis=1), 0).any()]\n", + "ripple = (np.mean([relaxed.positions[index, 2] for index in exposed_terrace if symbols[index] == \"N\"])\n", + " - np.mean([relaxed.positions[index, 2] for index in exposed_terrace if symbols[index] == \"Ti\"]))\n", + "print(f\"Ripple of the exposed terrace ({len(exposed_terrace)} atoms): {ripple:.3f} Å\")" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, + "source": [ + "## 5. Relax the adatom at a, c and i\n", + "\n", + "Each relaxation starts from the site placed in the structure notebook; the adatom's displacement from that site\n", + "shows whether it stayed there." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16", + "metadata": {}, + "outputs": [], + "source": [ + "energies = {}\n", + "for site, material in materials_with_adatom.items():\n", + " material_relaxed = relax_material(material, calculator, fmax=FMAX, max_steps=MAX_STEPS)\n", + " energies[site] = calculate_total_energy(material_relaxed, calculator)\n", + "\n", + " placed, final = to_ase(material), to_ase(material_relaxed)\n", + " adatom = len(final) - 1\n", + " displacement = np.linalg.norm(final.positions[adatom] - placed.positions[adatom])\n", + " distances = np.sort(final.get_distances(adatom, range(adatom), mic=True))[:3]\n", + " print(f\"{site}: E = {energies[site]:.3f} eV, adatom moved {displacement:.2f} Å from its site, \"\n", + " f\"three shortest distances {np.round(distances, 3)} Å\")" + ] + }, + { + "cell_type": "markdown", + "id": "17", + "metadata": {}, + "source": [ + "## 6. Isolated Ti atom\n", + "\n", + "The reference of the adsorption energy, Eq. (4) of the paper: one Ti atom in a cubic box, same calculator." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18", + "metadata": {}, + "outputs": [], + "source": [ + "from ase import Atoms\n", + "\n", + "adatom_element = materials_with_adatom[\"a\"].basis.elements.values[-1]\n", + "energy_isolated_adatom = calculate_total_energy(Atoms(adatom_element, cell=[ISOLATED_ATOM_BOX] * 3, pbc=True), calculator)\n", + "print(f\"E({adatom_element}, isolated) = {energy_isolated_adatom:.3f} eV\")" + ] + }, + { + "cell_type": "markdown", + "id": "19", + "metadata": {}, + "source": [ + "## 7. Compare with the paper\n", + "### 7.1. Energies relative to a, adsorption energy at a, island relaxation\n", + "\n", + "The paper's energies of c and i are read off Fig. 6 (±0.02 and ±0.05 eV); the adsorption energy at a, the\n", + "isolated Ti atom energy it uses, the island contraction and the ripple are from Sec. III.A. The adsorption energy\n", + "is printed with this notebook's isolated-atom energy and with the paper's." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "20", + "metadata": {}, + "outputs": [], + "source": [ + "# Sangiovanni et al. (2018): Fig. 6 upper panel (a-i, read off the axis); Sec. III.A\n", + "PAPER_FIG6 = {\"a\": 0.0, \"b\": 0.10, \"c\": -0.15, \"d\": -0.20, \"e\": -0.25, \"f\": -0.50, \"g\": -1.13, \"h\": -2.25, \"i\": -2.65}\n", + "PAPER_ADSORPTION_ENERGY = -2.81\n", + "PAPER_ISOLATED_ADATOM_ENERGY = -2.275\n", + "PAPER_ISLAND_CONTRACTION = {\"Ti–Ti along diagonals\": -6.8, \"Ti–N along medians\": -5.2}\n", + "PAPER_RIPPLE = 0.19\n", + "\n", + "relative_energies = {site: energy - energies[\"a\"] for site, energy in energies.items()}\n", + "print(f\"{'site':<6}{'E - E_a (eV)':>14}{'paper':>8}{'deviation':>12}\")\n", + "for site in (\"c\", \"i\"):\n", + " deviation = 100 * (relative_energies[site] / PAPER_FIG6[site] - 1)\n", + " print(f\"{site:<6}{relative_energies[site]:>14.3f}{PAPER_FIG6[site]:>8.2f}{deviation:>+11.1f}%\")\n", + "\n", + "print()\n", + "for label, isolated_energy in ((\"this notebook's\", energy_isolated_adatom), (\"the paper's\", PAPER_ISOLATED_ADATOM_ENERGY)):\n", + " adsorption_energy = energies[\"a\"] - energy_slab_with_island - isolated_energy\n", + " deviation = 100 * (adsorption_energy / PAPER_ADSORPTION_ENERGY - 1)\n", + " print(f\"E_ads(a) with {label} E_Ti ({isolated_energy:.3f} eV): {adsorption_energy:.3f} eV, \"\n", + " f\"paper {PAPER_ADSORPTION_ENERGY:.2f} eV, deviation {deviation:+.1f}%\")\n", + "\n", + "print()\n", + "for label, contraction in island_contraction.items():\n", + " print(f\"{label}: {contraction:+.1f} %, paper {PAPER_ISLAND_CONTRACTION[label]:+.1f} %\")\n", + "print(f\"Ripple: {ripple:.2f} Å, paper {PAPER_RIPPLE:.2f} Å\")" + ] + }, + { + "cell_type": "markdown", + "id": "21", + "metadata": {}, + "source": [ + "### 7.2. Fig. 6" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "22", + "metadata": {}, + "outputs": [], + "source": [ + "import plotly.graph_objects as go\n", + "\n", + "figure = go.Figure()\n", + "figure.add_trace(go.Scatter(x=list(PAPER_FIG6), y=list(PAPER_FIG6.values()), mode=\"lines+markers\",\n", + " name=\"Sangiovanni et al. (2018)\"))\n", + "figure.add_trace(go.Scatter(x=list(relative_energies), y=list(relative_energies.values()), mode=\"markers\",\n", + " marker={\"size\": 12}, name=\"this notebook (MACE-MP-0)\"))\n", + "figure.update_layout(title=\"Ti adatom descent from the 5×5 island edge (Fig. 6)\", xaxis_title=\"state\",\n", + " yaxis_title=\"energy relative to a (eV)\")\n", + "figure.show()" + ] + }, + { + "cell_type": "markdown", + "id": "23", + "metadata": {}, + "source": [ + "## References\n", + "\n", + "[1] D. G. Sangiovanni, A. B. Mei, D. Edström, L. Hultman, V. Chirita, I. Petrov, J. E. Greene, \"Effects of surface\n", + "vibrations on interlayer mass transport: Ab initio molecular dynamics investigation of Ti adatom descent pathways\n", + "and rates from TiN/TiN(001) islands\", Phys. Rev. B 97, 035406 (2018).\n", + "[DOI: 10.1103/PhysRevB.97.035406](https://doi.org/10.1103/PhysRevB.97.035406)\n", + "\n", + "[2] MACE-MP-0 foundation models: https://github.com/ACEsuit/mace" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From f589df6c0035b99ab9d413d6f89d45b250a9e365 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 8 Oct 2026 18:19:41 -0700 Subject: [PATCH 03/31] Apply review round 1: native-run instructions, site a and paper sources stated precisely The simulation notebook's Usage now says how to run it natively (pip install ".[all]" mace-torch torch-dftd) and that in JupyterLite the relaxations take hours without D3. Each paper constant carries its own location (the isolated Ti energy is from Sec. II.B, b = 0.10 eV is stated in Sec. III.C.1), and the isolated-atom section says the model's single-atom energy lies outside its training data. The structure notebook states that site a is the fourfold hollow between the edge N with the smaller x and the edge-centre Ti (the paper's FFH_edge), and names the bulk material as MATERIAL_ID = "mp-492" at the top: the name "TiN" matches tin (Sn, mp-117) first in Standata. Co-Authored-By: Claude Opus 5.5 --- .../specific_examples/Introduction.ipynb | 2 +- ...fect_surface_island_titanium_nitride.ipynb | 13 +++++++---- ...e_island_titanium_nitride_SIMULATION.ipynb | 23 +++++++++++-------- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/other/materials_designer/specific_examples/Introduction.ipynb b/other/materials_designer/specific_examples/Introduction.ipynb index 31c6d9bf4..df26331ad 100644 --- a/other/materials_designer/specific_examples/Introduction.ipynb +++ b/other/materials_designer/specific_examples/Introduction.ipynb @@ -36,7 +36,7 @@ "| `D-2D-ADA` | Adatom | [Pt Adatom/Island on MoS₂](defect_point_adatom_island_molybdenum_disulfide_platinum.ipynb) | *To be added* | [[10]](#ref10) |\n", "| `D-2D-ADA` | Adatom | [Adatom on Graphene](defect_surface_adatom_graphene.ipynb) | *To be added* | [[11]](#ref11) |\n", "| `D-2D-GBP` | Grain Boundary Planar | [Grain Boundary in 3D FCC Cu](defect_planar_grain_boundary_3d_fcc_metals_copper.ipynb) | *To be added* | [[13]](#ref13) |\n", - "| `D-2D-ISL` | Island | [TiN Island on Surface](defect_surface_island_titanium_nitride.ipynb) | [Ti Adatom Descent on a 5x5 TiN Island (MACE)](defect_surface_island_titanium_nitride_SIMULATION.ipynb) | [[14]](#ref14) |\n", + "| `D-2D-ISL` | Island | [TiN Island on Surface](defect_surface_island_titanium_nitride.ipynb) | [Ti Adatom Descent on a 5×5 TiN Island (MACE)](defect_surface_island_titanium_nitride_SIMULATION.ipynb) | [[14]](#ref14) |\n", "| `D-2D-TER` | Terrace | [Step/Terrace on Pt Surface](defect_surface_step_platinum.ipynb) | *To be added* | [[15]](#ref15) |\n", "| `D-1D-GBL` | Grain Boundary Linear | [Grain Boundary in 2D BN](defect_planar_grain_boundary_2d_boron_nitride.ipynb) | *To be added* | [[12]](#ref12) |\n", "| `D-0D-DFP` | Defect Pair | [Defect Pair in GaN](defect_point_pair_gallium_nitride.ipynb) | [Mg_Ga-V_N Pair Formation Energy in GaN](defect_point_pair_gallium_nitride_SIMULATION.ipynb) | [[16]](#ref16) |\n", diff --git a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb index 785fb5708..769bd44c0 100644 --- a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb +++ b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb @@ -37,9 +37,11 @@ "metadata": {}, "outputs": [], "source": [ + "MATERIAL_ID = \"mp-492\"\n", + "\n", "NUMBER_OF_ADDED_LAYERS = 0.5\n", "\n", - "# x and y minima one site apart put Ti atoms at the island corners\n", + "# x and y minima one site (1/12 of the 6×6 cell) apart put Ti atoms at the island corners\n", "SHAPE_PARAMETERS = {\n", " 'shape': 'box',\n", " 'min_coordinate': [0.3233, 0.24, 0],\n", @@ -106,7 +108,7 @@ "from mat3ra.made.material import Material\n", "from mat3ra.standata.materials import Materials\n", "\n", - "material = Material.create(Materials.get_by_name_first_match(\"mp-492\"))" + "material = Material.create(Materials.get_by_name_first_match(MATERIAL_ID))" ] }, { @@ -198,10 +200,11 @@ "### 2.1. Add the Adatom at the Sites of Fig. 6\n", "\n", "The paper gives no coordinates for the sites; they follow from the lattice and are measured on the island\n", - "built above. Take an N atom of the island's edge row at the largest y (the edge N atoms are equivalent) and\n", - "the bulk site spacing d = a/2:\n", + "built above. Take the N atom with the smaller x in the island's edge row at the largest y, and the bulk site\n", + "spacing d = a/2:\n", "\n", - "- **a**, the fourfold hollow on the island next to the edge: (x_N + d/2, y_edge − d/2), d above the island plane;\n", + "- **a**, the fourfold hollow on the island between that N and the edge-centre Ti, the paper's FFH_edge:\n", + " (x_N + d/2, y_edge − d/2), d above the island plane;\n", "- **c**, atop the edge N: (x_N, y_edge), d above the island plane;\n", "- **i**, atop the terrace N in front of it, the epitaxial site that extends the island: (x_N, y_edge + d), d\n", " above the terrace." diff --git a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride_SIMULATION.ipynb index b2a254791..6f4996539 100644 --- a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride_SIMULATION.ipynb @@ -19,12 +19,13 @@ "with the paper's. The paper computed them with DFT (GGA); here every relaxation uses the\n", "[MACE-MP-0](https://github.com/ACEsuit/mace) machine-learned force field with the D3 dispersion correction.\n", "\n", - "The four relaxations are 458-atom MACE runs, meant to be executed natively; the notebook took 16 to 34 minutes on an Apple M1 Pro CPU in two runs.\n", + "The four relaxations are MACE runs on 457 and 458 atoms, meant to be executed natively; the notebook took at most 34 minutes on an Apple M1 Pro CPU.\n", "\n", "

Usage

\n", "\n", "1. Create the materials in the [structure notebook](defect_surface_island_titanium_nitride.ipynb), which saves the island cell and the three adatom cells to the `uploads` folder.\n", "1. Set the material names and parameters in cells 1.2-1.3 (or use the defaults).\n", + "1. Run natively: `pip install \".[all]\" mace-torch torch-dftd`. In JupyterLite the four relaxations take hours and run without D3.\n", "1. Click \"Run\" > \"Run All\" to run all cells.\n", "1. Scroll down to view the results.\n", "\n", @@ -112,7 +113,7 @@ "MACE_DEFAULT_DTYPE = \"float64\"\n", "MACE_DEVICE = \"cpu\"\n", "\n", - "FMAX = 0.02 # eV/Å, every atom free\n", + "FMAX = 0.02 # eV/Å\n", "MAX_STEPS = 1000\n", "\n", "ISOLATED_ATOM_BOX = 15.0 # Å, edge of the cubic box around the isolated Ti atom" @@ -297,7 +298,9 @@ "source": [ "## 6. Isolated Ti atom\n", "\n", - "The reference of the adsorption energy, Eq. (4) of the paper: one Ti atom in a cubic box, same calculator." + "The reference of the adsorption energy, Eq. (4) of the paper: one Ti atom in a cubic box, same calculator.\n", + "This energy is the model's prediction for a single atom in a box, outside its training data (periodic\n", + "crystals); the comparison below prints the paper's −2.275 eV beside it." ] }, { @@ -323,8 +326,8 @@ "### 7.1. Energies relative to a, adsorption energy at a, island relaxation\n", "\n", "The paper's energies of c and i are read off Fig. 6 (±0.02 and ±0.05 eV); the adsorption energy at a, the\n", - "isolated Ti atom energy it uses, the island contraction and the ripple are from Sec. III.A. The adsorption energy\n", - "is printed with this notebook's isolated-atom energy and with the paper's." + "island contraction and the ripple are from Sec. III.A, the isolated Ti atom energy it uses from Sec. II.B.\n", + "The adsorption energy is printed with this notebook's isolated-atom energy and with the paper's." ] }, { @@ -334,12 +337,12 @@ "metadata": {}, "outputs": [], "source": [ - "# Sangiovanni et al. (2018): Fig. 6 upper panel (a-i, read off the axis); Sec. III.A\n", + "# Fig. 6 upper panel, read off; b = 0.10 eV also Sec. III.C.1\n", "PAPER_FIG6 = {\"a\": 0.0, \"b\": 0.10, \"c\": -0.15, \"d\": -0.20, \"e\": -0.25, \"f\": -0.50, \"g\": -1.13, \"h\": -2.25, \"i\": -2.65}\n", - "PAPER_ADSORPTION_ENERGY = -2.81\n", - "PAPER_ISOLATED_ADATOM_ENERGY = -2.275\n", - "PAPER_ISLAND_CONTRACTION = {\"Ti–Ti along diagonals\": -6.8, \"Ti–N along medians\": -5.2}\n", - "PAPER_RIPPLE = 0.19\n", + "PAPER_ADSORPTION_ENERGY = -2.81 # Sec. III.A, FFH_edge on the 5×5 island\n", + "PAPER_ISOLATED_ADATOM_ENERGY = -2.275 # Sec. II.B, Eq. (4), from ref. [68]\n", + "PAPER_ISLAND_CONTRACTION = {\"Ti–Ti along diagonals\": -6.8, \"Ti–N along medians\": -5.2} # Sec. III.A, p. 10\n", + "PAPER_RIPPLE = 0.19 # Sec. III.A, Fig. 2b\n", "\n", "relative_energies = {site: energy - energies[\"a\"] for site, energy in energies.items()}\n", "print(f\"{'site':<6}{'E - E_a (eV)':>14}{'paper':>8}{'deviation':>12}\")\n", From 4009740f83ede5549b0da68ae3e6e851db0eb9da Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 8 Oct 2026 18:53:36 -0700 Subject: [PATCH 04/31] Show the island cell with the Ti adatom at a, c and i in the structure notebook's result view The result visualization now includes the three adatom structures next to the slab and the island cell, so the placed sites can be checked before the materials are saved. Co-Authored-By: Claude Opus 5.5 --- .../defect_surface_island_titanium_nitride.ipynb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb index 769bd44c0..479ea4827 100644 --- a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb +++ b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb @@ -264,7 +264,8 @@ "source": [ "visualize_materials([{\"material\": slab, \"title\": \"Original material\", \"rotation\": \"-45x\"},\n", " {\"material\": slab_with_island,\n", - " \"title\": f\"Material with Island Defect ({SHAPE_PARAMETERS['shape']})\",\"rotation\": \"-45x\"}],\n", + " \"title\": f\"Material with Island Defect ({SHAPE_PARAMETERS['shape']})\",\"rotation\": \"-45x\"},\n", + " *[{\"material\": material, \"title\": material.name, \"rotation\": \"-45x\"} for material in materials_with_adatom]],\n", " # viewer=\"wave\"\n", " )" ] From 1b3cccb935d392713faedceb4e1a4d59c3f9c59c Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 8 Oct 2026 19:46:27 -0700 Subject: [PATCH 05/31] Restore the TiN island notebook to its main version The island structure notebook goes back unchanged; the paper's 458-atom cell with the Ti adatom moves to its own adatom notebook in the next commit. Co-Authored-By: Claude Opus 5.5 --- ...fect_surface_island_titanium_nitride.ipynb | 115 ++---------------- 1 file changed, 13 insertions(+), 102 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb index 479ea4827..0cb6cf936 100644 --- a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb +++ b/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride.ipynb @@ -17,7 +17,7 @@ "\n", "![Fig 2.](https://github.com/Exabyte-io/documentation/raw/12617167278ae3523adc028583b21ea4e8ebd197/images/tutorials/materials/defects/defect-creation-surface-island-titanium-nitride/0.png)\n", "\n", - "In this notebook we will reproduce the paper's 458-atom cell (Sec. II.A, Fig. 1b): a 5×5-atom island with Ti corners on a 12×12×3-atom TiN(001) slab with 15.3 Å of vacuum, with a Ti adatom at each of the sites a, c and i of Fig. 6. FIG. 2 above shows the larger 9×9-atom island.\n" + "In this notebook we will reproduce material from FIG. 2 a)\n" ] }, { @@ -37,34 +37,20 @@ "metadata": {}, "outputs": [], "source": [ - "MATERIAL_ID = \"mp-492\"\n", - "\n", "NUMBER_OF_ADDED_LAYERS = 0.5\n", "\n", - "# x and y minima one site (1/12 of the 6×6 cell) apart put Ti atoms at the island corners\n", "SHAPE_PARAMETERS = {\n", " 'shape': 'box',\n", - " 'min_coordinate': [0.3233, 0.24, 0],\n", - " 'max_coordinate': [0.7233, 0.64, 1]\n", + " 'min_coordinate': [0.25, 0.2, 0],\n", + " 'max_coordinate': [0.65, 0.6, 1]\n", "}\n", "\n", - "# Thickness counts conventional layers of two (001) planes; the bottom plane is removed after the\n", - "# island is added, leaving the paper's three planes.\n", "SLAB_PARAMETERS = {\n", " \"miller_indices\": (0, 0, 1),\n", - " \"thickness\": 2,\n", - " \"vacuum\": 15.3,\n", + " \"thickness\": 3,\n", + " \"vacuum\": 10.0,\n", " \"USE_ORTHOGONAL_C\": True,\n", - " \"xy_supercell_matrix\": [[6, 0], [0, 6]]\n", - "}\n", - "\n", - "ADATOM_ELEMENT = \"Ti\"\n", - "\n", - "ISLAND_MATERIAL_NAME = \"TiN(001) 12x12x3 island 5x5\"\n", - "ADATOM_MATERIAL_NAMES = {\n", - " \"a\": \"TiN(001) 12x12x3 island 5x5 + Ti a (FFH island)\",\n", - " \"c\": \"TiN(001) 12x12x3 island 5x5 + Ti c (atop-N edge)\",\n", - " \"i\": \"TiN(001) 12x12x3 island 5x5 + Ti i (atop-N terrace)\",\n", + " \"xy_supercell_matrix\": [[10, 0], [0, 10]]\n", "}" ] }, @@ -108,7 +94,7 @@ "from mat3ra.made.material import Material\n", "from mat3ra.standata.materials import Materials\n", "\n", - "material = Material.create(Materials.get_by_name_first_match(MATERIAL_ID))" + "material = Material.create(Materials.get_by_name_first_match(\"TiN\"))" ] }, { @@ -157,12 +143,8 @@ "metadata": {}, "outputs": [], "source": [ - "import numpy as np\n", - "from mat3ra.made.tools.analyze.other import get_atom_indices_by_layer\n", - "from mat3ra.made.tools.convert import to_ase\n", "from mat3ra.made.tools.entities.coordinate import BoxCoordinateCondition\n", "from mat3ra.made.tools.helpers import create_island\n", - "from mat3ra.made.tools.modify import filter_by_ids, remove_vacuum\n", "\n", "coordinate_condition = BoxCoordinateCondition(\n", " min_coordinate=SHAPE_PARAMETERS['min_coordinate'],\n", @@ -174,83 +156,13 @@ " condition=coordinate_condition,\n", " number_of_added_layers=NUMBER_OF_ADDED_LAYERS,\n", " use_cartesian_coordinates=False,\n", - ")\n", - "bottom_plane = get_atom_indices_by_layer(slab_with_island)[0]\n", - "slab_with_island = filter_by_ids(slab_with_island, ids=bottom_plane, invert=True, reset_ids=True)\n", - "slab_with_island = remove_vacuum(slab_with_island, fixed_padding=SLAB_PARAMETERS[\"vacuum\"])\n", - "slab_with_island.name = ISLAND_MATERIAL_NAME\n", - "\n", - "atoms = to_ase(slab_with_island)\n", - "symbols = np.array(atoms.get_chemical_symbols())\n", - "planes = get_atom_indices_by_layer(slab_with_island)\n", - "island, terrace = planes[-1], planes[-2]\n", - "island_x, island_y = atoms.positions[island, 0], atoms.positions[island, 1]\n", - "is_corner = ((np.isclose(island_x, island_x.min()) | np.isclose(island_x, island_x.max()))\n", - " & (np.isclose(island_y, island_y.min()) | np.isclose(island_y, island_y.max())))\n", - "print(f\"{slab_with_island.name}: {len(atoms)} atoms ({sum(symbols == 'Ti')} Ti, {sum(symbols == 'N')} N) \"\n", - " f\"in {len(planes)} planes, c = {atoms.cell[2, 2]:.3f} Å\")\n", - "print(f\"Island: {len(island)} atoms, corners {symbols[island][is_corner].tolist()}\")" + ")" ] }, { "cell_type": "markdown", "id": "11", "metadata": {}, - "source": [ - "### 2.1. Add the Adatom at the Sites of Fig. 6\n", - "\n", - "The paper gives no coordinates for the sites; they follow from the lattice and are measured on the island\n", - "built above. Take the N atom with the smaller x in the island's edge row at the largest y, and the bulk site\n", - "spacing d = a/2:\n", - "\n", - "- **a**, the fourfold hollow on the island between that N and the edge-centre Ti, the paper's FFH_edge:\n", - " (x_N + d/2, y_edge − d/2), d above the island plane;\n", - "- **c**, atop the edge N: (x_N, y_edge), d above the island plane;\n", - "- **i**, atop the terrace N in front of it, the epitaxial site that extends the island: (x_N, y_edge + d), d\n", - " above the terrace." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "12", - "metadata": {}, - "outputs": [], - "source": [ - "from mat3ra.made.tools.helpers import create_defect_point_interstitial\n", - "\n", - "site_spacing = material.lattice.a / 2\n", - "edge_y = island_y.max()\n", - "edge_nitrogen_x = min(atoms.positions[index, 0] for index in island\n", - " if symbols[index] == \"N\" and np.isclose(atoms.positions[index, 1], edge_y))\n", - "island_z = atoms.positions[island, 2].mean()\n", - "terrace_z = atoms.positions[terrace, 2].mean()\n", - "\n", - "adatom_sites = {\n", - " \"a\": [edge_nitrogen_x + site_spacing / 2, edge_y - site_spacing / 2, island_z + site_spacing],\n", - " \"c\": [edge_nitrogen_x, edge_y, island_z + site_spacing],\n", - " \"i\": [edge_nitrogen_x, edge_y + site_spacing, terrace_z + site_spacing],\n", - "}\n", - "\n", - "materials_with_adatom = []\n", - "for site, coordinate in adatom_sites.items():\n", - " material_with_adatom = create_defect_point_interstitial(\n", - " slab_with_island, coordinate, ADATOM_ELEMENT, \"exact_coordinate\", use_cartesian_coordinates=True\n", - " )\n", - " material_with_adatom.name = ADATOM_MATERIAL_NAMES[site]\n", - " materials_with_adatom.append(material_with_adatom)\n", - "\n", - " atoms_with_adatom = to_ase(material_with_adatom)\n", - " adatom = len(atoms_with_adatom) - 1\n", - " distances = np.sort(atoms_with_adatom.get_distances(adatom, range(adatom), mic=True))[:3]\n", - " print(f\"{material_with_adatom.name}: {len(atoms_with_adatom)} atoms, \"\n", - " f\"adatom's three shortest distances {np.round(distances, 3)} Å\")" - ] - }, - { - "cell_type": "markdown", - "id": "13", - "metadata": {}, "source": [ "## 3. Visualize the Result(s)" ] @@ -258,21 +170,20 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "12", "metadata": {}, "outputs": [], "source": [ "visualize_materials([{\"material\": slab, \"title\": \"Original material\", \"rotation\": \"-45x\"},\n", " {\"material\": slab_with_island,\n", - " \"title\": f\"Material with Island Defect ({SHAPE_PARAMETERS['shape']})\",\"rotation\": \"-45x\"},\n", - " *[{\"material\": material, \"title\": material.name, \"rotation\": \"-45x\"} for material in materials_with_adatom]],\n", + " \"title\": f\"Material with Island Defect ({SHAPE_PARAMETERS['shape']})\",\"rotation\": \"-45x\"}],\n", " # viewer=\"wave\"\n", " )" ] }, { "cell_type": "markdown", - "id": "15", + "id": "13", "metadata": {}, "source": [ "## 4. Pass data to the outside runtime" @@ -281,14 +192,14 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "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([slab_with_island, *materials_with_adatom])\n", + "set_materials(slab_with_island)\n", "download_content_to_file(slab_with_island.to_json(), \"TiN_slab_with_island.json\")" ] } From 081b157d28ff0ccadad649fef604d510438f9eb3 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 8 Oct 2026 19:58:19 -0700 Subject: [PATCH 06/31] Add a structure notebook for the Ti adatom on a 5x5 TiN island on TiN(001) The new adatom notebook builds Sangiovanni et al.'s cell (a 5x5 island with Ti corners on a 12x12x3-atom TiN(001) slab with 15.3 A of vacuum, 457 atoms) and saves it with a Ti adatom at the sites a, c and i of Fig. 6, derived from the island's edge N atom. Co-Authored-By: Claude Opus 5.5 --- .../specific_examples/Introduction.ipynb | 2 +- ...point_adatom_island_titanium_nitride.ipynb | 303 ++++++++++++++++++ ..._island_titanium_nitride_SIMULATION.ipynb} | 0 3 files changed, 304 insertions(+), 1 deletion(-) create mode 100644 other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb rename other/materials_designer/specific_examples/{defect_surface_island_titanium_nitride_SIMULATION.ipynb => defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb} (100%) diff --git a/other/materials_designer/specific_examples/Introduction.ipynb b/other/materials_designer/specific_examples/Introduction.ipynb index df26331ad..898458bb1 100644 --- a/other/materials_designer/specific_examples/Introduction.ipynb +++ b/other/materials_designer/specific_examples/Introduction.ipynb @@ -36,7 +36,7 @@ "| `D-2D-ADA` | Adatom | [Pt Adatom/Island on MoS₂](defect_point_adatom_island_molybdenum_disulfide_platinum.ipynb) | *To be added* | [[10]](#ref10) |\n", "| `D-2D-ADA` | Adatom | [Adatom on Graphene](defect_surface_adatom_graphene.ipynb) | *To be added* | [[11]](#ref11) |\n", "| `D-2D-GBP` | Grain Boundary Planar | [Grain Boundary in 3D FCC Cu](defect_planar_grain_boundary_3d_fcc_metals_copper.ipynb) | *To be added* | [[13]](#ref13) |\n", - "| `D-2D-ISL` | Island | [TiN Island on Surface](defect_surface_island_titanium_nitride.ipynb) | [Ti Adatom Descent on a 5×5 TiN Island (MACE)](defect_surface_island_titanium_nitride_SIMULATION.ipynb) | [[14]](#ref14) |\n", + "| `D-2D-ISL` | Island | [TiN Island on Surface](defect_surface_island_titanium_nitride.ipynb) | *To be added* | [[14]](#ref14) |\n", "| `D-2D-TER` | Terrace | [Step/Terrace on Pt Surface](defect_surface_step_platinum.ipynb) | *To be added* | [[15]](#ref15) |\n", "| `D-1D-GBL` | Grain Boundary Linear | [Grain Boundary in 2D BN](defect_planar_grain_boundary_2d_boron_nitride.ipynb) | *To be added* | [[12]](#ref12) |\n", "| `D-0D-DFP` | Defect Pair | [Defect Pair in GaN](defect_point_pair_gallium_nitride.ipynb) | [Mg_Ga-V_N Pair Formation Energy in GaN](defect_point_pair_gallium_nitride_SIMULATION.ipynb) | [[16]](#ref16) |\n", diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb new file mode 100644 index 000000000..e6fa20842 --- /dev/null +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb @@ -0,0 +1,303 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "0", + "metadata": {}, + "source": [ + "# Ti Adatom on a 5×5 TiN Island on TiN(001)\n", + "\n", + "## 0. Introduction\n", + "\n", + "This tutorial builds the cell of the Ti adatom descent study in the publication:\n", + "\n", + "> **D. G. Sangiovanni, A. B. Mei, D. Edström, L. Hultman, V. Chirita, I. Petrov, and J. E. Greene**, \"Effects of surface vibrations on interlayer mass transport: Ab initio molecular dynamics investigation of Ti adatom descent pathways and rates from TiN/TiN(001) islands\", Physical Review B 97, 035406 (2018). [DOI: 10.1103/PhysRevB.97.035406](https://doi.org/10.1103/PhysRevB.97.035406)\n", + "\n", + "The cell (Sec. II.A, Fig. 1b) is a 5×5-atom TiN island, one plane high with Ti corners, on a 12×12×3-atom\n", + "TiN(001) slab with 15.3 Å of vacuum: 457 atoms. A Ti adatom is added at each of three sites of Fig. 6, giving\n", + "three 458-atom cells:\n", + "\n", + "- **a**, the fourfold hollow on the island next to its edge;\n", + "- **c**, atop the edge N atom;\n", + "- **i**, atop the terrace N atom in front of the edge, the site that extends the island." + ] + }, + { + "cell_type": "markdown", + "id": "1", + "metadata": {}, + "source": [ + "## 1. Prepare the Environment\n", + "### 1.1. Set up defect parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2", + "metadata": {}, + "outputs": [], + "source": [ + "MATERIAL_NAME = \"Titanium Nitride\"\n", + "MILLER_INDICES = (0, 0, 1)\n", + "# Thickness counts conventional layers of two (001) planes; the bottom plane is removed after the\n", + "# island is added, leaving the paper's three planes.\n", + "SLAB_THICKNESS = 2\n", + "VACUUM = 15.3 # Angstrom\n", + "XY_SUPERCELL_MATRIX = [[6, 0], [0, 6]]\n", + "\n", + "NUMBER_OF_ADDED_LAYERS = 0.5\n", + "# x and y minima one site (1/12 of the 6×6 cell) apart put Ti atoms at the island corners\n", + "ISLAND_MIN_COORDINATE = [0.3233, 0.24, 0] # crystal coordinates\n", + "ISLAND_MAX_COORDINATE = [0.7233, 0.64, 1]\n", + "\n", + "ADATOM_ELEMENT = \"Ti\"\n", + "\n", + "ISLAND_MATERIAL_NAME = \"TiN(001) 12x12x3 island 5x5\"\n", + "ADATOM_MATERIAL_NAMES = {\n", + " \"a\": \"TiN(001) 12x12x3 island 5x5 + Ti a (FFH island)\",\n", + " \"c\": \"TiN(001) 12x12x3 island 5x5 + Ti c (atop-N edge)\",\n", + " \"i\": \"TiN(001) 12x12x3 island 5x5 + Ti i (atop-N terrace)\",\n", + "}" + ] + }, + { + "cell_type": "markdown", + "id": "3", + "metadata": {}, + "source": [ + "### 1.2. 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": "4", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.packages import install_packages\n", + "\n", + "await install_packages(\"made|specific_examples\")" + ] + }, + { + "cell_type": "markdown", + "id": "5", + "metadata": {}, + "source": [ + "### 1.3. Load input material" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.made.material import Material\n", + "from mat3ra.standata.materials import Materials\n", + "\n", + "material = Material.create(Materials.get_by_name_first_match(MATERIAL_NAME))" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "### 1.4. Create and preview Slab" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.made.tools.helpers import create_slab\n", + "from mat3ra.notebooks_utils.ipython.entity.material.visualize import visualize_materials\n", + "\n", + "slab = create_slab(\n", + " crystal=material,\n", + " termination_top=None, # Use default termination\n", + " miller_indices=MILLER_INDICES,\n", + " number_of_layers=SLAB_THICKNESS,\n", + " vacuum=VACUUM,\n", + " use_orthogonal_c=True,\n", + " xy_supercell_matrix=XY_SUPERCELL_MATRIX\n", + ")\n", + "\n", + "visualize_materials(slab)" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "## 2. Create the Island" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "from mat3ra.made.tools.analyze.other import get_atom_indices_by_layer\n", + "from mat3ra.made.tools.convert import to_ase\n", + "from mat3ra.made.tools.entities.coordinate import BoxCoordinateCondition\n", + "from mat3ra.made.tools.helpers import create_island\n", + "from mat3ra.made.tools.modify import filter_by_ids, remove_vacuum\n", + "\n", + "coordinate_condition = BoxCoordinateCondition(min_coordinate=ISLAND_MIN_COORDINATE, max_coordinate=ISLAND_MAX_COORDINATE)\n", + "\n", + "slab_with_island = create_island(\n", + " slab=slab,\n", + " condition=coordinate_condition,\n", + " number_of_added_layers=NUMBER_OF_ADDED_LAYERS,\n", + " use_cartesian_coordinates=False,\n", + ")\n", + "bottom_plane = get_atom_indices_by_layer(slab_with_island)[0]\n", + "slab_with_island = filter_by_ids(slab_with_island, ids=bottom_plane, invert=True, reset_ids=True)\n", + "slab_with_island = remove_vacuum(slab_with_island, fixed_padding=VACUUM)\n", + "slab_with_island.name = ISLAND_MATERIAL_NAME\n", + "\n", + "atoms = to_ase(slab_with_island)\n", + "symbols = np.array(atoms.get_chemical_symbols())\n", + "planes = get_atom_indices_by_layer(slab_with_island)\n", + "island, terrace = planes[-1], planes[-2]\n", + "island_x, island_y = atoms.positions[island, 0], atoms.positions[island, 1]\n", + "is_corner = ((np.isclose(island_x, island_x.min()) | np.isclose(island_x, island_x.max()))\n", + " & (np.isclose(island_y, island_y.min()) | np.isclose(island_y, island_y.max())))\n", + "print(f\"{slab_with_island.name}: {len(atoms)} atoms ({sum(symbols == 'Ti')} Ti, {sum(symbols == 'N')} N) \"\n", + " f\"in {len(planes)} planes, c = {atoms.cell[2, 2]:.3f} Å\")\n", + "print(f\"Island: {len(island)} atoms, corners {symbols[island][is_corner].tolist()}\")" + ] + }, + { + "cell_type": "markdown", + "id": "11", + "metadata": {}, + "source": [ + "## 3. Add the Adatom at the Sites of Fig. 6\n", + "\n", + "The paper gives no coordinates for the sites; they follow from the lattice and are measured on the island\n", + "built above. Take the N atom with the smaller x in the island's edge row at the largest y, and the bulk site\n", + "spacing d = a/2:\n", + "\n", + "- **a**, the fourfold hollow between that N and the edge-centre Ti, the paper's FFH_edge:\n", + " (x_N + d/2, y_edge − d/2), d above the island plane;\n", + "- **c**: (x_N, y_edge), d above the island plane;\n", + "- **i**: (x_N, y_edge + d), d above the terrace." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "12", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.made.tools.helpers import create_defect_point_interstitial\n", + "\n", + "site_spacing = material.lattice.a / 2\n", + "edge_y = island_y.max()\n", + "edge_nitrogen_x = min(atoms.positions[index, 0] for index in island\n", + " if symbols[index] == \"N\" and np.isclose(atoms.positions[index, 1], edge_y))\n", + "island_z = atoms.positions[island, 2].mean()\n", + "terrace_z = atoms.positions[terrace, 2].mean()\n", + "\n", + "adatom_sites = {\n", + " \"a\": [edge_nitrogen_x + site_spacing / 2, edge_y - site_spacing / 2, island_z + site_spacing],\n", + " \"c\": [edge_nitrogen_x, edge_y, island_z + site_spacing],\n", + " \"i\": [edge_nitrogen_x, edge_y + site_spacing, terrace_z + site_spacing],\n", + "}\n", + "\n", + "materials_with_adatom = []\n", + "for site, coordinate in adatom_sites.items():\n", + " material_with_adatom = create_defect_point_interstitial(\n", + " slab_with_island, coordinate, ADATOM_ELEMENT, \"exact_coordinate\", use_cartesian_coordinates=True\n", + " )\n", + " material_with_adatom.name = ADATOM_MATERIAL_NAMES[site]\n", + " materials_with_adatom.append(material_with_adatom)\n", + "\n", + " atoms_with_adatom = to_ase(material_with_adatom)\n", + " adatom = len(atoms_with_adatom) - 1\n", + " distances = np.sort(atoms_with_adatom.get_distances(adatom, range(adatom), mic=True))[:3]\n", + " print(f\"{material_with_adatom.name}: {len(atoms_with_adatom)} atoms, \"\n", + " f\"adatom's three shortest distances {np.round(distances, 3)} Å\")" + ] + }, + { + "cell_type": "markdown", + "id": "13", + "metadata": {}, + "source": [ + "## 4. Visualize the Result(s)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14", + "metadata": {}, + "outputs": [], + "source": [ + "visualize_materials([{\"material\": material_to_show, \"title\": material_to_show.name, \"rotation\": \"-45x\"}\n", + " for material_to_show in [slab_with_island, *materials_with_adatom]])" + ] + }, + { + "cell_type": "markdown", + "id": "15", + "metadata": {}, + "source": [ + "## 5. Pass data to the outside runtime" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.io import download_content_to_file\n", + "from mat3ra.notebooks_utils.material import set_materials\n", + "\n", + "materials = [slab_with_island, *materials_with_adatom]\n", + "set_materials(materials)\n", + "for material_to_save in materials:\n", + " download_content_to_file(material_to_save.to_json(), f\"{material_to_save.name}.json\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 2 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython2", + "version": "2.7.6" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/other/materials_designer/specific_examples/defect_surface_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb similarity index 100% rename from other/materials_designer/specific_examples/defect_surface_island_titanium_nitride_SIMULATION.ipynb rename to other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb From b35065f259e0573aed26045a07be78aa401042e9 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 8 Oct 2026 19:58:43 -0700 Subject: [PATCH 07/31] Pair the MACE simulation notebook with the Ti adatom notebook and list it under Adatom The simulation notebook, now named after the adatom notebook it reads from, builds the isolated Ti reference with made's point-defect atom builder and prints each computed value beside the manuscript's: E(c) - E(a) and E(i) - E(a) (Fig. 6), E_ads(a), E_Ti, the island contraction and the ripple. The Introduction lists the pair in a new D-2D-ADA row; the island row is unchanged from main. Co-Authored-By: Claude Opus 5.5 --- .../specific_examples/Introduction.ipynb | 1 + ...m_island_titanium_nitride_SIMULATION.ipynb | 54 +++++++++---------- 2 files changed, 26 insertions(+), 29 deletions(-) diff --git a/other/materials_designer/specific_examples/Introduction.ipynb b/other/materials_designer/specific_examples/Introduction.ipynb index 898458bb1..230324296 100644 --- a/other/materials_designer/specific_examples/Introduction.ipynb +++ b/other/materials_designer/specific_examples/Introduction.ipynb @@ -35,6 +35,7 @@ "| `D-3D-AMO` | Amorphous | *To be added* | — | — |\n", "| `D-2D-ADA` | Adatom | [Pt Adatom/Island on MoS₂](defect_point_adatom_island_molybdenum_disulfide_platinum.ipynb) | *To be added* | [[10]](#ref10) |\n", "| `D-2D-ADA` | Adatom | [Adatom on Graphene](defect_surface_adatom_graphene.ipynb) | *To be added* | [[11]](#ref11) |\n", + "| `D-2D-ADA` | Adatom | [Ti Adatom on a 5×5 TiN Island](defect_point_adatom_island_titanium_nitride.ipynb) | [Ti Adatom Descent on a 5×5 TiN Island (MACE)](defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb) | [[14]](#ref14) |\n", "| `D-2D-GBP` | Grain Boundary Planar | [Grain Boundary in 3D FCC Cu](defect_planar_grain_boundary_3d_fcc_metals_copper.ipynb) | *To be added* | [[13]](#ref13) |\n", "| `D-2D-ISL` | Island | [TiN Island on Surface](defect_surface_island_titanium_nitride.ipynb) | *To be added* | [[14]](#ref14) |\n", "| `D-2D-TER` | Terrace | [Step/Terrace on Pt Surface](defect_surface_step_platinum.ipynb) | *To be added* | [[15]](#ref15) |\n", diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index 6f4996539..ab865d946 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -13,7 +13,7 @@ "> [DOI: 10.1103/PhysRevB.97.035406](https://doi.org/10.1103/PhysRevB.97.035406)\n", "\n", "Relaxes a Ti adatom at three sites of the paper's Fig. 6 on the cell created in the\n", - "[structure notebook](defect_surface_island_titanium_nitride.ipynb): **a**, the fourfold hollow on the island\n", + "[structure notebook](defect_point_adatom_island_titanium_nitride.ipynb): **a**, the fourfold hollow on the island\n", "next to its edge; **c**, atop the edge N atom; **i**, atop the terrace N atom in front of the edge, the site\n", "that extends the island. The energies of c and i relative to a, and the adsorption energy at a, are compared\n", "with the paper's. The paper computed them with DFT (GGA); here every relaxation uses the\n", @@ -23,7 +23,7 @@ "\n", "

Usage

\n", "\n", - "1. Create the materials in the [structure notebook](defect_surface_island_titanium_nitride.ipynb), which saves the island cell and the three adatom cells to the `uploads` folder.\n", + "1. Create the materials in the [structure notebook](defect_point_adatom_island_titanium_nitride.ipynb), which saves the island cell and the three adatom cells to the `uploads` folder.\n", "1. Set the material names and parameters in cells 1.2-1.3 (or use the defaults).\n", "1. Run natively: `pip install \".[all]\" mace-torch torch-dftd`. In JupyterLite the four relaxations take hours and run without D3.\n", "1. Click \"Run\" > \"Run All\" to run all cells.\n", @@ -81,7 +81,7 @@ "metadata": {}, "outputs": [], "source": [ - "# Names saved by defect_surface_island_titanium_nitride.ipynb.\n", + "# Names saved by defect_point_adatom_island_titanium_nitride.ipynb.\n", "ISLAND_MATERIAL_NAME = \"TiN(001) 12x12x3 island 5x5\"\n", "ADATOM_MATERIAL_NAMES = {\n", " \"a\": \"TiN(001) 12x12x3 island 5x5 + Ti a (FFH island)\",\n", @@ -114,9 +114,7 @@ "MACE_DEVICE = \"cpu\"\n", "\n", "FMAX = 0.02 # eV/Å\n", - "MAX_STEPS = 1000\n", - "\n", - "ISOLATED_ATOM_BOX = 15.0 # Å, edge of the cubic box around the isolated Ti atom" + "MAX_STEPS = 1000" ] }, { @@ -298,9 +296,9 @@ "source": [ "## 6. Isolated Ti atom\n", "\n", - "The reference of the adsorption energy, Eq. (4) of the paper: one Ti atom in a cubic box, same calculator.\n", - "This energy is the model's prediction for a single atom in a box, outside its training data (periodic\n", - "crystals); the comparison below prints the paper's −2.275 eV beside it." + "The reference of the adsorption energy, Eq. (4) of the paper: one Ti atom at the centre of an otherwise\n", + "empty cell the size of the island cell, same calculator. This energy is the model's prediction for a single\n", + "atom, outside its training data (periodic crystals); the comparison below prints the paper's −2.275 eV beside it." ] }, { @@ -310,10 +308,14 @@ "metadata": {}, "outputs": [], "source": [ - "from ase import Atoms\n", + "from mat3ra.esse.models.materials_category_components.entities.core.zero_dimensional.atom import AtomSchema\n", + "from mat3ra.made.tools.build_components.entities.core.zero_dimensional.atom.builder import AtomAtCoordinateBuilder\n", + "from mat3ra.made.tools.build_components.entities.core.zero_dimensional.atom.configuration import AtomAtCoordinateConfiguration\n", "\n", "adatom_element = materials_with_adatom[\"a\"].basis.elements.values[-1]\n", - "energy_isolated_adatom = calculate_total_energy(Atoms(adatom_element, cell=[ISOLATED_ATOM_BOX] * 3, pbc=True), calculator)\n", + "isolated_adatom = AtomAtCoordinateBuilder().get_material(AtomAtCoordinateConfiguration(\n", + " crystal=slab_with_island, element=AtomSchema(chemical_element=adatom_element), coordinate=[0.5, 0.5, 0.5]))\n", + "energy_isolated_adatom = calculate_total_energy(isolated_adatom, calculator)\n", "print(f\"E({adatom_element}, isolated) = {energy_isolated_adatom:.3f} eV\")" ] }, @@ -326,8 +328,7 @@ "### 7.1. Energies relative to a, adsorption energy at a, island relaxation\n", "\n", "The paper's energies of c and i are read off Fig. 6 (±0.02 and ±0.05 eV); the adsorption energy at a, the\n", - "island contraction and the ripple are from Sec. III.A, the isolated Ti atom energy it uses from Sec. II.B.\n", - "The adsorption energy is printed with this notebook's isolated-atom energy and with the paper's." + "island contraction and the ripple are from Sec. III.A, the isolated Ti atom energy it uses from Sec. II.B." ] }, { @@ -345,22 +346,17 @@ "PAPER_RIPPLE = 0.19 # Sec. III.A, Fig. 2b\n", "\n", "relative_energies = {site: energy - energies[\"a\"] for site, energy in energies.items()}\n", - "print(f\"{'site':<6}{'E - E_a (eV)':>14}{'paper':>8}{'deviation':>12}\")\n", - "for site in (\"c\", \"i\"):\n", - " deviation = 100 * (relative_energies[site] / PAPER_FIG6[site] - 1)\n", - " print(f\"{site:<6}{relative_energies[site]:>14.3f}{PAPER_FIG6[site]:>8.2f}{deviation:>+11.1f}%\")\n", - "\n", - "print()\n", - "for label, isolated_energy in ((\"this notebook's\", energy_isolated_adatom), (\"the paper's\", PAPER_ISOLATED_ADATOM_ENERGY)):\n", - " adsorption_energy = energies[\"a\"] - energy_slab_with_island - isolated_energy\n", - " deviation = 100 * (adsorption_energy / PAPER_ADSORPTION_ENERGY - 1)\n", - " print(f\"E_ads(a) with {label} E_Ti ({isolated_energy:.3f} eV): {adsorption_energy:.3f} eV, \"\n", - " f\"paper {PAPER_ADSORPTION_ENERGY:.2f} eV, deviation {deviation:+.1f}%\")\n", - "\n", - "print()\n", - "for label, contraction in island_contraction.items():\n", - " print(f\"{label}: {contraction:+.1f} %, paper {PAPER_ISLAND_CONTRACTION[label]:+.1f} %\")\n", - "print(f\"Ripple: {ripple:.2f} Å, paper {PAPER_RIPPLE:.2f} Å\")" + "comparison = {\n", + " \"E(c) - E(a), eV\": (relative_energies[\"c\"], PAPER_FIG6[\"c\"]),\n", + " \"E(i) - E(a), eV\": (relative_energies[\"i\"], PAPER_FIG6[\"i\"]),\n", + " \"E_ads(a), eV\": (energies[\"a\"] - energy_slab_with_island - energy_isolated_adatom, PAPER_ADSORPTION_ENERGY),\n", + " \"E_Ti, isolated, eV\": (energy_isolated_adatom, PAPER_ISOLATED_ADATOM_ENERGY),\n", + " **{f\"{label}, %\": (island_contraction[label], PAPER_ISLAND_CONTRACTION[label]) for label in island_contraction},\n", + " \"Ripple, Å\": (ripple, PAPER_RIPPLE),\n", + "}\n", + "print(f\"{'':<28}{'this notebook':>15}{'manuscript':>12}\")\n", + "for label, (computed, manuscript) in comparison.items():\n", + " print(f\"{label:<28}{computed:>15.3f}{manuscript:>12}\")" ] }, { From b0711c7bfdf07d5d2a2d48f583b28e48adbf4b8f Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 8 Oct 2026 20:00:15 -0700 Subject: [PATCH 08/31] Say the site derivation once The adatom notebook's introduction states the cell and names the sites a, c and i; their description and coordinates stay in section 3. Co-Authored-By: Claude Opus 5.5 --- .../defect_point_adatom_island_titanium_nitride.ipynb | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb index e6fa20842..628445c9c 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb @@ -14,12 +14,8 @@ "> **D. G. Sangiovanni, A. B. Mei, D. Edström, L. Hultman, V. Chirita, I. Petrov, and J. E. Greene**, \"Effects of surface vibrations on interlayer mass transport: Ab initio molecular dynamics investigation of Ti adatom descent pathways and rates from TiN/TiN(001) islands\", Physical Review B 97, 035406 (2018). [DOI: 10.1103/PhysRevB.97.035406](https://doi.org/10.1103/PhysRevB.97.035406)\n", "\n", "The cell (Sec. II.A, Fig. 1b) is a 5×5-atom TiN island, one plane high with Ti corners, on a 12×12×3-atom\n", - "TiN(001) slab with 15.3 Å of vacuum: 457 atoms. A Ti adatom is added at each of three sites of Fig. 6, giving\n", - "three 458-atom cells:\n", - "\n", - "- **a**, the fourfold hollow on the island next to its edge;\n", - "- **c**, atop the edge N atom;\n", - "- **i**, atop the terrace N atom in front of the edge, the site that extends the island." + "TiN(001) slab with 15.3 Å of vacuum: 457 atoms. A Ti adatom is added at each of the sites a, c and i of Fig. 6,\n", + "giving three 458-atom cells." ] }, { From 59908ff8c3bb8b707bbd93ca3c39fe8a1b90718e Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 8 Oct 2026 20:14:54 -0700 Subject: [PATCH 09/31] Close the adatom notebook with References; name the c and i sites The adatom structure notebook now ends with the paper's reference, and its site list says what c and i are: atop the edge N, and atop the terrace N in front of it, the epitaxial site that extends the island. Co-Authored-By: Claude Opus 5.5 --- ..._point_adatom_island_titanium_nitride.ipynb | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb index 628445c9c..b02205681 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb @@ -190,8 +190,9 @@ "\n", "- **a**, the fourfold hollow between that N and the edge-centre Ti, the paper's FFH_edge:\n", " (x_N + d/2, y_edge − d/2), d above the island plane;\n", - "- **c**: (x_N, y_edge), d above the island plane;\n", - "- **i**: (x_N, y_edge + d), d above the terrace." + "- **c**, atop the edge N: (x_N, y_edge), d above the island plane;\n", + "- **i**, atop the terrace N in front of it, the epitaxial site that extends the island: (x_N, y_edge + d), d\n", + " above the terrace." ] }, { @@ -273,6 +274,19 @@ "for material_to_save in materials:\n", " download_content_to_file(material_to_save.to_json(), f\"{material_to_save.name}.json\")" ] + }, + { + "cell_type": "markdown", + "id": "17", + "metadata": {}, + "source": [ + "## References\n", + "\n", + "[1] D. G. Sangiovanni, A. B. Mei, D. Edström, L. Hultman, V. Chirita, I. Petrov, J. E. Greene, \"Effects of surface\n", + "vibrations on interlayer mass transport: Ab initio molecular dynamics investigation of Ti adatom descent pathways\n", + "and rates from TiN/TiN(001) islands\", Phys. Rev. B 97, 035406 (2018).\n", + "[DOI: 10.1103/PhysRevB.97.035406](https://doi.org/10.1103/PhysRevB.97.035406)" + ] } ], "metadata": { From 9e48ddf8ea1f410e277583f856d99ebe366e0347 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 8 Oct 2026 20:24:20 -0700 Subject: [PATCH 10/31] Show the manuscript's Fig. 1(b) in the adatom notebook The adatom notebook's introduction now shows the paper's Fig. 1(b), the 5x5 island cell it builds. Co-Authored-By: Claude Opus 5.5 --- .../defect_point_adatom_island_titanium_nitride.ipynb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb index b02205681..e59b9ba57 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb @@ -15,7 +15,9 @@ "\n", "The cell (Sec. II.A, Fig. 1b) is a 5×5-atom TiN island, one plane high with Ti corners, on a 12×12×3-atom\n", "TiN(001) slab with 15.3 Å of vacuum: 457 atoms. A Ti adatom is added at each of the sites a, c and i of Fig. 6,\n", - "giving three 458-atom cells." + "giving three 458-atom cells.\n", + "\n", + "![Fig. 1(b)](https://github.com/Exabyte-io/documentation/raw/98b0e6b61a7007a4a53e41d894fb56c891ccaaa0/images/tutorials/materials/defects/defect-point-adatom-island-titanium-nitride/0-figure-1b-from-manuscript.webp)" ] }, { From a61510e35d46b099003a516191700a86031956e8 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 9 Oct 2026 14:59:13 -0700 Subject: [PATCH 11/31] Expose the adatom sites as parameters The adatom notebook now takes its sites from ADATOM_SITES at the top: offsets from the island's edge N atom in units of the Ti-N site spacing, with the island plane as zero height. A reader can move a start point or add a site by adding one entry there and one to ADATOM_MATERIAL_NAMES. Co-Authored-By: Claude Opus 5.5 --- ...point_adatom_island_titanium_nitride.ipynb | 31 ++++++++++--------- 1 file changed, 17 insertions(+), 14 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb index e59b9ba57..36345d788 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb @@ -26,7 +26,11 @@ "metadata": {}, "source": [ "## 1. Prepare the Environment\n", - "### 1.1. Set up defect parameters" + "### 1.1. Set up defect parameters\n", + "\n", + "Each entry of `ADATOM_SITES` places one adatom relative to the N atom with the smaller x in the island's\n", + "edge row at the largest y, in units of the Ti–N site spacing d = a/2, with Δz = 0 the island plane; to add a\n", + "site, add an entry under a new letter to both `ADATOM_SITES` and `ADATOM_MATERIAL_NAMES`." ] }, { @@ -50,6 +54,13 @@ "ISLAND_MAX_COORDINATE = [0.7233, 0.64, 1]\n", "\n", "ADATOM_ELEMENT = \"Ti\"\n", + "# Adatom sites as (Δx, Δy, Δz) from the island's edge N atom, in units of the Ti–N site spacing;\n", + "# Δz = 0 is the island plane. Fig. 6's b and d–h are NEB images between these sites, not positions.\n", + "ADATOM_SITES = {\n", + " \"a\": (0.5, -0.5, 1), # fourfold hollow on the island beside the edge\n", + " \"c\": (0, 0, 1), # atop the edge N\n", + " \"i\": (0, 1, 0), # atop the terrace N in front of the edge\n", + "}\n", "\n", "ISLAND_MATERIAL_NAME = \"TiN(001) 12x12x3 island 5x5\"\n", "ADATOM_MATERIAL_NAMES = {\n", @@ -170,7 +181,7 @@ "atoms = to_ase(slab_with_island)\n", "symbols = np.array(atoms.get_chemical_symbols())\n", "planes = get_atom_indices_by_layer(slab_with_island)\n", - "island, terrace = planes[-1], planes[-2]\n", + "island = planes[-1]\n", "island_x, island_y = atoms.positions[island, 0], atoms.positions[island, 1]\n", "is_corner = ((np.isclose(island_x, island_x.min()) | np.isclose(island_x, island_x.max()))\n", " & (np.isclose(island_y, island_y.min()) | np.isclose(island_y, island_y.max())))\n", @@ -187,14 +198,8 @@ "## 3. Add the Adatom at the Sites of Fig. 6\n", "\n", "The paper gives no coordinates for the sites; they follow from the lattice and are measured on the island\n", - "built above. Take the N atom with the smaller x in the island's edge row at the largest y, and the bulk site\n", - "spacing d = a/2:\n", - "\n", - "- **a**, the fourfold hollow between that N and the edge-centre Ti, the paper's FFH_edge:\n", - " (x_N + d/2, y_edge − d/2), d above the island plane;\n", - "- **c**, atop the edge N: (x_N, y_edge), d above the island plane;\n", - "- **i**, atop the terrace N in front of it, the epitaxial site that extends the island: (x_N, y_edge + d), d\n", - " above the terrace." + "built above, from the offsets in `ADATOM_SITES`. Measured from the edge N with the smaller x, a lies between\n", + "that N and the edge-centre Ti, the paper's FFH_edge; i is the epitaxial site that extends the island." ] }, { @@ -211,12 +216,10 @@ "edge_nitrogen_x = min(atoms.positions[index, 0] for index in island\n", " if symbols[index] == \"N\" and np.isclose(atoms.positions[index, 1], edge_y))\n", "island_z = atoms.positions[island, 2].mean()\n", - "terrace_z = atoms.positions[terrace, 2].mean()\n", "\n", "adatom_sites = {\n", - " \"a\": [edge_nitrogen_x + site_spacing / 2, edge_y - site_spacing / 2, island_z + site_spacing],\n", - " \"c\": [edge_nitrogen_x, edge_y, island_z + site_spacing],\n", - " \"i\": [edge_nitrogen_x, edge_y + site_spacing, terrace_z + site_spacing],\n", + " site: [edge_nitrogen_x + offset_x * site_spacing, edge_y + offset_y * site_spacing, island_z + offset_z * site_spacing]\n", + " for site, (offset_x, offset_y, offset_z) in ADATOM_SITES.items()\n", "}\n", "\n", "materials_with_adatom = []\n", From e524a885cc74071406ed4aefc92d7068e38d79ec Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 9 Oct 2026 15:01:57 -0700 Subject: [PATCH 12/31] Drop the run timing from the notebook The simulation notebook keeps the guidance (the relaxations run natively; in JupyterLite they take hours and run without D3) and no longer records how long one run took on one machine. Co-Authored-By: Claude Opus 5.5 --- ...defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index ab865d946..0d1e24797 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -19,7 +19,7 @@ "with the paper's. The paper computed them with DFT (GGA); here every relaxation uses the\n", "[MACE-MP-0](https://github.com/ACEsuit/mace) machine-learned force field with the D3 dispersion correction.\n", "\n", - "The four relaxations are MACE runs on 457 and 458 atoms, meant to be executed natively; the notebook took at most 34 minutes on an Apple M1 Pro CPU.\n", + "The four relaxations are MACE runs on 457 and 458 atoms, meant to be executed natively.\n", "\n", "

Usage

\n", "\n", From fb6e3dadd06fc0ae321600ecfaa3c6c7c1ba379f Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 9 Oct 2026 17:23:10 -0700 Subject: [PATCH 13/31] Show each adatom site as built and relaxed After the relaxations, the simulation notebook shows the Ti adatom at a, c and i as built and as relaxed, viewed along the island edge with the island on the left and the terrace on the right. Co-Authored-By: Claude Opus 5.5 --- ...m_island_titanium_nitride_SIMULATION.ipynb | 38 ++++++++++++++++--- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index 0d1e24797..ebad715fa 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -277,8 +277,10 @@ "outputs": [], "source": [ "energies = {}\n", + "relaxed_materials_with_adatom = {}\n", "for site, material in materials_with_adatom.items():\n", " material_relaxed = relax_material(material, calculator, fmax=FMAX, max_steps=MAX_STEPS)\n", + " relaxed_materials_with_adatom[site] = material_relaxed\n", " energies[site] = calculate_total_energy(material_relaxed, calculator)\n", "\n", " placed, final = to_ase(material), to_ase(material_relaxed)\n", @@ -293,6 +295,30 @@ "cell_type": "markdown", "id": "17", "metadata": {}, + "source": [ + "### 5.1. Visualize each site as built and relaxed\n", + "\n", + "Side view along the island edge: the island is on the left, the terrace on the right." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.ipython.entity.material.visualize import visualize_materials\n", + "\n", + "visualize_materials([{\"material\": materials[site], \"title\": f\"{site} — {state}\", \"rotation\": \"-90x,-90y\"}\n", + " for state, materials in ((\"as built\", materials_with_adatom), (\"relaxed\", relaxed_materials_with_adatom))\n", + " for site in materials])" + ] + }, + { + "cell_type": "markdown", + "id": "19", + "metadata": {}, "source": [ "## 6. Isolated Ti atom\n", "\n", @@ -304,7 +330,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -321,7 +347,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "21", "metadata": {}, "source": [ "## 7. Compare with the paper\n", @@ -334,7 +360,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -361,7 +387,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "23", "metadata": {}, "source": [ "### 7.2. Fig. 6" @@ -370,7 +396,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -388,7 +414,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "25", "metadata": {}, "source": [ "## References\n", From 268e878dca6f3ff5b2ed7e1645bc96a45b60c257 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 9 Oct 2026 19:39:59 -0700 Subject: [PATCH 14/31] State the browser memory limit The simulation notebook's Usage now says what happens in JupyterLite: the install and the calculator run, but the first MACE force call on the 457-atom cell needs a 0.76 GB tensor and exceeds the browser's memory, so the relaxations run natively; D3 is off in the browser. Co-Authored-By: Claude Opus 5.5 --- ...defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index ebad715fa..d00d3fdb2 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -25,7 +25,7 @@ "\n", "1. Create the materials in the [structure notebook](defect_point_adatom_island_titanium_nitride.ipynb), which saves the island cell and the three adatom cells to the `uploads` folder.\n", "1. Set the material names and parameters in cells 1.2-1.3 (or use the defaults).\n", - "1. Run natively: `pip install \".[all]\" mace-torch torch-dftd`. In JupyterLite the four relaxations take hours and run without D3.\n", + "1. Run natively: `pip install \".[all]\" mace-torch torch-dftd`. In JupyterLite the install and the calculator run, but the first force call on the 457-atom cell exceeds the browser's memory (a 0.76 GB tensor), so the relaxations run natively; the browser also has no torch-dftd, so D3 is off there.\n", "1. Click \"Run\" > \"Run All\" to run all cells.\n", "1. Scroll down to view the results.\n", "\n", From 8a488c984ef1cde08ddb8dcba2cd32890a19f507 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 29 Oct 2026 10:51:47 -0700 Subject: [PATCH 15/31] Add DFT single-point energies on the MACE-relaxed structures Co-Authored-By: Claude Opus 5.5 --- ...m_island_titanium_nitride_SIMULATION.ipynb | 317 ++++++++++++++++-- 1 file changed, 297 insertions(+), 20 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index d00d3fdb2..c2064a9ec 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -17,7 +17,8 @@ "next to its edge; **c**, atop the edge N atom; **i**, atop the terrace N atom in front of the edge, the site\n", "that extends the island. The energies of c and i relative to a, and the adsorption energy at a, are compared\n", "with the paper's. The paper computed them with DFT (GGA); here every relaxation uses the\n", - "[MACE-MP-0](https://github.com/ACEsuit/mace) machine-learned force field with the D3 dispersion correction.\n", + "[MACE-MP-0](https://github.com/ACEsuit/mace) machine-learned force field with the D3 dispersion correction. DFT (PBE) total energies of the MACE-relaxed structures, computed on\n", + "the platform, are printed beside MACE's.\n", "\n", "The four relaxations are MACE runs on 457 and 458 atoms, meant to be executed natively.\n", "\n", @@ -27,16 +28,18 @@ "1. Set the material names and parameters in cells 1.2-1.3 (or use the defaults).\n", "1. Run natively: `pip install \".[all]\" mace-torch torch-dftd`. In JupyterLite the install and the calculator run, but the first force call on the 457-atom cell exceeds the browser's memory (a 0.76 GB tensor), so the relaxations run natively; the browser also has no torch-dftd, so D3 is off there.\n", "1. Click \"Run\" > \"Run All\" to run all cells.\n", + "1. Wait for the DFT jobs to finish.\n", "1. Scroll down to view the results.\n", "\n", "## Summary\n", "\n", - "1. Set up the environment and parameters: install packages (JupyterLite only), material names, force-field and relaxation parameters.\n", + "1. Set up the environment and parameters: install packages (JupyterLite only), material names, force-field, relaxation, DFT and compute parameters.\n", "1. Load the materials by name from the `uploads` folder.\n", "1. Build the MACE calculator.\n", "1. Relax the island cell; measure the island contraction and the surface ripple.\n", "1. Relax the adatom at a, c and i.\n", "1. Compute the energy of an isolated Ti atom.\n", + "1. Compute DFT total energies of the MACE-relaxed structures and of the isolated Ti atom on the platform.\n", "1. Compare with the paper: energies relative to a, the adsorption energy at a, and Fig. 6." ] }, @@ -105,6 +108,9 @@ "metadata": {}, "outputs": [], "source": [ + "from mat3ra.ide.compute import QueueName\n", + "\n", + "ORGANIZATION_NAME = None\n", "FOLDER = \"./uploads\"\n", "\n", "MACE_MODEL_FAMILY = \"MACE-MP-0\"\n", @@ -114,7 +120,26 @@ "MACE_DEVICE = \"cpu\"\n", "\n", "FMAX = 0.02 # eV/Å\n", - "MAX_STEPS = 1000" + "MAX_STEPS = 1000\n", + "\n", + "# DFT total energies of the MACE-relaxed structures; an empty list skips the platform jobs\n", + "DFT_MATERIAL_LABELS = [\"slab_with_island\", \"a\", \"c\", \"i\", \"isolated_adatom\"]\n", + "# The manuscript relaxed every structure with DFT (VASP, PAW, PW91); PW91 is set with \"input_dft\": \"pw91\" here.\n", + "DFT_SYSTEM_SETTINGS = {\"smearing\": \"mv\", \"degauss\": 0.01} # Ry\n", + "DFT_SPIN_SETTINGS = {\"isolated_adatom\": {\"nspin\": 2, \"starting_magnetization(1)\": 0.5}}\n", + "APPLICATION_NAME = \"espresso\"\n", + "TOTAL_ENERGY_SEARCH_TERM = \"total_energy.json\"\n", + "FUNCTIONAL = \"pbe\"\n", + "PSEUDOPOTENTIAL_TYPE = \"paw\"\n", + "ECUTWFC = 40 # Ry\n", + "ECUTRHO = 160 # Ry\n", + "DFT_KGRID = [1, 1, 1] # Γ only, as in the manuscript\n", + "\n", + "CLUSTER_NAME = \"001\"\n", + "QUEUE_NAME = QueueName.OF\n", + "PPN = 36\n", + "TIME_LIMIT = \"50:00:00\"\n", + "POLL_INTERVAL = 600 # seconds" ] }, { @@ -350,11 +375,13 @@ "id": "21", "metadata": {}, "source": [ - "## 7. Compare with the paper\n", - "### 7.1. Energies relative to a, adsorption energy at a, island relaxation\n", + "## 7. DFT total energies of the MACE-relaxed structures\n", "\n", - "The paper's energies of c and i are read off Fig. 6 (±0.02 and ±0.05 eV); the adsorption energy at a, the\n", - "island contraction and the ripple are from Sec. III.A, the isolated Ti atom energy it uses from Sec. II.B." + "One total-energy job on the platform per structure: the island cell and the adatom at a, c and i as MACE relaxed\n", + "them, and the isolated Ti atom, spin-polarized. A finished or running job of the same workflow on the same structure\n", + "is reused.\n", + "\n", + "### 7.1. Authenticate" ] }, { @@ -363,6 +390,252 @@ "id": "22", "metadata": {}, "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.auth import authenticate\n", + "\n", + "await authenticate()" + ] + }, + { + "cell_type": "markdown", + "id": "23", + "metadata": {}, + "source": [ + "### 7.2. Initialize the API client" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "24", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.api_client import APIClient\n", + "\n", + "client = APIClient.authenticate()" + ] + }, + { + "cell_type": "markdown", + "id": "25", + "metadata": {}, + "source": [ + "### 7.3. Select the account" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "26", + "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": "27", + "metadata": {}, + "source": [ + "### 7.4. Select the project" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "28", + "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": "29", + "metadata": {}, + "source": [ + "### 7.5. Save the structures to the platform" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "30", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.core.entity.material.api import get_or_create_material\n", + "\n", + "dft_materials = {label: material.clone() for label, material in\n", + " {\"slab_with_island\": slab_with_island_relaxed, **relaxed_materials_with_adatom}.items()}\n", + "for material in dft_materials.values():\n", + " material.name = f\"{material.name} (MACE-relaxed)\"\n", + "isolated_adatom.name = f\"{adatom_element} atom\"\n", + "dft_materials[\"isolated_adatom\"] = isolated_adatom\n", + "saved_materials = {label: get_or_create_material(client, dft_materials[label], ACCOUNT_ID) for label in DFT_MATERIAL_LABELS}" + ] + }, + { + "cell_type": "markdown", + "id": "31", + "metadata": {}, + "source": [ + "### 7.6. Set the DFT model" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "32", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.mode import ModelFactory\n", + "from mat3ra.standata.model_tree import ModelTreeStandata\n", + "\n", + "model_config = ModelTreeStandata.get_model_by_parameters(type=\"dft\", subtype=\"gga\", functional=FUNCTIONAL)\n", + "model_config[\"method\"] = {\"type\": \"pseudopotential\", \"subtype\": PSEUDOPOTENTIAL_TYPE}\n", + "model = ModelFactory.create(model_config)" + ] + }, + { + "cell_type": "markdown", + "id": "33", + "metadata": {}, + "source": [ + "### 7.7. Create the compute configuration" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "34", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.ide.compute import Compute\n", + "\n", + "cluster = next(cluster for cluster in client.clusters.list() if CLUSTER_NAME in cluster[\"hostname\"])\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}, time limit: {TIME_LIMIT}\")" + ] + }, + { + "cell_type": "markdown", + "id": "35", + "metadata": {}, + "source": [ + "### 7.8. Create and submit one total-energy job per structure" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.api.job import submit_jobs\n", + "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.workflow import apply_planewave_cutoffs, apply_scf_kgrid, patch_workflow_qe_input\n", + "from mat3ra.standata.workflows import WorkflowStandata\n", + "from mat3ra.wode.workflows import Workflow\n", + "\n", + "SCF_UNIT = \"pw_scf\"\n", + "total_energy_workflow_config = WorkflowStandata.filter_by_application(APPLICATION_NAME).get_by_name_first_match(\n", + " TOTAL_ENERGY_SEARCH_TERM\n", + ")\n", + "dft_job_ids, new_job_ids = {}, []\n", + "for label, material in saved_materials.items():\n", + " workflow = Workflow.create(total_energy_workflow_config)\n", + " workflow.subworkflows[0].model = model\n", + " apply_planewave_cutoffs(workflow, ECUTWFC, ECUTRHO, unit_name=SCF_UNIT)\n", + " apply_scf_kgrid(workflow, DFT_KGRID, material=dft_materials[label], unit_name=SCF_UNIT)\n", + " patch_workflow_qe_input(workflow, {\"system\": {**DFT_SYSTEM_SETTINGS, **DFT_SPIN_SETTINGS.get(label, {})}}, [SCF_UNIT])\n", + " job = find_job_for_material(client, material[\"_id\"], workflow.name, ACCOUNT_ID,\n", + " statuses=(\"submitted\", \"queued\", \"active\", \"finished\"), kgrid=DFT_KGRID)\n", + " if job is None:\n", + " job = create_job(api_client=client, materials=[material], workflow=workflow, project_id=project_id,\n", + " owner_id=ACCOUNT_ID, compute=compute.to_dict(), prefix=f\"{workflow.name} {material['name']}\")\n", + " new_job_ids.append(job[\"_id\"])\n", + " dft_job_ids[label] = job[\"_id\"]\n", + " print(f\"{label}: job {job['_id']}, {job['status']}\")\n", + "submit_jobs(client.jobs, new_job_ids)" + ] + }, + { + "cell_type": "markdown", + "id": "37", + "metadata": {}, + "source": [ + "### 7.9. Wait for the jobs to finish" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "38", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.api.job import wait_for_jobs_to_finish_async\n", + "\n", + "if dft_job_ids:\n", + " await wait_for_jobs_to_finish_async(client.jobs, list(dft_job_ids.values()), poll_interval=POLL_INTERVAL)" + ] + }, + { + "cell_type": "markdown", + "id": "39", + "metadata": {}, + "source": [ + "### 7.10. Read the total energies" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "40", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.notebooks_utils.core.entity.property.api import get_properties_for_job\n", + "\n", + "dft_energies = {label: get_properties_for_job(client, job_id, \"total_energy\")[0][\"value\"]\n", + " for label, job_id in dft_job_ids.items()}" + ] + }, + { + "cell_type": "markdown", + "id": "41", + "metadata": {}, + "source": [ + "## 8. Compare with the paper\n", + "### 8.1. Energies relative to a, adsorption energy at a, island relaxation\n", + "\n", + "The paper's energies of c and i are read off Fig. 6 (±0.02 and ±0.05 eV); the adsorption energy at a, the\n", + "island contraction and the ripple are from Sec. III.A, the isolated Ti atom energy it uses from Sec. II.B.\n", + "DFT takes the MACE geometries as they are, so it has no island contraction or ripple of its own." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "42", + "metadata": {}, + "outputs": [], "source": [ "# Fig. 6 upper panel, read off; b = 0.10 eV also Sec. III.C.1\n", "PAPER_FIG6 = {\"a\": 0.0, \"b\": 0.10, \"c\": -0.15, \"d\": -0.20, \"e\": -0.25, \"f\": -0.50, \"g\": -1.13, \"h\": -2.25, \"i\": -2.65}\n", @@ -372,31 +645,35 @@ "PAPER_RIPPLE = 0.19 # Sec. III.A, Fig. 2b\n", "\n", "relative_energies = {site: energy - energies[\"a\"] for site, energy in energies.items()}\n", + "mace_energies = {\"slab_with_island\": energy_slab_with_island, **energies, \"isolated_adatom\": energy_isolated_adatom}\n", + "dft_energies_or_nan = {label: dft_energies.get(label, np.nan) for label in mace_energies}\n", + "both = (mace_energies, dft_energies_or_nan)\n", "comparison = {\n", - " \"E(c) - E(a), eV\": (relative_energies[\"c\"], PAPER_FIG6[\"c\"]),\n", - " \"E(i) - E(a), eV\": (relative_energies[\"i\"], PAPER_FIG6[\"i\"]),\n", - " \"E_ads(a), eV\": (energies[\"a\"] - energy_slab_with_island - energy_isolated_adatom, PAPER_ADSORPTION_ENERGY),\n", - " \"E_Ti, isolated, eV\": (energy_isolated_adatom, PAPER_ISOLATED_ADATOM_ENERGY),\n", - " **{f\"{label}, %\": (island_contraction[label], PAPER_ISLAND_CONTRACTION[label]) for label in island_contraction},\n", - " \"Ripple, Å\": (ripple, PAPER_RIPPLE),\n", + " \"E(c) - E(a), eV\": [energy[\"c\"] - energy[\"a\"] for energy in both] + [PAPER_FIG6[\"c\"]],\n", + " \"E(i) - E(a), eV\": [energy[\"i\"] - energy[\"a\"] for energy in both] + [PAPER_FIG6[\"i\"]],\n", + " \"E_ads(a), eV\": [energy[\"a\"] - energy[\"slab_with_island\"] - energy[\"isolated_adatom\"] for energy in both]\n", + " + [PAPER_ADSORPTION_ENERGY],\n", + " \"E_Ti, isolated, eV\": [energy[\"isolated_adatom\"] for energy in both] + [PAPER_ISOLATED_ADATOM_ENERGY],\n", + " **{f\"{label}, %\": [island_contraction[label], np.nan, PAPER_ISLAND_CONTRACTION[label]] for label in island_contraction},\n", + " \"Ripple, Å\": [ripple, np.nan, PAPER_RIPPLE],\n", "}\n", - "print(f\"{'':<28}{'this notebook':>15}{'manuscript':>12}\")\n", - "for label, (computed, manuscript) in comparison.items():\n", - " print(f\"{label:<28}{computed:>15.3f}{manuscript:>12}\")" + "print(f\"{'':<28}{'MACE':>10}{'DFT':>10}{'manuscript':>12}\")\n", + "for label, (mace, dft, manuscript) in comparison.items():\n", + " print(f\"{label:<28}{mace:>10.3f}{dft:>10.3f}{manuscript:>12}\")" ] }, { "cell_type": "markdown", - "id": "23", + "id": "43", "metadata": {}, "source": [ - "### 7.2. Fig. 6" + "### 8.2. Fig. 6" ] }, { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "44", "metadata": {}, "outputs": [], "source": [ @@ -414,7 +691,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "45", "metadata": {}, "source": [ "## References\n", From 208d38664f56322b2c679a337ee5b52e7098fe5f Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 29 Oct 2026 12:45:57 -0700 Subject: [PATCH 16/31] Use GBRV ultrasoft pseudopotentials for the DFT energies Co-Authored-By: Claude Opus 5.5 --- ...fect_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index c2064a9ec..c0c1c932d 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -130,9 +130,9 @@ "APPLICATION_NAME = \"espresso\"\n", "TOTAL_ENERGY_SEARCH_TERM = \"total_energy.json\"\n", "FUNCTIONAL = \"pbe\"\n", - "PSEUDOPOTENTIAL_TYPE = \"paw\"\n", + "PSEUDOPOTENTIAL_TYPE = \"us\"\n", "ECUTWFC = 40 # Ry\n", - "ECUTRHO = 160 # Ry\n", + "ECUTRHO = 200 # Ry\n", "DFT_KGRID = [1, 1, 1] # Γ only, as in the manuscript\n", "\n", "CLUSTER_NAME = \"001\"\n", From 04d9d18474d952d2e0c55893f16335d7ceae9d30 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 29 Oct 2026 15:19:43 -0700 Subject: [PATCH 17/31] Do not write wavefunctions in the DFT jobs Co-Authored-By: Claude Opus 5.5 --- ...fect_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index c0c1c932d..e64706c93 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -126,6 +126,7 @@ "DFT_MATERIAL_LABELS = [\"slab_with_island\", \"a\", \"c\", \"i\", \"isolated_adatom\"]\n", "# The manuscript relaxed every structure with DFT (VASP, PAW, PW91); PW91 is set with \"input_dft\": \"pw91\" here.\n", "DFT_SYSTEM_SETTINGS = {\"smearing\": \"mv\", \"degauss\": 0.01} # Ry\n", + "DFT_CONTROL_SETTINGS = {\"disk_io\": \"none\"} # no wavefunction files on disk\n", "DFT_SPIN_SETTINGS = {\"isolated_adatom\": {\"nspin\": 2, \"starting_magnetization(1)\": 0.5}}\n", "APPLICATION_NAME = \"espresso\"\n", "TOTAL_ENERGY_SEARCH_TERM = \"total_energy.json\"\n", @@ -563,7 +564,8 @@ " workflow.subworkflows[0].model = model\n", " apply_planewave_cutoffs(workflow, ECUTWFC, ECUTRHO, unit_name=SCF_UNIT)\n", " apply_scf_kgrid(workflow, DFT_KGRID, material=dft_materials[label], unit_name=SCF_UNIT)\n", - " patch_workflow_qe_input(workflow, {\"system\": {**DFT_SYSTEM_SETTINGS, **DFT_SPIN_SETTINGS.get(label, {})}}, [SCF_UNIT])\n", + " system = {**DFT_SYSTEM_SETTINGS, **DFT_SPIN_SETTINGS.get(label, {})}\n", + " patch_workflow_qe_input(workflow, {\"control\": DFT_CONTROL_SETTINGS, \"system\": system}, [SCF_UNIT])\n", " job = find_job_for_material(client, material[\"_id\"], workflow.name, ACCOUNT_ID,\n", " statuses=(\"submitted\", \"queued\", \"active\", \"finished\"), kgrid=DFT_KGRID)\n", " if job is None:\n", From 8ae1ab17a83e1b016db43e0cefd3c465c0d5b45e Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 29 Oct 2026 16:21:10 -0700 Subject: [PATCH 18/31] Run the DFT energies on the OFplus queue Co-Authored-By: Claude Opus 5.5 --- ...defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index e64706c93..64b22903a 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -137,7 +137,7 @@ "DFT_KGRID = [1, 1, 1] # Γ only, as in the manuscript\n", "\n", "CLUSTER_NAME = \"001\"\n", - "QUEUE_NAME = QueueName.OF\n", + "QUEUE_NAME = QueueName.OFplus\n", "PPN = 36\n", "TIME_LIMIT = \"50:00:00\"\n", "POLL_INTERVAL = 600 # seconds" From af94c710ff65ec19983d875c64760e536fe26966 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 29 Oct 2026 16:33:36 -0700 Subject: [PATCH 19/31] Run the DFT energies within 24 hours Co-Authored-By: Claude Opus 5.5 --- ...defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index 64b22903a..eec0518fc 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -139,7 +139,7 @@ "CLUSTER_NAME = \"001\"\n", "QUEUE_NAME = QueueName.OFplus\n", "PPN = 36\n", - "TIME_LIMIT = \"50:00:00\"\n", + "TIME_LIMIT = \"24:00:00\"\n", "POLL_INTERVAL = 600 # seconds" ] }, From 265f79a7c864f70e0d1e1ba50b48f773825e7533 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 30 Oct 2026 21:25:39 -0700 Subject: [PATCH 20/31] Apply review of the DFT section Co-Authored-By: Claude Opus 5.5 --- ...m_island_titanium_nitride_SIMULATION.ipynb | 168 +++++++++++------- 1 file changed, 105 insertions(+), 63 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index eec0518fc..c834143d8 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -5,7 +5,7 @@ "id": "0", "metadata": {}, "source": [ - "# Ti Adatom Descent on a 5×5 TiN Island (MACE)\n", + "# Ti Adatom Descent on a 5×5 TiN Island (MACE and DFT)\n", "\n", "> **D. G. Sangiovanni, A. B. Mei, D. Edström, L. Hultman, V. Chirita, I. Petrov, and J. E. Greene**,\n", "> \"Effects of surface vibrations on interlayer mass transport: Ab initio molecular dynamics investigation of Ti\n", @@ -17,15 +17,15 @@ "next to its edge; **c**, atop the edge N atom; **i**, atop the terrace N atom in front of the edge, the site\n", "that extends the island. The energies of c and i relative to a, and the adsorption energy at a, are compared\n", "with the paper's. The paper computed them with DFT (GGA); here every relaxation uses the\n", - "[MACE-MP-0](https://github.com/ACEsuit/mace) machine-learned force field with the D3 dispersion correction. DFT (PBE) total energies of the MACE-relaxed structures, computed on\n", - "the platform, are printed beside MACE's.\n", + "[MACE-MP-0](https://github.com/ACEsuit/mace) machine-learned force field with the D3 dispersion correction.\n", + "DFT (PBE) total energies of the MACE-relaxed structures, computed on the platform, are printed beside MACE's.\n", "\n", "The four relaxations are MACE runs on 457 and 458 atoms, meant to be executed natively.\n", "\n", "

Usage

\n", "\n", "1. Create the materials in the [structure notebook](defect_point_adatom_island_titanium_nitride.ipynb), which saves the island cell and the three adatom cells to the `uploads` folder.\n", - "1. Set the material names and parameters in cells 1.2-1.3 (or use the defaults).\n", + "1. Set the material names and parameters in cells 1.2-1.5 (or use the defaults).\n", "1. Run natively: `pip install \".[all]\" mace-torch torch-dftd`. In JupyterLite the install and the calculator run, but the first force call on the 457-atom cell exceeds the browser's memory (a 0.76 GB tensor), so the relaxations run natively; the browser also has no torch-dftd, so D3 is off there.\n", "1. Click \"Run\" > \"Run All\" to run all cells.\n", "1. Wait for the DFT jobs to finish.\n", @@ -108,8 +108,6 @@ "metadata": {}, "outputs": [], "source": [ - "from mat3ra.ide.compute import QueueName\n", - "\n", "ORGANIZATION_NAME = None\n", "FOLDER = \"./uploads\"\n", "\n", @@ -122,19 +120,62 @@ "FMAX = 0.02 # eV/Å\n", "MAX_STEPS = 1000\n", "\n", - "# DFT total energies of the MACE-relaxed structures; an empty list skips the platform jobs\n", - "DFT_MATERIAL_LABELS = [\"slab_with_island\", \"a\", \"c\", \"i\", \"isolated_adatom\"]\n", - "# The manuscript relaxed every structure with DFT (VASP, PAW, PW91); PW91 is set with \"input_dft\": \"pw91\" here.\n", - "DFT_SYSTEM_SETTINGS = {\"smearing\": \"mv\", \"degauss\": 0.01} # Ry\n", - "DFT_CONTROL_SETTINGS = {\"disk_io\": \"none\"} # no wavefunction files on disk\n", - "DFT_SPIN_SETTINGS = {\"isolated_adatom\": {\"nspin\": 2, \"starting_magnetization(1)\": 0.5}}\n", + "# DFT total energies of the MACE-relaxed structures, one platform job each; an empty list skips the platform jobs.\n", + "# The other structures can be added one at a time, each after the previous job has finished.\n", + "DFT_MATERIAL_LABELS = [\n", + " \"slab_with_island\",\n", + " # \"a\",\n", + " # \"c\",\n", + " # \"i\",\n", + " # \"isolated_adatom\",\n", + "]" + ] + }, + { + "cell_type": "markdown", + "id": "7", + "metadata": {}, + "source": [ + "### 1.4. DFT model parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "8", + "metadata": {}, + "outputs": [], + "source": [ + "# manuscript: VASP, every structure relaxed with DFT; here DFT total energies of the MACE-relaxed structures\n", "APPLICATION_NAME = \"espresso\"\n", "TOTAL_ENERGY_SEARCH_TERM = \"total_energy.json\"\n", + "# manuscript: GGA of Perdew, Burke and Wang (PW91); for PW91 add \"input_dft\": \"pw91\" to DFT_SYSTEM_SETTINGS\n", "FUNCTIONAL = \"pbe\"\n", - "PSEUDOPOTENTIAL_TYPE = \"us\"\n", - "ECUTWFC = 40 # Ry\n", + "PSEUDOPOTENTIAL_TYPE = \"us\" # manuscript: PAW; ours GBRV ultrasoft\n", + "ECUTWFC = 40 # Ry; manuscript: 400 eV for the static calculations, Sec. II.B\n", "ECUTRHO = 200 # Ry\n", - "DFT_KGRID = [1, 1, 1] # Γ only, as in the manuscript\n", + "DFT_KGRID = [1, 1, 1] # manuscript: Γ only\n", + "DFT_SYSTEM_SETTINGS = {\"smearing\": \"mv\", \"degauss\": 0.01} # Ry\n", + "DFT_CONTROL_SETTINGS = {\"disk_io\": \"none\"} # no wavefunction files on disk\n", + "DFT_SPIN_SETTINGS_BY_LABEL = {\"isolated_adatom\": {\"nspin\": 2, \"tot_magnetization\": 2}} # two unpaired Ti d electrons" + ] + }, + { + "cell_type": "markdown", + "id": "9", + "metadata": {}, + "source": [ + "### 1.5. Compute parameters" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "10", + "metadata": {}, + "outputs": [], + "source": [ + "from mat3ra.ide.compute import QueueName\n", "\n", "CLUSTER_NAME = \"001\"\n", "QUEUE_NAME = QueueName.OFplus\n", @@ -145,7 +186,7 @@ }, { "cell_type": "markdown", - "id": "7", + "id": "11", "metadata": {}, "source": [ "## 2. Load the materials" @@ -154,7 +195,7 @@ { "cell_type": "code", "execution_count": null, - "id": "8", + "id": "12", "metadata": {}, "outputs": [], "source": [ @@ -170,7 +211,7 @@ }, { "cell_type": "markdown", - "id": "9", + "id": "13", "metadata": {}, "source": [ "## 3. Build the MACE calculator" @@ -179,7 +220,7 @@ { "cell_type": "code", "execution_count": null, - "id": "10", + "id": "14", "metadata": {}, "outputs": [], "source": [ @@ -206,7 +247,7 @@ }, { "cell_type": "markdown", - "id": "11", + "id": "15", "metadata": {}, "source": [ "## 4. Relax the island cell\n", @@ -218,7 +259,7 @@ { "cell_type": "code", "execution_count": null, - "id": "12", + "id": "16", "metadata": {}, "outputs": [], "source": [ @@ -234,7 +275,7 @@ }, { "cell_type": "markdown", - "id": "13", + "id": "17", "metadata": {}, "source": [ "### 4.2. Island contraction and surface ripple\n", @@ -247,7 +288,7 @@ { "cell_type": "code", "execution_count": null, - "id": "14", + "id": "18", "metadata": {}, "outputs": [], "source": [ @@ -286,7 +327,7 @@ }, { "cell_type": "markdown", - "id": "15", + "id": "19", "metadata": {}, "source": [ "## 5. Relax the adatom at a, c and i\n", @@ -298,7 +339,7 @@ { "cell_type": "code", "execution_count": null, - "id": "16", + "id": "20", "metadata": {}, "outputs": [], "source": [ @@ -319,7 +360,7 @@ }, { "cell_type": "markdown", - "id": "17", + "id": "21", "metadata": {}, "source": [ "### 5.1. Visualize each site as built and relaxed\n", @@ -330,7 +371,7 @@ { "cell_type": "code", "execution_count": null, - "id": "18", + "id": "22", "metadata": {}, "outputs": [], "source": [ @@ -343,7 +384,7 @@ }, { "cell_type": "markdown", - "id": "19", + "id": "23", "metadata": {}, "source": [ "## 6. Isolated Ti atom\n", @@ -356,7 +397,7 @@ { "cell_type": "code", "execution_count": null, - "id": "20", + "id": "24", "metadata": {}, "outputs": [], "source": [ @@ -373,7 +414,7 @@ }, { "cell_type": "markdown", - "id": "21", + "id": "25", "metadata": {}, "source": [ "## 7. DFT total energies of the MACE-relaxed structures\n", @@ -388,7 +429,7 @@ { "cell_type": "code", "execution_count": null, - "id": "22", + "id": "26", "metadata": {}, "outputs": [], "source": [ @@ -399,7 +440,7 @@ }, { "cell_type": "markdown", - "id": "23", + "id": "27", "metadata": {}, "source": [ "### 7.2. Initialize the API client" @@ -408,7 +449,7 @@ { "cell_type": "code", "execution_count": null, - "id": "24", + "id": "28", "metadata": {}, "outputs": [], "source": [ @@ -419,7 +460,7 @@ }, { "cell_type": "markdown", - "id": "25", + "id": "29", "metadata": {}, "source": [ "### 7.3. Select the account" @@ -428,7 +469,7 @@ { "cell_type": "code", "execution_count": null, - "id": "26", + "id": "30", "metadata": {}, "outputs": [], "source": [ @@ -443,7 +484,7 @@ }, { "cell_type": "markdown", - "id": "27", + "id": "31", "metadata": {}, "source": [ "### 7.4. Select the project" @@ -452,7 +493,7 @@ { "cell_type": "code", "execution_count": null, - "id": "28", + "id": "32", "metadata": {}, "outputs": [], "source": [ @@ -463,7 +504,7 @@ }, { "cell_type": "markdown", - "id": "29", + "id": "33", "metadata": {}, "source": [ "### 7.5. Save the structures to the platform" @@ -472,7 +513,7 @@ { "cell_type": "code", "execution_count": null, - "id": "30", + "id": "34", "metadata": {}, "outputs": [], "source": [ @@ -489,7 +530,7 @@ }, { "cell_type": "markdown", - "id": "31", + "id": "35", "metadata": {}, "source": [ "### 7.6. Set the DFT model" @@ -498,7 +539,7 @@ { "cell_type": "code", "execution_count": null, - "id": "32", + "id": "36", "metadata": {}, "outputs": [], "source": [ @@ -512,7 +553,7 @@ }, { "cell_type": "markdown", - "id": "33", + "id": "37", "metadata": {}, "source": [ "### 7.7. Create the compute configuration" @@ -521,20 +562,20 @@ { "cell_type": "code", "execution_count": null, - "id": "34", + "id": "38", "metadata": {}, "outputs": [], "source": [ "from mat3ra.ide.compute import Compute\n", "\n", - "cluster = next(cluster for cluster in client.clusters.list() if CLUSTER_NAME in cluster[\"hostname\"])\n", + "cluster = next(cluster for cluster in client.clusters.list() if not CLUSTER_NAME or CLUSTER_NAME in cluster[\"hostname\"])\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}, time limit: {TIME_LIMIT}\")" ] }, { "cell_type": "markdown", - "id": "35", + "id": "39", "metadata": {}, "source": [ "### 7.8. Create and submit one total-energy job per structure" @@ -543,7 +584,7 @@ { "cell_type": "code", "execution_count": null, - "id": "36", + "id": "40", "metadata": {}, "outputs": [], "source": [ @@ -564,7 +605,7 @@ " workflow.subworkflows[0].model = model\n", " apply_planewave_cutoffs(workflow, ECUTWFC, ECUTRHO, unit_name=SCF_UNIT)\n", " apply_scf_kgrid(workflow, DFT_KGRID, material=dft_materials[label], unit_name=SCF_UNIT)\n", - " system = {**DFT_SYSTEM_SETTINGS, **DFT_SPIN_SETTINGS.get(label, {})}\n", + " system = {**DFT_SYSTEM_SETTINGS, **DFT_SPIN_SETTINGS_BY_LABEL.get(label, {})}\n", " patch_workflow_qe_input(workflow, {\"control\": DFT_CONTROL_SETTINGS, \"system\": system}, [SCF_UNIT])\n", " job = find_job_for_material(client, material[\"_id\"], workflow.name, ACCOUNT_ID,\n", " statuses=(\"submitted\", \"queued\", \"active\", \"finished\"), kgrid=DFT_KGRID)\n", @@ -579,7 +620,7 @@ }, { "cell_type": "markdown", - "id": "37", + "id": "41", "metadata": {}, "source": [ "### 7.9. Wait for the jobs to finish" @@ -588,7 +629,7 @@ { "cell_type": "code", "execution_count": null, - "id": "38", + "id": "42", "metadata": {}, "outputs": [], "source": [ @@ -600,7 +641,7 @@ }, { "cell_type": "markdown", - "id": "39", + "id": "43", "metadata": {}, "source": [ "### 7.10. Read the total energies" @@ -609,7 +650,7 @@ { "cell_type": "code", "execution_count": null, - "id": "40", + "id": "44", "metadata": {}, "outputs": [], "source": [ @@ -621,7 +662,7 @@ }, { "cell_type": "markdown", - "id": "41", + "id": "45", "metadata": {}, "source": [ "## 8. Compare with the paper\n", @@ -635,7 +676,7 @@ { "cell_type": "code", "execution_count": null, - "id": "42", + "id": "46", "metadata": {}, "outputs": [], "source": [ @@ -649,24 +690,25 @@ "relative_energies = {site: energy - energies[\"a\"] for site, energy in energies.items()}\n", "mace_energies = {\"slab_with_island\": energy_slab_with_island, **energies, \"isolated_adatom\": energy_isolated_adatom}\n", "dft_energies_or_nan = {label: dft_energies.get(label, np.nan) for label in mace_energies}\n", - "both = (mace_energies, dft_energies_or_nan)\n", + "energies_by_method = {\"MACE\": mace_energies, \"DFT\": dft_energies_or_nan}\n", "comparison = {\n", - " \"E(c) - E(a), eV\": [energy[\"c\"] - energy[\"a\"] for energy in both] + [PAPER_FIG6[\"c\"]],\n", - " \"E(i) - E(a), eV\": [energy[\"i\"] - energy[\"a\"] for energy in both] + [PAPER_FIG6[\"i\"]],\n", - " \"E_ads(a), eV\": [energy[\"a\"] - energy[\"slab_with_island\"] - energy[\"isolated_adatom\"] for energy in both]\n", - " + [PAPER_ADSORPTION_ENERGY],\n", - " \"E_Ti, isolated, eV\": [energy[\"isolated_adatom\"] for energy in both] + [PAPER_ISOLATED_ADATOM_ENERGY],\n", + " \"E(c) - E(a), eV\": [energy[\"c\"] - energy[\"a\"] for energy in energies_by_method.values()] + [PAPER_FIG6[\"c\"]],\n", + " \"E(i) - E(a), eV\": [energy[\"i\"] - energy[\"a\"] for energy in energies_by_method.values()] + [PAPER_FIG6[\"i\"]],\n", + " \"E_ads(a), eV\": [energy[\"a\"] - energy[\"slab_with_island\"] - energy[\"isolated_adatom\"]\n", + " for energy in energies_by_method.values()] + [PAPER_ADSORPTION_ENERGY],\n", + " \"E_Ti, isolated, eV\": [energy_isolated_adatom, np.nan, PAPER_ISOLATED_ADATOM_ENERGY],\n", " **{f\"{label}, %\": [island_contraction[label], np.nan, PAPER_ISLAND_CONTRACTION[label]] for label in island_contraction},\n", " \"Ripple, Å\": [ripple, np.nan, PAPER_RIPPLE],\n", "}\n", "print(f\"{'':<28}{'MACE':>10}{'DFT':>10}{'manuscript':>12}\")\n", "for label, (mace, dft, manuscript) in comparison.items():\n", - " print(f\"{label:<28}{mace:>10.3f}{dft:>10.3f}{manuscript:>12}\")" + " dft_cell = \"—\" if np.isnan(dft) else f\"{dft:.3f}\"\n", + " print(f\"{label:<28}{mace:>10.3f}{dft_cell:>10}{manuscript:>12}\")" ] }, { "cell_type": "markdown", - "id": "43", + "id": "47", "metadata": {}, "source": [ "### 8.2. Fig. 6" @@ -675,7 +717,7 @@ { "cell_type": "code", "execution_count": null, - "id": "44", + "id": "48", "metadata": {}, "outputs": [], "source": [ @@ -693,7 +735,7 @@ }, { "cell_type": "markdown", - "id": "45", + "id": "49", "metadata": {}, "source": [ "## References\n", From 8c70d4fd68de7a7a15858b18ab78158f6540d7b2 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Sun, 1 Nov 2026 14:00:02 -0800 Subject: [PATCH 21/31] Converge the DFT energies to 1e-4 Ry with local-TF mixing Co-Authored-By: Claude Opus 5.5 --- ...ct_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index c834143d8..4e3fb785b 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -157,6 +157,8 @@ "DFT_KGRID = [1, 1, 1] # manuscript: Γ only\n", "DFT_SYSTEM_SETTINGS = {\"smearing\": \"mv\", \"degauss\": 0.01} # Ry\n", "DFT_CONTROL_SETTINGS = {\"disk_io\": \"none\"} # no wavefunction files on disk\n", + "# conv_thr 1e-4 Ry ≈ 1.4 meV on the total energy; local-TF mixing for a slab with vacuum\n", + "DFT_ELECTRONS_SETTINGS = {\"conv_thr\": 1e-4, \"mixing_mode\": \"local-TF\", \"mixing_beta\": 0.2}\n", "DFT_SPIN_SETTINGS_BY_LABEL = {\"isolated_adatom\": {\"nspin\": 2, \"tot_magnetization\": 2}} # two unpaired Ti d electrons" ] }, @@ -606,7 +608,9 @@ " apply_planewave_cutoffs(workflow, ECUTWFC, ECUTRHO, unit_name=SCF_UNIT)\n", " apply_scf_kgrid(workflow, DFT_KGRID, material=dft_materials[label], unit_name=SCF_UNIT)\n", " system = {**DFT_SYSTEM_SETTINGS, **DFT_SPIN_SETTINGS_BY_LABEL.get(label, {})}\n", - " patch_workflow_qe_input(workflow, {\"control\": DFT_CONTROL_SETTINGS, \"system\": system}, [SCF_UNIT])\n", + " patch_workflow_qe_input(\n", + " workflow, {\"control\": DFT_CONTROL_SETTINGS, \"system\": system, \"electrons\": DFT_ELECTRONS_SETTINGS}, [SCF_UNIT]\n", + " )\n", " job = find_job_for_material(client, material[\"_id\"], workflow.name, ACCOUNT_ID,\n", " statuses=(\"submitted\", \"queued\", \"active\", \"finished\"), kgrid=DFT_KGRID)\n", " if job is None:\n", From 3af706a99e3677cc4c8fd109fa7cacf510f35539 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Mon, 2 Nov 2026 22:59:17 -0800 Subject: [PATCH 22/31] Choose the cell size, freeze the bottom slab plane and relax with DFT Co-Authored-By: Claude Opus 5.5 --- ...point_adatom_island_titanium_nitride.ipynb | 36 +++++--- ...m_island_titanium_nitride_SIMULATION.ipynb | 88 +++++++++++-------- 2 files changed, 73 insertions(+), 51 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb index 36345d788..c4158656e 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb @@ -30,7 +30,11 @@ "\n", "Each entry of `ADATOM_SITES` places one adatom relative to the N atom with the smaller x in the island's\n", "edge row at the largest y, in units of the Ti–N site spacing d = a/2, with Δz = 0 the island plane; to add a\n", - "site, add an entry under a new letter to both `ADATOM_SITES` and `ADATOM_MATERIAL_NAMES`." + "site, add an entry under a new letter to both `ADATOM_SITES` and `ADATOM_MATERIAL_NAMES`.\n", + "\n", + "`CELL_SIZE` picks the cell: `\"12x12x3\"`, the manuscript's (12×12 sites, 3 slab planes, 457 atoms), or `\"10x10x2\"`\n", + "(10×10 sites, 2 slab planes, 225 atoms). With the bottom slab plane frozen, MACE gives E(c) − E(a) = 0.315 and 0.311 eV,\n", + "E(i) − E(a) = −2.247 and −2.109 eV, and E_ads(a) = −3.015 and −3.067 eV on the two." ] }, { @@ -42,16 +46,19 @@ "source": [ "MATERIAL_NAME = \"Titanium Nitride\"\n", "MILLER_INDICES = (0, 0, 1)\n", - "# Thickness counts conventional layers of two (001) planes; the bottom plane is removed after the\n", - "# island is added, leaving the paper's three planes.\n", + "# Thickness counts conventional layers of two (001) planes; bottom planes are removed after the island is added.\n", "SLAB_THICKNESS = 2\n", "VACUUM = 15.3 # Angstrom\n", - "XY_SUPERCELL_MATRIX = [[6, 0], [0, 6]]\n", - "\n", "NUMBER_OF_ADDED_LAYERS = 0.5\n", - "# x and y minima one site (1/12 of the 6×6 cell) apart put Ti atoms at the island corners\n", - "ISLAND_MIN_COORDINATE = [0.3233, 0.24, 0] # crystal coordinates\n", - "ISLAND_MAX_COORDINATE = [0.7233, 0.64, 1]\n", + "\n", + "# Cell sizes as (xy supercell, island box minimum and maximum in crystal coordinates, bottom planes removed);\n", + "# x and y minima one site apart put Ti atoms at the island corners\n", + "CELL_SIZES = {\n", + " \"12x12x3\": ([[6, 0], [0, 6]], [0.3233, 0.24, 0], [0.7233, 0.64, 1], 1),\n", + " \"10x10x2\": ([[5, 0], [0, 5]], [0.29, 0.19, 0], [0.75, 0.65, 1], 2),\n", + "}\n", + "CELL_SIZE = \"12x12x3\"\n", + "XY_SUPERCELL_MATRIX, ISLAND_MIN_COORDINATE, ISLAND_MAX_COORDINATE, PLANES_REMOVED = CELL_SIZES[CELL_SIZE]\n", "\n", "ADATOM_ELEMENT = \"Ti\"\n", "# Adatom sites as (Δx, Δy, Δz) from the island's edge N atom, in units of the Ti–N site spacing;\n", @@ -62,11 +69,11 @@ " \"i\": (0, 1, 0), # atop the terrace N in front of the edge\n", "}\n", "\n", - "ISLAND_MATERIAL_NAME = \"TiN(001) 12x12x3 island 5x5\"\n", + "ISLAND_MATERIAL_NAME = f\"TiN(001) {CELL_SIZE} island 5x5\"\n", "ADATOM_MATERIAL_NAMES = {\n", - " \"a\": \"TiN(001) 12x12x3 island 5x5 + Ti a (FFH island)\",\n", - " \"c\": \"TiN(001) 12x12x3 island 5x5 + Ti c (atop-N edge)\",\n", - " \"i\": \"TiN(001) 12x12x3 island 5x5 + Ti i (atop-N terrace)\",\n", + " \"a\": f\"{ISLAND_MATERIAL_NAME} + Ti a (FFH island)\",\n", + " \"c\": f\"{ISLAND_MATERIAL_NAME} + Ti c (atop-N edge)\",\n", + " \"i\": f\"{ISLAND_MATERIAL_NAME} + Ti i (atop-N terrace)\",\n", "}" ] }, @@ -173,8 +180,9 @@ " number_of_added_layers=NUMBER_OF_ADDED_LAYERS,\n", " use_cartesian_coordinates=False,\n", ")\n", - "bottom_plane = get_atom_indices_by_layer(slab_with_island)[0]\n", - "slab_with_island = filter_by_ids(slab_with_island, ids=bottom_plane, invert=True, reset_ids=True)\n", + "for _ in range(PLANES_REMOVED):\n", + " bottom_plane = get_atom_indices_by_layer(slab_with_island)[0]\n", + " slab_with_island = filter_by_ids(slab_with_island, ids=bottom_plane, invert=True, reset_ids=True)\n", "slab_with_island = remove_vacuum(slab_with_island, fixed_padding=VACUUM)\n", "slab_with_island.name = ISLAND_MATERIAL_NAME\n", "\n", diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index 4e3fb785b..0270c70c7 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -18,13 +18,13 @@ "that extends the island. The energies of c and i relative to a, and the adsorption energy at a, are compared\n", "with the paper's. The paper computed them with DFT (GGA); here every relaxation uses the\n", "[MACE-MP-0](https://github.com/ACEsuit/mace) machine-learned force field with the D3 dispersion correction.\n", - "DFT (PBE) total energies of the MACE-relaxed structures, computed on the platform, are printed beside MACE's.\n", + "DFT (PBE) relaxations on the platform, started from the MACE-relaxed structures, give the energies printed beside MACE's.\n", "\n", - "The four relaxations are MACE runs on 457 and 458 atoms, meant to be executed natively.\n", + "The four relaxations are MACE runs on 457 and 458 atoms in the manuscript's cell, meant to be executed natively.\n", "\n", "

Usage

\n", "\n", - "1. Create the materials in the [structure notebook](defect_point_adatom_island_titanium_nitride.ipynb), which saves the island cell and the three adatom cells to the `uploads` folder.\n", + "1. Create the materials in the [structure notebook](defect_point_adatom_island_titanium_nitride.ipynb) with the same `CELL_SIZE`, which saves the island cell and the three adatom cells to the `uploads` folder.\n", "1. Set the material names and parameters in cells 1.2-1.5 (or use the defaults).\n", "1. Run natively: `pip install \".[all]\" mace-torch torch-dftd`. In JupyterLite the install and the calculator run, but the first force call on the 457-atom cell exceeds the browser's memory (a 0.76 GB tensor), so the relaxations run natively; the browser also has no torch-dftd, so D3 is off there.\n", "1. Click \"Run\" > \"Run All\" to run all cells.\n", @@ -39,7 +39,7 @@ "1. Relax the island cell; measure the island contraction and the surface ripple.\n", "1. Relax the adatom at a, c and i.\n", "1. Compute the energy of an isolated Ti atom.\n", - "1. Compute DFT total energies of the MACE-relaxed structures and of the isolated Ti atom on the platform.\n", + "1. Relax the MACE-relaxed structures and the isolated Ti atom with DFT on the platform.\n", "1. Compare with the paper: energies relative to a, the adsorption energy at a, and Fig. 6." ] }, @@ -84,12 +84,13 @@ "metadata": {}, "outputs": [], "source": [ - "# Names saved by defect_point_adatom_island_titanium_nitride.ipynb.\n", - "ISLAND_MATERIAL_NAME = \"TiN(001) 12x12x3 island 5x5\"\n", + "# Names saved by defect_point_adatom_island_titanium_nitride.ipynb, with the CELL_SIZE set there.\n", + "CELL_SIZE = \"12x12x3\"\n", + "ISLAND_MATERIAL_NAME = f\"TiN(001) {CELL_SIZE} island 5x5\"\n", "ADATOM_MATERIAL_NAMES = {\n", - " \"a\": \"TiN(001) 12x12x3 island 5x5 + Ti a (FFH island)\",\n", - " \"c\": \"TiN(001) 12x12x3 island 5x5 + Ti c (atop-N edge)\",\n", - " \"i\": \"TiN(001) 12x12x3 island 5x5 + Ti i (atop-N terrace)\",\n", + " \"a\": f\"{ISLAND_MATERIAL_NAME} + Ti a (FFH island)\",\n", + " \"c\": f\"{ISLAND_MATERIAL_NAME} + Ti c (atop-N edge)\",\n", + " \"i\": f\"{ISLAND_MATERIAL_NAME} + Ti i (atop-N terrace)\",\n", "}" ] }, @@ -119,8 +120,9 @@ "\n", "FMAX = 0.02 # eV/Å\n", "MAX_STEPS = 1000\n", + "FROZEN_SLAB_PLANES = 1 # bottom slab planes held fixed in the MACE and DFT relaxations\n", "\n", - "# DFT total energies of the MACE-relaxed structures, one platform job each; an empty list skips the platform jobs.\n", + "# DFT relaxations of the MACE-relaxed structures, one platform job each; an empty list skips the platform jobs.\n", "# The other structures can be added one at a time, each after the previous job has finished.\n", "DFT_MATERIAL_LABELS = [\n", " \"slab_with_island\",\n", @@ -146,9 +148,9 @@ "metadata": {}, "outputs": [], "source": [ - "# manuscript: VASP, every structure relaxed with DFT; here DFT total energies of the MACE-relaxed structures\n", + "# manuscript: VASP, every structure relaxed with DFT; here the DFT relaxation starts from the MACE-relaxed structure\n", "APPLICATION_NAME = \"espresso\"\n", - "TOTAL_ENERGY_SEARCH_TERM = \"total_energy.json\"\n", + "RELAXATION_SEARCH_TERM = \"fixed_cell_relaxation.json\"\n", "# manuscript: GGA of Perdew, Burke and Wang (PW91); for PW91 add \"input_dft\": \"pw91\" to DFT_SYSTEM_SETTINGS\n", "FUNCTIONAL = \"pbe\"\n", "PSEUDOPOTENTIAL_TYPE = \"us\" # manuscript: PAW; ours GBRV ultrasoft\n", @@ -156,9 +158,12 @@ "ECUTRHO = 200 # Ry\n", "DFT_KGRID = [1, 1, 1] # manuscript: Γ only\n", "DFT_SYSTEM_SETTINGS = {\"smearing\": \"mv\", \"degauss\": 0.01} # Ry\n", - "DFT_CONTROL_SETTINGS = {\"disk_io\": \"none\"} # no wavefunction files on disk\n", + "MAXIMUM_IONIC_STEPS = 4 # per job, so that it ends within TIME_LIMIT; the next job continues from its last structure\n", + "DAVIDSON_SUBSPACE_DIMENSION = 2 # half the default 4: less memory per process\n", + "DFT_CONTROL_SETTINGS = {\"disk_io\": \"none\", \"nstep\": MAXIMUM_IONIC_STEPS} # no wavefunction files on disk\n", "# conv_thr 1e-4 Ry ≈ 1.4 meV on the total energy; local-TF mixing for a slab with vacuum\n", - "DFT_ELECTRONS_SETTINGS = {\"conv_thr\": 1e-4, \"mixing_mode\": \"local-TF\", \"mixing_beta\": 0.2}\n", + "DFT_ELECTRONS_SETTINGS = {\"conv_thr\": 1e-4, \"mixing_mode\": \"local-TF\", \"mixing_beta\": 0.2,\n", + " \"diago_david_ndim\": DAVIDSON_SUBSPACE_DIMENSION}\n", "DFT_SPIN_SETTINGS_BY_LABEL = {\"isolated_adatom\": {\"nspin\": 2, \"tot_magnetization\": 2}} # two unpaired Ti d electrons" ] }, @@ -180,9 +185,9 @@ "from mat3ra.ide.compute import QueueName\n", "\n", "CLUSTER_NAME = \"001\"\n", - "QUEUE_NAME = QueueName.OFplus\n", + "QUEUE_NAME = QueueName.OF\n", "PPN = 36\n", - "TIME_LIMIT = \"24:00:00\"\n", + "TIME_LIMIT = \"08:00:00\"\n", "POLL_INTERVAL = 600 # seconds" ] }, @@ -255,7 +260,7 @@ "## 4. Relax the island cell\n", "### 4.1. Relax\n", "\n", - "Every atom is free, as in the paper's 0 K relaxations." + "The bottom slab plane is held fixed, as in the paper's AIMD runs (Sec. II.A); every other atom is free." ] }, { @@ -266,11 +271,15 @@ "outputs": [], "source": [ "import numpy as np\n", + "from mat3ra.made.tools.analyze.other import get_atom_indices_by_layer\n", "from mat3ra.made.tools.calculate import calculate_total_energy\n", "from mat3ra.made.tools.convert import to_ase\n", "from mat3ra.notebooks_utils.workflows.relaxation import relax_material\n", "\n", - "slab_with_island_relaxed = relax_material(slab_with_island, calculator, fmax=FMAX, max_steps=MAX_STEPS)\n", + "frozen_atom_indices = [index for plane in get_atom_indices_by_layer(slab_with_island)[:FROZEN_SLAB_PLANES]\n", + " for index in plane]\n", + "slab_with_island_relaxed = relax_material(slab_with_island, calculator, fmax=FMAX, max_steps=MAX_STEPS,\n", + " fixed_atom_indices=frozen_atom_indices)\n", "energy_slab_with_island = calculate_total_energy(slab_with_island_relaxed, calculator)\n", "print(f\"E(slab + island) = {energy_slab_with_island:.3f} eV\")" ] @@ -294,8 +303,6 @@ "metadata": {}, "outputs": [], "source": [ - "from mat3ra.made.tools.analyze.other import get_atom_indices_by_layer\n", - "\n", "built, relaxed = to_ase(slab_with_island), to_ase(slab_with_island_relaxed)\n", "symbols = np.array(built.get_chemical_symbols())\n", "planes = get_atom_indices_by_layer(slab_with_island)\n", @@ -348,7 +355,8 @@ "energies = {}\n", "relaxed_materials_with_adatom = {}\n", "for site, material in materials_with_adatom.items():\n", - " material_relaxed = relax_material(material, calculator, fmax=FMAX, max_steps=MAX_STEPS)\n", + " material_relaxed = relax_material(material, calculator, fmax=FMAX, max_steps=MAX_STEPS,\n", + " fixed_atom_indices=frozen_atom_indices)\n", " relaxed_materials_with_adatom[site] = material_relaxed\n", " energies[site] = calculate_total_energy(material_relaxed, calculator)\n", "\n", @@ -419,11 +427,11 @@ "id": "25", "metadata": {}, "source": [ - "## 7. DFT total energies of the MACE-relaxed structures\n", + "## 7. DFT relaxation of the MACE-relaxed structures\n", "\n", - "One total-energy job on the platform per structure: the island cell and the adatom at a, c and i as MACE relaxed\n", - "them, and the isolated Ti atom, spin-polarized. A finished or running job of the same workflow on the same structure\n", - "is reused.\n", + "One fixed-cell relaxation job on the platform per structure, starting from the island cell and the adatom at a, c and\n", + "i as MACE relaxed them, with the same bottom slab plane fixed; and one for the isolated Ti atom, spin-polarized. A\n", + "finished or running job of the same workflow on the same structure is reused.\n", "\n", "### 7.1. Authenticate" ] @@ -519,12 +527,15 @@ "metadata": {}, "outputs": [], "source": [ + "from mat3ra.code.array_with_ids import ArrayWithIds\n", "from mat3ra.notebooks_utils.core.entity.material.api import get_or_create_material\n", "\n", "dft_materials = {label: material.clone() for label, material in\n", " {\"slab_with_island\": slab_with_island_relaxed, **relaxed_materials_with_adatom}.items()}\n", "for material in dft_materials.values():\n", " material.name = f\"{material.name} (MACE-relaxed)\"\n", + " material.basis.constraints = ArrayWithIds.from_values(\n", + " [[index not in frozen_atom_indices] * 3 for index in range(material.basis.number_of_atoms)])\n", "isolated_adatom.name = f\"{adatom_element} atom\"\n", "dft_materials[\"isolated_adatom\"] = isolated_adatom\n", "saved_materials = {label: get_or_create_material(client, dft_materials[label], ACCOUNT_ID) for label in DFT_MATERIAL_LABELS}" @@ -580,7 +591,7 @@ "id": "39", "metadata": {}, "source": [ - "### 7.8. Create and submit one total-energy job per structure" + "### 7.8. Create and submit one relaxation job per structure" ] }, { @@ -597,22 +608,23 @@ "from mat3ra.standata.workflows import WorkflowStandata\n", "from mat3ra.wode.workflows import Workflow\n", "\n", - "SCF_UNIT = \"pw_scf\"\n", - "total_energy_workflow_config = WorkflowStandata.filter_by_application(APPLICATION_NAME).get_by_name_first_match(\n", - " TOTAL_ENERGY_SEARCH_TERM\n", + "RELAX_UNIT = \"pw_relax\"\n", + "relaxation_workflow_config = WorkflowStandata.filter_by_application(APPLICATION_NAME).get_by_name_first_match(\n", + " RELAXATION_SEARCH_TERM\n", ")\n", "dft_job_ids, new_job_ids = {}, []\n", "for label, material in saved_materials.items():\n", - " workflow = Workflow.create(total_energy_workflow_config)\n", + " workflow = Workflow.create(relaxation_workflow_config)\n", " workflow.subworkflows[0].model = model\n", - " apply_planewave_cutoffs(workflow, ECUTWFC, ECUTRHO, unit_name=SCF_UNIT)\n", - " apply_scf_kgrid(workflow, DFT_KGRID, material=dft_materials[label], unit_name=SCF_UNIT)\n", + " apply_planewave_cutoffs(workflow, ECUTWFC, ECUTRHO, unit_name=RELAX_UNIT)\n", + " apply_scf_kgrid(workflow, DFT_KGRID, material=dft_materials[label], unit_name=RELAX_UNIT)\n", " system = {**DFT_SYSTEM_SETTINGS, **DFT_SPIN_SETTINGS_BY_LABEL.get(label, {})}\n", " patch_workflow_qe_input(\n", - " workflow, {\"control\": DFT_CONTROL_SETTINGS, \"system\": system, \"electrons\": DFT_ELECTRONS_SETTINGS}, [SCF_UNIT]\n", + " workflow, {\"control\": DFT_CONTROL_SETTINGS, \"system\": system, \"electrons\": DFT_ELECTRONS_SETTINGS}, [RELAX_UNIT]\n", " )\n", " job = find_job_for_material(client, material[\"_id\"], workflow.name, ACCOUNT_ID,\n", - " statuses=(\"submitted\", \"queued\", \"active\", \"finished\"), kgrid=DFT_KGRID)\n", + " statuses=(\"submitted\", \"queued\", \"active\", \"finished\"), kgrid=DFT_KGRID,\n", + " unit_name=RELAX_UNIT)\n", " if job is None:\n", " job = create_job(api_client=client, materials=[material], workflow=workflow, project_id=project_id,\n", " owner_id=ACCOUNT_ID, compute=compute.to_dict(), prefix=f\"{workflow.name} {material['name']}\")\n", @@ -648,7 +660,7 @@ "id": "43", "metadata": {}, "source": [ - "### 7.10. Read the total energies" + "### 7.10. Read the final energies and structures" ] }, { @@ -658,10 +670,12 @@ "metadata": {}, "outputs": [], "source": [ + "from mat3ra.notebooks_utils.core.entity.material.api import get_final_structure_for_job\n", "from mat3ra.notebooks_utils.core.entity.property.api import get_properties_for_job\n", "\n", "dft_energies = {label: get_properties_for_job(client, job_id, \"total_energy\")[0][\"value\"]\n", - " for label, job_id in dft_job_ids.items()}" + " for label, job_id in dft_job_ids.items()}\n", + "dft_relaxed_materials = {label: get_final_structure_for_job(client, job_id) for label, job_id in dft_job_ids.items()}" ] }, { @@ -674,7 +688,7 @@ "\n", "The paper's energies of c and i are read off Fig. 6 (±0.02 and ±0.05 eV); the adsorption energy at a, the\n", "island contraction and the ripple are from Sec. III.A, the isolated Ti atom energy it uses from Sec. II.B.\n", - "DFT takes the MACE geometries as they are, so it has no island contraction or ripple of its own." + "The island contraction and the ripple are measured on the MACE relaxation only." ] }, { From 40b37a82a5d7a38e64ff1353747fefd8749add97 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Tue, 3 Nov 2026 20:02:34 -0800 Subject: [PATCH 23/31] Let QE write its data file so the final structure is extracted Co-Authored-By: Claude Opus 5.5 --- ...defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index 0270c70c7..fa78ab049 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -160,7 +160,7 @@ "DFT_SYSTEM_SETTINGS = {\"smearing\": \"mv\", \"degauss\": 0.01} # Ry\n", "MAXIMUM_IONIC_STEPS = 4 # per job, so that it ends within TIME_LIMIT; the next job continues from its last structure\n", "DAVIDSON_SUBSPACE_DIMENSION = 2 # half the default 4: less memory per process\n", - "DFT_CONTROL_SETTINGS = {\"disk_io\": \"none\", \"nstep\": MAXIMUM_IONIC_STEPS} # no wavefunction files on disk\n", + "DFT_CONTROL_SETTINGS = {\"nstep\": MAXIMUM_IONIC_STEPS}\n", "# conv_thr 1e-4 Ry ≈ 1.4 meV on the total energy; local-TF mixing for a slab with vacuum\n", "DFT_ELECTRONS_SETTINGS = {\"conv_thr\": 1e-4, \"mixing_mode\": \"local-TF\", \"mixing_beta\": 0.2,\n", " \"diago_david_ndim\": DAVIDSON_SUBSPACE_DIMENSION}\n", From 03449ed9de045f2afda8dfa39c5513878dbfbbcd Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Tue, 3 Nov 2026 20:02:36 -0800 Subject: [PATCH 24/31] Allow five ionic steps per DFT job Co-Authored-By: Claude Opus 5.5 --- ...defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index fa78ab049..8afe7067d 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -158,7 +158,7 @@ "ECUTRHO = 200 # Ry\n", "DFT_KGRID = [1, 1, 1] # manuscript: Γ only\n", "DFT_SYSTEM_SETTINGS = {\"smearing\": \"mv\", \"degauss\": 0.01} # Ry\n", - "MAXIMUM_IONIC_STEPS = 4 # per job, so that it ends within TIME_LIMIT; the next job continues from its last structure\n", + "MAXIMUM_IONIC_STEPS = 5 # per job, so that it ends within TIME_LIMIT; the next job continues from its last structure\n", "DAVIDSON_SUBSPACE_DIMENSION = 2 # half the default 4: less memory per process\n", "DFT_CONTROL_SETTINGS = {\"nstep\": MAXIMUM_IONIC_STEPS}\n", "# conv_thr 1e-4 Ry ≈ 1.4 meV on the total energy; local-TF mixing for a slab with vacuum\n", From 178c1f0475a4d75b0c7e23be0a0801ebdbafad93 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Tue, 3 Nov 2026 21:51:32 -0800 Subject: [PATCH 25/31] Pin api-client to store the frozen plane with the material mat3ra-api-client at 0e8752d (SOF-8060, mat3ra/api-client#52) stores basis.constraints when a material is created or updated. Cell 7.5 updates each saved material, so a material reused by hash gets the constraints too. Re-pin to the release when it publishes. Co-Authored-By: Claude Opus 5.5 --- config.yml | 4 ++-- ...fect_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 4 +++- ..._api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl | 3 +++ pyproject.toml | 2 +- 4 files changed, 9 insertions(+), 4 deletions(-) create mode 100644 packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl diff --git a/config.yml b/config.yml index 7b88d0f05..4e3b45f8b 100644 --- a/config.yml +++ b/config.yml @@ -66,7 +66,7 @@ notebooks: - ipywidgets - tabulate==0.9.0 - mat3ra-utils - - mat3ra-api-client>=2026.10.8.post0 + - emfs:/drive/packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl - name: dataframe packages_pyodide: - jinja2 @@ -79,7 +79,7 @@ notebooks: - emfs:/drive/packages/pydantic-2.7.1-py3-none-any.whl - mat3ra-standata - mat3ra-ide - - mat3ra-api-client>=2026.10.8.post0 + - emfs:/drive/packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl - requests - mat3ra-ade - mat3ra-mode diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index 8afe7067d..1eeb1575f 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -538,7 +538,9 @@ " [[index not in frozen_atom_indices] * 3 for index in range(material.basis.number_of_atoms)])\n", "isolated_adatom.name = f\"{adatom_element} atom\"\n", "dft_materials[\"isolated_adatom\"] = isolated_adatom\n", - "saved_materials = {label: get_or_create_material(client, dft_materials[label], ACCOUNT_ID) for label in DFT_MATERIAL_LABELS}" + "saved_materials = {label: get_or_create_material(client, dft_materials[label], ACCOUNT_ID) for label in DFT_MATERIAL_LABELS}\n", + "saved_materials = {label: client.materials.update(saved[\"_id\"], dft_materials[label].to_dict())\n", + " for label, saved in saved_materials.items()}" ] }, { diff --git a/packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl b/packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl new file mode 100644 index 000000000..8fa29e9a5 --- /dev/null +++ b/packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d11012257f0699ffb7be7d30d2a99aa56957b8d7a19318c4bf012f070e4f100 +size 26452 diff --git a/pyproject.toml b/pyproject.toml index 2840c8d43..4dfaa668a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ utils_standata = [ "mat3ra-standata", ] api = [ - "mat3ra-api-client>=2026.10.8.post0", + "mat3ra-api-client @ git+https://github.com/mat3ra/api-client@0e8752d5fdac3f459ba62daf621ce8c032ad84c0", ] materials = [ # ase >=3.25.0 is required for supercell to be generated, From 9a358884ac8c340745bc0dcb06e6619fabdb7bc3 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 5 Nov 2026 11:12:04 -0800 Subject: [PATCH 26/31] Use the whole node the job is billed for Co-Authored-By: Claude Opus 5 --- ...defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index 1eeb1575f..6ac42ca11 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -186,7 +186,7 @@ "\n", "CLUSTER_NAME = \"001\"\n", "QUEUE_NAME = QueueName.OF\n", - "PPN = 36\n", + "PPN = 60 # OF's maxPPN: the job is billed for the whole node\n", "TIME_LIMIT = \"08:00:00\"\n", "POLL_INTERVAL = 600 # seconds" ] From a375341caf9c9c64f120a26c23e75c35f53e8c78 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Thu, 5 Nov 2026 21:41:25 -0800 Subject: [PATCH 27/31] Draw the DFT energies beside the MACE ones on the Fig. 6 panel The Fig. 6 panel now carries a second marker series for the sites the DFT section relaxed, each energy relative to this notebook's own DFT energy at a, so the two methods and the manuscript's curve are read off one plot. A run that skips the DFT section draws the panel as before. Co-Authored-By: Claude Opus 5 --- ...ct_point_adatom_island_titanium_nitride_SIMULATION.ipynb | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index 6ac42ca11..e5a82e8f6 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -743,11 +743,17 @@ "source": [ "import plotly.graph_objects as go\n", "\n", + "dft_sites = [site for site in relative_energies if site in dft_energies] if \"a\" in dft_energies else []\n", + "\n", "figure = go.Figure()\n", "figure.add_trace(go.Scatter(x=list(PAPER_FIG6), y=list(PAPER_FIG6.values()), mode=\"lines+markers\",\n", " name=\"Sangiovanni et al. (2018)\"))\n", "figure.add_trace(go.Scatter(x=list(relative_energies), y=list(relative_energies.values()), mode=\"markers\",\n", " marker={\"size\": 12}, name=\"this notebook (MACE-MP-0)\"))\n", + "if dft_sites:\n", + " figure.add_trace(go.Scatter(x=dft_sites, y=[dft_energies[site] - dft_energies[\"a\"] for site in dft_sites],\n", + " mode=\"markers\", marker={\"size\": 14, \"symbol\": \"diamond-open\"},\n", + " name=\"this notebook (DFT)\"))\n", "figure.update_layout(title=\"Ti adatom descent from the 5×5 island edge (Fig. 6)\", xaxis_title=\"state\",\n", " yaxis_title=\"energy relative to a (eV)\")\n", "figure.show()" From f0540df957fb14b3c3bb17b4f89886641a899cab Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 6 Nov 2026 05:59:34 -0800 Subject: [PATCH 28/31] Ship no DFT jobs listed, and say which cell the DFT settings are sized for Running the simulation notebook as it ships now does the MACE part and stops: the DFT settings are sized for the 10x10x2 cell, and section 1.3 says so and what to set to run them. A reader who wants the DFT energies picks that cell in both notebooks and lists the structures to run. Co-Authored-By: Claude Opus 5 --- ..._point_adatom_island_titanium_nitride_SIMULATION.ipynb | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index e5a82e8f6..eabde7414 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -99,7 +99,11 @@ "id": "5", "metadata": {}, "source": [ - "### 1.3. Parameters" + "### 1.3. Parameters\n", + "\n", + "The DFT settings below — `MAXIMUM_IONIC_STEPS`, `TIME_LIMIT` and the queue — are sized for the `\"10x10x2\"`\n", + "cell: to run them, set `CELL_SIZE = \"10x10x2\"` in both notebooks and list the structures to run in\n", + "`DFT_MATERIAL_LABELS`." ] }, { @@ -125,7 +129,7 @@ "# DFT relaxations of the MACE-relaxed structures, one platform job each; an empty list skips the platform jobs.\n", "# The other structures can be added one at a time, each after the previous job has finished.\n", "DFT_MATERIAL_LABELS = [\n", - " \"slab_with_island\",\n", + " # \"slab_with_island\",\n", " # \"a\",\n", " # \"c\",\n", " # \"i\",\n", From dfc07181f2988b865bb93bd5b1215115b828872e Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 6 Nov 2026 05:59:42 -0800 Subject: [PATCH 29/31] Run the isolated Ti atom as a total-energy job The isolated Ti atom now gets the Total Energy workflow, one SCF, which is what its published energy was calculated with and what the atom needs: a single atom has nothing to relax. Section 8.1 says why the DFT column leaves E_Ti out, the atom's material name carries the cell size like the other four, and the Introduction lists the notebook under both methods. Co-Authored-By: Claude Opus 5 --- .../specific_examples/Introduction.ipynb | 2 +- ...point_adatom_island_titanium_nitride.ipynb | 3 +- ...m_island_titanium_nitride_SIMULATION.ipynb | 33 ++++++++++--------- 3 files changed, 19 insertions(+), 19 deletions(-) diff --git a/other/materials_designer/specific_examples/Introduction.ipynb b/other/materials_designer/specific_examples/Introduction.ipynb index 230324296..1582835c0 100644 --- a/other/materials_designer/specific_examples/Introduction.ipynb +++ b/other/materials_designer/specific_examples/Introduction.ipynb @@ -35,7 +35,7 @@ "| `D-3D-AMO` | Amorphous | *To be added* | — | — |\n", "| `D-2D-ADA` | Adatom | [Pt Adatom/Island on MoS₂](defect_point_adatom_island_molybdenum_disulfide_platinum.ipynb) | *To be added* | [[10]](#ref10) |\n", "| `D-2D-ADA` | Adatom | [Adatom on Graphene](defect_surface_adatom_graphene.ipynb) | *To be added* | [[11]](#ref11) |\n", - "| `D-2D-ADA` | Adatom | [Ti Adatom on a 5×5 TiN Island](defect_point_adatom_island_titanium_nitride.ipynb) | [Ti Adatom Descent on a 5×5 TiN Island (MACE)](defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb) | [[14]](#ref14) |\n", + "| `D-2D-ADA` | Adatom | [Ti Adatom on a 5×5 TiN Island](defect_point_adatom_island_titanium_nitride.ipynb) | [Ti Adatom Descent on a 5×5 TiN Island (MACE and DFT)](defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb) | [[14]](#ref14) |\n", "| `D-2D-GBP` | Grain Boundary Planar | [Grain Boundary in 3D FCC Cu](defect_planar_grain_boundary_3d_fcc_metals_copper.ipynb) | *To be added* | [[13]](#ref13) |\n", "| `D-2D-ISL` | Island | [TiN Island on Surface](defect_surface_island_titanium_nitride.ipynb) | *To be added* | [[14]](#ref14) |\n", "| `D-2D-TER` | Terrace | [Step/Terrace on Pt Surface](defect_surface_step_platinum.ipynb) | *To be added* | [[15]](#ref15) |\n", diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb index c4158656e..02fb97193 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride.ipynb @@ -14,8 +14,7 @@ "> **D. G. Sangiovanni, A. B. Mei, D. Edström, L. Hultman, V. Chirita, I. Petrov, and J. E. Greene**, \"Effects of surface vibrations on interlayer mass transport: Ab initio molecular dynamics investigation of Ti adatom descent pathways and rates from TiN/TiN(001) islands\", Physical Review B 97, 035406 (2018). [DOI: 10.1103/PhysRevB.97.035406](https://doi.org/10.1103/PhysRevB.97.035406)\n", "\n", "The cell (Sec. II.A, Fig. 1b) is a 5×5-atom TiN island, one plane high with Ti corners, on a 12×12×3-atom\n", - "TiN(001) slab with 15.3 Å of vacuum: 457 atoms. A Ti adatom is added at each of the sites a, c and i of Fig. 6,\n", - "giving three 458-atom cells.\n", + "TiN(001) slab with 15.3 Å of vacuum: 457 atoms. A Ti adatom is added at each of the sites a, c and i of Fig. 6.\n", "\n", "![Fig. 1(b)](https://github.com/Exabyte-io/documentation/raw/98b0e6b61a7007a4a53e41d894fb56c891ccaaa0/images/tutorials/materials/defects/defect-point-adatom-island-titanium-nitride/0-figure-1b-from-manuscript.webp)" ] diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index eabde7414..2d13c5a6c 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -26,7 +26,7 @@ "\n", "1. Create the materials in the [structure notebook](defect_point_adatom_island_titanium_nitride.ipynb) with the same `CELL_SIZE`, which saves the island cell and the three adatom cells to the `uploads` folder.\n", "1. Set the material names and parameters in cells 1.2-1.5 (or use the defaults).\n", - "1. Run natively: `pip install \".[all]\" mace-torch torch-dftd`. In JupyterLite the install and the calculator run, but the first force call on the 457-atom cell exceeds the browser's memory (a 0.76 GB tensor), so the relaxations run natively; the browser also has no torch-dftd, so D3 is off there.\n", + "1. Run natively: `pip install \".[all]\" mace-torch torch-dftd`. In JupyterLite the install and the calculator run, but the first force call on the manuscript's cell exceeds the browser's memory (a 0.76 GB tensor), so the relaxations run natively; the browser also has no torch-dftd, so D3 is off there.\n", "1. Click \"Run\" > \"Run All\" to run all cells.\n", "1. Wait for the DFT jobs to finish.\n", "1. Scroll down to view the results.\n", @@ -155,6 +155,7 @@ "# manuscript: VASP, every structure relaxed with DFT; here the DFT relaxation starts from the MACE-relaxed structure\n", "APPLICATION_NAME = \"espresso\"\n", "RELAXATION_SEARCH_TERM = \"fixed_cell_relaxation.json\"\n", + "TOTAL_ENERGY_SEARCH_TERM = \"total_energy.json\" # the isolated atom: one SCF, nothing to relax\n", "# manuscript: GGA of Perdew, Burke and Wang (PW91); for PW91 add \"input_dft\": \"pw91\" to DFT_SYSTEM_SETTINGS\n", "FUNCTIONAL = \"pbe\"\n", "PSEUDOPOTENTIAL_TYPE = \"us\" # manuscript: PAW; ours GBRV ultrasoft\n", @@ -162,7 +163,7 @@ "ECUTRHO = 200 # Ry\n", "DFT_KGRID = [1, 1, 1] # manuscript: Γ only\n", "DFT_SYSTEM_SETTINGS = {\"smearing\": \"mv\", \"degauss\": 0.01} # Ry\n", - "MAXIMUM_IONIC_STEPS = 5 # per job, so that it ends within TIME_LIMIT; the next job continues from its last structure\n", + "MAXIMUM_IONIC_STEPS = 5 # per job, so that it ends within TIME_LIMIT\n", "DAVIDSON_SUBSPACE_DIMENSION = 2 # half the default 4: less memory per process\n", "DFT_CONTROL_SETTINGS = {\"nstep\": MAXIMUM_IONIC_STEPS}\n", "# conv_thr 1e-4 Ry ≈ 1.4 meV on the total energy; local-TF mixing for a slab with vacuum\n", @@ -540,8 +541,8 @@ " material.name = f\"{material.name} (MACE-relaxed)\"\n", " material.basis.constraints = ArrayWithIds.from_values(\n", " [[index not in frozen_atom_indices] * 3 for index in range(material.basis.number_of_atoms)])\n", - "isolated_adatom.name = f\"{adatom_element} atom\"\n", - "dft_materials[\"isolated_adatom\"] = isolated_adatom\n", + "dft_materials[\"isolated_adatom\"] = isolated_adatom.clone()\n", + "dft_materials[\"isolated_adatom\"].name = f\"{adatom_element} atom {CELL_SIZE}\"\n", "saved_materials = {label: get_or_create_material(client, dft_materials[label], ACCOUNT_ID) for label in DFT_MATERIAL_LABELS}\n", "saved_materials = {label: client.materials.update(saved[\"_id\"], dft_materials[label].to_dict())\n", " for label, saved in saved_materials.items()}" @@ -614,23 +615,23 @@ "from mat3ra.standata.workflows import WorkflowStandata\n", "from mat3ra.wode.workflows import Workflow\n", "\n", - "RELAX_UNIT = \"pw_relax\"\n", - "relaxation_workflow_config = WorkflowStandata.filter_by_application(APPLICATION_NAME).get_by_name_first_match(\n", - " RELAXATION_SEARCH_TERM\n", - ")\n", + "RELAXATION_WORKFLOW = (RELAXATION_SEARCH_TERM, \"pw_relax\", DFT_CONTROL_SETTINGS)\n", + "WORKFLOW_BY_LABEL = {\"isolated_adatom\": (TOTAL_ENERGY_SEARCH_TERM, \"pw_scf\", {})}\n", "dft_job_ids, new_job_ids = {}, []\n", "for label, material in saved_materials.items():\n", - " workflow = Workflow.create(relaxation_workflow_config)\n", + " search_term, unit_name, control = WORKFLOW_BY_LABEL.get(label, RELAXATION_WORKFLOW)\n", + " workflow = Workflow.create(\n", + " WorkflowStandata.filter_by_application(APPLICATION_NAME).get_by_name_first_match(search_term))\n", " workflow.subworkflows[0].model = model\n", - " apply_planewave_cutoffs(workflow, ECUTWFC, ECUTRHO, unit_name=RELAX_UNIT)\n", - " apply_scf_kgrid(workflow, DFT_KGRID, material=dft_materials[label], unit_name=RELAX_UNIT)\n", + " apply_planewave_cutoffs(workflow, ECUTWFC, ECUTRHO, unit_name=unit_name)\n", + " apply_scf_kgrid(workflow, DFT_KGRID, material=dft_materials[label], unit_name=unit_name)\n", " system = {**DFT_SYSTEM_SETTINGS, **DFT_SPIN_SETTINGS_BY_LABEL.get(label, {})}\n", " patch_workflow_qe_input(\n", - " workflow, {\"control\": DFT_CONTROL_SETTINGS, \"system\": system, \"electrons\": DFT_ELECTRONS_SETTINGS}, [RELAX_UNIT]\n", + " workflow, {\"control\": control, \"system\": system, \"electrons\": DFT_ELECTRONS_SETTINGS}, [unit_name]\n", " )\n", " job = find_job_for_material(client, material[\"_id\"], workflow.name, ACCOUNT_ID,\n", " statuses=(\"submitted\", \"queued\", \"active\", \"finished\"), kgrid=DFT_KGRID,\n", - " unit_name=RELAX_UNIT)\n", + " unit_name=unit_name)\n", " if job is None:\n", " job = create_job(api_client=client, materials=[material], workflow=workflow, project_id=project_id,\n", " owner_id=ACCOUNT_ID, compute=compute.to_dict(), prefix=f\"{workflow.name} {material['name']}\")\n", @@ -676,12 +677,10 @@ "metadata": {}, "outputs": [], "source": [ - "from mat3ra.notebooks_utils.core.entity.material.api import get_final_structure_for_job\n", "from mat3ra.notebooks_utils.core.entity.property.api import get_properties_for_job\n", "\n", "dft_energies = {label: get_properties_for_job(client, job_id, \"total_energy\")[0][\"value\"]\n", - " for label, job_id in dft_job_ids.items()}\n", - "dft_relaxed_materials = {label: get_final_structure_for_job(client, job_id) for label, job_id in dft_job_ids.items()}" + " for label, job_id in dft_job_ids.items()}" ] }, { @@ -694,6 +693,8 @@ "\n", "The paper's energies of c and i are read off Fig. 6 (±0.02 and ±0.05 eV); the adsorption energy at a, the\n", "island contraction and the ripple are from Sec. III.A, the isolated Ti atom energy it uses from Sec. II.B.\n", + "Quantum ESPRESSO's absolute energy for the free Ti atom is not on the manuscript's scale, so the DFT column\n", + "leaves E_Ti out; it cancels in E_ads(a), where it is used.\n", "The island contraction and the ripple are measured on the MACE relaxation only." ] }, From ca878eab28f585a1e6cbfee81b9f212d69961e98 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 6 Nov 2026 06:19:28 -0800 Subject: [PATCH 30/31] Say that the isolated Ti atom gets a total energy, not a relaxation Section 7, its summary line, the job-list comment and the job heading now describe what the notebook runs: a fixed-cell relaxation on the four slab structures, and a total energy on the isolated Ti atom, which has nothing to relax. Section 7.10 no longer promises structures it stopped reading, and the two workflow units are named beside the two workflow search terms. Co-Authored-By: Claude Opus 5 --- ...m_island_titanium_nitride_SIMULATION.ipynb | 26 +++++++++++-------- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb index 2d13c5a6c..2a49c229c 100644 --- a/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb +++ b/other/materials_designer/specific_examples/defect_point_adatom_island_titanium_nitride_SIMULATION.ipynb @@ -39,7 +39,7 @@ "1. Relax the island cell; measure the island contraction and the surface ripple.\n", "1. Relax the adatom at a, c and i.\n", "1. Compute the energy of an isolated Ti atom.\n", - "1. Relax the MACE-relaxed structures and the isolated Ti atom with DFT on the platform.\n", + "1. Run DFT on the platform: a fixed-cell relaxation on the four slab structures, and a total energy on the isolated Ti atom, which has nothing to relax.\n", "1. Compare with the paper: energies relative to a, the adsorption energy at a, and Fig. 6." ] }, @@ -126,8 +126,9 @@ "MAX_STEPS = 1000\n", "FROZEN_SLAB_PLANES = 1 # bottom slab planes held fixed in the MACE and DFT relaxations\n", "\n", - "# DFT relaxations of the MACE-relaxed structures, one platform job each; an empty list skips the platform jobs.\n", - "# The other structures can be added one at a time, each after the previous job has finished.\n", + "# One platform job per structure: a fixed-cell relaxation on the MACE-relaxed slab structures, and a total\n", + "# energy on the isolated Ti atom, which has nothing to relax; an empty list skips the platform jobs.\n", + "# The structures can be added one at a time, each after the previous job has finished.\n", "DFT_MATERIAL_LABELS = [\n", " # \"slab_with_island\",\n", " # \"a\",\n", @@ -156,6 +157,8 @@ "APPLICATION_NAME = \"espresso\"\n", "RELAXATION_SEARCH_TERM = \"fixed_cell_relaxation.json\"\n", "TOTAL_ENERGY_SEARCH_TERM = \"total_energy.json\" # the isolated atom: one SCF, nothing to relax\n", + "RELAX_UNIT = \"pw_relax\"\n", + "SCF_UNIT = \"pw_scf\"\n", "# manuscript: GGA of Perdew, Burke and Wang (PW91); for PW91 add \"input_dft\": \"pw91\" to DFT_SYSTEM_SETTINGS\n", "FUNCTIONAL = \"pbe\"\n", "PSEUDOPOTENTIAL_TYPE = \"us\" # manuscript: PAW; ours GBRV ultrasoft\n", @@ -432,11 +435,12 @@ "id": "25", "metadata": {}, "source": [ - "## 7. DFT relaxation of the MACE-relaxed structures\n", + "## 7. DFT on the platform\n", "\n", - "One fixed-cell relaxation job on the platform per structure, starting from the island cell and the adatom at a, c and\n", - "i as MACE relaxed them, with the same bottom slab plane fixed; and one for the isolated Ti atom, spin-polarized. A\n", - "finished or running job of the same workflow on the same structure is reused.\n", + "One job per structure: a fixed-cell relaxation on the four slab structures, starting from the island cell and the\n", + "adatom at a, c and i as MACE relaxed them, with the same bottom slab plane fixed; and a total energy on the\n", + "isolated Ti atom, which has nothing to relax, spin-polarized. A finished or running job of the same workflow on\n", + "the same structure is reused.\n", "\n", "### 7.1. Authenticate" ] @@ -598,7 +602,7 @@ "id": "39", "metadata": {}, "source": [ - "### 7.8. Create and submit one relaxation job per structure" + "### 7.8. Create and submit one job per structure" ] }, { @@ -615,8 +619,8 @@ "from mat3ra.standata.workflows import WorkflowStandata\n", "from mat3ra.wode.workflows import Workflow\n", "\n", - "RELAXATION_WORKFLOW = (RELAXATION_SEARCH_TERM, \"pw_relax\", DFT_CONTROL_SETTINGS)\n", - "WORKFLOW_BY_LABEL = {\"isolated_adatom\": (TOTAL_ENERGY_SEARCH_TERM, \"pw_scf\", {})}\n", + "RELAXATION_WORKFLOW = (RELAXATION_SEARCH_TERM, RELAX_UNIT, DFT_CONTROL_SETTINGS)\n", + "WORKFLOW_BY_LABEL = {\"isolated_adatom\": (TOTAL_ENERGY_SEARCH_TERM, SCF_UNIT, {})}\n", "dft_job_ids, new_job_ids = {}, []\n", "for label, material in saved_materials.items():\n", " search_term, unit_name, control = WORKFLOW_BY_LABEL.get(label, RELAXATION_WORKFLOW)\n", @@ -667,7 +671,7 @@ "id": "43", "metadata": {}, "source": [ - "### 7.10. Read the final energies and structures" + "### 7.10. Read the final energies" ] }, { From d9d83a9de3774189cd8bd342556c270ce7952e67 Mon Sep 17 00:00:00 2001 From: VsevolodX Date: Fri, 6 Nov 2026 13:30:11 -0800 Subject: [PATCH 31/31] Pin api-client to the version that reads constraints back mat3ra-api-client at b5f25f7 (SOF-8060, mat3ra/api-client#52) creates, updates and reads materials over /api/v1, so a saved material's atomic constraints come back from materials.get instead of only reaching a job's rendered input. Re-pin to the release when it publishes. Co-Authored-By: Claude Opus 5 --- config.yml | 4 ++-- ..._api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl | 3 --- ..._api_client-2026.11.4.post1.dev7+gb5f25f7-py3-none-any.whl | 3 +++ pyproject.toml | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) delete mode 100644 packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl create mode 100644 packages/mat3ra_api_client-2026.11.4.post1.dev7+gb5f25f7-py3-none-any.whl diff --git a/config.yml b/config.yml index 4e3b45f8b..5c9cca38b 100644 --- a/config.yml +++ b/config.yml @@ -66,7 +66,7 @@ notebooks: - ipywidgets - tabulate==0.9.0 - mat3ra-utils - - emfs:/drive/packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl + - emfs:/drive/packages/mat3ra_api_client-2026.11.4.post1.dev7+gb5f25f7-py3-none-any.whl - name: dataframe packages_pyodide: - jinja2 @@ -79,7 +79,7 @@ notebooks: - emfs:/drive/packages/pydantic-2.7.1-py3-none-any.whl - mat3ra-standata - mat3ra-ide - - emfs:/drive/packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl + - emfs:/drive/packages/mat3ra_api_client-2026.11.4.post1.dev7+gb5f25f7-py3-none-any.whl - requests - mat3ra-ade - mat3ra-mode diff --git a/packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl b/packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl deleted file mode 100644 index 8fa29e9a5..000000000 --- a/packages/mat3ra_api_client-2026.10.8.post1.dev3+g0e8752d-py3-none-any.whl +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:8d11012257f0699ffb7be7d30d2a99aa56957b8d7a19318c4bf012f070e4f100 -size 26452 diff --git a/packages/mat3ra_api_client-2026.11.4.post1.dev7+gb5f25f7-py3-none-any.whl b/packages/mat3ra_api_client-2026.11.4.post1.dev7+gb5f25f7-py3-none-any.whl new file mode 100644 index 000000000..e655f953a --- /dev/null +++ b/packages/mat3ra_api_client-2026.11.4.post1.dev7+gb5f25f7-py3-none-any.whl @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2e0999d8a1f3a41775a85d8c1d86ba509c00ab0f7663fc3f890927cafa779728 +size 28984 diff --git a/pyproject.toml b/pyproject.toml index 4dfaa668a..a501d7e6f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -24,7 +24,7 @@ utils_standata = [ "mat3ra-standata", ] api = [ - "mat3ra-api-client @ git+https://github.com/mat3ra/api-client@0e8752d5fdac3f459ba62daf621ce8c032ad84c0", + "mat3ra-api-client @ git+https://github.com/mat3ra/api-client@b5f25f755db5c40d7580662affa16ac642a8d67c", ] materials = [ # ase >=3.25.0 is required for supercell to be generated,