{ "cells": [ { "cell_type": "markdown", "id": "ea6b25ee", "metadata": {}, "source": [ "# UUIDs and Lineage Tracking\n", "\n", "ASSYST workflows generate, relax, and perturb structures in successive steps.\n", "Keeping track of *which* structure came from *which* parent is essential\n", "for two reasons:\n", "\n", "1. **Reproducibility** — when a structure causes a problem (e.g. an exploding\n", " DFT run) we want to find the seed it grew from.\n", "2. **Joining data** — energies and forces are typically computed in a\n", " separate workflow. A stable identifier lets us merge those results back\n", " onto the original structures.\n", "\n", "ASSYST does this with three keys stored in `atoms.info`:\n", "\n", "| key | meaning |\n", "|-----------|---------------------------------------------------------------|\n", "| `uuid` | unique id of *this* structure |\n", "| `seed` | uuid of the original ancestor (set once, never changes) |\n", "| `lineage` | list of all previous uuids, oldest first |\n", "\n", "This notebook walks through how each step in the workflow updates these." ] }, { "cell_type": "markdown", "id": "de103b30", "metadata": {}, "source": [ "## Imports" ] }, { "cell_type": "code", "execution_count": 1, "id": "f026f253", "metadata": { "execution": { "iopub.execute_input": "2026-05-04T23:32:27.414608Z", "iopub.status.busy": "2026-05-04T23:32:27.414400Z", "iopub.status.idle": "2026-05-04T23:32:28.647558Z", "shell.execute_reply": "2026-05-04T23:32:28.646390Z" } }, "outputs": [ { "name": "stderr", "output_type": "stream", "text": "/root/.local/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\nfrom .autonotebook import tqdm as notebook_tqdm\n" } ], "source": [ "from assyst.crystals import pyxtal\n", "from assyst.perturbations import Rattle, Stretch\n", "from assyst.relaxations import Relax\n", "from assyst.calculators import Morse" ] }, { "cell_type": "markdown", "id": "98180d60", "metadata": {}, "source": [ "## 1. Generation\n", "\n", "A freshly generated structure has no ancestors. Its `uuid` and `seed` are\n", "identical and the lineage is empty." ] }, { "cell_type": "code", "execution_count": 2, "id": "5aed7c68", "metadata": { "execution": { "iopub.execute_input": "2026-05-04T23:32:28.649702Z", "iopub.status.busy": "2026-05-04T23:32:28.649514Z", "iopub.status.idle": "2026-05-04T23:32:28.727691Z", "shell.execute_reply": "2026-05-04T23:32:28.726475Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": "uuid: f6d3b4dd-af88-4bbb-81f0-bb7a55089926\nseed: f6d3b4dd-af88-4bbb-81f0-bb7a55089926\nlineage: []\n" } ], "source": [ "atoms = pyxtal(225, species=['Cu'], num_ions=[4])\n", "\n", "print(f\"uuid: {atoms.info['uuid']}\")\n", "print(f\"seed: {atoms.info['seed']}\")\n", "print(f\"lineage: {atoms.info.get('lineage', [])}\")" ] }, { "cell_type": "markdown", "id": "0441ad97", "metadata": {}, "source": [ "## 2. Relaxation\n", "\n", "Relaxing a structure produces a new `Atoms` object: it gets a *new* `uuid`,\n", "the previous one moves into `lineage`, and the `seed` is preserved." ] }, { "cell_type": "code", "execution_count": 3, "id": "01addac3", "metadata": { "execution": { "iopub.execute_input": "2026-05-04T23:32:28.730319Z", "iopub.status.busy": "2026-05-04T23:32:28.729534Z", "iopub.status.idle": "2026-05-04T23:32:28.739838Z", "shell.execute_reply": "2026-05-04T23:32:28.738963Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": "uuid: ecad2002-c6c3-4ba3-81b7-278f5504a31d\nseed: f6d3b4dd-af88-4bbb-81f0-bb7a55089926\nlineage: ['f6d3b4dd-af88-4bbb-81f0-bb7a55089926']\n" } ], "source": [ "relax = Relax(max_steps=5)\n", "atoms.calc = Morse().get_calculator()\n", "relaxed = relax.relax(atoms)\n", "\n", "print(f\"uuid: {relaxed.info['uuid']}\")\n", "print(f\"seed: {relaxed.info['seed']}\")\n", "print(f\"lineage: {relaxed.info['lineage']}\")" ] }, { "cell_type": "markdown", "id": "cc5bb8aa", "metadata": {}, "source": [ "## 3. Perturbation\n", "\n", "Perturbations work the same way: the lineage grows, the seed stays put." ] }, { "cell_type": "code", "execution_count": 4, "id": "d47b721f", "metadata": { "execution": { "iopub.execute_input": "2026-05-04T23:32:28.742231Z", "iopub.status.busy": "2026-05-04T23:32:28.741529Z", "iopub.status.idle": "2026-05-04T23:32:28.747200Z", "shell.execute_reply": "2026-05-04T23:32:28.746277Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": "uuid: a8eb4310-65a5-4311-9de7-8763626133b8\nseed: f6d3b4dd-af88-4bbb-81f0-bb7a55089926\nlineage: ['f6d3b4dd-af88-4bbb-81f0-bb7a55089926', 'ecad2002-c6c3-4ba3-81b7-278f5504a31d']\n" } ], "source": [ "rattled = Rattle(sigma=0.05)(relaxed.copy())\n", "\n", "print(f\"uuid: {rattled.info['uuid']}\")\n", "print(f\"seed: {rattled.info['seed']}\")\n", "print(f\"lineage: {rattled.info['lineage']}\")" ] }, { "cell_type": "markdown", "id": "52bfd643", "metadata": {}, "source": [ "## 4. Chained modifications\n", "\n", "Stacking another perturbation on top extends the lineage further. The\n", "ancestry of any structure is fully recoverable from the `lineage` list." ] }, { "cell_type": "code", "execution_count": 5, "id": "32b8c7e2", "metadata": { "execution": { "iopub.execute_input": "2026-05-04T23:32:28.749393Z", "iopub.status.busy": "2026-05-04T23:32:28.748703Z", "iopub.status.idle": "2026-05-04T23:32:28.754566Z", "shell.execute_reply": "2026-05-04T23:32:28.753673Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": "uuid: edcc557b-efea-45bd-bde2-8c37a2de4562\nseed: f6d3b4dd-af88-4bbb-81f0-bb7a55089926\nlineage: ['f6d3b4dd-af88-4bbb-81f0-bb7a55089926', 'ecad2002-c6c3-4ba3-81b7-278f5504a31d', 'a8eb4310-65a5-4311-9de7-8763626133b8']\n" } ], "source": [ "final = Stretch(hydro=0.05, shear=0.05)(rattled.copy())\n", "\n", "print(f\"uuid: {final.info['uuid']}\")\n", "print(f\"seed: {final.info['seed']}\")\n", "print(f\"lineage: {final.info['lineage']}\")" ] }, { "cell_type": "markdown", "id": "3160c5af", "metadata": {}, "source": [ "## Summary\n", "\n", "Tracing back from `final` we can reconstruct the full history:" ] }, { "cell_type": "code", "execution_count": 6, "id": "a891cb34", "metadata": { "execution": { "iopub.execute_input": "2026-05-04T23:32:28.756856Z", "iopub.status.busy": "2026-05-04T23:32:28.756196Z", "iopub.status.idle": "2026-05-04T23:32:28.761450Z", "shell.execute_reply": "2026-05-04T23:32:28.760619Z" } }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": "seed: f6d3b4dd-af88-4bbb-81f0-bb7a55089926\nstep 1: ecad2002-c6c3-4ba3-81b7-278f5504a31d\nstep 2: a8eb4310-65a5-4311-9de7-8763626133b8\ncurrent: edcc557b-efea-45bd-bde2-8c37a2de4562\n" } ], "source": [ "for i, u in enumerate([final.info['seed'], *final.info['lineage'][1:], final.info['uuid']]):\n", " role = 'seed' if i == 0 else ('current' if u == final.info['uuid'] else f'step {i}')\n", " print(f\"{role:>8}: {u}\")" ] } ], "metadata": { "kernelspec": { "display_name": "Python 3 (ipykernel)", "language": "python", "name": "python3" }, "language_info": { "codemirror_mode": { "name": "ipython", "version": 3 }, "file_extension": ".py", "mimetype": "text/x-python", "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", "version": "3.11.15" } }, "nbformat": 4, "nbformat_minor": 5 }