diff --git a/other/materials_designer/text_on_nanoribbon.ipynb b/other/materials_designer/text_on_nanoribbon.ipynb new file mode 100644 index 00000000..5eff1223 --- /dev/null +++ b/other/materials_designer/text_on_nanoribbon.ipynb @@ -0,0 +1,253 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "d8a8021cf80ad95c", + "metadata": {}, + "source": [ + "# Create a nanoribbon material with the digits (or letters) on a nanoribbon." + ] + }, + { + "cell_type": "code", + "id": "b1158553", + "metadata": {}, + "source": [ + "from mat3ra.made.material import Material\n", + "from mat3ra.made.tools.build.nanoribbon import create_nanoribbon, NanoribbonConfiguration\n", + "from mat3ra.standata.materials import Materials\n", + "from mat3ra.made.tools.modify import rotate\n", + "from IPython.display import display\n", + "import numpy as np\n", + "\n", + "\n", + "DIGITS_STRING = \"2026\"\n", + "grid_size = 10\n", + "\n", + "SHOW_DIGITS = False\n", + "\n", + "combined_length = 32\n", + "material = Material(Material.default_config)\n", + "graphene = Material(Materials.get_by_name_first_match(\"Graphene\"))\n", + "config = NanoribbonConfiguration(material=graphene, width=4 * 10, length=combined_length, edge_type=\"zigzag\")\n", + "nanoribbon = create_nanoribbon(config)\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "f6ba0797", + "metadata": {}, + "source": [ + "def generate_digit_grid(digit, grid_size=10):\n", + " \"\"\"\n", + " Generate a binary grid for a digit and return ON pixel coordinates.\n", + " \"\"\"\n", + " from PIL import Image, ImageDraw, ImageFont\n", + " \n", + " image = Image.new(\"1\", (grid_size, grid_size), color=1)\n", + " draw = ImageDraw.Draw(image)\n", + " \n", + " try:\n", + " font = ImageFont.load_default()\n", + " except IOError:\n", + " raise RuntimeError(\"Failed to load bitmap font.\")\n", + " \n", + " draw.text((0, 0), digit, fill=0, font=font)\n", + " grid = np.array(image)\n", + " \n", + " on_pixels = [(x, y) for y in range(grid.shape[0]) for x in range(grid.shape[1]) if not grid[y, x]]\n", + " return on_pixels\n", + "\n", + "def visualize_digit_coords(coords, grid_size=10):\n", + " \"\"\"\n", + " Visualize digit coordinates as a grid and image.\n", + " \"\"\"\n", + " from PIL import Image\n", + " \n", + " grid = np.ones((grid_size, grid_size), dtype=int)\n", + " for x, y in coords:\n", + " if 0 <= y < grid_size and 0 <= x < grid_size:\n", + " grid[y, x] = 0\n", + " \n", + " print(\" \", end=\"\")\n", + " for x in range(grid_size):\n", + " print(f\"{x:2}\", end=\" \")\n", + " print()\n", + " \n", + " for y in range(grid_size):\n", + " print(f\"{y:2} \", end=\"\")\n", + " for x in range(grid_size):\n", + " print(f\"{grid[y, x]:2}\", end=\" \")\n", + " print()\n", + " \n", + " image = Image.fromarray((grid * 255).astype(np.uint8), mode='L')\n", + " scale_factor = 10\n", + " scaled_image = image.resize((grid_size * scale_factor, grid_size * scale_factor), resample=Image.NEAREST)\n", + " display(scaled_image)\n", + " \n", + " print(f\"\\nON pixels: {coords}\")\n", + "\n", + "def toggle_pixels(coords, toggles):\n", + " \"\"\"\n", + " Toggle pixels in the coordinate list.\n", + " If a coordinate is in the list, remove it. If not, add it.\n", + " \"\"\"\n", + " coords_set = set(coords)\n", + " for toggle in toggles:\n", + " if toggle in coords_set:\n", + " coords_set.remove(toggle)\n", + " else:\n", + " coords_set.add(toggle)\n", + " return list(coords_set)\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "c625e22c", + "metadata": {}, + "source": [ + "\n", + "digits_coords = []\n", + "for i, digit in enumerate(DIGITS_STRING):\n", + " coords = generate_digit_grid(digit, grid_size)\n", + " digits_coords.append(coords)\n", + " if SHOW_DIGITS:\n", + " print(f\"Digit {i} ('{digit}'):\")\n", + " visualize_digit_coords(coords, grid_size)\n", + " print()\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "187f99ff", + "metadata": {}, + "source": [ + "adjustments = {\n", + " # 3: [(5, 4)],\n", + "}\n", + "\n", + "\n", + "for digit_index, toggles in adjustments.items():\n", + " digits_coords[digit_index] = toggle_pixels(digits_coords[digit_index], toggles)\n", + " print(f\"Adjusted Digit {digit_index} ('{DIGITS_STRING[digit_index]}'):\")\n", + " visualize_digit_coords(digits_coords[digit_index], grid_size)\n", + " print()\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "03ef6570", + "metadata": {}, + "source": [ + "def create_material_from_digit_coords(digit_coords_list, nanoribbon, grid_size, lattice_param=2.46, spacing=0, x_shift=-5):\n", + " \"\"\"\n", + " Create material with atoms positioned based on digit coordinates.\n", + " \"\"\"\n", + " material = nanoribbon.clone()\n", + " x_offset = 0\n", + " \n", + " for digit_coords in digit_coords_list:\n", + " x_offset += grid_size * lattice_param + spacing * lattice_param + x_shift\n", + " \n", + " for x, y in digit_coords:\n", + " coord = np.array([\n", + " x * lattice_param + x_offset - lattice_param * 7,\n", + " y * lattice_param + lattice_param * 2 + 90,\n", + " 2 * lattice_param\n", + " ])\n", + " material.add_atom(\"Au\", coord, use_cartesian_coordinates=True)\n", + " \n", + " mirror_coord = np.array([\n", + " -coord[0],\n", + " coord[1],\n", + " 5 * lattice_param\n", + " ])\n", + " material.add_atom(\"Cs\", mirror_coord, use_cartesian_coordinates=True)\n", + " \n", + " return material\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "0e554c39", + "metadata": {}, + "source": [ + "lattice_param = 2.46\n", + "spacing = 0\n", + "x_shift = -5\n", + "\n", + "material = create_material_from_digit_coords(digits_coords, nanoribbon, grid_size, lattice_param, spacing, x_shift)\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "code", + "id": "bca66033", + "metadata": {}, + "source": [ + "from utils.jupyterlite import set_materials\n", + "from utils.visualize import visualize_materials\n", + "from mat3ra.made.tools.modify import add_vacuum, translate_to_z_level\n", + "\n", + "material_copy = material.clone()\n", + "material_copy = add_vacuum(material_copy, 20, to_bottom=True)\n", + "material_copy = translate_to_z_level(material_copy, \"center\")\n", + "material_copy = rotate(material_copy, [1, 0, 0], -90, rotate_cell=False)\n", + "\n", + "visualize_materials([material_copy], rotation=\"-180x\")\n", + "visualize_materials([material_copy], rotation=\"-90x\")\n", + "\n", + "material_copy.name = DIGITS_STRING\n", + "set_materials([material_copy])\n" + ], + "outputs": [], + "execution_count": null + }, + { + "cell_type": "markdown", + "id": "71c7e7b7", + "metadata": {}, + "source": [] + }, + { + "cell_type": "code", + "id": "cfb846e053e5b355", + "metadata": {}, + "source": [], + "outputs": [], + "execution_count": null + } + ], + "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 +}