diff --git a/.github/workflows/cicd.yml b/.github/workflows/cicd.yml index 1cc9e532..feb78351 100644 --- a/.github/workflows/cicd.yml +++ b/.github/workflows/cicd.yml @@ -28,6 +28,31 @@ jobs: python -m pip install pre-commit pre-commit run --all-files --show-diff-on-failure + publish-py-package: + needs: [run-linter] + runs-on: ubuntu-latest + if: github.ref_name == 'dev' + + steps: + - name: Checkout this repository + uses: actions/checkout@v4 + with: + lfs: true + + - name: Checkout actions repository + uses: actions/checkout@v4 + with: + repository: Exabyte-io/actions + token: ${{ secrets.BOT_GITHUB_TOKEN }} + path: actions + + - name: Publish python release + uses: ./actions/py/publish + with: + python-version: 3.8.x + github-token: ${{ secrets.BOT_GITHUB_TOKEN }} + pypi-api-token: ${{ secrets.PYPI_API_TOKEN }} + # TODO: Add back when when fixed. # build-and-deploy-docs: # runs-on: ubuntu-20.04 diff --git a/other/jupyterlite/utils.py b/other/jupyterlite/utils.py index 238eead0..e133816b 100644 --- a/other/jupyterlite/utils.py +++ b/other/jupyterlite/utils.py @@ -69,22 +69,28 @@ async def install_packages(notebook_name, requirements_path="config.yml", verbos requirements_hash = str(hash(json.dumps(requirements))) if os.environ.get("requirements_hash") != requirements_hash: packages_default_common = requirements.get("default", {}).get("packages_common", []) or [] - packages_default_environment_specific = requirements.get("default", {}).get(f"packages_{ENVIRONMENT.value}", []) or [] + packages_default_environment_specific = ( + requirements.get("default", {}).get(f"packages_{ENVIRONMENT.value}", []) or [] + ) notebook_requirements = next( (cfg for cfg in requirements.get("notebooks", []) if cfg.get("name") == notebook_name), None ) if notebook_requirements: packages_notebook_common = notebook_requirements.get("packages_common", []) or [] - packages_notebook_environment_specific= notebook_requirements.get(f"packages_{ENVIRONMENT.value}", []) or [] + packages_notebook_environment_specific = ( + notebook_requirements.get(f"packages_{ENVIRONMENT.value}", []) or [] + ) else: raise ValueError(f"No packages found for notebook {notebook_name}") + # Note: environment specific packages have to be installed first, + # because in Pyodide common packages might depend on them packages = [ - *packages_default_common, *packages_default_environment_specific, - *packages_notebook_common, *packages_notebook_environment_specific, + *packages_default_common, + *packages_notebook_common, ] for pkg in packages: diff --git a/other/materials_designer/create_interface_with_min_strain_zsl.ipynb b/other/materials_designer/create_interface_with_min_strain_zsl.ipynb index 7277ddfd..c02b225b 100644 --- a/other/materials_designer/create_interface_with_min_strain_zsl.ipynb +++ b/other/materials_designer/create_interface_with_min_strain_zsl.ipynb @@ -10,8 +10,7 @@ "\n", "

Usage

\n", "\n", - "0. Make sure to select Input Materials\n", - "1. Execute \"Run first: ...\" cell below to load Input Materials into the current kernel\n", + "1. Make sure to select Input Materials\n", "2. Set Input Parameters (e.g. `MILLER_INDICES`, `THICKNESS`, `MAX_AREA`) below or use the default values\n", "3. Click \"Run\" > \"Run All Cells\" to run all cells\n", "4. Wait for the run to complete (depending on the area, it can take 1-2 min or more). Scroll down to view cell results.\n", @@ -31,25 +30,6 @@ "3. When the strain matching is finished, the interface with the lowest strain (and the smallest number of atoms) is selected. We create the corresponding supercells and place them at a specified distance from each other (note no shift is performed currently).\n" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "

Run first: load input materials in current kernel

\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from jupyterlite.utils import get_data\n", - "\n", - "# Get the list of input materials and load them into `materials_in` variable\n", - "get_data(\"materials_in\", globals())" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -75,7 +55,9 @@ " \"MATERIAL_INDEX\": 1, # the index of the material in the materials_in list\n", " \"MILLER_INDICES\": (0, 0, 1), # the miller indices of the interfacial plane\n", " \"THICKNESS\": 1, # in layers\n", - "}" + "}\n", + "\n", + "USE_CONVENTIONAL_CELL = True # if True, the surface plane is constructed using miller indices of the conventional cell" ] }, { @@ -143,12 +125,45 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 3. Create interfaces\n", + "## 3. Load and prepare input Materials\n" + ] + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "from jupyterlite.utils import get_data\n", + "from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer\n", + "from src.utils import to_pymatgen\n", + "\n", + "# Get the list of input materials and load them into `materials_in` variable\n", + "get_data(\"materials_in\", globals())\n", + "\n", + "if \"materials_in\" in globals():\n", + " pymatgen_materials = [to_pymatgen(item) for item in materials_in]\n", + " if USE_CONVENTIONAL_CELL: pymatgen_materials = [SpacegroupAnalyzer(item).get_conventional_standard_structure() for\n", + " item in pymatgen_materials]\n", + "\n", + " for material in pymatgen_materials:\n", + " print(material, \"\\n\")" + ], + "metadata": { + "collapsed": false + }, + "execution_count": null + }, + { + "cell_type": "markdown", + "source": [ + "## 4. Create interfaces\n", "\n", - "### 3.1. Extract Interfaces and Terminations\n", + "### 4.1. Extract Interfaces and Terminations\n", "\n", "Extract all possible layer/substrate supercell combinations within the maximum area including different terminations." - ] + ], + "metadata": { + "collapsed": false + } }, { "cell_type": "code", @@ -160,14 +175,11 @@ "outputs": [], "source": [ "from src.pymatgen_coherent_interface_builder import CoherentInterfaceBuilder, ZSLGenerator\n", - "from src.utils import to_pymatgen\n", - "\n", - "if \"materials_in\" in globals():\n", - " pymatgen_materials = [to_pymatgen(item) for item in materials_in]\n", - "for material in pymatgen_materials:\n", - " print(material, \"\\n\")\n", - "\n", + "from src.utils import translate_to_bottom\n", "\n", + "# Translate the materials to the bottom of the cell to allow for multilayer heterostructures creation\n", + "pymatgen_materials = [translate_to_bottom(item) for item in pymatgen_materials]\n", + " \n", "def create_interfaces(settings):\n", " print(\"Creating interfaces...\")\n", " zsl = ZSLGenerator(\n", @@ -221,7 +233,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 3.2. Print out the interfaces and terminations" + "### 5.2. Print out the interfaces and terminations" ] }, { @@ -239,9 +251,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 4. Sort interfaces by strain\n", + "## 5. Sort interfaces by strain\n", "\n", - "### 4.1. Sort all interfaces" + "### 5.1. Sort all interfaces" ] }, { @@ -271,7 +283,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 4.2. Print out interfaces with lowest strain for each termination" + "### 5.2. Print out interfaces with lowest strain for each termination" ] }, { @@ -291,7 +303,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 5. Plot the results\n", + "## 6. Plot the results\n", "\n", "Plot the number of atoms vs strain. Adjust the parameters as needed.\n" ] @@ -367,9 +379,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 6. Select the interface to pass outside this kernel\n", + "## 7. Select the interface to pass outside this kernel\n", "\n", - "### 6.1. Select the interface with the desired termination and strain\n", + "### 7.1. Select the interface with the desired termination and strain\n", "\n", "The data in `sorted_interfaces` now contains an object with the following structure:\n", "\n", @@ -409,7 +421,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 6.2. Pass data to the outside runtime\n" + "### 7.2. Pass data to the outside runtime\n" ] }, { diff --git a/other/materials_designer/create_interface_with_relaxation_ase_emt.ipynb b/other/materials_designer/create_interface_with_relaxation_ase_emt.ipynb index 5cdd03e4..8f8f5474 100644 --- a/other/materials_designer/create_interface_with_relaxation_ase_emt.ipynb +++ b/other/materials_designer/create_interface_with_relaxation_ase_emt.ipynb @@ -11,8 +11,7 @@ "\n", "

Usage

\n", "\n", - "0. Make sure to select Input Materials\n", - "1. Execute \"Run first: ...\" cell below to load Input Materials into the current kernel\n", + "1. Make sure to select Input Materials\n", "2. Set Input Parameters (e.g. `THICKNESS`, `MAX_AREA`, `FMAX`) below or use the default values\n", "3. Click \"Run\" > \"Run All\" to run all cells\n", "4. Wait for the run to complete (depending on the parameters it can take a few min or more). Scroll down to view cell results.\n", @@ -29,25 +28,6 @@ "2. The interface with the lowest strain is selected and relaxed using the optimizer selected below (BFGS, by default). The EMT potential is used as an energy calculator.\n" ] }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "

Run first: load input materials in current kernel

\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from jupyterlite.utils import get_data\n", - "\n", - "# Get the list of input materials and load them into `materials_in` variable\n", - "get_data(\"materials_in\", globals())" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -147,13 +127,45 @@ "await install_packages(\"create_interface_with_min_strain_zsl.ipynb\")" ] }, + { + "cell_type": "markdown", + "source": [ + "## 3. Load and prepare Input Materials" + ], + "metadata": { + "collapsed": false + } + }, + { + "cell_type": "code", + "outputs": [], + "source": [ + "from jupyterlite.utils import get_data\n", + "from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer\n", + "from src.utils import to_pymatgen\n", + "\n", + "# Get the list of input materials and load them into `materials_in` variable\n", + "get_data(\"materials_in\", globals())\n", + "\n", + "if \"materials_in\" in globals():\n", + " pymatgen_materials = [to_pymatgen(item) for item in materials_in]\n", + " if USE_CONVENTIONAL_CELL: pymatgen_materials = [SpacegroupAnalyzer(item).get_conventional_standard_structure() for\n", + " item in pymatgen_materials]\n", + "\n", + " for material in pymatgen_materials:\n", + " print(material, \"\\n\")" + ], + "metadata": { + "collapsed": false + } + }, { "cell_type": "markdown", "metadata": {}, "source": [ - "## 3. Create interfaces\n", + "## 4. Create interfaces\n", "\n", - "### 3.1. Extract Interfaces and Terminations\n", + "### 4.1. Extract Interfaces and Terminations\n", "\n", "Extract all possible layer/substrate supercell combinations within the maximum area including different terminations.\n" ] @@ -168,17 +180,10 @@ "outputs": [], "source": [ "from src.pymatgen_coherent_interface_builder import CoherentInterfaceBuilder, ZSLGenerator\n", - "from pymatgen.analysis.structure_analyzer import SpacegroupAnalyzer\n", - "from src.utils import to_pymatgen\n", - "\n", - "if \"materials_in\" in globals():\n", - " pymatgen_materials = [to_pymatgen(item) for item in materials_in]\n", - " if USE_CONVENTIONAL_CELL: pymatgen_materials = [SpacegroupAnalyzer(item).get_conventional_standard_structure() for\n", - " item in pymatgen_materials]\n", - "\n", - " for material in pymatgen_materials:\n", - " print(material, \"\\n\")\n", + "from src.utils import translate_to_bottom\n", "\n", + "# Translate the materials to the bottom of the cell to allow for multilayer heterostructures creation\n", + "pymatgen_materials = [translate_to_bottom(item) for item in pymatgen_materials]\n", "\n", "def create_interfaces(settings: dict):\n", " print(\"Creating interfaces...\")\n", @@ -233,7 +238,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 3.2. Print out the interfaces and terminations\n" + "### 4.2. Print out the interfaces and terminations\n" ] }, { @@ -251,9 +256,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 4. Sort interfaces by strain\n", + "## 5. Sort interfaces by strain\n", "\n", - "### 4.1. Sort all interfaces\n" + "### 5.1. Sort all interfaces\n" ] }, { @@ -283,7 +288,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 4.2. Print out interfaces with lowest strain for each termination\n" + "### 5.2. Print out interfaces with lowest strain for each termination\n" ] }, { @@ -303,7 +308,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 5. Plot the results\n", + "## 6. Plot the results\n", "\n", "Plot the number of atoms vs strain. Adjust the parameters as needed.\n" ] @@ -379,7 +384,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 6. Select the interface with the desired termination and strain\n", + "## 7. Select the interface with the desired termination and strain\n", "\n", "The data in `sorted_interfaces` now contains an object with the following structure:\n", "\n", @@ -421,9 +426,9 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "## 7. Apply relaxation to the interface\n", + "## 8. Apply relaxation to the interface\n", "\n", - "### 7.1. Apply relaxation to the selected interface with ASE\n", + "### 8.1. Apply relaxation to the selected interface with ASE\n", "\n", "Optimizer is set from the available options in the settings and EMT is used as the energy calculator." ] @@ -516,7 +521,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 7.2. View structure before and after relaxation\n" + "### 8.2. View structure before and after relaxation\n" ] }, { @@ -579,7 +584,7 @@ "collapsed": false }, "source": [ - "### 7.3. Calculate the energy metrics\n", + "### 8.3. Calculate the energy metrics\n", "Calculate the energy metrics for the relaxed interface.\n", "The effective delta energy per area calculation accounts for the energy contribution of each component (substrate and layer) relative to their proportion in the overall interface. \n" ] @@ -675,7 +680,7 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "### 8. Pass relaxed interface to Materials Designer" + "## 9. Pass relaxed interface to Materials Designer" ] }, { diff --git a/other/materials_designer/src/utils.py b/other/materials_designer/src/utils.py index 13973502..5bef131e 100644 --- a/other/materials_designer/src/utils.py +++ b/other/materials_designer/src/utils.py @@ -348,3 +348,20 @@ def from_ase(atoms: Atoms): structure = ase_to_pymatgen(atoms) material = from_pymatgen(structure) return material + + +def translate_to_bottom(structure): + """ + Translate the structure to the bottom of the cell. + Args: + structure (Structure): The pymatgen Structure object to translate. + + Returns: + Structure: The translated pymatgen Structure object. + """ + min_c = min(site.c for site in structure) + translation_vector = [0, 0, -min_c] + translated_structure = structure.copy() + for site in translated_structure: + site.coords += translation_vector + return translated_structure diff --git a/pyproject.toml b/pyproject.toml index 8df51515..d64f835a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,31 +1,26 @@ -[build-system] -requires = ["setuptools>=64", "setuptools_scm[toml]>=6.2", "wheel"] -build-backend = "setuptools.build_meta" - [project] name = "mat3ra-api-examples" -version = "0.1.0" +dynamic = ["version"] description = "Mat3ra API Examples" readme = "README.md" requires-python = ">=3.8" - -[project.optional-dependencies] -colab = [ +dependencies = [ "ase>=3.21.1", "exabyte-api-client>=2023.6.13.post0", "matplotlib>=3.4.1", "pandas>=1.5.3", "pymatgen>=2023.5.31", ] -localhost = [ - "ase>=3.21.1", - "exabyte-api-client>=2023.6.13.post0", - "matplotlib>=3.4.1", - "pandas>=1.1.4", - "pymatgen>=2023.5.31", + +[project.optional-dependencies] +# Install all above dependencies in colab +colab = ["mat3ra-api-examples"] +jupyterlab = [ "jupyterlab>=3.0.17", "nbconvert>=6.0.7", ] +# Install colab + jupyterlab on localhost +localhost = ["mat3ra-api-examples[jupyterlab]"] dev = [ "pre-commit>=3.3.3", "pip-tools>=6.13.0", @@ -47,6 +42,13 @@ repository = "https://github.com/Exabyte-io/api-examples" [project.scripts] notebook-path = "utils.notebook:print_notebook_path" +[build-system] +requires = ["setuptools>=64", "setuptools_scm[toml]>=6.2", "wheel"] +build-backend = "setuptools.build_meta" + +[tool.setuptools_scm] +git_describe_command = "git describe --tags --long" + [tool.setuptools.packages.find] include = ["utils"]