From adfa3767b799549ef22590ff9960817e75389a6b Mon Sep 17 00:00:00 2001 From: Gonza10V Date: Sat, 11 Jul 2026 21:31:41 -0600 Subject: [PATCH 1/4] full build workflow and demonstration --- .vscode/settings.json | 6 + AGENTS_log.md | 301 ++++++ docs/Tutorials.rst | 53 +- ...ldcompiler_transformation_quickstart.ipynb | 324 +++++++ notebooks/full_build_workflow_examples.ipynb | 373 ++++++++ .../Loop Assembly.xlsx | Bin 0 -> 5576 bytes .../assembly_lvl1_pudu_input.json | 13 + .../plating_input.json | 16 + .../plating_layout.json | 36 + .../plating_layout.xlsx | Bin 0 -> 6125 bytes .../pudu_assembly_protocol.py | 91 ++ .../pudu_assembly_protocol.simulate.log | 152 +++ .../pudu_plating_protocol.py | 125 +++ .../pudu_plating_protocol.simulate.log | 105 ++ .../pudu_transformation_protocol.py | 217 +++++ .../pudu_transformation_protocol.simulate.log | 78 ++ .../transformation_input.json | 5 + .../transformation_lvl1_products.xml | 550 +++++++++++ .../transformation_lvl1_pudu_input.json | 9 + .../transformation_products.xml | 619 ++++++++++++ .../transformation_summary.json | 49 + .../assembly_lvl1_pudu_assembly_input.json | 13 + .../assembly_lvl1_pudu_assembly_protocol.py | 26 + .../lvl1_success 2/full_build_manifest.json | 156 +++ .../lvl1_success 2/plating_pudu_input.json | 5 + .../lvl1_success 2/pudu_plating_protocol.py | 18 + .../pudu_transformation_protocol.py | 31 + .../manual_plating_protocol.md | 22 + .../plate_layout_dataframe.csv | 2 + .../standard_GFP_plating/plate_map.csv | 2 + .../standard_GFP_plating/plate_map.json | 13 + .../standard_GFP_plating/plating_input.json | 5 + .../transformation_plasmid_locations.json | 5 + .../transformation_pudu_input.json | 9 + .../lvl1_success.zip | Bin 0 -> 5617 bytes .../assembly_lvl1_pudu_assembly_input.json | 13 + .../assembly_lvl1_pudu_assembly_protocol.py | 26 + .../lvl1_success/full_build_manifest.json | 156 +++ .../lvl1_success/plating_pudu_input.json | 5 + .../lvl1_success/pudu_plating_protocol.py | 18 + .../pudu_transformation_protocol.py | 31 + .../manual_plating_protocol.md | 22 + .../plate_layout_dataframe.csv | 2 + .../standard_GFP_plating/plate_map.csv | 2 + .../standard_GFP_plating/plate_map.json | 13 + .../standard_GFP_plating/plating_input.json | 5 + .../transformation_plasmid_locations.json | 5 + .../transformation_pudu_input.json | 9 + .../lvl2_triggers_all_stages.zip | Bin 0 -> 4940 bytes .../assembly_lvl1_pudu_assembly_input.json | 10 + .../assembly_lvl1_pudu_assembly_protocol.py | 23 + .../assembly_lvl2_pudu_assembly_input.json | 10 + .../assembly_lvl2_pudu_assembly_protocol.py | 23 + .../domestication_pudu_assembly_input.json | 10 + .../domestication_pudu_assembly_protocol.py | 23 + .../full_build_manifest.json | 164 ++++ .../plating_pudu_input.json | 19 + .../pudu_plating_protocol.py | 32 + .../pudu_transformation_protocol.py | 51 + .../transformation_plasmid_locations.json | 11 + .../transformation_pudu_input.json | 23 + src/buildcompiler/adapters/pudu/__init__.py | 2 + .../adapters/pudu/plating_json.py | 11 +- .../adapters/pudu/transformation_json.py | 33 + src/buildcompiler/buildcompiler.py | 902 +++++++++++++++++- tests/test_buildcompiler_transformation.py | 42 + tests/test_full_build.py | 137 +++ tests/unit/adapters/pudu/test_plating_json.py | 12 +- .../adapters/pudu/test_transformation_json.py | 20 + 69 files changed, 5280 insertions(+), 14 deletions(-) create mode 100644 .vscode/settings.json create mode 100644 AGENTS_log.md create mode 100644 notebooks/buildcompiler_transformation_quickstart.ipynb create mode 100644 notebooks/full_build_workflow_examples.ipynb create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/Loop Assembly.xlsx create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/assembly_lvl1_pudu_input.json create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/plating_input.json create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/plating_layout.json create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/plating_layout.xlsx create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/pudu_assembly_protocol.py create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/pudu_assembly_protocol.simulate.log create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/pudu_plating_protocol.py create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/pudu_plating_protocol.simulate.log create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/pudu_transformation_protocol.py create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/pudu_transformation_protocol.simulate.log create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/transformation_input.json create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/transformation_lvl1_products.xml create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/transformation_lvl1_pudu_input.json create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/transformation_products.xml create mode 100644 notebooks/results/buildcompiler_transformation_quickstart/transformation_summary.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/assembly_lvl1_pudu_assembly_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/assembly_lvl1_pudu_assembly_protocol.py create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/full_build_manifest.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/plating_pudu_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/pudu_plating_protocol.py create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/pudu_transformation_protocol.py create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/manual_plating_protocol.md create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_layout_dataframe.csv create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_map.csv create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_map.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plating_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/transformation_plasmid_locations.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success 2/transformation_pudu_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success.zip create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_protocol.py create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/full_build_manifest.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/plating_pudu_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/pudu_plating_protocol.py create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/pudu_transformation_protocol.py create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/manual_plating_protocol.md create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_layout_dataframe.csv create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.csv create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plating_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/transformation_plasmid_locations.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl1_success/transformation_pudu_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages.zip create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl1_pudu_assembly_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl1_pudu_assembly_protocol.py create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl2_pudu_assembly_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl2_pudu_assembly_protocol.py create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/domestication_pudu_assembly_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/domestication_pudu_assembly_protocol.py create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/full_build_manifest.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/plating_pudu_input.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/pudu_plating_protocol.py create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/pudu_transformation_protocol.py create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/transformation_plasmid_locations.json create mode 100644 notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/transformation_pudu_input.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000..b4e74a6 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "python.defaultInterpreterPath": "/Users/gonzalovidal/opt/anaconda3/envs/GLLDB_py310/bin/python", + "python.terminal.activateEnvironment": true, + "jupyter.interactiveWindow.creationMode": "perFile", + "jupyter.notebookFileRoot": "${workspaceFolder}" +} diff --git a/AGENTS_log.md b/AGENTS_log.md new file mode 100644 index 0000000..c62ef9b --- /dev/null +++ b/AGENTS_log.md @@ -0,0 +1,301 @@ +# BuildCompiler Agent Handoff Log + +Last updated: 2026-07-11 + +This log captures the recent BuildCompiler work so future agents can continue +without rediscovering the same repository and PUDU context. + +## Repository Mental Model + +BuildCompiler is a workflow orchestrator. Keep stages independently callable: + +- `index_collections` +- `domestication` +- `assembly_lvl1` +- `assembly_lvl2` +- `transformation` +- `plating` +- `full_build` + +Stage contracts should stay explicit: + +- Inputs: SBOL objects/documents or JSON payloads. +- Outputs: SBOL, JSON, and protocol files. +- Avoid hidden side effects except explicitly named output files. +- Prefer deterministic JSON ordering and deterministic generated artifacts. + +## Environment + +Primary tested environment: + +```bash +/Users/gonzalovidal/opt/anaconda3/bin/conda run -n GLLDB_py310 python ... +``` + +Useful commands: + +```bash +/Users/gonzalovidal/opt/anaconda3/bin/conda run -n GLLDB_py310 python -m pytest tests/unit/adapters/pudu/test_transformation_json.py tests/unit/adapters/pudu/test_plating_json.py tests/test_buildcompiler_transformation.py +``` + +`opentrons_simulate` is available inside `GLLDB_py310`: + +```bash +/Users/gonzalovidal/opt/anaconda3/bin/conda run -n GLLDB_py310 which opentrons_simulate +``` + +PUDU local source tree used for integration: + +```text +/Users/gonzalovidal/Documents/GitHub/PUDU +``` + +When using PUDU from notebooks/scripts without installing it, prepend: + +```python +sys.path.insert(0, "/Users/gonzalovidal/Documents/GitHub/PUDU/src") +``` + +## Recent BuildCompiler Changes + +### Transformation input normalization + +File: + +- `src/buildcompiler/buildcompiler.py` + +Added `_normalize_transformation_inputs()` so `BuildCompiler.transformation()` +accepts: + +- BuildCompiler `Plasmid` objects produced by `assembly_lvl1`/`assembly_lvl2`. +- Raw `sbol2.ComponentDefinition` plasmids. +- Dict payloads with `plasmid` or `plasmid_definition`. + +Reason: the active `BuildCompiler.transformation()` method referenced this +missing helper and failed when called with level-1 assembly products. + +Regression test: + +- `tests/test_buildcompiler_transformation.py::test_transformation_accepts_lvl1_assembly_products` + +### PUDU transformation adapter + +Files: + +- `src/buildcompiler/adapters/pudu/transformation_json.py` +- `src/buildcompiler/adapters/pudu/__init__.py` +- `tests/unit/adapters/pudu/test_transformation_json.py` + +Confirmed PUDU transformation spec shape: + +```json +[ + { + "Strain": "https://SBOL2Build.org/composite_strain_1/1", + "Chassis": "https://sbolcanvas.org/DH5alpha/1", + "Plasmids": ["https://SBOL2Build.org/composite_plasmid_1/1"] + } +] +``` + +Added `plasmid_locations_to_pudu_json()` for PUDU's assembly-output location map: + +```json +{ + "https://SBOL2Build.org/composite_plasmid_1/1": ["A1"] +} +``` + +This map is consumed by PUDU transformation protocol generation as +`--plasmid-locations transformation_input.json`. + +Note: the notebook now prefers the location map produced by simulating PUDU's +assembly protocol, because that is the real handoff in the PUDU workflow. + +### PUDU plating adapter + +Files: + +- `src/buildcompiler/adapters/pudu/plating_json.py` +- `tests/unit/adapters/pudu/test_plating_json.py` + +Updated `plating_to_pudu_json()` to match PUDU directly. PUDU expects +thermocycler well names as keys: + +```json +{ + "bacterium_locations": { + "A1": [ + "composite_strain_1", + "Competent_Cell_DH5alpha", + "composite_plasmid_1", + "Media_1" + ] + } +} +``` + +Removed the old nested `advanced_parameters` wrapper from the adapter output. +Optional advanced parameters now pass through as top-level PUDU parameters. + +## Notebook Added + +New notebook: + +```text +notebooks/buildcompiler_transformation_quickstart.ipynb +``` + +It demonstrates the full offline/PUDU chain: + +1. Load local SBOL collections: + - `tests/test_files/CIDARMoCloParts_collection.xml` + - `tests/test_files/CIDARMoCloPlasmidsKit_collection.xml` + - `tests/test_files/Enzyme_Implementations_collection.xml` + - `tests/test_files/impl_test_collection.xml` +2. Load `tests/test_files/abstract_design.xml`. +3. Run BuildCompiler `assembly_lvl1`. +4. Run BuildCompiler `transformation`. +5. Write BuildCompiler SBOL and JSON artifacts. +6. Generate PUDU assembly protocol. +7. Run `opentrons_simulate pudu_assembly_protocol.py`. +8. Use generated `transformation_input.json`. +9. Generate PUDU transformation protocol. +10. Run `opentrons_simulate pudu_transformation_protocol.py`. +11. Use generated `plating_input.json`. +12. Generate PUDU plating protocol. +13. Run `opentrons_simulate pudu_plating_protocol.py`. +14. Produce final `plating_layout.json` and `plating_layout.xlsx`. + +Important implementation detail: SBOL files are written with +`Document.writeString()` and `Path.write_text()` rather than `Document.write()` +to avoid PySBOL2's online validator in offline notebook runs. + +## Generated Notebook Artifacts + +Directory: + +```text +notebooks/results/buildcompiler_transformation_quickstart/ +``` + +Current generated files include: + +- `assembly_lvl1_pudu_input.json` +- `transformation_lvl1_products.xml` +- `transformation_products.xml` +- `transformation_summary.json` +- `transformation_lvl1_pudu_input.json` +- `pudu_assembly_protocol.py` +- `pudu_assembly_protocol.simulate.log` +- `transformation_input.json` +- `pudu_transformation_protocol.py` +- `pudu_transformation_protocol.simulate.log` +- `plating_input.json` +- `pudu_plating_protocol.py` +- `pudu_plating_protocol.simulate.log` +- `plating_layout.json` +- `plating_layout.xlsx` +- `Loop Assembly.xlsx` + +The simulation logs showed the expected handoff: + +- Assembly simulation generated `transformation_input.json`. +- Transformation simulation generated `plating_input.json`. +- Plating simulation generated `plating_layout.json` and `plating_layout.xlsx`. + +## PUDU Reference Points + +Local files inspected: + +- `/Users/gonzalovidal/Documents/GitHub/PUDU/docs/guide/workflow.rst` +- `/Users/gonzalovidal/Documents/GitHub/PUDU/docs/api/transformation.rst` +- `/Users/gonzalovidal/Documents/GitHub/PUDU/src/pudu/generate_protocol.py` +- `/Users/gonzalovidal/Documents/GitHub/PUDU/src/pudu/transformation.py` +- `/Users/gonzalovidal/Documents/GitHub/PUDU/src/pudu/plating.py` +- `/Users/gonzalovidal/Documents/GitHub/PUDU/workflow_example/transformation_spec.json` +- `/Users/gonzalovidal/Documents/GitHub/PUDU/workflow_example/transformation_input.json` +- `/Users/gonzalovidal/Documents/GitHub/PUDU/workflow_example/plating_input.json` + +PUDU's documented flow: + +```text +assembly_input.json + -> pudu_assembly_protocol.py + -> opentrons_simulate + -> transformation_input.json + -> pudu_transformation_protocol.py + -> opentrons_simulate + -> plating_input.json + -> pudu_plating_protocol.py + -> opentrons_simulate + -> plating_layout.json / plating_layout.xlsx +``` + +PUDU Python API used in notebook: + +```python +from pudu.generate_protocol import detect_protocol_type, generate_protocol +``` + +PUDU CLI equivalent: + +```bash +python -m pudu.generate_protocol assembly_input.json -o assembly_protocol.py --protocol-type assembly +opentrons_simulate assembly_protocol.py + +python -m pudu.generate_protocol transformation_spec.json -o transformation_protocol.py --protocol-type transformation --plasmid-locations transformation_input.json +opentrons_simulate transformation_protocol.py + +python -m pudu.generate_protocol plating_input.json -o plating_protocol.py --protocol-type plating +opentrons_simulate plating_protocol.py +``` + +## Validation Performed + +Notebook execution: + +```bash +/Users/gonzalovidal/opt/anaconda3/bin/conda run -n GLLDB_py310 python -c "import json; ns={}; nb=json.load(open('notebooks/buildcompiler_transformation_quickstart.ipynb')); [exec(''.join(cell.get('source', [])), ns) for cell in nb['cells'] if cell.get('cell_type') == 'code']" +``` + +Adapter and regression tests: + +```bash +/Users/gonzalovidal/opt/anaconda3/bin/conda run -n GLLDB_py310 python -m pytest tests/unit/adapters/pudu/test_transformation_json.py tests/unit/adapters/pudu/test_plating_json.py tests/test_buildcompiler_transformation.py +``` + +Last observed targeted results: + +- PUDU transformation/plating adapter tests: passed. +- BuildCompiler transformation regression tests: passed. +- Full notebook simulation chain: passed. + +## Current Worktree Notes + +At the time this log was written, expected modified/untracked files included: + +- `src/buildcompiler/adapters/pudu/__init__.py` +- `src/buildcompiler/adapters/pudu/transformation_json.py` +- `src/buildcompiler/adapters/pudu/plating_json.py` +- `src/buildcompiler/buildcompiler.py` +- `tests/test_buildcompiler_transformation.py` +- `tests/unit/adapters/pudu/test_transformation_json.py` +- `tests/unit/adapters/pudu/test_plating_json.py` +- `notebooks/buildcompiler_transformation_quickstart.ipynb` +- `notebooks/results/buildcompiler_transformation_quickstart/` +- `AGENTS_log.md` + +Do not revert unrelated user changes. If these files differ from this log, +inspect before editing. + +## Next Work Suggestions + +- Add a dedicated notebook/test for full-build output feeding the same PUDU + protocol chain. +- Decide whether generated notebook results should be committed or moved to an + ignored artifact path. +- Consider a higher-level BuildCompiler helper that returns all PUDU artifacts + for a stage chain without requiring notebook glue code. +- Add optional dependency documentation for PUDU and Opentrons simulation. +- Keep PUDU as optional unless the package is intentionally added as a dependency. diff --git a/docs/Tutorials.rst b/docs/Tutorials.rst index 9e25bb6..98d58a7 100644 --- a/docs/Tutorials.rst +++ b/docs/Tutorials.rst @@ -34,4 +34,55 @@ Create golden gate assembly plan object with all the parts, the acceptor backbon assembly_plan = s2b.golden_gate_assembly_plan('tutorial_assembly_plan', [promoter, rbs, cds, terminator], backbone, 'BsaI', assembly_doc) - composites = assembly_plan.run() \ No newline at end of file + composites = assembly_plan.run() + +Full build level-2 PUDU artifact package +---------------------------------------- + +The legacy artifact-producing compiler can run a level-2 design and package all +generated SBOL, JSON, and PUDU protocol inputs into a single zip file. If the +level-2 design is missing level-1 region inputs, ``full_build`` attempts level-1 +assembly, falls back to domestication for missing parts, then retries the +downstream assemblies. + +.. code:: python + + from pathlib import Path + + import sbol2 + + from buildcompiler.buildcompiler import BuildCompiler + + test_files = Path("tests/test_files") + collection_docs = [] + for filename in ( + "CIDARMoCloParts_collection.xml", + "CIDARMoCloPlasmidsKit_collection.xml", + "Enzyme_Implementations_collection.xml", + "impl_test_collection.xml", + ): + doc = sbol2.Document() + doc.read(str(test_files / filename)) + collection_docs.append(doc) + + lvl2_design_doc = sbol2.Document() + lvl2_design_doc.read(str(test_files / "ExampleLvl2_design.xml")) + + compiler = BuildCompiler.from_local_documents( + collection_docs, + design_doc=lvl2_design_doc, + ) + result = compiler.full_build( + designs=lvl2_design_doc, + results_dir="results/full_build_lvl2_pudu", + overwrite=True, + ) + + print(result["zip_path"]) + +The zip archive includes ``full_build_manifest.json`` plus PUDU assembly, +transformation, and plating inputs/scripts such as +``assembly_lvl2_pudu_assembly_input.json``, +``assembly_lvl1_pudu_assembly_input.json``, +``domestication_pudu_assembly_input.json``, +``pudu_transformation_protocol.py``, and ``pudu_plating_protocol.py``. diff --git a/notebooks/buildcompiler_transformation_quickstart.ipynb b/notebooks/buildcompiler_transformation_quickstart.ipynb new file mode 100644 index 0000000..e0467ef --- /dev/null +++ b/notebooks/buildcompiler_transformation_quickstart.ipynb @@ -0,0 +1,324 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# BuildCompiler Transformation Quickstart\n", + "\n", + "This notebook runs a local level-1 assembly from `tests/test_files/abstract_design.xml`, then uses the assembly product as the input for chemical transformation." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 1. Imports and Local Paths\n", + "\n", + "Run this notebook from the repository checkout after installing BuildCompiler with `python -m pip install -e .`." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import json\n", + "import os\n", + "import subprocess\n", + "import sys\n", + "from pathlib import Path\n", + "\n", + "import sbol2\n", + "\n", + "from buildcompiler.abstract_translator import extract_toplevel_definition\n", + "from buildcompiler.adapters.pudu import plating_to_pudu_json, transformations_to_pudu_json, write_assembly_pudu_input_json\n", + "from buildcompiler.buildcompiler import BuildCompiler\n", + "\n", + "\n", + "def find_repo_root(start: Path) -> Path:\n", + " for path in [start, *start.parents]:\n", + " if (path / \"pyproject.toml\").exists() and (path / \"tests\" / \"test_files\").exists():\n", + " return path\n", + " raise RuntimeError(\"Could not find BuildCompiler repository root.\")\n", + "\n", + "\n", + "REPO_ROOT = find_repo_root(Path.cwd().resolve())\n", + "TEST_FILES = REPO_ROOT / \"tests\" / \"test_files\"\n", + "RESULTS_DIR = REPO_ROOT / \"notebooks\" / \"results\" / \"buildcompiler_transformation_quickstart\"\n", + "PUDU_REPO = REPO_ROOT.parent / \"PUDU\"\n", + "PUDU_SRC = PUDU_REPO / \"src\"\n", + "RESULTS_DIR.mkdir(parents=True, exist_ok=True)\n", + "\n", + "print(\"Repository:\", REPO_ROOT)\n", + "print(\"Results:\", RESULTS_DIR)\n", + "print(\"PUDU source:\", PUDU_SRC if PUDU_SRC.exists() else \"not found\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 2. Load Offline SBOL Collections\n", + "\n", + "The compiler indexes local plasmids, backbones, and enzyme implementations from these fixture collections." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "collection_paths = [\n", + " TEST_FILES / \"CIDARMoCloParts_collection.xml\",\n", + " TEST_FILES / \"CIDARMoCloPlasmidsKit_collection.xml\",\n", + " TEST_FILES / \"Enzyme_Implementations_collection.xml\",\n", + " TEST_FILES / \"impl_test_collection.xml\",\n", + "]\n", + "\n", + "collection_docs = []\n", + "for path in collection_paths:\n", + " doc = sbol2.Document()\n", + " doc.read(str(path))\n", + " collection_docs.append(doc)\n", + " print(path.name, \"components=\", len(doc.componentDefinitions), \"implementations=\", len(doc.implementations))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 3. Build Level-1 Assembly Products\n", + "\n", + "`abstract_design.xml` is resolved against the local collections and assembled into a level-1 plasmid product." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "design_doc = sbol2.Document()\n", + "design_doc.read(str(TEST_FILES / \"abstract_design.xml\"))\n", + "design = extract_toplevel_definition(design_doc)\n", + "\n", + "compiler = BuildCompiler.from_local_documents(collection_docs, design_doc=design_doc)\n", + "\n", + "assembly_doc = sbol2.Document()\n", + "assembly_routes, assembly_doc = compiler.assembly_lvl1(\n", + " [design],\n", + " final_doc=assembly_doc,\n", + " product_name=\"transformation_lvl1\",\n", + ")\n", + "assembly_products = assembly_routes[design.identity]\n", + "\n", + "lvl1_sbol_path = RESULTS_DIR / \"transformation_lvl1_products.xml\"\n", + "lvl1_pudu_path = RESULTS_DIR / \"assembly_lvl1_pudu_input.json\"\n", + "lvl1_sbol_path.write_text(assembly_doc.writeString(), encoding=\"utf-8\")\n", + "write_assembly_pudu_input_json(compiler.last_assembly_pudu_json, lvl1_pudu_path)\n", + "\n", + "print(\"Design:\", design.displayId)\n", + "print(\"Assembly products:\", [product.plasmid_definition.displayId for product in assembly_products])\n", + "print(\"Level-1 SBOL:\", lvl1_sbol_path)\n", + "print(\"Level-1 assembly PUDU input:\", lvl1_pudu_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 4. Transform the Level-1 Product\n", + "\n", + "The transformation stage consumes the structured level-1 assembly output directly and writes PUDU-compatible transformation inputs." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "CHASSIS_NAME = \"E_coli_DH5alpha\"\n", + "PUDU_CHASSIS_URI = \"https://sbolcanvas.org/DH5alpha/1\"\n", + "\n", + "transformation_result = compiler.transformation(\n", + " assembly_products,\n", + " chassis_name=CHASSIS_NAME,\n", + " transformation_doc=assembly_doc,\n", + ")\n", + "\n", + "transformation_sbol_path = RESULTS_DIR / \"transformation_products.xml\"\n", + "transformation_summary_path = RESULTS_DIR / \"transformation_summary.json\"\n", + "transformation_pudu_path = RESULTS_DIR / \"transformation_lvl1_pudu_input.json\"\n", + "\n", + "transformation_sbol_path.write_text(assembly_doc.writeString(), encoding=\"utf-8\")\n", + "transformation_summary_path.write_text(json.dumps(transformation_result, indent=2), encoding=\"utf-8\")\n", + "\n", + "transformation_pudu = transformations_to_pudu_json(\n", + " strain_identities=[artifact[\"transformed_strain_module\"] for artifact in transformation_result[\"sbol_artifacts\"]],\n", + " chassis_identities=[PUDU_CHASSIS_URI for _ in transformation_result[\"sbol_artifacts\"]],\n", + " plasmid_sets=[[product.plasmid_definition.identity] for product in assembly_products],\n", + ")\n", + "transformation_pudu_path.write_text(json.dumps(transformation_pudu, indent=2), encoding=\"utf-8\")\n", + "\n", + "print(\"Transformation inputs:\", transformation_result[\"inputs\"])\n", + "print(\"Transformation SBOL:\", transformation_sbol_path)\n", + "print(\"Transformation summary:\", transformation_summary_path)\n", + "print(\"Transformation PUDU spec:\", transformation_pudu_path)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 5. Inspect the Generated Records" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "print(json.dumps(transformation_pudu, indent=2))\n", + "print(\"Transformation SBOL artifacts:\")\n", + "for artifact in transformation_result[\"sbol_artifacts\"]:\n", + " print(json.dumps(artifact, indent=2))" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## 6. Run the PUDU Assembly to Transformation to Plating Chain\n", + "\n", + "PUDU uses `opentrons_simulate` as the handoff between stages: assembly simulation writes `transformation_input.json`, transformation simulation writes `plating_input.json`, and plating simulation writes the final plating layout files." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "if not PUDU_SRC.exists():\n", + " raise RuntimeError(f\"PUDU source tree not found at {PUDU_SRC}\")\n", + "if str(PUDU_SRC) not in sys.path:\n", + " sys.path.insert(0, str(PUDU_SRC))\n", + "\n", + "from pudu.generate_protocol import detect_protocol_type, generate_protocol\n", + "\n", + "\n", + "def run_opentrons_simulation(protocol_path: Path) -> Path:\n", + " env = os.environ.copy()\n", + " existing_pythonpath = env.get(\"PYTHONPATH\")\n", + " env[\"PYTHONPATH\"] = str(PUDU_SRC) if not existing_pythonpath else f\"{PUDU_SRC}{os.pathsep}{existing_pythonpath}\"\n", + " log_path = protocol_path.with_suffix(\".simulate.log\")\n", + " result = subprocess.run(\n", + " [\"opentrons_simulate\", protocol_path.name],\n", + " cwd=RESULTS_DIR,\n", + " env=env,\n", + " text=True,\n", + " capture_output=True,\n", + " check=True,\n", + " )\n", + " log_path.write_text(result.stdout + result.stderr, encoding=\"utf-8\")\n", + " return log_path\n", + "\n", + "\n", + "assembly_pudu = json.loads(lvl1_pudu_path.read_text(encoding=\"utf-8\"))\n", + "protocol_type, assembly_subtype = detect_protocol_type(assembly_pudu)\n", + "assert (protocol_type, assembly_subtype) == (\"assembly\", \"SBOL\")\n", + "pudu_assembly_protocol_path = RESULTS_DIR / \"pudu_assembly_protocol.py\"\n", + "pudu_assembly_protocol_path.write_text(\n", + " generate_protocol(\n", + " protocol_data=assembly_pudu,\n", + " protocol_type=\"assembly\",\n", + " assembly_subtype=\"SBOL\",\n", + " metadata={\n", + " \"protocolName\": \"BuildCompiler Level-1 Assembly\",\n", + " \"author\": \"BuildCompiler\",\n", + " \"description\": \"PUDU assembly generated from BuildCompiler level-1 input.\",\n", + " },\n", + " ),\n", + " encoding=\"utf-8\",\n", + ")\n", + "assembly_log_path = run_opentrons_simulation(pudu_assembly_protocol_path)\n", + "transformation_locations_path = RESULTS_DIR / \"transformation_input.json\"\n", + "plasmid_locations = json.loads(transformation_locations_path.read_text(encoding=\"utf-8\"))\n", + "\n", + "protocol_type, assembly_subtype = detect_protocol_type(transformation_pudu)\n", + "assert (protocol_type, assembly_subtype) == (\"transformation\", None)\n", + "\n", + "pudu_protocol_path = RESULTS_DIR / \"pudu_transformation_protocol.py\"\n", + "pudu_protocol_code = generate_protocol(\n", + " protocol_data=transformation_pudu,\n", + " protocol_type=\"transformation\",\n", + " plasmid_locations=plasmid_locations,\n", + " metadata={\n", + " \"protocolName\": \"BuildCompiler Level-1 Transformation\",\n", + " \"author\": \"BuildCompiler\",\n", + " \"description\": \"PUDU heat-shock transformation generated from BuildCompiler level-1 output.\",\n", + " },\n", + ")\n", + "pudu_protocol_path.write_text(pudu_protocol_code, encoding=\"utf-8\")\n", + "transformation_log_path = run_opentrons_simulation(pudu_protocol_path)\n", + "plating_input_path = RESULTS_DIR / \"plating_input.json\"\n", + "plating_input = json.loads(plating_input_path.read_text(encoding=\"utf-8\"))\n", + "plating_input = plating_to_pudu_json(bacterium_locations=plating_input[\"bacterium_locations\"])\n", + "plating_input_path.write_text(json.dumps(plating_input, indent=2), encoding=\"utf-8\")\n", + "\n", + "protocol_type, assembly_subtype = detect_protocol_type(plating_input)\n", + "assert (protocol_type, assembly_subtype) == (\"plating\", None)\n", + "pudu_plating_protocol_path = RESULTS_DIR / \"pudu_plating_protocol.py\"\n", + "pudu_plating_protocol_path.write_text(\n", + " generate_protocol(\n", + " protocol_data=plating_input,\n", + " protocol_type=\"plating\",\n", + " metadata={\n", + " \"protocolName\": \"BuildCompiler Plating\",\n", + " \"author\": \"BuildCompiler\",\n", + " \"description\": \"PUDU plating generated from BuildCompiler transformation output.\",\n", + " },\n", + " ),\n", + " encoding=\"utf-8\",\n", + ")\n", + "plating_log_path = run_opentrons_simulation(pudu_plating_protocol_path)\n", + "\n", + "print(\"Generated PUDU assembly protocol:\", pudu_assembly_protocol_path)\n", + "print(\"Assembly simulation log:\", assembly_log_path)\n", + "print(\"Assembly output for transformation:\", transformation_locations_path)\n", + "print(\"Generated PUDU protocol:\", pudu_protocol_path)\n", + "print(\"Transformation simulation log:\", transformation_log_path)\n", + "print(\"Transformation output for plating:\", plating_input_path)\n", + "print(\"Generated PUDU plating protocol:\", pudu_plating_protocol_path)\n", + "print(\"Plating simulation log:\", plating_log_path)\n", + "print(\"Final plating layout JSON:\", RESULTS_DIR / \"plating_layout.json\")" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.10" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/full_build_workflow_examples.ipynb b/notebooks/full_build_workflow_examples.ipynb new file mode 100644 index 0000000..f631556 --- /dev/null +++ b/notebooks/full_build_workflow_examples.ipynb @@ -0,0 +1,373 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Full Build Workflow Examples\n", + "\n", + "This notebook shows two ways to use the legacy artifact-producing `BuildCompiler.full_build(...)` workflow:\n", + "\n", + "1. A level-1 design that assembles successfully in one pass, then generates transformation and plating artifacts.\n", + "2. A level-2 design example that triggers the recovery stack: assembly level 2, assembly level 1, domestication, transformation, and plating.\n", + "\n", + "`full_build(...)` returns a dictionary with `zip_path` / `artifact_zip`. The zip contains the manifest and all generated PUDU input JSON/scripts." + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Imports and paths" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from pathlib import Path\n", + "import json\n", + "import zipfile\n", + "from unittest.mock import patch\n", + "\n", + "import sbol2\n", + "\n", + "from buildcompiler.abstract_translator import extract_toplevel_definition\n", + "from buildcompiler.buildcompiler import BuildCompiler\n", + "from buildcompiler.constants import ENGINEERED_PLASMID" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "ROOT = Path.cwd()\n", + "if not (ROOT / \"tests\" / \"test_files\").exists():\n", + " ROOT = ROOT.parent\n", + "\n", + "TEST_FILES = ROOT / \"tests\" / \"test_files\"\n", + "RESULTS_DIR = ROOT / \"notebooks\" / \"results\" / \"full_build_workflow_examples\"\n", + "RESULTS_DIR.mkdir(parents=True, exist_ok=True)\n", + "\n", + "def load_sbol(filename):\n", + " doc = sbol2.Document()\n", + " doc.read(str(TEST_FILES / filename))\n", + " return doc\n", + "\n", + "def list_zip(zip_path):\n", + " with zipfile.ZipFile(zip_path, \"r\") as archive:\n", + " return sorted(archive.namelist())\n", + "\n", + "def show_manifest(result):\n", + " manifest = json.loads(Path(result[\"manifest_path\"]).read_text())\n", + " print(json.dumps({\n", + " \"zip_path\": manifest[\"zip_path\"],\n", + " \"domestication\": manifest[\"domestication\"],\n", + " \"assembly_lvl1\": manifest[\"assembly_lvl1\"],\n", + " \"assembly_lvl2\": manifest[\"assembly_lvl2\"],\n", + " \"transformation_count\": len(manifest[\"transformation\"][\"successful\"]),\n", + " \"plating_count\": len(manifest[\"plating\"][\"successful\"]),\n", + " }, indent=2))\n", + "\n", + "print(TEST_FILES)\n", + "print(RESULTS_DIR)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Load local SBOL inventory fixtures\n", + "\n", + "The first example uses the local SBOL fixtures in `tests/test_files` so it can run without SynBioHub credentials." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "collection_docs = [\n", + " load_sbol(\"CIDARMoCloParts_collection.xml\"),\n", + " load_sbol(\"CIDARMoCloPlasmidsKit_collection.xml\"),\n", + " load_sbol(\"Enzyme_Implementations_collection.xml\"),\n", + " load_sbol(\"impl_test_collection.xml\"),\n", + "]\n", + "\n", + "len(collection_docs)" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 1: level-1 design succeeds in one pass\n", + "\n", + "This runs a direct level-1 full build. Since the fixture inventory contains the required part plasmids and backbone, the build should go straight through assembly level 1, transformation, plating, manifest writing, and zip packaging. Level 2 is recorded as skipped because this input is a level-1 design." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "lvl1_design_doc = load_sbol(\"abstract_design.xml\")\n", + "lvl1_design = extract_toplevel_definition(lvl1_design_doc)\n", + "\n", + "lvl1_compiler = BuildCompiler.from_local_documents(\n", + " collection_docs,\n", + " design_doc=lvl1_design_doc,\n", + ")\n", + "\n", + "lvl1_result = lvl1_compiler.full_build(\n", + " designs=[lvl1_design],\n", + " results_dir=RESULTS_DIR / \"lvl1_success\",\n", + " overwrite=True,\n", + ")\n", + "\n", + "print(lvl1_result[\"zip_path\"])\n", + "show_manifest(lvl1_result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_zip(lvl1_result[\"zip_path\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Example 2: level-2 design triggers all stages\n", + "\n", + "The recovery path depends on the available inventory. To make the stage sequence deterministic in a notebook, this example uses a tiny SBOL level-2 design and patches the stage methods to simulate the exact condition we want to demonstrate:\n", + "\n", + "1. The first level-2 assembly attempt fails because level-1 regions are missing.\n", + "2. The first level-1 assembly attempt fails because a part needs domestication.\n", + "3. Domestication produces a part plasmid and PUDU assembly payload.\n", + "4. Level-1 assembly retries successfully.\n", + "5. Level-2 assembly retries successfully.\n", + "6. Transformation and plating artifacts are produced and packaged.\n", + "\n", + "For a real run, remove the patches and provide SBOL collections/designs that naturally produce this dependency stack." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def make_plasmid(doc, display_id):\n", + " plasmid = sbol2.ComponentDefinition(display_id)\n", + " plasmid.roles = [ENGINEERED_PLASMID]\n", + " doc.add(plasmid)\n", + " return plasmid\n", + "\n", + "def make_lvl2_doc():\n", + " doc = sbol2.Document()\n", + " tu = sbol2.ComponentDefinition(\"demo_tu\")\n", + " lvl2 = sbol2.ComponentDefinition(\"demo_lvl2_design\")\n", + " doc.add(tu)\n", + " doc.add(lvl2)\n", + " comp = lvl2.components.create(\"demo_tu_component\")\n", + " comp.definition = tu.identity\n", + " return doc\n", + "\n", + "trigger_doc = sbol2.Document()\n", + "trigger_compiler = BuildCompiler.from_local_documents([], design_doc=trigger_doc)\n", + "\n", + "missing_part = make_plasmid(trigger_compiler.sbol_doc, \"missing_promoter\")\n", + "domesticated = make_plasmid(trigger_compiler.sbol_doc, \"domesticated_missing_promoter\")\n", + "lvl1_product = make_plasmid(trigger_compiler.sbol_doc, \"assembled_demo_tu\")\n", + "lvl2_product = make_plasmid(trigger_compiler.sbol_doc, \"assembled_demo_lvl2\")\n", + "lvl2_design_doc = make_lvl2_doc()\n", + "\n", + "stage_calls = []" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def fake_assembly_lvl2(*args, **kwargs):\n", + " stage_calls.append(\"assembly_lvl2\")\n", + " if stage_calls.count(\"assembly_lvl2\") == 1:\n", + " raise RuntimeError(\"level-2 input is missing level-1 regions\")\n", + " trigger_compiler.last_assembly_pudu_json_by_stage = {\n", + " \"assembly_lvl2\": [\n", + " {\n", + " \"Product\": lvl2_product.identity,\n", + " \"Backbone\": \"demo_lvl2_backbone\",\n", + " \"PartsList\": [lvl1_product.identity],\n", + " \"Restriction Enzyme\": \"BbsI\",\n", + " }\n", + " ]\n", + " }\n", + " return [lvl2_product], trigger_compiler.sbol_doc\n", + "\n", + "def fake_assembly_lvl1(*args, **kwargs):\n", + " stage_calls.append(\"assembly_lvl1\")\n", + " if stage_calls.count(\"assembly_lvl1\") == 1:\n", + " raise RuntimeError(\"level-1 input is missing a domesticated part\")\n", + " trigger_compiler.last_assembly_pudu_json_by_stage = {\n", + " \"assembly_lvl1\": [\n", + " {\n", + " \"Product\": lvl1_product.identity,\n", + " \"Backbone\": \"demo_lvl1_backbone\",\n", + " \"PartsList\": [domesticated.identity],\n", + " \"Restriction Enzyme\": \"BsaI\",\n", + " }\n", + " ]\n", + " }\n", + " return [lvl1_product], trigger_compiler.sbol_doc\n", + "\n", + "def fake_domestication(parts):\n", + " stage_calls.append(\"domestication\")\n", + " trigger_compiler.last_assembly_pudu_json_by_stage = {\n", + " \"domestication\": [\n", + " {\n", + " \"Product\": domesticated.identity,\n", + " \"Backbone\": \"demo_domestication_backbone\",\n", + " \"PartsList\": [missing_part.identity],\n", + " \"Restriction Enzyme\": \"BsaI\",\n", + " }\n", + " ]\n", + " }\n", + " return [domesticated]\n", + "\n", + "def fake_transformation(products, chassis_name=\"E_coli_DH5alpha\", transformation_doc=None):\n", + " stage_calls.append(\"transformation\")\n", + " product_id = products[0].identity\n", + " return {\n", + " \"stage\": \"transformation\",\n", + " \"chassis\": chassis_name,\n", + " \"sbol_artifacts\": [\n", + " {\n", + " \"transformed_strain_module\": f\"{product_id}_strain\",\n", + " \"transformed_strain_implementation\": f\"{product_id}_strain_impl\",\n", + " }\n", + " ],\n", + " }\n", + "\n", + "def fake_plating(*args, **kwargs):\n", + " stage_calls.append(\"plating\")\n", + " return {\n", + " \"stage\": \"plating\",\n", + " \"json_intermediate\": {\n", + " \"plating_data\": {\n", + " \"bacterium_locations\": {\"A1\": \"demo_transformed_strain\"}\n", + " }\n", + " },\n", + " }" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "with patch.object(trigger_compiler, \"assembly_lvl2\", side_effect=fake_assembly_lvl2), \\\n", + " patch.object(trigger_compiler, \"assembly_lvl1\", side_effect=fake_assembly_lvl1), \\\n", + " patch.object(trigger_compiler, \"domestication\", side_effect=fake_domestication), \\\n", + " patch.object(trigger_compiler, \"transformation\", side_effect=fake_transformation), \\\n", + " patch.object(trigger_compiler, \"plating\", side_effect=fake_plating), \\\n", + " patch.object(trigger_compiler, \"_find_missing_parts_for_lvl1\", return_value=[{\"part\": missing_part}]):\n", + " lvl2_result = trigger_compiler.full_build(\n", + " designs=lvl2_design_doc,\n", + " results_dir=RESULTS_DIR / \"lvl2_triggers_all_stages\",\n", + " overwrite=True,\n", + " )\n", + "\n", + "print(stage_calls)\n", + "print(lvl2_result[\"zip_path\"])\n", + "show_manifest(lvl2_result)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "list_zip(lvl2_result[\"zip_path\"])" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Expected PUDU artifacts\n", + "\n", + "For the level-2 staged example, the zip should include at least these PUDU-facing files:\n", + "\n", + "- `assembly_lvl2_pudu_assembly_input.json`\n", + "- `assembly_lvl1_pudu_assembly_input.json`\n", + "- `domestication_pudu_assembly_input.json`\n", + "- `pudu_transformation_protocol.py`\n", + "- `transformation_pudu_input.json`\n", + "- `transformation_plasmid_locations.json`\n", + "- `pudu_plating_protocol.py`\n", + "- `plating_pudu_input.json`\n", + "- `full_build_manifest.json`" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "expected = {\n", + " \"assembly_lvl2_pudu_assembly_input.json\",\n", + " \"assembly_lvl1_pudu_assembly_input.json\",\n", + " \"domestication_pudu_assembly_input.json\",\n", + " \"pudu_transformation_protocol.py\",\n", + " \"transformation_pudu_input.json\",\n", + " \"transformation_plasmid_locations.json\",\n", + " \"pudu_plating_protocol.py\",\n", + " \"plating_pudu_input.json\",\n", + " \"full_build_manifest.json\",\n", + "}\n", + "\n", + "names = set(list_zip(lvl2_result[\"zip_path\"]))\n", + "missing = sorted(expected - names)\n", + "print(\"Missing expected artifacts:\", missing)\n", + "assert not missing" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/results/buildcompiler_transformation_quickstart/Loop Assembly.xlsx b/notebooks/results/buildcompiler_transformation_quickstart/Loop Assembly.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..47c835a22f7b3d78f539e11c10651c63c708ff85 GIT binary patch literal 5576 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 literal 0 HcmV?d00001 diff --git a/notebooks/results/buildcompiler_transformation_quickstart/assembly_lvl1_pudu_input.json b/notebooks/results/buildcompiler_transformation_quickstart/assembly_lvl1_pudu_input.json new file mode 100644 index 0000000..5be9b9c --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/assembly_lvl1_pudu_input.json @@ -0,0 +1,13 @@ +[ + { + "Product": "http://buildcompiler.org/standard_GFP_transformation_lvl1/1", + "Backbone": "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/DVK_AE/1", + "PartsList": [ + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pJ23100_AB/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0034_BC/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pE0040_CD/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0015_DE/1" + ], + "Restriction Enzyme": "https://synbiohub.org/user/Gon/Enzyme_Implementations/BsaI/1" + } +] diff --git a/notebooks/results/buildcompiler_transformation_quickstart/plating_input.json b/notebooks/results/buildcompiler_transformation_quickstart/plating_input.json new file mode 100644 index 0000000..3e59b45 --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/plating_input.json @@ -0,0 +1,16 @@ +{ + "bacterium_locations": { + "A1": [ + "E_coli_DH5alpha_with_standard_GFP_transformation_lvl1", + "Competent_Cell_DH5alpha", + "standard_GFP_transformation_lvl1", + "Media_1" + ], + "B1": [ + "E_coli_DH5alpha_with_standard_GFP_transformation_lvl1", + "Competent_Cell_DH5alpha", + "standard_GFP_transformation_lvl1", + "Media_1" + ] + } +} \ No newline at end of file diff --git a/notebooks/results/buildcompiler_transformation_quickstart/plating_layout.json b/notebooks/results/buildcompiler_transformation_quickstart/plating_layout.json new file mode 100644 index 0000000..03cf209 --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/plating_layout.json @@ -0,0 +1,36 @@ +{ + "agar_plates": { + "plate_1": { + "dilution_1": { + "ratio": "1/10", + "wells": { + "A1": { + "construct": "E_coli_DH5alpha_with_standard_GFP_transformation_lvl1, Competent_Cell_DH5alpha, standard_GFP_transformation_lvl1, Media_1", + "source_well": "A1", + "replicate": 1 + }, + "B1": { + "construct": "E_coli_DH5alpha_with_standard_GFP_transformation_lvl1, Competent_Cell_DH5alpha, standard_GFP_transformation_lvl1, Media_1", + "source_well": "B1", + "replicate": 1 + } + } + }, + "dilution_2": { + "ratio": "1/100", + "wells": { + "A7": { + "construct": "E_coli_DH5alpha_with_standard_GFP_transformation_lvl1, Competent_Cell_DH5alpha, standard_GFP_transformation_lvl1, Media_1", + "source_well": "A1", + "replicate": 1 + }, + "B7": { + "construct": "E_coli_DH5alpha_with_standard_GFP_transformation_lvl1, Competent_Cell_DH5alpha, standard_GFP_transformation_lvl1, Media_1", + "source_well": "B1", + "replicate": 1 + } + } + } + } + } +} \ No newline at end of file diff --git a/notebooks/results/buildcompiler_transformation_quickstart/plating_layout.xlsx b/notebooks/results/buildcompiler_transformation_quickstart/plating_layout.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..de02328d1422d37ad8c4591933509f445ccf9bd5 GIT binary patch literal 6125 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 S`1KF0n|Hv?bJhj_`t~nh|CieU literal 0 HcmV?d00001 diff --git a/notebooks/results/buildcompiler_transformation_quickstart/pudu_assembly_protocol.py b/notebooks/results/buildcompiler_transformation_quickstart/pudu_assembly_protocol.py new file mode 100644 index 0000000..0071dfa --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/pudu_assembly_protocol.py @@ -0,0 +1,91 @@ +from pudu.assembly import SBOLLoopAssembly +from opentrons import protocol_api + + +# Protocol data +assembly_data = [ + { + 'Product': 'http://buildcompiler.org/standard_GFP_transformation_lvl1/1', + 'Backbone': 'https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/DVK_AE/1', + 'PartsList': [ + 'https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pJ23100_AB/1', + 'https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0034_BC/1', + 'https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pE0040_CD/1', + 'https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0015_DE/1' + ], + 'Restriction Enzyme': 'https://synbiohub.org/user/Gon/Enzyme_Implementations/BsaI/1' + } +] + +# Protocol metadata +metadata = { + 'protocolName': 'BuildCompiler Level-1 Assembly', + 'author': 'BuildCompiler', + 'description': 'PUDU assembly generated from BuildCompiler level-1 input.', + 'apiLevel': '2.21' +} + + +def run(protocol: protocol_api.ProtocolContext): + """Main protocol execution function""" + + protocol_instance = SBOLLoopAssembly(assembly_data=assembly_data) + protocol_instance.run(protocol) + + + +# ====================================================================== +# PARAMETER REFERENCE — SBOLLoopAssembly +# +# To customize your protocol, add any of the parameters below +# to the SBOLLoopAssembly() constructor call in run() above. +# Example: protocol_instance = SBOLLoopAssembly( +# assembly_data=assembly_data, +# replicates=3, +# initial_tip='B1', +# ) +# ====================================================================== +# +# [SBOLLoopAssembly] +# assembly_data Optional = None +# json_params Optional = None +# assemblies Optional = None +# +# [BaseAssembly] +# volume_total_reaction float = 20 +# volume_part float = 2 +# volume_restriction_enzyme float = 2 +# volume_t4_dna_ligase float = 4 +# volume_t4_dna_ligase_buffer float = 2 +# replicates int = 1 +# thermocycler_starting_well int = 0 +# thermocycler_labware str = nest_96_wellplate_100ul_pcr_full_skirt +# temperature_module_labware str = opentrons_24_aluminumblock_nest_1.5ml_snapcap +# temperature_module_position str = 1 +# tiprack_labware str = opentrons_96_tiprack_20ul +# tiprack_positions Optional = None +# pipette str = p20_single_gen2 +# pipette_position str = left +# initial_tip Optional = None +# aspiration_rate float = 0.5 +# dispense_rate float = 1 +# take_picture bool = False +# take_video bool = False +# water_testing bool = False +# output_xlsx bool = True +# protocol_name str = +# +# ---------------------------------------------------------------------- +# Full parameter descriptions: +# +# [SBOLLoopAssembly] +# SBOL Loop Assembly - handles explicit assembly dictionaries from SBOL format. +# Each assembly dictionary represents one specific construct to build. +# +# [BaseAssembly] +# Abstract base class for Loop Assembly protocols. +# Contains shared hardware setup, liquid handling, and tip management functionality. +# +# [ABC] +# Helper class that provides a standard way to create an ABC using +# inheritance. \ No newline at end of file diff --git a/notebooks/results/buildcompiler_transformation_quickstart/pudu_assembly_protocol.simulate.log b/notebooks/results/buildcompiler_transformation_quickstart/pudu_assembly_protocol.simulate.log new file mode 100644 index 0000000..eefb7f3 --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/pudu_assembly_protocol.simulate.log @@ -0,0 +1,152 @@ +Parts and reagents in temp_module +{'Deionized Water': 'A1', 'T4 DNA Ligase Buffer': 'B1', 'T4 DNA Ligase': 'C1', 'Restriction Enzyme BsaI': 'D1', 'DVK_AE': 'A2', 'pB0015_DE': 'B2', 'pB0034_BC': 'C2', 'pE0040_CD': 'D2', 'pJ23100_AB': 'A3'} +Assembled parts in thermocycler_module +{'Replicate: 1, Product: standard_GFP_transformation_lvl1': 'A1'} +DNA list for transformation protocol +['standard_GFP_transformation_lvl1_rep1'] +Protocol requires 9 tips (1 racks) +Loaded Deionized Water at position A1 +Loaded T4 DNA Ligase Buffer at position B1 +Loaded T4 DNA Ligase at position C1 +Loaded Restriction Enzyme BsaI at position D1 +Loaded DVK_AE at position A2 +Loaded pB0015_DE at position B2 +Loaded pB0034_BC at position C2 +Loaded pE0040_CD at position D2 +Loaded pJ23100_AB at position A3 +Opening Thermocycler lid +Setting Temperature Module temperature to 4.0 °C (rounded off to nearest integer) +Setting Thermocycler well block temperature to 4.0 °C +Picking up tip from A1 of Opentrons OT-2 96 Tip Rack 20 µL on slot 2 +Aspirating 2.0 uL from A1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 3.78 uL/sec +Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Touching tip +Dropping tip into Trash Bin on slot 12 +Picking up tip from B1 of Opentrons OT-2 96 Tip Rack 20 µL on slot 2 +Mixing 3 times with a volume of 2.0 ul + Aspirating 2.0 uL from B1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into B1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from B1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into B1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from B1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into B1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec +Aspirating 2.0 uL from B1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 3.78 uL/sec +Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Touching tip +Dropping tip into Trash Bin on slot 12 +Picking up tip from C1 of Opentrons OT-2 96 Tip Rack 20 µL on slot 2 +Mixing 3 times with a volume of 4.0 ul + Aspirating 4.0 uL from C1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 4.0 uL into C1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 4.0 uL from C1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 4.0 uL into C1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 4.0 uL from C1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 4.0 uL into C1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec +Aspirating 4.0 uL from C1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 3.78 uL/sec +Dispensing 4.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Touching tip +Dropping tip into Trash Bin on slot 12 +Picking up tip from D1 of Opentrons OT-2 96 Tip Rack 20 µL on slot 2 +Mixing 3 times with a volume of 2.0 ul + Aspirating 2.0 uL from D1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into D1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from D1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into D1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from D1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into D1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec +Aspirating 2.0 uL from D1 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 3.78 uL/sec +Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Touching tip +Dropping tip into Trash Bin on slot 12 +Picking up tip from E1 of Opentrons OT-2 96 Tip Rack 20 µL on slot 2 +Mixing 3 times with a volume of 2.0 ul + Aspirating 2.0 uL from A2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into A2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from A2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into A2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from A2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into A2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec +Aspirating 2.0 uL from A2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 3.78 uL/sec +Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Touching tip +Dropping tip into Trash Bin on slot 12 +Picking up tip from F1 of Opentrons OT-2 96 Tip Rack 20 µL on slot 2 +Mixing 3 times with a volume of 2.0 ul + Aspirating 2.0 uL from A3 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into A3 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from A3 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into A3 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from A3 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into A3 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec +Aspirating 2.0 uL from A3 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 3.78 uL/sec +Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Touching tip +Dropping tip into Trash Bin on slot 12 +Picking up tip from G1 of Opentrons OT-2 96 Tip Rack 20 µL on slot 2 +Mixing 3 times with a volume of 2.0 ul + Aspirating 2.0 uL from C2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into C2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from C2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into C2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from C2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into C2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec +Aspirating 2.0 uL from C2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 3.78 uL/sec +Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Touching tip +Dropping tip into Trash Bin on slot 12 +Picking up tip from H1 of Opentrons OT-2 96 Tip Rack 20 µL on slot 2 +Mixing 3 times with a volume of 2.0 ul + Aspirating 2.0 uL from D2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into D2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from D2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into D2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from D2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into D2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec +Aspirating 2.0 uL from D2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 3.78 uL/sec +Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Touching tip +Dropping tip into Trash Bin on slot 12 +Picking up tip from A2 of Opentrons OT-2 96 Tip Rack 20 µL on slot 2 +Mixing 3 times with a volume of 2.0 ul + Aspirating 2.0 uL from B2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into B2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from B2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into B2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Aspirating 2.0 uL from B2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec + Dispensing 2.0 uL into B2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 7.56 uL/sec +Aspirating 2.0 uL from B2 of Opentrons 24 Well Aluminum Block with NEST 1.5 mL Snapcap on Temperature Module GEN1 on slot 1 at 3.78 uL/sec +Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Touching tip +Aspirating 20.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Dispensing 20.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Touching tip +Aspirating 20.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Dispensing 20.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Touching tip +Dropping tip into Trash Bin on slot 12 +Take out the reagents since the temperature module will be turn off +Closing Thermocycler lid +Setting Thermocycler lid temperature to 42.0 °C +Deactivating Temperature Module +Thermocycler starting 75 repetitions of cycle composed of the following steps: [{'temperature': 42, 'hold_time_minutes': 2}, {'temperature': 16, 'hold_time_minutes': 5}] +Thermocycler starting 1 repetitions of cycle composed of the following steps: [{'temperature': 60, 'hold_time_minutes': 10}, {'temperature': 80, 'hold_time_minutes': 10}] +Setting Thermocycler well block temperature to 4.0 °C + +====================================================================== +Generated transformation_input.json for transformation protocol + Products: 1 +====================================================================== +/Users/gonzalovidal/.opentrons/robot_settings.json not found. Loading defaults +Deck calibration not found. +/Users/gonzalovidal/.opentrons/deck_calibration.json not found. Loading defaults diff --git a/notebooks/results/buildcompiler_transformation_quickstart/pudu_plating_protocol.py b/notebooks/results/buildcompiler_transformation_quickstart/pudu_plating_protocol.py new file mode 100644 index 0000000..52707ce --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/pudu_plating_protocol.py @@ -0,0 +1,125 @@ +from pudu.plating import Plating +from opentrons import protocol_api + + +# Protocol data +plating_data = { + 'bacterium_locations': { + 'A1': [ + 'E_coli_DH5alpha_with_standard_GFP_transformation_lvl1', + 'Competent_Cell_DH5alpha', + 'standard_GFP_transformation_lvl1', + 'Media_1' + ], + 'B1': [ + 'E_coli_DH5alpha_with_standard_GFP_transformation_lvl1', + 'Competent_Cell_DH5alpha', + 'standard_GFP_transformation_lvl1', + 'Media_1' + ] + } +} + +# Protocol metadata +metadata = { + 'protocolName': 'BuildCompiler Plating', + 'author': 'BuildCompiler', + 'description': 'PUDU plating generated from BuildCompiler transformation output.', + 'apiLevel': '2.21' +} + + +def run(protocol: protocol_api.ProtocolContext): + """Main protocol execution function""" + + protocol_instance = Plating(plating_data=plating_data) + protocol_instance.run(protocol) + + + +# ====================================================================== +# PARAMETER REFERENCE — Plating +# +# To customize your protocol, add any of the parameters below +# to the Plating() constructor call in run() above. +# Example: protocol_instance = Plating( +# plating_data=plating_data, +# replicates=3, +# initial_tip='B1', +# ) +# ====================================================================== +# +# [Plating] +# plating_data Optional = None +# json_params Optional = None +# volume_total_reaction float = 20 +# volume_bacteria_transfer float = 2 +# volume_colony float = 4 +# dilution_factor float = 10 +# volume_lb float = 10000 +# replicates int = 1 +# number_dilutions int = 2 +# max_colonies int = 192 +# thermocycler_starting_well int = 0 +# thermocycler_labware str = biorad_96_wellplate_200ul_pcr +# small_tiprack str = opentrons_96_filtertiprack_20ul +# small_tiprack_position str = 9 +# initial_small_tip Optional = None +# large_tiprack str = opentrons_96_filtertiprack_200ul +# large_tiprack_position str = 1 +# initial_large_tip Optional = None +# small_pipette str = p20_single_gen2 +# small_pipette_position str = left +# large_pipette str = p300_single_gen2 +# large_pipette_position str = right +# dilution_plate str = nest_96_wellplate_100ul_pcr_full_skirt +# dilution_plate_position1 str = 2 +# dilution_plate_position2 str = 3 +# agar_plate str = nest_96_wellplate_100ul_pcr_full_skirt +# agar_plate_position1 str = 5 +# agar_plate_position2 str = 6 +# tube_rack str = opentrons_15_tuberack_falcon_15ml_conical +# tube_rack_position str = 4 +# lb_tube_position int = 0 +# aspiration_rate float = 0.5 +# dispense_rate float = 1 +# bacterium_locations Optional = None +# protocol_name str = plating_layout +# +# ---------------------------------------------------------------------- +# Full parameter descriptions: +# +# [Plating] +# Automated serial-dilution and spot-plating protocol for the Opentrons OT-2. +# +# Takes transformed bacteria from a thermocycler plate, performs up to two +# sequential 10× (or custom) dilutions in a dilution plate, and spots each +# dilution onto an agar plate. Supports multiple replicates and automatically +# distributes across two physical plates when colony counts exceed 96. +# +# After simulation, writes a JSON and an Excel file mapping each agar-plate +# well to the construct name, dilution ratio, and replicate number. +# +# Attributes: +# volume_total_reaction: Volume of bacteria loaded in each thermocycler +# source well, in µL. Used for liquid-tracking display only. +# volume_bacteria_transfer: Volume transferred from each source well into +# the dilution well, in µL. +# volume_colony: Volume spotted from each dilution well onto the agar +# plate per replicate, in µL. +# dilution_factor: Serial dilution factor applied at each step (e.g. 10 +# for a 1:10 dilution). The LB volume pre-loaded into each dilution +# well is ``volume_bacteria_transfer × (dilution_factor − 1)``. +# volume_lb: Total LB volume in the stock tube, in µL. Used for liquid +# tracking on the Opentrons deck visualiser. +# replicates: Number of agar spots per construct per dilution step. +# number_dilutions: Number of serial dilution steps to perform (max 2). +# number_constructs: Number of unique constructs derived from +# ``bacterium_locations``. +# total_colonies: Total agar wells that will be plated +# (``number_constructs × number_dilutions × replicates``). +# max_colonies: Hard cap on ``total_colonies``; raises ``ValueError`` +# if exceeded. +# bacterium_locations: Dict mapping thermocycler well names to construct +# identifiers, e.g. ``{'A1': 'GFP_construct', 'B1': ['RFP', 'v2']}``. +# protocol_name: Base name for output files (JSON and Excel). \ No newline at end of file diff --git a/notebooks/results/buildcompiler_transformation_quickstart/pudu_plating_protocol.simulate.log b/notebooks/results/buildcompiler_transformation_quickstart/pudu_plating_protocol.simulate.log new file mode 100644 index 0000000..1aa3a42 --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/pudu_plating_protocol.simulate.log @@ -0,0 +1,105 @@ +Using one plate: 2 wells per dilution fits in each half +Using one plate: 2 wells per dilution fits in each half +Setting Thermocycler well block temperature to 4.0 °C +Opening Thermocycler lid + +=== Step 1: Distributing LB to dilution wells === +Picking up tip from A1 of Opentrons OT-2 96 Filter Tip Rack 200 µL on slot 1 +Conical calculation: 10000µL remaining = 61.7mm height +Distributing to wells 1-4 +Distributing 18.0 from A1 of Opentrons 15 Tube Rack with Falcon 15 mL Conical on slot 4 to A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 + Transferring 18.0 from A1 of Opentrons 15 Tube Rack with Falcon 15 mL Conical on slot 4 to A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 + Aspirating 76.0 uL from A1 of Opentrons 15 Tube Rack with Falcon 15 mL Conical on slot 4 at 92.86 uL/sec + Dispensing 18.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 92.86 uL/sec + Dispensing 18.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 92.86 uL/sec + Dispensing 18.0 uL into A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 92.86 uL/sec + Dispensing 18.0 uL into B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 92.86 uL/sec + Blowing out into Trash Bin on slot 12 +Dropping tip into Trash Bin on slot 12 + +=== Step 2: Transferring bacteria and plating === + +Processing construct 1: ['E_coli_DH5alpha_with_standard_GFP_transformation_lvl1', 'Competent_Cell_DH5alpha', 'standard_GFP_transformation_lvl1', 'Media_1'] +Picking up tip from A1 of Opentrons OT-2 96 Filter Tip Rack 20 µL on slot 9 +Aspirating 2.0 uL from A1 of Bio-Rad 96 Well Plate 200 µL PCR on Thermocycler Module GEN1 on slot 7 at 3.78 uL/sec +Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec +Mixing 5 times with a volume of 19.0 ul + Aspirating 19.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec +Aspirating 2.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 3.78 uL/sec +Dispensing 2.0 uL into A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec +Mixing 5 times with a volume of 19.0 ul + Aspirating 19.0 uL from A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec +Aspirating 4.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 3.78 uL/sec +Dispensing 4.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 5 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 5 +Dropping tip into Trash Bin on slot 12 +Picking up tip from B1 of Opentrons OT-2 96 Filter Tip Rack 20 µL on slot 9 +Aspirating 4.0 uL from A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 3.78 uL/sec +Dispensing 4.0 uL into A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 5 at 7.56 uL/sec +Blowing out at A7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 5 +Dropping tip into Trash Bin on slot 12 + +Processing construct 2: ['E_coli_DH5alpha_with_standard_GFP_transformation_lvl1', 'Competent_Cell_DH5alpha', 'standard_GFP_transformation_lvl1', 'Media_1'] +Picking up tip from C1 of Opentrons OT-2 96 Filter Tip Rack 20 µL on slot 9 +Aspirating 2.0 uL from B1 of Bio-Rad 96 Well Plate 200 µL PCR on Thermocycler Module GEN1 on slot 7 at 3.78 uL/sec +Dispensing 2.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec +Mixing 5 times with a volume of 19.0 ul + Aspirating 19.0 uL from B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec +Aspirating 2.0 uL from B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 3.78 uL/sec +Dispensing 2.0 uL into B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec +Mixing 5 times with a volume of 19.0 ul + Aspirating 19.0 uL from B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 19.0 uL from B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 19.0 uL into B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec +Aspirating 4.0 uL from B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 3.78 uL/sec +Dispensing 4.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 5 at 7.56 uL/sec +Blowing out at B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 5 +Dropping tip into Trash Bin on slot 12 +Picking up tip from D1 of Opentrons OT-2 96 Filter Tip Rack 20 µL on slot 9 +Aspirating 4.0 uL from B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 3.78 uL/sec +Dispensing 4.0 uL into B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 5 at 7.56 uL/sec +Blowing out at B7 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 5 +Dropping tip into Trash Bin on slot 12 + +=== Plating protocol complete === +Plated 2 constructs with 1 replicates +Created a total of 4 colonies +Generated plating_layout.json +Generated plating_layout.xlsx +/Users/gonzalovidal/.opentrons/robot_settings.json not found. Loading defaults +Deck calibration not found. +/Users/gonzalovidal/.opentrons/deck_calibration.json not found. Loading defaults diff --git a/notebooks/results/buildcompiler_transformation_quickstart/pudu_transformation_protocol.py b/notebooks/results/buildcompiler_transformation_quickstart/pudu_transformation_protocol.py new file mode 100644 index 0000000..a76c2f2 --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/pudu_transformation_protocol.py @@ -0,0 +1,217 @@ +from pudu.transformation import HeatShockTransformation +from opentrons import protocol_api + + +# Protocol data +transformation_data = [ + { + 'Strain': 'http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_transformation_lvl1/1', + 'Chassis': 'https://sbolcanvas.org/DH5alpha/1', + 'Plasmids': ['http://buildcompiler.org/standard_GFP_transformation_lvl1/1'] + } +] + +# Plasmid well locations from assembly protocol output +plasmid_locations = { + 'http://buildcompiler.org/standard_GFP_transformation_lvl1/1': ['A1'] +} + +# Protocol metadata +metadata = { + 'protocolName': 'BuildCompiler Level-1 Transformation', + 'author': 'BuildCompiler', + 'description': 'PUDU heat-shock transformation generated from BuildCompiler level-1 output.', + 'apiLevel': '2.21' +} + + +def run(protocol: protocol_api.ProtocolContext): + """Main protocol execution function""" + + protocol_instance = HeatShockTransformation( + transformation_data=transformation_data, + plasmid_locations=plasmid_locations + ) + protocol_instance.run(protocol) + + + +# ====================================================================== +# PARAMETER REFERENCE — HeatShockTransformation +# +# To customize your protocol, add any of the parameters below +# to the HeatShockTransformation() constructor call in run() above. +# Example: protocol_instance = HeatShockTransformation( +# transformation_data=transformation_data, +# replicates=3, +# initial_tip='B1', +# ) +# ====================================================================== +# +# [HeatShockTransformation] +# transformation_data Optional = None +# plasmid_locations Optional = None +# json_params Optional = None +# transfer_volume_dna float = 2 +# transfer_volume_competent_cell float = 20 +# tube_volume_competent_cell float = 100 +# transfer_volume_recovery_media float = 60 +# tube_volume_recovery_media float = 1200 +# cold_incubation1 Optional = None +# heat_shock Optional = None +# cold_incubation2 Optional = None +# recovery_incubation Optional = None +# +# [Transformation] +# volume_dna float = 20 +# replicates int = 2 +# thermocycler_starting_well int = 0 +# thermocycler_labware str = nest_96_wellplate_100ul_pcr_full_skirt +# temperature_module_labware str = opentrons_24_aluminumblock_nest_1.5ml_snapcap +# temperature_module_position str = 1 +# dna_plate str = nest_96_wellplate_100ul_pcr_full_skirt +# dna_plate_position str = 2 +# use_dna_96plate bool = False +# tiprack_p20_labware str = opentrons_96_tiprack_20ul +# tiprack_p20_position str = 9 +# tiprack_p200_labware str = opentrons_96_filtertiprack_200ul +# tiprack_p200_position str = 6 +# pipette_p20 str = p20_single_gen2 +# pipette_p20_position str = left +# pipette_p300 str = p300_single_gen2 +# pipette_p300_position str = right +# aspiration_rate float = 0.5 +# dispense_rate float = 1 +# initial_dna_well int = 0 +# water_testing bool = False +# initial_tip_p20 Optional = None +# initial_tip_p300 Optional = None +# tube_rack_labware str = opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap +# tube_rack_position str = 3 +# +# ---------------------------------------------------------------------- +# Full parameter descriptions: +# +# [HeatShockTransformation] +# Heat shock transformation protocol for the Opentrons OT-2. +# +# Automates the full heat shock transformation workflow: loading DNA and competent +# cells into a thermocycler plate, running the heat shock cycle, adding recovery +# media, and exporting a plating map for the next protocol step. +# +# Inherits all base parameters from Transformation. The attributes below are +# specific to the heat shock transformation protocol. +# +# Attributes +# ---------- +# transfer_volume_dna : float +# Volume of DNA to transfer into each thermocycler well, in microliters. +# By default, 2 microliters. Note: this is the volume actually pipetted per +# reaction, distinct from volume_dna (the volume loaded into the source well). +# transfer_volume_competent_cell : float +# Volume of competent cells to transfer into each thermocycler well, in +# microliters. By default, 20 microliters. +# tube_volume_competent_cell : float +# Total usable volume of competent cells per tube, in microliters. Used to +# calculate how many reactions each tube can supply before switching to the +# next tube. By default, 100 microliters. +# transfer_volume_recovery_media : float +# Volume of recovery media to add to each well after heat shock, in +# microliters. By default, 60 microliters. +# tube_volume_recovery_media : float +# Total usable volume of recovery media per tube, in microliters. Used to +# calculate how many wells each tube can supply. By default, 1200 microliters. +# cold_incubation1 : dict +# First cold incubation step (on ice before heat shock). A dict with keys +# 'temperature' (°C) and 'hold_time_minutes'. +# By default, {'temperature': 4, 'hold_time_minutes': 30}. +# heat_shock : dict +# Heat shock step. A dict with keys 'temperature' (°C) and 'hold_time_minutes'. +# By default, {'temperature': 42, 'hold_time_minutes': 1}. +# cold_incubation2 : dict +# Second cold incubation immediately after heat shock. A dict with keys +# 'temperature' (°C) and 'hold_time_minutes'. +# By default, {'temperature': 4, 'hold_time_minutes': 2}. +# recovery_incubation : dict +# Recovery incubation after recovery media addition. A dict with keys +# 'temperature' (°C) and 'hold_time_minutes'. +# By default, {'temperature': 37, 'hold_time_minutes': 60}. +# +# [Transformation] +# Base class for automated transformation protocols on the Opentrons OT-2. +# +# Handles loading transformation data, validating parameters, and providing +# shared utilities used by all transformation subclasses. Subclasses implement +# the specific thermocycler workflow (e.g. heat shock). +# +# Attributes +# ---------- +# volume_dna : float +# Volume of DNA loaded into each source well, in microliters. By default, +# 20 microliters. We suggest 2 µL for extracted plasmid and 5 µL for PCR +# products when setting transfer_volume_dna in the subclass. +# replicates : int +# Number of transformation replicates per strain per assembly location. +# By default, 2. +# thermocycler_starting_well : int +# Zero-indexed starting well in the thermocycler plate. By default, 0 (well A1). +# thermocycler_labware : str +# Labware type for the thermocycler plate. +# By default, 'nest_96_wellplate_100ul_pcr_full_skirt'. +# temperature_module_labware : str +# Labware type for the aluminum block on the temperature module. +# By default, 'opentrons_24_aluminumblock_nest_1.5ml_snapcap'. +# temperature_module_position : str +# Deck slot for the temperature module. By default, '1'. +# dna_plate : str +# Labware type for the 96-well DNA source plate (used when use_dna_96plate=True). +# By default, 'nest_96_wellplate_100ul_pcr_full_skirt'. +# dna_plate_position : str +# Deck slot for the 96-well DNA source plate. By default, '2'. +# use_dna_96plate : bool +# If True, DNA is sourced from a 96-well plate at fixed positions given by +# plasmid_locations. Automatically set to True when plasmid_locations is +# provided. By default, False. +# tiprack_p20_labware : str +# Labware type for the p20 tip rack. By default, 'opentrons_96_tiprack_20ul'. +# tiprack_p20_position : str +# Deck slot for the p20 tip rack. By default, '9'. +# tiprack_p200_labware : str +# Labware type for the p200 tip rack. +# By default, 'opentrons_96_filtertiprack_200ul'. +# tiprack_p200_position : str +# Deck slot for the p200 tip rack. By default, '6'. +# pipette_p20 : str +# Pipette model for the p20 single-channel. By default, 'p20_single_gen2'. +# pipette_p20_position : str +# Mount for the p20 pipette ('left' or 'right'). By default, 'left'. +# pipette_p300 : str +# Pipette model for the p300 single-channel. By default, 'p300_single_gen2'. +# pipette_p300_position : str +# Mount for the p300 pipette ('left' or 'right'). By default, 'right'. +# aspiration_rate : float +# Relative aspiration speed as a fraction of the pipette's maximum flow +# rate, where 1.0 is full speed and 0.5 is half speed. Lower values +# reduce bubble formation. By default, 0.5. +# dispense_rate : float +# Relative dispense speed as a fraction of the pipette's maximum flow +# rate, where 1.0 is full speed. By default, 1.0. +# initial_dna_well : int +# Zero-indexed starting well for DNA tubes on the aluminum block (used when +# use_dna_96plate=False). By default, 0. +# water_testing : bool +# If True, uses water in place of competent cells and recovery media during +# simulation/testing runs. By default, False. +# initial_tip_p20 : str, optional +# Well name of the first tip to use from the p20 tip rack (e.g. 'B1'). +# If None, starts from the first available tip. By default, None. +# initial_tip_p300 : str, optional +# Well name of the first tip to use from the p300 tip rack (e.g. 'C3'). +# If None, starts from the first available tip. By default, None. +# tube_rack_labware : str +# Labware type for the tube rack that holds competent cells and recovery +# media. Moving these off the temperature module frees the entire aluminum +# block for DNA plasmids, maximising unique constructs per run. +# By default, 'opentrons_24_tuberack_eppendorf_1.5ml_safelock_snapcap'. +# tube_rack_position : str +# Deck slot for the tube rack. By default, '3'. \ No newline at end of file diff --git a/notebooks/results/buildcompiler_transformation_quickstart/pudu_transformation_protocol.simulate.log b/notebooks/results/buildcompiler_transformation_quickstart/pudu_transformation_protocol.simulate.log new file mode 100644 index 0000000..949672b --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/pudu_transformation_protocol.simulate.log @@ -0,0 +1,78 @@ +DNA constructs in DNA plate +{'standard_GFP_transformation_lvl1': ['A1']} +Competent cells and media in tube rack +{'Competent Cell DH5alpha_1': 'A1', 'Media_1': 'B1'} +Genetically modified organisms in thermocycler +{'A1': ['E_coli_DH5alpha_with_standard_GFP_transformation_lvl1', 'Competent_Cell_DH5alpha', 'standard_GFP_transformation_lvl1', 'Media_1'], 'B1': ['E_coli_DH5alpha_with_standard_GFP_transformation_lvl1', 'Competent_Cell_DH5alpha', 'standard_GFP_transformation_lvl1', 'Media_1']} +Simulation detected - enabling water testing mode +Opening Thermocycler lid +Distributing 20.0 from A1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 to A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 + Transferring 20.0 from A1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 to A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 + Picking up tip from A1 of Opentrons OT-2 96 Filter Tip Rack 200 µL on slot 6 + Mixing 3 times with a volume of 50.0 ul + Aspirating 50.0 uL from A1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 at 92.86 uL/sec + Dispensing 50.0 uL into A1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 at 92.86 uL/sec + Aspirating 50.0 uL from A1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 at 92.86 uL/sec + Dispensing 50.0 uL into A1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 at 92.86 uL/sec + Aspirating 50.0 uL from A1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 at 92.86 uL/sec + Dispensing 50.0 uL into A1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 at 92.86 uL/sec + Aspirating 40.0 uL from A1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 at 92.86 uL/sec + Dispensing 20.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 92.86 uL/sec + Dispensing 20.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 92.86 uL/sec + Dropping tip into Trash Bin on slot 12 +Picking up tip from A1 of Opentrons OT-2 96 Tip Rack 20 µL on slot 9 +Mixing 3 times with a volume of 2.0 ul + Aspirating 2.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 2.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 2.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec +Aspirating 2.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 3.78 uL/sec +Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Aspirating 20.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Dispensing 20.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Aspirating 20.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Dispensing 20.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Touching tip +Dropping tip into Trash Bin on slot 12 +Picking up tip from B1 of Opentrons OT-2 96 Tip Rack 20 µL on slot 9 +Mixing 3 times with a volume of 2.0 ul + Aspirating 2.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 2.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Aspirating 2.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec + Dispensing 2.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 7.56 uL/sec +Aspirating 2.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on slot 2 at 3.78 uL/sec +Dispensing 2.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Blowing out at B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 +Aspirating 20.0 uL from B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Dispensing 20.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Aspirating 20.0 uL from B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Dispensing 20.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 7.56 uL/sec +Touching tip +Dropping tip into Trash Bin on slot 12 +Closing Thermocycler lid +Opening Thermocycler lid +Distributing 60.0 from B1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 to A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 + Transferring 60.0 from B1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 to A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 + Picking up tip from B1 of Opentrons OT-2 96 Filter Tip Rack 200 µL on slot 6 + Aspirating 120.0 uL from B1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 at 92.86 uL/sec + Air gap of 10 uL + Aspirating 10.0 uL from B1 of Opentrons 24 Tube Rack with Eppendorf 1.5 mL Safe-Lock Snapcap on slot 3 at 92.86 uL/sec + Dispensing 70.0 uL into A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 92.86 uL/sec + Air gap of 10 uL + Aspirating 10.0 uL from A1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 92.86 uL/sec + Dispensing 70.0 uL into B1 of NEST 96 Well Plate 100 µL PCR Full Skirt on Thermocycler Module GEN1 on slot 7 at 92.86 uL/sec + Dropping tip into Trash Bin on slot 12 +Closing Thermocycler lid + +====================================================================== +Generated plating_input.json for next protocol + Bacteria locations: 2 +====================================================================== +/Users/gonzalovidal/.opentrons/robot_settings.json not found. Loading defaults +Deck calibration not found. +/Users/gonzalovidal/.opentrons/deck_calibration.json not found. Loading defaults diff --git a/notebooks/results/buildcompiler_transformation_quickstart/transformation_input.json b/notebooks/results/buildcompiler_transformation_quickstart/transformation_input.json new file mode 100644 index 0000000..195ee0f --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/transformation_input.json @@ -0,0 +1,5 @@ +{ + "http://buildcompiler.org/standard_GFP_transformation_lvl1/1": [ + "A1" + ] +} \ No newline at end of file diff --git a/notebooks/results/buildcompiler_transformation_quickstart/transformation_lvl1_products.xml b/notebooks/results/buildcompiler_transformation_quickstart/transformation_lvl1_products.xml new file mode 100644 index 0000000..17363de --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/transformation_lvl1_products.xml @@ -0,0 +1,550 @@ + + + + + + + Ligation_Scar_A + 1 + + + + + + Ligation_Scar_B + + + 1 + + + + + + 1 + + + + + + Ligation_Scar_C + + + + + + + Ligation_Scar_D + + 1 + + + + + + 1 + + Ligation_Scar_E + + + + + + + + + + 1 + + + J23100 + + + + + + + B0015_3_annotation + 1 + + + B0015_3_location + 1 + 793 + 921 + + + + + + + + + + Ligation_Scar_D_annotation + + + + 1 + 792 + 789 + + Ligation_Scar_D_location + + + 1 + + + + + + + + + + Ligation_Scar_C_B0034 + + + 1 + + + standard_GFP_transformation_lvl1 + + + + + + + 1 + 1 + 4 + + Ligation_Scar_A_location + + + Ligation_Scar_A_annotation + 1 + + + + + + + + Ligation_Scar_E + + 1 + + + + + + + 1 + Ligation_Scar_A + + + + + + + 1 + + B0015 + + + + + + + + Ligation_Scar_E_B0015 + + 1 + + + + + + + + + + 3152 + 926 + 1 + + dvk_backbone_core_5_location + + + + dvk_backbone_core_5_annotation + 1 + + + + + + dvk_backbone_core + + 1 + + + + + + + + + Ligation_Scar_E_annotation + + + + 922 + Ligation_Scar_E_location + 925 + 1 + + + + 1 + + + + + Ligation_Scar_C_annotation + + + + 1 + + 68 + Ligation_Scar_C_location + + 65 + + + 1 + + + + + + B0034_Ligation_Scar_B + + 1 + + + + + + + + + + + 69 + 1 + + 788 + E0040m_gfp_3_location + + + + + E0040m_gfp_3_annotation + 1 + + + standard_GFP_transformation_lvl1 + + + + + 1 + E0040m_gfp + + + + + + + + + + 1 + 43 + + Ligation_Scar_B_location + 40 + + + 1 + + + Ligation_Scar_B_annotation + + + + + + 1 + + + Ligation_Scar_B + + + + + B0034 + + 1 + + + + + + + 1 + + + + + dvk_backbone_core_Ligation_Scar_E + + + + + + + 1 + B0034_3_location + 64 + + + 44 + + + B0034_3_annotation + + + 1 + + + + + + + J23100_Ligation_Scar_A + 1 + + + + + + + + J23100_3_annotation + 1 + + + + + J23100_3_location + 5 + + + 39 + 1 + + + + + + + + + 1 + + + Ligation_Scar_D_E0040m_gfp + + + 1 + + + + + Ligation_Scar_B_J23100 + + 1 + + + + + + 1 + + + B0015_Ligation_Scar_D + + + + + + + + + + 1 + Ligation_Scar_C + + + + + + Ligation_Scar_D + 1 + + + + + + + 1 + + E0040m_gfp_Ligation_Scar_C + + + + + + + + + + 1 + Ligation_Scar_A_sequence + GGAG + + + + + 1 + Ligation_Scar_B_sequence + TACT + + + + 1 + + Ligation_Scar_C_sequence + AATG + + + + + Ligation_Scar_D_sequence + 1 + AGGT + + + + + Ligation_Scar_E_sequence + 1 + GCTT + + + + GGAGTTGACGGCTAGCTCAGTCCTAGGTACAGTGCTAGCTACTAGAGAAAGAGGAGAAATACTAAATGATGCGTAAAGGAGAAGAACTTTTCACTGGAGTTGTCCCAATTCTTGTTGAATTAGATGGTGATGTTAATGGGCACAAATTTTCTGTCAGTGGAGAGGGTGAAGGTGATGCAACATACGGAAAACTTACCCTTAAATTTATTTGCACTACTGGAAAACTACCTGTTCCATGGCCAACACTTGTCACTACTTTCGGTTATGGTGTTCAATGCTTTGCGAGATACCCAGATCATATGAAACAGCATGACTTTTTCAAGAGTGCCATGCCCGAAGGTTATGTACAGGAAAGAACTATATTTTTCAAAGATGACGGGAACTACAAGACACGTGCTGAAGTCAAGTTTGAAGGTGATACCCTTGTTAATAGAATCGAGTTAAAAGGTATTGATTTTAAAGAAGATGGAAACATTCTTGGACACAAATTGGAATACAACTATAACTCACACAATGTATACATCATGGCAGACAAACAAAAGAATGGAATCAAAGTTAACTTCAAAATTAGACACAACATTGAAGATGGAAGCGTTCAACTAGCAGACCATTATCAACAAAATACTCCAATTGGCGATGGCCCTGTCCTTTTACCAGACAACCATTACCTGTCCACACAATCTGCCCTTTCGAAAGATCCCAACGAAAAGAGAGATCACATGGTCCTTCTTGAGTTTGTAACAGCTGCTGGGATTACACATGGCATGGATGAACTATACAAATAATAAAGGTCCAGGCATCAAATAAAACGAAAGGCTCAGTCGAAAGACTGGGCCTTTCGTTTTATCTGTTGTTTGTCGGTGAACGCTCTCTACTAGAGTCACACTGGCTCACCTTCGGGTGGGCCTTTCTGCGTTTATAGCTTatgtcttctactagtagcggccgctgcagtccggcaaaaaagggcaaggtgtcaccaccctgccctttttctttaaaaccgaaaagattacttcgcgttatgcaggcttcctcgctcactgactcgctgcgctcggtcgttcggctgcggcgagcggtatcagctcactcaaaggcggtaatacggttatccacagaatcaggggataacgcaggaaagaacatgtgagcaaaaggccagcaaaaggccaggaaccgtaaaaaggccgcgttgctggcgtttttccacaggctccgcccccctgacgagcatcacaaaaatcgacgctcaagtcagaggtggcgaaacccgacaggactataaagataccaggcgtttccccctggaagctccctcgtgcgctctcctgttccgaccctgccgcttaccggatacctgtccgcctttctcccttcgggaagcgtggcgctttctcatagctcacgctgtaggtatctcagttcggtgtaggtcgttcgctccaagctgggctgtgtgcacgaaccccccgttcagcccgaccgctgcgccttatccggtaactatcgtcttgagtccaacccggtaagacacgacttatcgccactggcagcagccactggtaacaggattagcagagcgaggtatgtaggcggtgctacagagttcttgaagtggtggcctaactacggctacactagaagaacagtatttggtatctgcgctctgctgaagccagttaccttcggaaaaagagttggtagctcttgatccggcaaacaaaccaccgctggtagcggtggtttttttgtttgcaagcagcagattacgcgcagaaaaaaaggatctcaagaagatcctttgatcttttctacggggtctgacgctcagtggaacgaaaactcacgttaagggattttggtcatgagattatcaaaaaggatcttcacctagatccttttaaattaaaaatgaagttttaaatcaatctaaagtatatatgagtaaacttggtctgacagctcgagtcccgtcaagtcagcgtaatgctctgccagtgttacaaccaattaaccaattctgattagaaaaactcatcgagcatcaaatgaaactgcaatttattcatatcaggattatcaataccatatttttgaaaaagccgtttctgtaatgaaggagaaaactcaccgaggcagttccataggatggcaagatcctggtatcggtctgcgattccgactcgtccaacatcaatacaacctattaatttcccctcgtcaaaaataaggttatcaagtgagaaatcaccatgagtgacgactgaatccggtgagaatggcaaaagcttatgcatttctttccagacttgttcaacaggccagccattacgctcgtcatcaaaatcactcgcatcaaccaaaccgttattcattcgtgattgcgcctgagcgagacgaaatacgcgatcgctgttaaaaggacaattacaaacaggaatcgaatgcaaccggcgcaggaacactgccagcgcatcaacaatattttcacctgaatcaggatattcttctaatacctggaatgctgttttcccggggatcgcagtggtgagtaaccatgcatcatcaggagtacggataaaatgcttgatggtcggaagaggcataaattccgtcagccagtttagtctgaccatctcatctgtaacatcattggcaacgctacctttgccatgtttcagaaacaactctggcgcatcgggcttcccatacaatcgatagattgtcgcacctgattgcccgacattatcgcgagcccatttatacccatataaatcagcatccatgttggaatttaatcgcggcctggagcaagacgtttcccgttgaatatggctcataacaccccttgtattactgtttatgtaagcagacagttttattgttcatgatgatatatttttatcttgtgcaatgtaacatcagagattttgagacacaacgtggctttgttgaataaatcgaacttttgctgagttgaaggatcagctcgagtgccacctgacgtctaagaaaccattattatcatgacattaacctataaaaataggcgtatcacgaggcagaatttcagataaaaaaaatccttagctttcgctaaggatgatttctggaattcgcggccgcttctagagactagtggaagacat + + standard_GFP_transformation_lvl1_seq + 1 + + + 1 + standard_GFP_transformation_lvl1_impl + + + + + + 1 + + + 1 + + + pB0015_DE_impl + + + + DNA Assembly + + + pE0040_CD_impl + + 1 + + + + + + + + + T4_Ligase + 1 + + + + + + + + pB0034_BC_impl + 1 + + + + + + + + + + 1 + DVK_AE_impl + + + + + 1 + + + BsaI_enzyme + + + + + + + + + 1 + + assemble_ + + + standard_GFP_transformation_lvl1_assembly + + + + 1 + + pJ23100_AB_impl + + + + + diff --git a/notebooks/results/buildcompiler_transformation_quickstart/transformation_lvl1_pudu_input.json b/notebooks/results/buildcompiler_transformation_quickstart/transformation_lvl1_pudu_input.json new file mode 100644 index 0000000..67eaa63 --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/transformation_lvl1_pudu_input.json @@ -0,0 +1,9 @@ +[ + { + "Strain": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_transformation_lvl1/1", + "Chassis": "https://sbolcanvas.org/DH5alpha/1", + "Plasmids": [ + "http://buildcompiler.org/standard_GFP_transformation_lvl1/1" + ] + } +] \ No newline at end of file diff --git a/notebooks/results/buildcompiler_transformation_quickstart/transformation_products.xml b/notebooks/results/buildcompiler_transformation_quickstart/transformation_products.xml new file mode 100644 index 0000000..ccb41eb --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/transformation_products.xml @@ -0,0 +1,619 @@ + + + + + + + Ligation_Scar_A + 1 + + + + + + Ligation_Scar_B + + + 1 + + + + + + 1 + + + + + + Ligation_Scar_C + + + + + + + Ligation_Scar_D + + 1 + + + + + + 1 + + Ligation_Scar_E + + + + + + + + + + 1 + + + J23100 + + + + + + + B0015_3_annotation + 1 + + + B0015_3_location + 1 + 793 + 921 + + + + + + + + + + Ligation_Scar_D_annotation + + + + 1 + 792 + 789 + + Ligation_Scar_D_location + + + 1 + + + + + + + + + + Ligation_Scar_C_B0034 + + + 1 + + + standard_GFP_transformation_lvl1 + + + + + + + 1 + 1 + 4 + + Ligation_Scar_A_location + + + Ligation_Scar_A_annotation + 1 + + + + + + + + Ligation_Scar_E + + 1 + + + + + + + 1 + Ligation_Scar_A + + + + + + + 1 + + B0015 + + + + + + + + Ligation_Scar_E_B0015 + + 1 + + + + + + + + + + 3152 + 926 + 1 + + dvk_backbone_core_5_location + + + + dvk_backbone_core_5_annotation + 1 + + + + + + dvk_backbone_core + + 1 + + + + + + + + + Ligation_Scar_E_annotation + + + + 922 + Ligation_Scar_E_location + 925 + 1 + + + + 1 + + + + + Ligation_Scar_C_annotation + + + + 1 + + 68 + Ligation_Scar_C_location + + 65 + + + 1 + + + + + + B0034_Ligation_Scar_B + + 1 + + + + + + + + + + + 69 + 1 + + 788 + E0040m_gfp_3_location + + + + + E0040m_gfp_3_annotation + 1 + + + standard_GFP_transformation_lvl1 + + + + + 1 + E0040m_gfp + + + + + + + + + + 1 + 43 + + Ligation_Scar_B_location + 40 + + + 1 + + + Ligation_Scar_B_annotation + + + + + + 1 + + + Ligation_Scar_B + + + + + B0034 + + 1 + + + + + + + 1 + + + + + dvk_backbone_core_Ligation_Scar_E + + + + + + + 1 + B0034_3_location + 64 + + + 44 + + + B0034_3_annotation + + + 1 + + + + + + + J23100_Ligation_Scar_A + 1 + + + + + + + + J23100_3_annotation + 1 + + + + + J23100_3_location + 5 + + + 39 + 1 + + + + + + + + + 1 + + + Ligation_Scar_D_E0040m_gfp + + + 1 + + + + + Ligation_Scar_B_J23100 + + 1 + + + + + + 1 + + + B0015_Ligation_Scar_D + + + + + + + + + + 1 + Ligation_Scar_C + + + + + + Ligation_Scar_D + 1 + + + + + + + 1 + + E0040m_gfp_Ligation_Scar_C + + + + + + + + + + 1 + Ligation_Scar_A_sequence + GGAG + + + + + 1 + Ligation_Scar_B_sequence + TACT + + + + 1 + + Ligation_Scar_C_sequence + AATG + + + + + Ligation_Scar_D_sequence + 1 + AGGT + + + + + Ligation_Scar_E_sequence + 1 + GCTT + + + + GGAGTTGACGGCTAGCTCAGTCCTAGGTACAGTGCTAGCTACTAGAGAAAGAGGAGAAATACTAAATGATGCGTAAAGGAGAAGAACTTTTCACTGGAGTTGTCCCAATTCTTGTTGAATTAGATGGTGATGTTAATGGGCACAAATTTTCTGTCAGTGGAGAGGGTGAAGGTGATGCAACATACGGAAAACTTACCCTTAAATTTATTTGCACTACTGGAAAACTACCTGTTCCATGGCCAACACTTGTCACTACTTTCGGTTATGGTGTTCAATGCTTTGCGAGATACCCAGATCATATGAAACAGCATGACTTTTTCAAGAGTGCCATGCCCGAAGGTTATGTACAGGAAAGAACTATATTTTTCAAAGATGACGGGAACTACAAGACACGTGCTGAAGTCAAGTTTGAAGGTGATACCCTTGTTAATAGAATCGAGTTAAAAGGTATTGATTTTAAAGAAGATGGAAACATTCTTGGACACAAATTGGAATACAACTATAACTCACACAATGTATACATCATGGCAGACAAACAAAAGAATGGAATCAAAGTTAACTTCAAAATTAGACACAACATTGAAGATGGAAGCGTTCAACTAGCAGACCATTATCAACAAAATACTCCAATTGGCGATGGCCCTGTCCTTTTACCAGACAACCATTACCTGTCCACACAATCTGCCCTTTCGAAAGATCCCAACGAAAAGAGAGATCACATGGTCCTTCTTGAGTTTGTAACAGCTGCTGGGATTACACATGGCATGGATGAACTATACAAATAATAAAGGTCCAGGCATCAAATAAAACGAAAGGCTCAGTCGAAAGACTGGGCCTTTCGTTTTATCTGTTGTTTGTCGGTGAACGCTCTCTACTAGAGTCACACTGGCTCACCTTCGGGTGGGCCTTTCTGCGTTTATAGCTTatgtcttctactagtagcggccgctgcagtccggcaaaaaagggcaaggtgtcaccaccctgccctttttctttaaaaccgaaaagattacttcgcgttatgcaggcttcctcgctcactgactcgctgcgctcggtcgttcggctgcggcgagcggtatcagctcactcaaaggcggtaatacggttatccacagaatcaggggataacgcaggaaagaacatgtgagcaaaaggccagcaaaaggccaggaaccgtaaaaaggccgcgttgctggcgtttttccacaggctccgcccccctgacgagcatcacaaaaatcgacgctcaagtcagaggtggcgaaacccgacaggactataaagataccaggcgtttccccctggaagctccctcgtgcgctctcctgttccgaccctgccgcttaccggatacctgtccgcctttctcccttcgggaagcgtggcgctttctcatagctcacgctgtaggtatctcagttcggtgtaggtcgttcgctccaagctgggctgtgtgcacgaaccccccgttcagcccgaccgctgcgccttatccggtaactatcgtcttgagtccaacccggtaagacacgacttatcgccactggcagcagccactggtaacaggattagcagagcgaggtatgtaggcggtgctacagagttcttgaagtggtggcctaactacggctacactagaagaacagtatttggtatctgcgctctgctgaagccagttaccttcggaaaaagagttggtagctcttgatccggcaaacaaaccaccgctggtagcggtggtttttttgtttgcaagcagcagattacgcgcagaaaaaaaggatctcaagaagatcctttgatcttttctacggggtctgacgctcagtggaacgaaaactcacgttaagggattttggtcatgagattatcaaaaaggatcttcacctagatccttttaaattaaaaatgaagttttaaatcaatctaaagtatatatgagtaaacttggtctgacagctcgagtcccgtcaagtcagcgtaatgctctgccagtgttacaaccaattaaccaattctgattagaaaaactcatcgagcatcaaatgaaactgcaatttattcatatcaggattatcaataccatatttttgaaaaagccgtttctgtaatgaaggagaaaactcaccgaggcagttccataggatggcaagatcctggtatcggtctgcgattccgactcgtccaacatcaatacaacctattaatttcccctcgtcaaaaataaggttatcaagtgagaaatcaccatgagtgacgactgaatccggtgagaatggcaaaagcttatgcatttctttccagacttgttcaacaggccagccattacgctcgtcatcaaaatcactcgcatcaaccaaaccgttattcattcgtgattgcgcctgagcgagacgaaatacgcgatcgctgttaaaaggacaattacaaacaggaatcgaatgcaaccggcgcaggaacactgccagcgcatcaacaatattttcacctgaatcaggatattcttctaatacctggaatgctgttttcccggggatcgcagtggtgagtaaccatgcatcatcaggagtacggataaaatgcttgatggtcggaagaggcataaattccgtcagccagtttagtctgaccatctcatctgtaacatcattggcaacgctacctttgccatgtttcagaaacaactctggcgcatcgggcttcccatacaatcgatagattgtcgcacctgattgcccgacattatcgcgagcccatttatacccatataaatcagcatccatgttggaatttaatcgcggcctggagcaagacgtttcccgttgaatatggctcataacaccccttgtattactgtttatgtaagcagacagttttattgttcatgatgatatatttttatcttgtgcaatgtaacatcagagattttgagacacaacgtggctttgttgaataaatcgaacttttgctgagttgaaggatcagctcgagtgccacctgacgtctaagaaaccattattatcatgacattaacctataaaaataggcgtatcacgaggcagaatttcagataaaaaaaatccttagctttcgctaaggatgatttctggaattcgcggccgcttctagagactagtggaagacat + + standard_GFP_transformation_lvl1_seq + 1 + + + 1 + standard_GFP_transformation_lvl1_impl + + + + + + + E_coli_DH5alpha_impl + + 1 + + + + + 1 + E_coli_DH5alpha_with_standard_GFP_transformation_lvl1_impl + + + + 1 + + + 1 + + + pB0015_DE_impl + + + + DNA Assembly + + + pE0040_CD_impl + + 1 + + + + + + + + + + T4_Ligase + 1 + + + + + + + pB0034_BC_impl + 1 + + + + + + + + + + 1 + DVK_AE_impl + + + + + 1 + + + BsaI_enzyme + + + + + + + + + 1 + + assemble_ + + + standard_GFP_transformation_lvl1_assembly + + + + 1 + + pJ23100_AB_impl + + + + + + 1 + Transform E_coli_DH5alpha with standard_GFP_transformation_lvl1 + transform_standard_GFP_transformation_lvl1_1 + + + + 1 + + + + transform_standard_GFP_transformation_lvl1_1_plasmid_usage + + + + + + + + 1 + transform_standard_GFP_transformation_lvl1_1_chassis_usage + + + + + + + E_coli_DH5alpha + E_coli_DH5alpha + + 1 + + + 1 + E_coli_DH5alpha_with_standard_GFP_transformation_lvl1 + + + + + 1 + + E_coli_DH5alpha_with_standard_GFP_transformation_lvl1_plasmid_fc + + + + + + E_coli_DH5alpha_with_standard_GFP_transformation_lvl1_chassis_module + + 1 + + + + E_coli_DH5alpha transformed with standard_GFP_transformation_lvl1 + + + diff --git a/notebooks/results/buildcompiler_transformation_quickstart/transformation_summary.json b/notebooks/results/buildcompiler_transformation_quickstart/transformation_summary.json new file mode 100644 index 0000000..48efd2b --- /dev/null +++ b/notebooks/results/buildcompiler_transformation_quickstart/transformation_summary.json @@ -0,0 +1,49 @@ +{ + "stage": "transformation", + "inputs": [ + "standard_GFP_transformation_lvl1_A_E" + ], + "chassis": "E_coli_DH5alpha", + "sbol_artifacts": [ + { + "transformation_activity": "http://buildcompiler.org/transform_standard_GFP_transformation_lvl1_1/1", + "transformed_strain_module": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_transformation_lvl1/1", + "transformed_strain_implementation": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_transformation_lvl1_impl/1" + } + ], + "json_intermediate": { + "protocol": "chemical_transformation", + "version": "0.1", + "steps": [ + { + "step": 1, + "plasmid": "standard_GFP_transformation_lvl1", + "chassis": "E_coli_DH5alpha", + "mix_ul": { + "competent_cells": 50, + "assembly_product": 5 + }, + "heat_shock": { + "temperature_c": 42, + "duration_seconds": 45 + }, + "recovery": { + "medium": "SOC", + "volume_ul": 950, + "duration_min": 60 + } + } + ] + }, + "protocol_artifacts": { + "ot2_script": "TODO: adapter to protocol generator", + "human_instructions": [ + "Thaw competent cells on ice.", + "Combine assembly product with competent cells as specified.", + "Run heat shock and recovery according to generated parameters." + ], + "logs": [ + "Prepared transformation input for plasmid standard_GFP_transformation_lvl1 into chassis E_coli_DH5alpha." + ] + } +} \ No newline at end of file diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/assembly_lvl1_pudu_assembly_input.json b/notebooks/results/full_build_workflow_examples/lvl1_success 2/assembly_lvl1_pudu_assembly_input.json new file mode 100644 index 0000000..c687f78 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/assembly_lvl1_pudu_assembly_input.json @@ -0,0 +1,13 @@ +[ + { + "Product": "http://buildcompiler.org/standard_GFP_full_build/1", + "Backbone": "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/DVK_AE/1", + "PartsList": [ + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pJ23100_AB/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0034_BC/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pE0040_CD/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0015_DE/1" + ], + "Restriction Enzyme": "https://synbiohub.org/user/Gon/Enzyme_Implementations/BsaI/1" + } +] diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/assembly_lvl1_pudu_assembly_protocol.py b/notebooks/results/full_build_workflow_examples/lvl1_success 2/assembly_lvl1_pudu_assembly_protocol.py new file mode 100644 index 0000000..73b1757 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/assembly_lvl1_pudu_assembly_protocol.py @@ -0,0 +1,26 @@ +from pudu.assembly import SBOLLoopAssembly +from opentrons import protocol_api + +assembly_data = [ + { + "Product": "http://buildcompiler.org/standard_GFP_full_build/1", + "Backbone": "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/DVK_AE/1", + "PartsList": [ + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pJ23100_AB/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0034_BC/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pE0040_CD/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0015_DE/1" + ], + "Restriction Enzyme": "https://synbiohub.org/user/Gon/Enzyme_Implementations/BsaI/1" + } +] + +metadata = { + 'protocolName': 'BuildCompiler assembly_lvl1 Assembly', + 'author': 'BuildCompiler', + 'apiLevel': '2.21', +} + +def run(protocol: protocol_api.ProtocolContext): + protocol_instance = SBOLLoopAssembly(assembly_data=assembly_data) + protocol_instance.run(protocol) diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/full_build_manifest.json b/notebooks/results/full_build_workflow_examples/lvl1_success 2/full_build_manifest.json new file mode 100644 index 0000000..3b85fe6 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/full_build_manifest.json @@ -0,0 +1,156 @@ +{ + "results_dir": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success", + "domestication": { + "successful": [], + "failed": [] + }, + "assembly_lvl1": { + "successful": [ + { + "design": "standard_GFP", + "products": [ + "http://buildcompiler.org/standard_GFP_full_build/1" + ] + } + ], + "failed": [] + }, + "assembly_lvl2": { + "successful": [], + "failed": [] + }, + "transformation": { + "successful": [ + { + "stage_label": "standard_GFP", + "products": [ + "http://buildcompiler.org/standard_GFP_full_build/1" + ], + "result": { + "stage": "transformation", + "inputs": [ + "standard_GFP_full_build_A_E" + ], + "chassis": "E_coli_DH5alpha", + "sbol_artifacts": [ + { + "transformation_activity": "http://buildcompiler.org/transform_standard_GFP_full_build_1/1", + "transformed_strain_module": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1", + "transformed_strain_implementation": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1" + } + ], + "json_intermediate": { + "protocol": "chemical_transformation", + "version": "0.1", + "steps": [ + { + "step": 1, + "plasmid": "standard_GFP_full_build", + "chassis": "E_coli_DH5alpha", + "mix_ul": { + "competent_cells": 50, + "assembly_product": 5 + }, + "heat_shock": { + "temperature_c": 42, + "duration_seconds": 45 + }, + "recovery": { + "medium": "SOC", + "volume_ul": 950, + "duration_min": 60 + } + } + ] + }, + "protocol_artifacts": { + "ot2_script": "TODO: adapter to protocol generator", + "human_instructions": [ + "Thaw competent cells on ice.", + "Combine assembly product with competent cells as specified.", + "Run heat shock and recovery according to generated parameters." + ], + "logs": [ + "Prepared transformation input for plasmid standard_GFP_full_build into chassis E_coli_DH5alpha." + ] + } + } + } + ], + "failed": [] + }, + "plating": { + "successful": [ + { + "stage_label": "standard_GFP", + "result": { + "stage": "plating", + "protocol_type": "manual", + "plate": { + "plate_implementation": "solid_96_well_plate", + "plate_map": { + "A1": "1_plated_A1_impl" + } + }, + "metadata": { + "plate_rows": [ + { + "well": "A1", + "source_transformed_strain_implementation": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1", + "strain_module": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1", + "plated_strain_implementation": "1_plated_A1_impl", + "strain_display_name": "1_plated_A1_impl" + } + ], + "layout_dataframe_columns": [ + "well", + "source_transformed_strain_implementation", + "strain_module", + "plated_strain_implementation", + "strain_display_name" + ] + }, + "json_intermediate": { + "plating_data": { + "bacterium_locations": { + "A1": "1_plated_A1_impl" + } + }, + "advanced_params": {} + }, + "protocol_artifacts": { + "plate_map_json": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.json", + "plate_map_csv": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.csv", + "plate_layout_dataframe_csv": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_layout_dataframe.csv", + "logs": [], + "pudu": { + "runner_script": "https://github.com/MyersResearchGroup/PUDU/blob/main/scripts/run_sbol2plating_with_params.py", + "mode": "manual", + "advanced_params": {} + }, + "manual_protocol_markdown": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/manual_plating_protocol.md" + } + } + } + ], + "failed": [] + }, + "skipped": [ + { + "stage": "assembly_lvl2", + "reason": "no level-2 design provided" + } + ], + "artifacts": [ + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_input.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_protocol.py", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/transformation_pudu_input.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/transformation_plasmid_locations.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/pudu_transformation_protocol.py", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/plating_pudu_input.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/pudu_plating_protocol.py" + ], + "manifest_path": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/full_build_manifest.json", + "zip_path": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success.zip", + "artifact_zip": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success.zip" +} diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/plating_pudu_input.json b/notebooks/results/full_build_workflow_examples/lvl1_success 2/plating_pudu_input.json new file mode 100644 index 0000000..9812604 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/plating_pudu_input.json @@ -0,0 +1,5 @@ +{ + "bacterium_locations": { + "A1": "1_plated_A1_impl" + } +} diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/pudu_plating_protocol.py b/notebooks/results/full_build_workflow_examples/lvl1_success 2/pudu_plating_protocol.py new file mode 100644 index 0000000..e8c41f8 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/pudu_plating_protocol.py @@ -0,0 +1,18 @@ +from pudu.plating import Plating +from opentrons import protocol_api + +plating_data = { + "bacterium_locations": { + "A1": "1_plated_A1_impl" + } +} + +metadata = { + 'protocolName': 'BuildCompiler Plating', + 'author': 'BuildCompiler', + 'apiLevel': '2.21', +} + +def run(protocol: protocol_api.ProtocolContext): + protocol_instance = Plating(plating_data=plating_data) + protocol_instance.run(protocol) diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/pudu_transformation_protocol.py b/notebooks/results/full_build_workflow_examples/lvl1_success 2/pudu_transformation_protocol.py new file mode 100644 index 0000000..42392d7 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/pudu_transformation_protocol.py @@ -0,0 +1,31 @@ +from pudu.transformation import HeatShockTransformation +from opentrons import protocol_api + +transformation_data = [ + { + "Strain": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1", + "Chassis": "E_coli_DH5alpha", + "Plasmids": [ + "http://buildcompiler.org/standard_GFP_full_build/1" + ] + } +] + +plasmid_locations = { + "http://buildcompiler.org/standard_GFP_full_build/1": [ + "A1" + ] +} + +metadata = { + 'protocolName': 'BuildCompiler Transformation', + 'author': 'BuildCompiler', + 'apiLevel': '2.21', +} + +def run(protocol: protocol_api.ProtocolContext): + protocol_instance = HeatShockTransformation( + transformation_data=transformation_data, + plasmid_locations=plasmid_locations, + ) + protocol_instance.run(protocol) diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/manual_plating_protocol.md b/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/manual_plating_protocol.md new file mode 100644 index 0000000..bc86255 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/manual_plating_protocol.md @@ -0,0 +1,22 @@ +# BuildCompiler Plating Protocol + +## Plate +- Plate ID: `solid_96_well_plate` +- Protocol type: `manual` + +## Input transformed strains +- 1_plated_A1_impl + +## Parameters +- (none) + +## 96-well plate map +| Well | Source transformed strain implementation | Plated strain implementation | Strain module | +|---|---|---|---| +| A1 | http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1 | 1_plated_A1_impl | http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1 | + +## Steps +1. Prepare one sterile solid-media 96-well plate. +2. Label the plate with the plate ID and date. +3. Transfer each transformed strain to the destination well shown in the map. +4. Incubate according to lab defaults or parameters above. diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_layout_dataframe.csv b/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_layout_dataframe.csv new file mode 100644 index 0000000..0053e37 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_layout_dataframe.csv @@ -0,0 +1,2 @@ +well,source_transformed_strain_implementation,strain_module,plated_strain_implementation,strain_display_name +A1,http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1,http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1,1_plated_A1_impl,1_plated_A1_impl diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_map.csv b/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_map.csv new file mode 100644 index 0000000..0053e37 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_map.csv @@ -0,0 +1,2 @@ +well,source_transformed_strain_implementation,strain_module,plated_strain_implementation,strain_display_name +A1,http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1,http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1,1_plated_A1_impl,1_plated_A1_impl diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_map.json b/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_map.json new file mode 100644 index 0000000..b8c290a --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plate_map.json @@ -0,0 +1,13 @@ +{ + "plate_implementation": "solid_96_well_plate", + "protocol_type": "manual", + "well_map": [ + { + "well": "A1", + "source_transformed_strain_implementation": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1", + "strain_module": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1", + "plated_strain_implementation": "1_plated_A1_impl", + "strain_display_name": "1_plated_A1_impl" + } + ] +} \ No newline at end of file diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plating_input.json b/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plating_input.json new file mode 100644 index 0000000..ff85937 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/standard_GFP_plating/plating_input.json @@ -0,0 +1,5 @@ +{ + "bacterium_locations": { + "A1": "1_plated_A1_impl" + } +} \ No newline at end of file diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/transformation_plasmid_locations.json b/notebooks/results/full_build_workflow_examples/lvl1_success 2/transformation_plasmid_locations.json new file mode 100644 index 0000000..e722f2c --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/transformation_plasmid_locations.json @@ -0,0 +1,5 @@ +{ + "http://buildcompiler.org/standard_GFP_full_build/1": [ + "A1" + ] +} diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success 2/transformation_pudu_input.json b/notebooks/results/full_build_workflow_examples/lvl1_success 2/transformation_pudu_input.json new file mode 100644 index 0000000..ebff170 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success 2/transformation_pudu_input.json @@ -0,0 +1,9 @@ +[ + { + "Strain": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1", + "Chassis": "E_coli_DH5alpha", + "Plasmids": [ + "http://buildcompiler.org/standard_GFP_full_build/1" + ] + } +] diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success.zip b/notebooks/results/full_build_workflow_examples/lvl1_success.zip new file mode 100644 index 0000000000000000000000000000000000000000..71614b319d8a2946544dd06d23131932e9f0de3b GIT binary patch literal 5617 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 P;loZ20JIYR0Ra35U*B0& literal 0 HcmV?d00001 diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_input.json b/notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_input.json new file mode 100644 index 0000000..c687f78 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_input.json @@ -0,0 +1,13 @@ +[ + { + "Product": "http://buildcompiler.org/standard_GFP_full_build/1", + "Backbone": "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/DVK_AE/1", + "PartsList": [ + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pJ23100_AB/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0034_BC/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pE0040_CD/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0015_DE/1" + ], + "Restriction Enzyme": "https://synbiohub.org/user/Gon/Enzyme_Implementations/BsaI/1" + } +] diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_protocol.py b/notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_protocol.py new file mode 100644 index 0000000..73b1757 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_protocol.py @@ -0,0 +1,26 @@ +from pudu.assembly import SBOLLoopAssembly +from opentrons import protocol_api + +assembly_data = [ + { + "Product": "http://buildcompiler.org/standard_GFP_full_build/1", + "Backbone": "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/DVK_AE/1", + "PartsList": [ + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pJ23100_AB/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0034_BC/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pE0040_CD/1", + "https://synbiohub.org/user/Gon/CIDARMoCloPlasmidsKit/pB0015_DE/1" + ], + "Restriction Enzyme": "https://synbiohub.org/user/Gon/Enzyme_Implementations/BsaI/1" + } +] + +metadata = { + 'protocolName': 'BuildCompiler assembly_lvl1 Assembly', + 'author': 'BuildCompiler', + 'apiLevel': '2.21', +} + +def run(protocol: protocol_api.ProtocolContext): + protocol_instance = SBOLLoopAssembly(assembly_data=assembly_data) + protocol_instance.run(protocol) diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/full_build_manifest.json b/notebooks/results/full_build_workflow_examples/lvl1_success/full_build_manifest.json new file mode 100644 index 0000000..3b85fe6 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/full_build_manifest.json @@ -0,0 +1,156 @@ +{ + "results_dir": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success", + "domestication": { + "successful": [], + "failed": [] + }, + "assembly_lvl1": { + "successful": [ + { + "design": "standard_GFP", + "products": [ + "http://buildcompiler.org/standard_GFP_full_build/1" + ] + } + ], + "failed": [] + }, + "assembly_lvl2": { + "successful": [], + "failed": [] + }, + "transformation": { + "successful": [ + { + "stage_label": "standard_GFP", + "products": [ + "http://buildcompiler.org/standard_GFP_full_build/1" + ], + "result": { + "stage": "transformation", + "inputs": [ + "standard_GFP_full_build_A_E" + ], + "chassis": "E_coli_DH5alpha", + "sbol_artifacts": [ + { + "transformation_activity": "http://buildcompiler.org/transform_standard_GFP_full_build_1/1", + "transformed_strain_module": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1", + "transformed_strain_implementation": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1" + } + ], + "json_intermediate": { + "protocol": "chemical_transformation", + "version": "0.1", + "steps": [ + { + "step": 1, + "plasmid": "standard_GFP_full_build", + "chassis": "E_coli_DH5alpha", + "mix_ul": { + "competent_cells": 50, + "assembly_product": 5 + }, + "heat_shock": { + "temperature_c": 42, + "duration_seconds": 45 + }, + "recovery": { + "medium": "SOC", + "volume_ul": 950, + "duration_min": 60 + } + } + ] + }, + "protocol_artifacts": { + "ot2_script": "TODO: adapter to protocol generator", + "human_instructions": [ + "Thaw competent cells on ice.", + "Combine assembly product with competent cells as specified.", + "Run heat shock and recovery according to generated parameters." + ], + "logs": [ + "Prepared transformation input for plasmid standard_GFP_full_build into chassis E_coli_DH5alpha." + ] + } + } + } + ], + "failed": [] + }, + "plating": { + "successful": [ + { + "stage_label": "standard_GFP", + "result": { + "stage": "plating", + "protocol_type": "manual", + "plate": { + "plate_implementation": "solid_96_well_plate", + "plate_map": { + "A1": "1_plated_A1_impl" + } + }, + "metadata": { + "plate_rows": [ + { + "well": "A1", + "source_transformed_strain_implementation": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1", + "strain_module": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1", + "plated_strain_implementation": "1_plated_A1_impl", + "strain_display_name": "1_plated_A1_impl" + } + ], + "layout_dataframe_columns": [ + "well", + "source_transformed_strain_implementation", + "strain_module", + "plated_strain_implementation", + "strain_display_name" + ] + }, + "json_intermediate": { + "plating_data": { + "bacterium_locations": { + "A1": "1_plated_A1_impl" + } + }, + "advanced_params": {} + }, + "protocol_artifacts": { + "plate_map_json": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.json", + "plate_map_csv": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.csv", + "plate_layout_dataframe_csv": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_layout_dataframe.csv", + "logs": [], + "pudu": { + "runner_script": "https://github.com/MyersResearchGroup/PUDU/blob/main/scripts/run_sbol2plating_with_params.py", + "mode": "manual", + "advanced_params": {} + }, + "manual_protocol_markdown": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/manual_plating_protocol.md" + } + } + } + ], + "failed": [] + }, + "skipped": [ + { + "stage": "assembly_lvl2", + "reason": "no level-2 design provided" + } + ], + "artifacts": [ + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_input.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/assembly_lvl1_pudu_assembly_protocol.py", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/transformation_pudu_input.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/transformation_plasmid_locations.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/pudu_transformation_protocol.py", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/plating_pudu_input.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/pudu_plating_protocol.py" + ], + "manifest_path": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success/full_build_manifest.json", + "zip_path": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success.zip", + "artifact_zip": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl1_success.zip" +} diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/plating_pudu_input.json b/notebooks/results/full_build_workflow_examples/lvl1_success/plating_pudu_input.json new file mode 100644 index 0000000..9812604 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/plating_pudu_input.json @@ -0,0 +1,5 @@ +{ + "bacterium_locations": { + "A1": "1_plated_A1_impl" + } +} diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/pudu_plating_protocol.py b/notebooks/results/full_build_workflow_examples/lvl1_success/pudu_plating_protocol.py new file mode 100644 index 0000000..e8c41f8 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/pudu_plating_protocol.py @@ -0,0 +1,18 @@ +from pudu.plating import Plating +from opentrons import protocol_api + +plating_data = { + "bacterium_locations": { + "A1": "1_plated_A1_impl" + } +} + +metadata = { + 'protocolName': 'BuildCompiler Plating', + 'author': 'BuildCompiler', + 'apiLevel': '2.21', +} + +def run(protocol: protocol_api.ProtocolContext): + protocol_instance = Plating(plating_data=plating_data) + protocol_instance.run(protocol) diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/pudu_transformation_protocol.py b/notebooks/results/full_build_workflow_examples/lvl1_success/pudu_transformation_protocol.py new file mode 100644 index 0000000..42392d7 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/pudu_transformation_protocol.py @@ -0,0 +1,31 @@ +from pudu.transformation import HeatShockTransformation +from opentrons import protocol_api + +transformation_data = [ + { + "Strain": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1", + "Chassis": "E_coli_DH5alpha", + "Plasmids": [ + "http://buildcompiler.org/standard_GFP_full_build/1" + ] + } +] + +plasmid_locations = { + "http://buildcompiler.org/standard_GFP_full_build/1": [ + "A1" + ] +} + +metadata = { + 'protocolName': 'BuildCompiler Transformation', + 'author': 'BuildCompiler', + 'apiLevel': '2.21', +} + +def run(protocol: protocol_api.ProtocolContext): + protocol_instance = HeatShockTransformation( + transformation_data=transformation_data, + plasmid_locations=plasmid_locations, + ) + protocol_instance.run(protocol) diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/manual_plating_protocol.md b/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/manual_plating_protocol.md new file mode 100644 index 0000000..bc86255 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/manual_plating_protocol.md @@ -0,0 +1,22 @@ +# BuildCompiler Plating Protocol + +## Plate +- Plate ID: `solid_96_well_plate` +- Protocol type: `manual` + +## Input transformed strains +- 1_plated_A1_impl + +## Parameters +- (none) + +## 96-well plate map +| Well | Source transformed strain implementation | Plated strain implementation | Strain module | +|---|---|---|---| +| A1 | http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1 | 1_plated_A1_impl | http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1 | + +## Steps +1. Prepare one sterile solid-media 96-well plate. +2. Label the plate with the plate ID and date. +3. Transfer each transformed strain to the destination well shown in the map. +4. Incubate according to lab defaults or parameters above. diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_layout_dataframe.csv b/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_layout_dataframe.csv new file mode 100644 index 0000000..0053e37 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_layout_dataframe.csv @@ -0,0 +1,2 @@ +well,source_transformed_strain_implementation,strain_module,plated_strain_implementation,strain_display_name +A1,http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1,http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1,1_plated_A1_impl,1_plated_A1_impl diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.csv b/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.csv new file mode 100644 index 0000000..0053e37 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.csv @@ -0,0 +1,2 @@ +well,source_transformed_strain_implementation,strain_module,plated_strain_implementation,strain_display_name +A1,http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1,http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1,1_plated_A1_impl,1_plated_A1_impl diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.json b/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.json new file mode 100644 index 0000000..b8c290a --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plate_map.json @@ -0,0 +1,13 @@ +{ + "plate_implementation": "solid_96_well_plate", + "protocol_type": "manual", + "well_map": [ + { + "well": "A1", + "source_transformed_strain_implementation": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build_impl/1", + "strain_module": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1", + "plated_strain_implementation": "1_plated_A1_impl", + "strain_display_name": "1_plated_A1_impl" + } + ] +} \ No newline at end of file diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plating_input.json b/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plating_input.json new file mode 100644 index 0000000..ff85937 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/standard_GFP_plating/plating_input.json @@ -0,0 +1,5 @@ +{ + "bacterium_locations": { + "A1": "1_plated_A1_impl" + } +} \ No newline at end of file diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/transformation_plasmid_locations.json b/notebooks/results/full_build_workflow_examples/lvl1_success/transformation_plasmid_locations.json new file mode 100644 index 0000000..e722f2c --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/transformation_plasmid_locations.json @@ -0,0 +1,5 @@ +{ + "http://buildcompiler.org/standard_GFP_full_build/1": [ + "A1" + ] +} diff --git a/notebooks/results/full_build_workflow_examples/lvl1_success/transformation_pudu_input.json b/notebooks/results/full_build_workflow_examples/lvl1_success/transformation_pudu_input.json new file mode 100644 index 0000000..ebff170 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl1_success/transformation_pudu_input.json @@ -0,0 +1,9 @@ +[ + { + "Strain": "http://buildcompiler.org/E_coli_DH5alpha_with_standard_GFP_full_build/1", + "Chassis": "E_coli_DH5alpha", + "Plasmids": [ + "http://buildcompiler.org/standard_GFP_full_build/1" + ] + } +] diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages.zip b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages.zip new file mode 100644 index 0000000000000000000000000000000000000000..828d424aedf9374da0f76b2136f15642be35f595 GIT binary patch literal 4940 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 literal 0 HcmV?d00001 diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl1_pudu_assembly_input.json b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl1_pudu_assembly_input.json new file mode 100644 index 0000000..6a7484a --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl1_pudu_assembly_input.json @@ -0,0 +1,10 @@ +[ + { + "Product": "http://buildcompiler.org/assembled_demo_tu/1", + "Backbone": "demo_lvl1_backbone", + "PartsList": [ + "http://buildcompiler.org/domesticated_missing_promoter/1" + ], + "Restriction Enzyme": "BsaI" + } +] diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl1_pudu_assembly_protocol.py b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl1_pudu_assembly_protocol.py new file mode 100644 index 0000000..0f4ed2b --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl1_pudu_assembly_protocol.py @@ -0,0 +1,23 @@ +from pudu.assembly import SBOLLoopAssembly +from opentrons import protocol_api + +assembly_data = [ + { + "Product": "http://buildcompiler.org/assembled_demo_tu/1", + "Backbone": "demo_lvl1_backbone", + "PartsList": [ + "http://buildcompiler.org/domesticated_missing_promoter/1" + ], + "Restriction Enzyme": "BsaI" + } +] + +metadata = { + 'protocolName': 'BuildCompiler assembly_lvl1 Assembly', + 'author': 'BuildCompiler', + 'apiLevel': '2.21', +} + +def run(protocol: protocol_api.ProtocolContext): + protocol_instance = SBOLLoopAssembly(assembly_data=assembly_data) + protocol_instance.run(protocol) diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl2_pudu_assembly_input.json b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl2_pudu_assembly_input.json new file mode 100644 index 0000000..789a52b --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl2_pudu_assembly_input.json @@ -0,0 +1,10 @@ +[ + { + "Product": "http://buildcompiler.org/assembled_demo_lvl2/1", + "Backbone": "demo_lvl2_backbone", + "PartsList": [ + "http://buildcompiler.org/assembled_demo_tu/1" + ], + "Restriction Enzyme": "BbsI" + } +] diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl2_pudu_assembly_protocol.py b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl2_pudu_assembly_protocol.py new file mode 100644 index 0000000..62f7c9f --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl2_pudu_assembly_protocol.py @@ -0,0 +1,23 @@ +from pudu.assembly import SBOLLoopAssembly +from opentrons import protocol_api + +assembly_data = [ + { + "Product": "http://buildcompiler.org/assembled_demo_lvl2/1", + "Backbone": "demo_lvl2_backbone", + "PartsList": [ + "http://buildcompiler.org/assembled_demo_tu/1" + ], + "Restriction Enzyme": "BbsI" + } +] + +metadata = { + 'protocolName': 'BuildCompiler assembly_lvl2 Assembly', + 'author': 'BuildCompiler', + 'apiLevel': '2.21', +} + +def run(protocol: protocol_api.ProtocolContext): + protocol_instance = SBOLLoopAssembly(assembly_data=assembly_data) + protocol_instance.run(protocol) diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/domestication_pudu_assembly_input.json b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/domestication_pudu_assembly_input.json new file mode 100644 index 0000000..847b17e --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/domestication_pudu_assembly_input.json @@ -0,0 +1,10 @@ +[ + { + "Product": "http://buildcompiler.org/domesticated_missing_promoter/1", + "Backbone": "demo_domestication_backbone", + "PartsList": [ + "http://buildcompiler.org/missing_promoter/1" + ], + "Restriction Enzyme": "BsaI" + } +] diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/domestication_pudu_assembly_protocol.py b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/domestication_pudu_assembly_protocol.py new file mode 100644 index 0000000..92d915e --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/domestication_pudu_assembly_protocol.py @@ -0,0 +1,23 @@ +from pudu.assembly import SBOLLoopAssembly +from opentrons import protocol_api + +assembly_data = [ + { + "Product": "http://buildcompiler.org/domesticated_missing_promoter/1", + "Backbone": "demo_domestication_backbone", + "PartsList": [ + "http://buildcompiler.org/missing_promoter/1" + ], + "Restriction Enzyme": "BsaI" + } +] + +metadata = { + 'protocolName': 'BuildCompiler domestication Assembly', + 'author': 'BuildCompiler', + 'apiLevel': '2.21', +} + +def run(protocol: protocol_api.ProtocolContext): + protocol_instance = SBOLLoopAssembly(assembly_data=assembly_data) + protocol_instance.run(protocol) diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/full_build_manifest.json b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/full_build_manifest.json new file mode 100644 index 0000000..12015ad --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/full_build_manifest.json @@ -0,0 +1,164 @@ +{ + "results_dir": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages", + "domestication": { + "successful": [ + { + "parts": [ + "missing_promoter" + ], + "products": [ + "http://buildcompiler.org/domesticated_missing_promoter/1" + ] + } + ], + "failed": [] + }, + "assembly_lvl1": { + "successful": [ + { + "design": "demo_tu", + "products": [ + "http://buildcompiler.org/assembled_demo_tu/1" + ] + } + ], + "failed": [ + { + "design": "demo_tu", + "error": "level-1 input is missing a domesticated part" + } + ] + }, + "assembly_lvl2": { + "successful": [ + { + "design": "demo_lvl2_design", + "products": [ + "http://buildcompiler.org/assembled_demo_lvl2/1" + ], + "after_recovery": true + } + ], + "failed": [ + { + "design": "demo_lvl2_design", + "error": "level-2 input is missing level-1 regions", + "recovery": "attempting level-1 assembly and domestication" + } + ] + }, + "transformation": { + "successful": [ + { + "stage_label": "domestication", + "products": [ + "http://buildcompiler.org/domesticated_missing_promoter/1" + ], + "result": { + "stage": "transformation", + "chassis": "E_coli_DH5alpha", + "sbol_artifacts": [ + { + "transformed_strain_module": "http://buildcompiler.org/domesticated_missing_promoter/1_strain", + "transformed_strain_implementation": "http://buildcompiler.org/domesticated_missing_promoter/1_strain_impl" + } + ] + } + }, + { + "stage_label": "full_build_lvl2_1_lvl1", + "products": [ + "http://buildcompiler.org/assembled_demo_tu/1" + ], + "result": { + "stage": "transformation", + "chassis": "E_coli_DH5alpha", + "sbol_artifacts": [ + { + "transformed_strain_module": "http://buildcompiler.org/assembled_demo_tu/1_strain", + "transformed_strain_implementation": "http://buildcompiler.org/assembled_demo_tu/1_strain_impl" + } + ] + } + }, + { + "stage_label": "lvl2_1_final", + "products": [ + "http://buildcompiler.org/assembled_demo_lvl2/1" + ], + "result": { + "stage": "transformation", + "chassis": "E_coli_DH5alpha", + "sbol_artifacts": [ + { + "transformed_strain_module": "http://buildcompiler.org/assembled_demo_lvl2/1_strain", + "transformed_strain_implementation": "http://buildcompiler.org/assembled_demo_lvl2/1_strain_impl" + } + ] + } + } + ], + "failed": [] + }, + "plating": { + "successful": [ + { + "stage_label": "domestication", + "result": { + "stage": "plating", + "json_intermediate": { + "plating_data": { + "bacterium_locations": { + "A1": "demo_transformed_strain" + } + } + } + } + }, + { + "stage_label": "full_build_lvl2_1_lvl1", + "result": { + "stage": "plating", + "json_intermediate": { + "plating_data": { + "bacterium_locations": { + "A1": "demo_transformed_strain" + } + } + } + } + }, + { + "stage_label": "lvl2_1_final", + "result": { + "stage": "plating", + "json_intermediate": { + "plating_data": { + "bacterium_locations": { + "A1": "demo_transformed_strain" + } + } + } + } + } + ], + "failed": [] + }, + "skipped": [], + "artifacts": [ + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl1_pudu_assembly_input.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl1_pudu_assembly_protocol.py", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl2_pudu_assembly_input.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/assembly_lvl2_pudu_assembly_protocol.py", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/domestication_pudu_assembly_input.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/domestication_pudu_assembly_protocol.py", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/transformation_pudu_input.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/transformation_plasmid_locations.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/pudu_transformation_protocol.py", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/plating_pudu_input.json", + "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/pudu_plating_protocol.py" + ], + "manifest_path": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/full_build_manifest.json", + "zip_path": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages.zip", + "artifact_zip": "/Users/gonzalovidal/Documents/GitHub/BuildCompiler/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages.zip" +} diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/plating_pudu_input.json b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/plating_pudu_input.json new file mode 100644 index 0000000..a5114c5 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/plating_pudu_input.json @@ -0,0 +1,19 @@ +{ + "batches": [ + { + "bacterium_locations": { + "A1": "demo_transformed_strain" + } + }, + { + "bacterium_locations": { + "A1": "demo_transformed_strain" + } + }, + { + "bacterium_locations": { + "A1": "demo_transformed_strain" + } + } + ] +} diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/pudu_plating_protocol.py b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/pudu_plating_protocol.py new file mode 100644 index 0000000..f5ed7f5 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/pudu_plating_protocol.py @@ -0,0 +1,32 @@ +from pudu.plating import Plating +from opentrons import protocol_api + +plating_data = { + "batches": [ + { + "bacterium_locations": { + "A1": "demo_transformed_strain" + } + }, + { + "bacterium_locations": { + "A1": "demo_transformed_strain" + } + }, + { + "bacterium_locations": { + "A1": "demo_transformed_strain" + } + } + ] +} + +metadata = { + 'protocolName': 'BuildCompiler Plating', + 'author': 'BuildCompiler', + 'apiLevel': '2.21', +} + +def run(protocol: protocol_api.ProtocolContext): + protocol_instance = Plating(plating_data=plating_data) + protocol_instance.run(protocol) diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/pudu_transformation_protocol.py b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/pudu_transformation_protocol.py new file mode 100644 index 0000000..6a1d04d --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/pudu_transformation_protocol.py @@ -0,0 +1,51 @@ +from pudu.transformation import HeatShockTransformation +from opentrons import protocol_api + +transformation_data = [ + { + "Strain": "http://buildcompiler.org/domesticated_missing_promoter/1_strain", + "Chassis": "E_coli_DH5alpha", + "Plasmids": [ + "http://buildcompiler.org/domesticated_missing_promoter/1" + ] + }, + { + "Strain": "http://buildcompiler.org/assembled_demo_tu/1_strain", + "Chassis": "E_coli_DH5alpha", + "Plasmids": [ + "http://buildcompiler.org/assembled_demo_tu/1" + ] + }, + { + "Strain": "http://buildcompiler.org/assembled_demo_lvl2/1_strain", + "Chassis": "E_coli_DH5alpha", + "Plasmids": [ + "http://buildcompiler.org/assembled_demo_lvl2/1" + ] + } +] + +plasmid_locations = { + "http://buildcompiler.org/domesticated_missing_promoter/1": [ + "A1" + ], + "http://buildcompiler.org/assembled_demo_tu/1": [ + "B1" + ], + "http://buildcompiler.org/assembled_demo_lvl2/1": [ + "C1" + ] +} + +metadata = { + 'protocolName': 'BuildCompiler Transformation', + 'author': 'BuildCompiler', + 'apiLevel': '2.21', +} + +def run(protocol: protocol_api.ProtocolContext): + protocol_instance = HeatShockTransformation( + transformation_data=transformation_data, + plasmid_locations=plasmid_locations, + ) + protocol_instance.run(protocol) diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/transformation_plasmid_locations.json b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/transformation_plasmid_locations.json new file mode 100644 index 0000000..849779b --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/transformation_plasmid_locations.json @@ -0,0 +1,11 @@ +{ + "http://buildcompiler.org/domesticated_missing_promoter/1": [ + "A1" + ], + "http://buildcompiler.org/assembled_demo_tu/1": [ + "B1" + ], + "http://buildcompiler.org/assembled_demo_lvl2/1": [ + "C1" + ] +} diff --git a/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/transformation_pudu_input.json b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/transformation_pudu_input.json new file mode 100644 index 0000000..9ed14f5 --- /dev/null +++ b/notebooks/results/full_build_workflow_examples/lvl2_triggers_all_stages/transformation_pudu_input.json @@ -0,0 +1,23 @@ +[ + { + "Strain": "http://buildcompiler.org/domesticated_missing_promoter/1_strain", + "Chassis": "E_coli_DH5alpha", + "Plasmids": [ + "http://buildcompiler.org/domesticated_missing_promoter/1" + ] + }, + { + "Strain": "http://buildcompiler.org/assembled_demo_tu/1_strain", + "Chassis": "E_coli_DH5alpha", + "Plasmids": [ + "http://buildcompiler.org/assembled_demo_tu/1" + ] + }, + { + "Strain": "http://buildcompiler.org/assembled_demo_lvl2/1_strain", + "Chassis": "E_coli_DH5alpha", + "Plasmids": [ + "http://buildcompiler.org/assembled_demo_lvl2/1" + ] + } +] diff --git a/src/buildcompiler/adapters/pudu/__init__.py b/src/buildcompiler/adapters/pudu/__init__.py index eb22839..242d8f4 100644 --- a/src/buildcompiler/adapters/pudu/__init__.py +++ b/src/buildcompiler/adapters/pudu/__init__.py @@ -11,6 +11,7 @@ ) from .plating_json import plating_to_pudu_json from .transformation_json import ( + plasmid_locations_to_pudu_json, transformation_to_pudu_json, transformations_to_pudu_json, ) @@ -23,6 +24,7 @@ "legacy_assembly_route_to_pudu_json", "legacy_assembly_routes_to_pudu_json", "write_assembly_pudu_input_json", + "plasmid_locations_to_pudu_json", "transformation_to_pudu_json", "transformations_to_pudu_json", "plating_to_pudu_json", diff --git a/src/buildcompiler/adapters/pudu/plating_json.py b/src/buildcompiler/adapters/pudu/plating_json.py index 3648e20..a6656cf 100644 --- a/src/buildcompiler/adapters/pudu/plating_json.py +++ b/src/buildcompiler/adapters/pudu/plating_json.py @@ -7,16 +7,21 @@ def plating_to_pudu_json( *, - bacterium_locations: Mapping[str, str], + bacterium_locations: Mapping[str, str | list[str]], advanced_parameters: Mapping[str, object] | None = None, ) -> dict[str, object]: - """Adapt plating records into deterministic legacy-compatible PUDU JSON keys.""" + """Adapt plating records into PUDU's plating input JSON. + + PUDU expects thermocycler source wells as keys and transformed construct + identifiers as values, wrapped under ``bacterium_locations``. + """ stable_locations = OrderedDict( sorted(bacterium_locations.items(), key=lambda kv: kv[0]) ) payload: dict[str, Any] = { "bacterium_locations": dict(stable_locations), - "advanced_parameters": dict(advanced_parameters or {}), } + if advanced_parameters: + payload.update(dict(advanced_parameters)) return payload diff --git a/src/buildcompiler/adapters/pudu/transformation_json.py b/src/buildcompiler/adapters/pudu/transformation_json.py index 207a561..4385da9 100644 --- a/src/buildcompiler/adapters/pudu/transformation_json.py +++ b/src/buildcompiler/adapters/pudu/transformation_json.py @@ -5,6 +5,11 @@ from buildcompiler.domain import IndexedPlasmid +PUDU_96_WELL_ORDER = tuple( + f"{row}{column}" for column in range(1, 13) for row in "ABCDEFGH" +) + + def _stable_identifier(identity: str, display_id: str | None) -> str: return identity or display_id or "" @@ -51,3 +56,31 @@ def transformations_to_pudu_json( strict=True, ) ] + + +def plasmid_locations_to_pudu_json( + plasmids: Sequence[IndexedPlasmid | str], + *, + wells: Sequence[str] | None = None, +) -> dict[str, list[str]]: + """Create PUDU's assembly-output plasmid location map. + + PUDU's transformation protocol optionally consumes the + ``transformation_input.json`` emitted by its assembly simulation. The shape + is ``{"plasmid_uri": ["A1"]}``, where each value is a list because one + plasmid may be available in multiple source wells. + """ + + if wells is None: + wells = PUDU_96_WELL_ORDER[: len(plasmids)] + if len(plasmids) != len(wells): + raise ValueError("plasmids and wells must have the same length.") + + locations: dict[str, list[str]] = {} + for plasmid, well in zip(plasmids, wells, strict=True): + plasmid_id = _plasmid_identifier(plasmid) + if not plasmid_id: + raise ValueError("plasmid identity cannot be empty.") + locations.setdefault(plasmid_id, []).append(well) + + return locations diff --git a/src/buildcompiler/buildcompiler.py b/src/buildcompiler/buildcompiler.py index d450f4a..44bab10 100644 --- a/src/buildcompiler/buildcompiler.py +++ b/src/buildcompiler/buildcompiler.py @@ -4,6 +4,7 @@ import re import shutil import warnings +import zipfile from typing import Any, List, Dict, Tuple import urllib.parse import csv @@ -32,7 +33,13 @@ write_plate_map_json, write_plating_protocol_script, ) -from .adapters.pudu import legacy_assembly_routes_to_pudu_json +from .adapters.pudu import ( + legacy_assembly_routes_to_pudu_json, + plasmid_locations_to_pudu_json, + plating_to_pudu_json, + transformations_to_pudu_json, + write_assembly_pudu_input_json, +) from .constants import ( AMP, ENGINEERED_REGION, @@ -80,6 +87,7 @@ def __init__( self.restriction_enzyme_implementations = [] self.ligase_implementations = [] self.last_assembly_pudu_json = [] + self.last_assembly_pudu_json_by_stage = {} self.BsaI_impl = None self.BbsI_impl = None self.T4_ligase_impl = None @@ -103,6 +111,7 @@ def from_local_documents( compiler.restriction_enzyme_implementations = [] compiler.ligase_implementations = [] compiler.last_assembly_pudu_json = [] + compiler.last_assembly_pudu_json_by_stage = {} compiler.BsaI_impl = None compiler.BbsI_impl = None compiler.T4_ligase_impl = None @@ -294,6 +303,7 @@ def _remove_internal_bsai_sites(sequence: str) -> tuple[str, int]: dsDNAs = [] domesticated_parts = [] + pudu_payloads = [] for part in parts: part_role = next( @@ -394,7 +404,21 @@ def _remove_internal_bsai_sites(sequence: str) -> tuple[str, int]: assembly_products, assembly_doc = assembly.run() product_definition = assembly_products[0].plasmid_definition domesticated_parts.append(product_definition) + pudu_payloads.extend( + legacy_assembly_routes_to_pudu_json( + product_plasmids=assembly_products, + part_plasmid_routes=[ + [insert_plasmid] for _ in range(len(assembly_products)) + ], + backbones=[backbone for _ in range(len(assembly_products))], + restriction_enzymes=[ + self.BsaI_impl for _ in range(len(assembly_products)) + ], + ) + ) + self.last_assembly_pudu_json = pudu_payloads + self.last_assembly_pudu_json_by_stage["domestication"] = list(pudu_payloads) return domesticated_parts def assembly_lvl1( @@ -429,8 +453,8 @@ def assembly_lvl1( enumerated_part_lists = enumerate_design_variants(combinatorial_part_dict) - for i, list in enumerate(enumerated_part_lists): - plasmid_dict = self._construct_plasmid_dict(list, AMP) + for i, part_list in enumerate(enumerated_part_lists): + plasmid_dict = self._construct_plasmid_dict(part_list, AMP) if isinstance(backbone, dict): raise ValueError( @@ -567,6 +591,7 @@ def assembly_lvl1( assembly_dict[abstract_design.identity] = composite_plasmids self.last_assembly_pudu_json = pudu_payloads + self.last_assembly_pudu_json_by_stage["assembly_lvl1"] = list(pudu_payloads) return assembly_dict, final_doc def assembly_lvl2( @@ -610,6 +635,7 @@ def assembly_lvl2( composite_plasmid_dict, final_doc = self.assembly_lvl1( TUs, backbone=backbone_dict, product_name=f"{TU.displayId}_plas" ) + lvl1_pudu_payloads = list(self.last_assembly_pudu_json) for key, composites in composite_plasmid_dict.items(): simplified_representation, new_defs = self._encapsulate_TU(composites[0]) @@ -655,12 +681,15 @@ def assembly_lvl2( ) lvl2_plasmids, final_doc = assembly.run() # TODO upload product_doc? - self.last_assembly_pudu_json = legacy_assembly_routes_to_pudu_json( + lvl2_pudu_payloads = legacy_assembly_routes_to_pudu_json( product_plasmids=lvl2_plasmids, part_plasmid_routes=[lvl1_plasmids for _ in range(len(lvl2_plasmids))], backbones=[backbone for _ in range(len(lvl2_plasmids))], restriction_enzymes=[self.BbsI_impl for _ in range(len(lvl2_plasmids))], ) + self.last_assembly_pudu_json = lvl2_pudu_payloads + self.last_assembly_pudu_json_by_stage["assembly_lvl1"] = lvl1_pudu_payloads + self.last_assembly_pudu_json_by_stage["assembly_lvl2"] = list(lvl2_pudu_payloads) self.indexed_plasmids.extend(lvl2_plasmids) return lvl2_plasmids, final_doc @@ -1065,6 +1094,820 @@ def plating( "protocol_artifacts": protocol_artifacts, } + def full_build( + self, + designs: Any = None, + results_dir: str | Path = "full_build_results", + overwrite: bool = False, + chassis_name: str = "E_coli_DH5alpha", + plating_protocol_type: str = "manual", + plating_advanced_params: dict | None = None, + product_name: str = "full_build", + ) -> Dict[str, Any]: + """Run the legacy full build workflow and return packaged artifacts. + + The workflow is deliberately file-oriented: each stage writes explicit + intermediates/protocol inputs under ``results_dir`` and the return value + includes a zip archive containing those artifacts. + """ + + results_path = Path(results_dir) + if results_path.exists() and overwrite: + shutil.rmtree(results_path) + results_path.mkdir(parents=True, exist_ok=True) + self.last_assembly_pudu_json = [] + self.last_assembly_pudu_json_by_stage = {} + + result: Dict[str, Any] = { + "results_dir": str(results_path), + "domestication": {"successful": [], "failed": []}, + "assembly_lvl1": {"successful": [], "failed": []}, + "assembly_lvl2": {"successful": [], "failed": []}, + "transformation": {"successful": [], "failed": []}, + "plating": {"successful": [], "failed": []}, + "skipped": [], + "artifacts": [], + } + assembly_payloads: Dict[str, list[dict[str, object]]] = { + "assembly_lvl1": [], + "assembly_lvl2": [], + "domestication": [], + } + + lvl2_docs, lvl1_designs = self._split_full_build_inputs(designs) + + for index, lvl2_doc in enumerate(lvl2_docs, start=1): + label = f"lvl2_{index}" + try: + lvl2_products, lvl2_doc_out = self._run_full_build_lvl2( + lvl2_doc, + product_name=f"{product_name}_{label}", + result=result, + assembly_payloads=assembly_payloads, + chassis_name=chassis_name, + results_path=results_path, + plating_protocol_type=plating_protocol_type, + plating_advanced_params=plating_advanced_params, + overwrite=overwrite, + ) + self._run_transformation_and_plating( + lvl2_products, + stage_label=f"{label}_final", + result=result, + results_path=results_path, + chassis_name=chassis_name, + transformation_doc=lvl2_doc_out, + plating_protocol_type=plating_protocol_type, + plating_advanced_params=plating_advanced_params, + overwrite=overwrite, + ) + except Exception as exc: + result["assembly_lvl2"]["failed"].append( + {"design": label, "error": str(exc)} + ) + + if lvl1_designs: + self._run_full_build_lvl1_designs( + lvl1_designs, + result=result, + assembly_payloads=assembly_payloads, + chassis_name=chassis_name, + results_path=results_path, + plating_protocol_type=plating_protocol_type, + plating_advanced_params=plating_advanced_params, + overwrite=overwrite, + product_name=product_name, + ) + elif not lvl2_docs: + result["skipped"].append( + {"stage": "assembly_lvl2", "reason": "no level-2 design provided"} + ) + + artifact_paths = self._write_full_build_artifacts( + result=result, + assembly_payloads=assembly_payloads, + results_path=results_path, + ) + result["artifacts"].extend(str(path) for path in artifact_paths) + + manifest_path = results_path / "full_build_manifest.json" + zip_path = self._resolve_full_build_zip_path(results_path, overwrite=overwrite) + result["manifest_path"] = str(manifest_path) + result["zip_path"] = str(zip_path) + result["artifact_zip"] = str(zip_path) + self._write_json(manifest_path, result) + self._archive_full_build_results(results_path, zip_path) + + return result + + def _split_full_build_inputs( + self, designs: Any + ) -> tuple[list[sbol2.Document], list[sbol2.ComponentDefinition]]: + if designs is None: + return [], [self._get_abstract_design()] + if isinstance(designs, sbol2.Document): + return [designs], [] + if isinstance(designs, sbol2.CombinatorialDerivation): + return [], self._normalize_full_build_designs(designs) + if isinstance(designs, sbol2.ComponentDefinition): + return [], [designs] + if isinstance(designs, list) or isinstance(designs, tuple): + lvl2_docs = [item for item in designs if isinstance(item, sbol2.Document)] + lvl1_inputs = [ + item for item in designs if not isinstance(item, sbol2.Document) + ] + lvl1_designs = ( + self._normalize_full_build_designs(lvl1_inputs) + if lvl1_inputs + else [] + ) + return lvl2_docs, lvl1_designs + return [], self._normalize_full_build_designs(designs) + + def _run_full_build_lvl2( + self, + lvl2_doc: sbol2.Document, + *, + product_name: str, + result: Dict[str, Any], + assembly_payloads: Dict[str, list[dict[str, object]]], + chassis_name: str, + results_path: Path, + plating_protocol_type: str, + plating_advanced_params: dict | None, + overwrite: bool, + ) -> tuple[list[Any], sbol2.Document]: + try: + lvl2_products, lvl2_doc_out = self.assembly_lvl2( + lvl2_doc, product_name=product_name + ) + result["assembly_lvl2"]["successful"].append( + { + "design": self._document_label(lvl2_doc), + "products": self._product_identities(lvl2_products), + } + ) + self._capture_assembly_payloads(assembly_payloads) + return list(lvl2_products), lvl2_doc_out + except Exception as lvl2_exc: + result["assembly_lvl2"]["failed"].append( + { + "design": self._document_label(lvl2_doc), + "error": str(lvl2_exc), + "recovery": "attempting level-1 assembly and domestication", + } + ) + + tus = _extract_lvl2_TUs(lvl2_doc) + lvl1_products = self._attempt_lvl1_then_domesticate( + tus, + result=result, + assembly_payloads=assembly_payloads, + product_name=f"{product_name}_lvl1", + results_path=results_path, + chassis_name=chassis_name, + plating_protocol_type=plating_protocol_type, + plating_advanced_params=plating_advanced_params, + overwrite=overwrite, + ) + if lvl1_products: + self._run_transformation_and_plating( + lvl1_products, + stage_label=f"{product_name}_lvl1", + result=result, + results_path=results_path, + chassis_name=chassis_name, + transformation_doc=self.sbol_doc, + plating_protocol_type=plating_protocol_type, + plating_advanced_params=plating_advanced_params, + overwrite=overwrite, + ) + + lvl2_products, lvl2_doc_out = self.assembly_lvl2( + lvl2_doc, product_name=product_name + ) + result["assembly_lvl2"]["successful"].append( + { + "design": self._document_label(lvl2_doc), + "products": self._product_identities(lvl2_products), + "after_recovery": True, + } + ) + self._capture_assembly_payloads(assembly_payloads) + return list(lvl2_products), lvl2_doc_out + + def _run_full_build_lvl1_designs( + self, + designs: list[sbol2.ComponentDefinition], + *, + result: Dict[str, Any], + assembly_payloads: Dict[str, list[dict[str, object]]], + chassis_name: str, + results_path: Path, + plating_protocol_type: str, + plating_advanced_params: dict | None, + overwrite: bool, + product_name: str, + ) -> None: + missing_parts = [] + seen_missing = set() + for design in designs: + for missing in self._find_missing_parts_for_lvl1(design): + part = missing["part"] + if part.identity not in seen_missing: + missing_parts.append(part) + seen_missing.add(part.identity) + + if missing_parts: + self._run_domestication( + missing_parts, + result=result, + assembly_payloads=assembly_payloads, + results_path=results_path, + chassis_name=chassis_name, + plating_protocol_type=plating_protocol_type, + plating_advanced_params=plating_advanced_params, + overwrite=overwrite, + ) + + for design in designs: + try: + products, stage_doc = self._run_one_lvl1_design( + design, + result=result, + assembly_payloads=assembly_payloads, + product_name=product_name, + ) + except Exception as exc: + result["assembly_lvl1"]["failed"].append( + {"design": design.displayId or design.identity, "error": str(exc)} + ) + continue + self._run_transformation_and_plating( + products, + stage_label=design.displayId or "lvl1", + result=result, + results_path=results_path, + chassis_name=chassis_name, + transformation_doc=stage_doc, + plating_protocol_type=plating_protocol_type, + plating_advanced_params=plating_advanced_params, + overwrite=overwrite, + ) + + result["skipped"].append( + {"stage": "assembly_lvl2", "reason": "no level-2 design provided"} + ) + + def _attempt_lvl1_then_domesticate( + self, + designs: list[sbol2.ComponentDefinition], + *, + result: Dict[str, Any], + assembly_payloads: Dict[str, list[dict[str, object]]], + product_name: str, + results_path: Path, + chassis_name: str, + plating_protocol_type: str, + plating_advanced_params: dict | None, + overwrite: bool, + ) -> list[Any]: + products: list[Any] = [] + failed_designs: list[sbol2.ComponentDefinition] = [] + for design in designs: + try: + design_products, _ = self._run_one_lvl1_design( + design, + result=result, + assembly_payloads=assembly_payloads, + product_name=product_name, + ) + products.extend(design_products) + except Exception as exc: + result["assembly_lvl1"]["failed"].append( + {"design": design.displayId or design.identity, "error": str(exc)} + ) + failed_designs.append(design) + + missing_parts = [] + seen_missing = set() + for design in failed_designs: + for missing in self._find_missing_parts_for_lvl1(design): + part = missing["part"] + if part.identity not in seen_missing: + missing_parts.append(part) + seen_missing.add(part.identity) + + if missing_parts: + self._run_domestication( + missing_parts, + result=result, + assembly_payloads=assembly_payloads, + results_path=results_path, + chassis_name=chassis_name, + plating_protocol_type=plating_protocol_type, + plating_advanced_params=plating_advanced_params, + overwrite=overwrite, + ) + + for design in failed_designs: + design_products, _ = self._run_one_lvl1_design( + design, + result=result, + assembly_payloads=assembly_payloads, + product_name=product_name, + ) + products.extend(design_products) + + return products + + def _run_one_lvl1_design( + self, + design: sbol2.ComponentDefinition, + *, + result: Dict[str, Any], + assembly_payloads: Dict[str, list[dict[str, object]]], + product_name: str, + ) -> tuple[list[Any], sbol2.Document]: + output = self.assembly_lvl1([design], product_name=product_name) + products, stage_doc = self._normalize_lvl1_output(output, design) + result["assembly_lvl1"]["successful"].append( + { + "design": design.displayId or design.identity, + "products": self._product_identities(products), + } + ) + self._capture_assembly_payloads(assembly_payloads, default_stage="assembly_lvl1") + return products, stage_doc + + def _run_domestication( + self, + parts: list[sbol2.ComponentDefinition], + *, + result: Dict[str, Any], + assembly_payloads: Dict[str, list[dict[str, object]]], + results_path: Path, + chassis_name: str, + plating_protocol_type: str, + plating_advanced_params: dict | None, + overwrite: bool, + ) -> list[Any]: + try: + products = list(self.domestication(parts)) + except Exception as exc: + result["domestication"]["failed"].append( + { + "parts": [part.displayId or part.identity for part in parts], + "error": str(exc), + } + ) + return [] + + for product in products: + if isinstance(product, sbol2.ComponentDefinition): + self._sort_plasmid_components(product, self.sbol_doc) + + result["domestication"]["successful"].append( + { + "parts": [part.displayId or part.identity for part in parts], + "products": self._product_identities(products), + } + ) + self._capture_assembly_payloads(assembly_payloads, default_stage="domestication") + self._run_transformation_and_plating( + products, + stage_label="domestication", + result=result, + results_path=results_path, + chassis_name=chassis_name, + transformation_doc=self.sbol_doc, + plating_protocol_type=plating_protocol_type, + plating_advanced_params=plating_advanced_params, + overwrite=overwrite, + ) + return products + + def _run_transformation_and_plating( + self, + products: list[Any], + *, + stage_label: str, + result: Dict[str, Any], + results_path: Path, + chassis_name: str, + transformation_doc: sbol2.Document, + plating_protocol_type: str, + plating_advanced_params: dict | None, + overwrite: bool, + ) -> None: + if not products: + return + try: + transformation_result = self.transformation( + products, + chassis_name=chassis_name, + transformation_doc=transformation_doc, + ) + result["transformation"]["successful"].append( + { + "stage_label": stage_label, + "products": self._product_identities(products), + "result": transformation_result, + } + ) + except Exception as exc: + result["transformation"]["failed"].append( + { + "stage_label": stage_label, + "products": self._product_identities(products), + "error": str(exc), + } + ) + return + + try: + plating_result = self.plating( + transformation_result, + results_dir=results_path / f"{stage_label}_plating", + protocol_type=plating_protocol_type, + advanced_params=plating_advanced_params, + plating_doc=transformation_doc, + overwrite=overwrite, + ) + result["plating"]["successful"].append( + {"stage_label": stage_label, "result": plating_result} + ) + except Exception as exc: + result["plating"]["failed"].append( + {"stage_label": stage_label, "error": str(exc)} + ) + + def _normalize_full_build_designs(self, designs: Any) -> list[sbol2.ComponentDefinition]: + if isinstance(designs, sbol2.ComponentDefinition): + return [designs] + if isinstance(designs, sbol2.CombinatorialDerivation): + return self._expand_combinatorial_derivation(designs) + if isinstance(designs, list) or isinstance(designs, tuple): + normalized: list[sbol2.ComponentDefinition] = [] + for design in designs: + if isinstance(design, sbol2.CombinatorialDerivation): + normalized.extend(self._expand_combinatorial_derivation(design)) + elif isinstance(design, sbol2.ComponentDefinition): + normalized.append(design) + else: + raise ValueError( + "full_build designs must be SBOL ComponentDefinitions, " + "CombinatorialDerivations, Documents, or lists of those." + ) + return normalized + raise ValueError( + "full_build designs must be SBOL ComponentDefinitions, " + "CombinatorialDerivations, Documents, or lists of those." + ) + + def _expand_combinatorial_derivation( + self, + derivation: sbol2.CombinatorialDerivation, + product_name_prefix: str = "full_build", + ) -> list[sbol2.ComponentDefinition]: + template = get_or_pull( + self.sbol_doc, self.sbh, derivation.masterTemplate, self.server_mode + ) + variant_lists = enumerate_design_variants( + extract_combinatorial_design_parts(template, derivation) + ) + variants = [] + for index, parts in enumerate(variant_lists, start=1): + variant = sbol2.ComponentDefinition( + f"{product_name_prefix}_variant_{index:03d}" + ) + self.sbol_doc.add(variant) + created_components = [] + for part_index, part in enumerate(parts, start=1): + component = variant.components.create(f"part_{part_index}") + component.definition = part.identity + created_components.append(component) + for constraint_index in range(len(created_components) - 1): + constraint = variant.sequenceConstraints.create( + f"constraint_{constraint_index + 1}" + ) + constraint.subject = created_components[constraint_index].identity + constraint.object = created_components[constraint_index + 1].identity + constraint.restriction = sbol2.SBOL_RESTRICTION_PRECEDES + variants.append(variant) + return variants + + def _find_missing_parts_for_lvl1( + self, design: sbol2.ComponentDefinition + ) -> list[dict[str, Any]]: + missing = [] + parts = self._extract_design_parts(design) + plasmid_dict = self._construct_plasmid_dict(parts, AMP) + for part in parts: + if not plasmid_dict.get(part.displayId): + missing.append({"part": part, "reason": "no implemented plasmid"}) + + if missing: + return missing + + backbone, compatible = self._get_backbone( + plasmid_dict, antibiotic_resistance=KAN + ) + if backbone is None or not compatible: + return [ + { + "part": part, + "reason": "no compatible level-1 route", + } + for part in parts + ] + return [] + + def _normalize_lvl1_output( + self, output: Any, design: sbol2.ComponentDefinition + ) -> tuple[list[Any], sbol2.Document]: + stage_doc = self.sbol_doc + payload = output + if isinstance(output, tuple): + payload = output[0] + if len(output) > 1 and isinstance(output[1], sbol2.Document): + stage_doc = output[1] + if isinstance(payload, dict): + products = list(payload.get(design.identity, [])) + if not products: + products = [ + product + for product_list in payload.values() + for product in ( + product_list + if isinstance(product_list, list) + else [product_list] + ) + ] + return products, stage_doc + if isinstance(payload, list): + return payload, stage_doc + return [payload], stage_doc + + def _capture_assembly_payloads( + self, + assembly_payloads: Dict[str, list[dict[str, object]]], + default_stage: str = "assembly_lvl1", + ) -> None: + staged = getattr(self, "last_assembly_pudu_json_by_stage", {}) or {} + if staged: + for stage, payloads in staged.items(): + assembly_payloads.setdefault(stage, []) + assembly_payloads[stage].extend(self._dedupe_payloads(payloads)) + return + payloads = getattr(self, "last_assembly_pudu_json", []) or [] + assembly_payloads.setdefault(default_stage, []) + assembly_payloads[default_stage].extend(self._dedupe_payloads(payloads)) + + def _write_full_build_artifacts( + self, + *, + result: Dict[str, Any], + assembly_payloads: Dict[str, list[dict[str, object]]], + results_path: Path, + ) -> list[Path]: + written: list[Path] = [] + + for stage, payloads in sorted(assembly_payloads.items()): + payloads = self._dedupe_payloads(payloads) + if not payloads: + continue + json_path = write_assembly_pudu_input_json( + payloads, results_path / f"{stage}_pudu_assembly_input.json" + ) + written.append(json_path) + written.append( + self._write_pudu_assembly_protocol_script( + results_path / f"{stage}_pudu_assembly_protocol.py", + payloads, + protocol_name=f"BuildCompiler {stage} Assembly", + ) + ) + + transformation_payloads = [] + plasmid_location_inputs = [] + for entry in result["transformation"]["successful"]: + products = entry.get("products", []) + tx_result = entry.get("result", {}) + artifacts = tx_result.get("sbol_artifacts", []) if isinstance(tx_result, dict) else [] + strain_ids = [ + artifact.get("transformed_strain_module") + or artifact.get("transformed_strain_implementation") + for artifact in artifacts + if isinstance(artifact, dict) + ] + if not strain_ids: + strain_ids = [f"{entry.get('stage_label', 'transformation')}_strain"] + chassis = ( + tx_result.get("chassis", "E_coli_DH5alpha") + if isinstance(tx_result, dict) + else "E_coli_DH5alpha" + ) + transformation_payloads.extend( + transformations_to_pudu_json( + strain_identities=strain_ids, + chassis_identities=[chassis for _ in strain_ids], + plasmid_sets=[products for _ in strain_ids], + ) + ) + plasmid_location_inputs.extend(products) + + if transformation_payloads: + tx_path = results_path / "transformation_pudu_input.json" + self._write_json(tx_path, transformation_payloads) + written.append(tx_path) + location_payload = plasmid_locations_to_pudu_json(plasmid_location_inputs) + loc_path = results_path / "transformation_plasmid_locations.json" + self._write_json(loc_path, location_payload) + written.append(loc_path) + written.append( + self._write_pudu_transformation_protocol_script( + results_path / "pudu_transformation_protocol.py", + transformation_payloads, + location_payload, + ) + ) + + plating_payloads = [] + for entry in result["plating"]["successful"]: + plating_result = entry.get("result", {}) + if not isinstance(plating_result, dict): + continue + plating_data = ( + plating_result.get("json_intermediate", {}).get("plating_data", {}) + ) + bacterium_locations = plating_data.get("bacterium_locations") + if bacterium_locations: + plating_payloads.append( + plating_to_pudu_json(bacterium_locations=bacterium_locations) + ) + + if plating_payloads: + plating_payload = ( + plating_payloads[0] + if len(plating_payloads) == 1 + else {"batches": plating_payloads} + ) + plating_path = results_path / "plating_pudu_input.json" + self._write_json(plating_path, plating_payload) + written.append(plating_path) + written.append( + self._write_pudu_plating_protocol_script( + results_path / "pudu_plating_protocol.py", plating_payload + ) + ) + + return written + + def _write_pudu_assembly_protocol_script( + self, path: Path, payload: list[dict[str, object]], protocol_name: str + ) -> Path: + script = ( + "from pudu.assembly import SBOLLoopAssembly\n" + "from opentrons import protocol_api\n\n" + f"assembly_data = {json.dumps(payload, indent=4)}\n\n" + "metadata = {\n" + f" 'protocolName': {protocol_name!r},\n" + " 'author': 'BuildCompiler',\n" + " 'apiLevel': '2.21',\n" + "}\n\n" + "def run(protocol: protocol_api.ProtocolContext):\n" + " protocol_instance = SBOLLoopAssembly(assembly_data=assembly_data)\n" + " protocol_instance.run(protocol)\n" + ) + path.write_text(script, encoding="utf-8") + return path + + def _write_pudu_transformation_protocol_script( + self, + path: Path, + transformation_payload: list[dict[str, object]], + plasmid_locations: dict[str, list[str]], + ) -> Path: + script = ( + "from pudu.transformation import HeatShockTransformation\n" + "from opentrons import protocol_api\n\n" + f"transformation_data = {json.dumps(transformation_payload, indent=4)}\n\n" + f"plasmid_locations = {json.dumps(plasmid_locations, indent=4)}\n\n" + "metadata = {\n" + " 'protocolName': 'BuildCompiler Transformation',\n" + " 'author': 'BuildCompiler',\n" + " 'apiLevel': '2.21',\n" + "}\n\n" + "def run(protocol: protocol_api.ProtocolContext):\n" + " protocol_instance = HeatShockTransformation(\n" + " transformation_data=transformation_data,\n" + " plasmid_locations=plasmid_locations,\n" + " )\n" + " protocol_instance.run(protocol)\n" + ) + path.write_text(script, encoding="utf-8") + return path + + def _write_pudu_plating_protocol_script( + self, path: Path, plating_payload: dict[str, object] + ) -> Path: + script = ( + "from pudu.plating import Plating\n" + "from opentrons import protocol_api\n\n" + f"plating_data = {json.dumps(plating_payload, indent=4)}\n\n" + "metadata = {\n" + " 'protocolName': 'BuildCompiler Plating',\n" + " 'author': 'BuildCompiler',\n" + " 'apiLevel': '2.21',\n" + "}\n\n" + "def run(protocol: protocol_api.ProtocolContext):\n" + " protocol_instance = Plating(plating_data=plating_data)\n" + " protocol_instance.run(protocol)\n" + ) + path.write_text(script, encoding="utf-8") + return path + + def _resolve_full_build_zip_path( + self, results_path: Path, overwrite: bool + ) -> Path: + zip_path = results_path.with_suffix(".zip") + if zip_path.exists() and overwrite: + zip_path.unlink() + if zip_path.exists(): + index = 1 + while True: + candidate = results_path.with_name(f"{results_path.name}_{index}.zip") + if not candidate.exists(): + zip_path = candidate + break + index += 1 + return zip_path + + def _archive_full_build_results( + self, results_path: Path, zip_path: Path + ) -> Path: + with zipfile.ZipFile(zip_path, "w", compression=zipfile.ZIP_DEFLATED) as archive: + for path in sorted(results_path.rglob("*")): + if path.is_file(): + archive.write(path, path.relative_to(results_path)) + return zip_path + + def _write_json(self, path: Path, payload: Any) -> Path: + path.write_text( + json.dumps(self._json_safe(payload), indent=2) + "\n", + encoding="utf-8", + ) + return path + + def _json_safe(self, value: Any) -> Any: + if isinstance(value, Path): + return str(value) + if isinstance(value, dict): + return {str(key): self._json_safe(item) for key, item in value.items()} + if isinstance(value, (list, tuple, set)): + return [self._json_safe(item) for item in value] + if isinstance(value, (str, int, float, bool)) or value is None: + return value + if hasattr(value, "identity"): + return getattr(value, "identity") + if hasattr(value, "plasmid_definition"): + return self._plasmid_identity(value) + return str(value) + + def _product_identities(self, products: list[Any]) -> list[str]: + return [self._plasmid_identity(product) for product in products] + + def _plasmid_identity(self, product: Any) -> str: + if isinstance(product, str): + return product + definition = getattr(product, "plasmid_definition", product) + return str( + getattr(definition, "identity", None) + or getattr(definition, "displayId", None) + or product + ) + + def _document_label(self, doc: sbol2.Document) -> str: + try: + top_level = extract_toplevel_definition(doc) + return top_level.displayId or top_level.identity + except Exception: + return "level_2_design" + + def _dedupe_payloads( + self, payloads: list[dict[str, object]] + ) -> list[dict[str, object]]: + deduped = [] + seen = set() + for payload in payloads or []: + key = json.dumps(self._json_safe(payload), sort_keys=True) + if key in seen: + continue + seen.add(key) + deduped.append(payload) + return deduped + def _extract_plasmids_from_strain( self, strain: sbol2.ModuleDefinition, @@ -1643,6 +2486,57 @@ def _add_if_absent(self, doc: sbol2.Document, obj: Any): if doc.find(obj.identity) is None: doc.add(obj) + def _normalize_transformation_inputs( + self, assembly_products: List[Any] + ) -> List[Dict[str, sbol2.ComponentDefinition | str]]: + """Normalize supported transformation inputs into plasmid definitions. + + Transformation can be called directly after assembly, where inputs are + BuildCompiler ``Plasmid`` objects, or independently with SBOL plasmid + definitions/dict payloads. This keeps that adapter logic out of the SBOL + writer so transformation remains usable as a standalone stage. + """ + + normalized_products = [] + for product in assembly_products: + source = None + plasmid = None + + if isinstance(product, dict): + source = product.get("source") or product.get("name") + product = product.get("plasmid") or product.get("plasmid_definition") + + if isinstance(product, Plasmid): + plasmid = product.plasmid_definition + source = source or product.name or plasmid.displayId + elif isinstance(product, sbol2.ComponentDefinition): + plasmid = product + source = source or plasmid.displayId + elif hasattr(product, "plasmid_definition"): + plasmid = product.plasmid_definition + source = source or getattr(product, "name", None) or plasmid.displayId + + if plasmid is None: + raise ValueError( + "transformation inputs must be Plasmid objects, " + "sbol2.ComponentDefinition plasmids, or dictionaries with a " + "'plasmid' entry." + ) + if not isinstance(plasmid, sbol2.ComponentDefinition): + raise ValueError( + f"transformation plasmid input must resolve to a " + f"ComponentDefinition, got {type(plasmid).__name__}." + ) + + normalized_products.append( + { + "source": source or plasmid.displayId or plasmid.identity, + "plasmid": plasmid, + } + ) + + return normalized_products + def _get_or_create_chassis( self, doc: sbol2.Document, chassis_name: str ) -> tuple[sbol2.ModuleDefinition, sbol2.Implementation]: diff --git a/tests/test_buildcompiler_transformation.py b/tests/test_buildcompiler_transformation.py index 0b9a6e7..137ab88 100644 --- a/tests/test_buildcompiler_transformation.py +++ b/tests/test_buildcompiler_transformation.py @@ -1,11 +1,13 @@ import os import sys import unittest +from pathlib import Path import sbol2 sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../src"))) +from buildcompiler.abstract_translator import extract_toplevel_definition from buildcompiler.buildcompiler import BuildCompiler from buildcompiler.constants import ENGINEERED_PLASMID @@ -59,6 +61,46 @@ def test_transformation_requires_inputs(self): with self.assertRaises(ValueError): self.compiler.transformation([]) + def test_transformation_accepts_lvl1_assembly_products(self): + test_files = Path(__file__).parent / "test_files" + collection_docs = [] + for filename in ( + "CIDARMoCloParts_collection.xml", + "CIDARMoCloPlasmidsKit_collection.xml", + "Enzyme_Implementations_collection.xml", + "impl_test_collection.xml", + ): + doc = sbol2.Document() + doc.read(str(test_files / filename)) + collection_docs.append(doc) + + design_doc = sbol2.Document() + design_doc.read(str(test_files / "abstract_design.xml")) + design = extract_toplevel_definition(design_doc) + compiler = BuildCompiler.from_local_documents( + collection_docs, design_doc=design_doc + ) + + assembly_routes, assembly_doc = compiler.assembly_lvl1( + [design], + final_doc=sbol2.Document(), + product_name="transformation_lvl1", + ) + + products = assembly_routes[design.identity] + result = compiler.transformation( + products, + chassis_name="E_coli_DH5alpha", + transformation_doc=assembly_doc, + ) + + self.assertEqual(result["stage"], "transformation") + self.assertEqual(result["inputs"], [products[0].name]) + self.assertEqual(len(result["sbol_artifacts"]), 1) + self.assertIsNotNone( + assembly_doc.find(result["sbol_artifacts"][0]["transformation_activity"]) + ) + if __name__ == "__main__": unittest.main() diff --git a/tests/test_full_build.py b/tests/test_full_build.py index eb3a532..7758877 100644 --- a/tests/test_full_build.py +++ b/tests/test_full_build.py @@ -57,6 +57,16 @@ def _make_plasmid(self, display_id: str) -> sbol2.ComponentDefinition: self.doc.add(plasmid) return plasmid + def _make_lvl2_document(self) -> tuple[sbol2.Document, sbol2.ComponentDefinition]: + doc = sbol2.Document() + tu = sbol2.ComponentDefinition("example_tu") + lvl2 = sbol2.ComponentDefinition("example_lvl2_design") + doc.add(tu) + doc.add(lvl2) + comp = lvl2.components.create("tu_component") + comp.definition = tu.identity + return doc, tu + def test_normalize_full_build_designs_input_shapes(self): d1 = self._make_design("design_a", ["part_a"]) d2 = self._make_design("design_b", ["part_b"]) @@ -173,6 +183,133 @@ def test_full_build_writes_manifest_and_zip_and_return_shape(self): names = archive.namelist() self.assertIn("full_build_manifest.json", names) + def test_full_build_lvl2_example_packages_pudu_protocols_for_recovery_stack(self): + lvl2_doc, _ = self._make_lvl2_document() + missing_part = self._make_part("missing_promoter") + domesticated = self._make_plasmid("domesticated_missing_promoter") + lvl1_product = self._make_plasmid("assembled_example_tu") + lvl2_product = self._make_plasmid("assembled_example_lvl2") + calls = [] + + def fake_assembly_lvl2(*args, **kwargs): + calls.append("assembly_lvl2") + if calls.count("assembly_lvl2") == 1: + raise RuntimeError("level-2 input is missing level-1 regions") + self.compiler.last_assembly_pudu_json_by_stage = { + "assembly_lvl2": [ + { + "Product": lvl2_product.identity, + "Backbone": "lvl2_backbone", + "PartsList": [lvl1_product.identity], + "Restriction Enzyme": "BbsI", + } + ] + } + return [lvl2_product], self.doc + + def fake_assembly_lvl1(*args, **kwargs): + calls.append("assembly_lvl1") + if calls.count("assembly_lvl1") == 1: + raise RuntimeError("level-1 input is missing domesticated part") + self.compiler.last_assembly_pudu_json_by_stage = { + "assembly_lvl1": [ + { + "Product": lvl1_product.identity, + "Backbone": "lvl1_backbone", + "PartsList": [domesticated.identity], + "Restriction Enzyme": "BsaI", + } + ] + } + return [lvl1_product], self.doc + + def fake_domestication(parts): + calls.append("domestication") + self.compiler.last_assembly_pudu_json_by_stage = { + "domestication": [ + { + "Product": domesticated.identity, + "Backbone": "domestication_backbone", + "PartsList": [missing_part.identity], + "Restriction Enzyme": "BsaI", + } + ] + } + return [domesticated] + + def fake_transformation( + products, chassis_name="E_coli_DH5alpha", transformation_doc=None + ): + calls.append("transformation") + product_id = products[0].identity + return { + "stage": "transformation", + "chassis": chassis_name, + "sbol_artifacts": [ + { + "transformed_strain_module": f"{product_id}_strain", + "transformed_strain_implementation": f"{product_id}_strain_impl", + } + ], + } + + def fake_plating(*args, **kwargs): + calls.append("plating") + return { + "stage": "plating", + "json_intermediate": { + "plating_data": { + "bacterium_locations": {"A1": "example_transformed_strain"} + } + }, + } + + with tempfile.TemporaryDirectory() as tmpdir, patch.object( + self.compiler, "assembly_lvl2", side_effect=fake_assembly_lvl2 + ), patch.object( + self.compiler, "assembly_lvl1", side_effect=fake_assembly_lvl1 + ), patch.object( + self.compiler, + "_find_missing_parts_for_lvl1", + return_value=[{"part": missing_part}], + ), patch.object( + self.compiler, "domestication", side_effect=fake_domestication + ), patch.object( + self.compiler, "transformation", side_effect=fake_transformation + ), patch.object( + self.compiler, "plating", side_effect=fake_plating + ): + result = self.compiler.full_build( + designs=lvl2_doc, + results_dir=Path(tmpdir) / "lvl2_full_build", + overwrite=True, + ) + zip_path = Path(result["zip_path"]) + self.assertTrue(zip_path.exists()) + with zipfile.ZipFile(zip_path, "r") as archive: + names = set(archive.namelist()) + + self.assertEqual( + calls[:3], ["assembly_lvl2", "assembly_lvl1", "domestication"] + ) + self.assertEqual(result["artifact_zip"], result["zip_path"]) + + expected_artifacts = { + "assembly_lvl1_pudu_assembly_input.json", + "assembly_lvl2_pudu_assembly_input.json", + "domestication_pudu_assembly_input.json", + "assembly_lvl1_pudu_assembly_protocol.py", + "assembly_lvl2_pudu_assembly_protocol.py", + "domestication_pudu_assembly_protocol.py", + "transformation_pudu_input.json", + "transformation_plasmid_locations.json", + "pudu_transformation_protocol.py", + "plating_pudu_input.json", + "pudu_plating_protocol.py", + "full_build_manifest.json", + } + self.assertTrue(expected_artifacts.issubset(names)) + if __name__ == "__main__": unittest.main() diff --git a/tests/unit/adapters/pudu/test_plating_json.py b/tests/unit/adapters/pudu/test_plating_json.py index aa075e5..320b660 100644 --- a/tests/unit/adapters/pudu/test_plating_json.py +++ b/tests/unit/adapters/pudu/test_plating_json.py @@ -3,17 +3,17 @@ def test_plating_to_pudu_json_shape_and_values(): payload = plating_to_pudu_json( - bacterium_locations={"strain_b": "B2", "strain_a": "A1"}, + bacterium_locations={"B2": "strain_b", "A1": "strain_a"}, advanced_parameters={"replicates": 2}, ) assert payload == { - "bacterium_locations": {"strain_a": "A1", "strain_b": "B2"}, - "advanced_parameters": {"replicates": 2}, + "bacterium_locations": {"A1": "strain_a", "B2": "strain_b"}, + "replicates": 2, } -def test_plating_to_pudu_json_defaults_advanced_parameters(): - payload = plating_to_pudu_json(bacterium_locations={"strain_a": "A1"}) +def test_plating_to_pudu_json_omits_empty_advanced_parameters(): + payload = plating_to_pudu_json(bacterium_locations={"A1": "strain_a"}) - assert payload["advanced_parameters"] == {} + assert payload == {"bacterium_locations": {"A1": "strain_a"}} diff --git a/tests/unit/adapters/pudu/test_transformation_json.py b/tests/unit/adapters/pudu/test_transformation_json.py index d18f7ab..d632132 100644 --- a/tests/unit/adapters/pudu/test_transformation_json.py +++ b/tests/unit/adapters/pudu/test_transformation_json.py @@ -1,4 +1,5 @@ from buildcompiler.adapters.pudu import ( + plasmid_locations_to_pudu_json, transformation_to_pudu_json, transformations_to_pudu_json, ) @@ -36,3 +37,22 @@ def test_transformations_to_pudu_json_batch_helper_is_deterministic(): {"Strain": "s1", "Chassis": "c1", "Plasmids": ["p1"]}, {"Strain": "s2", "Chassis": "c2", "Plasmids": ["p2", "p3"]}, ] + + +def test_plasmid_locations_to_pudu_json_uses_deterministic_wells(): + payload = plasmid_locations_to_pudu_json(["p1", "p2", "p3"]) + + assert payload == { + "p1": ["A1"], + "p2": ["B1"], + "p3": ["C1"], + } + + +def test_plasmid_locations_to_pudu_json_accepts_explicit_wells_and_duplicates(): + payload = plasmid_locations_to_pudu_json(["p1", "p1", "p2"], wells=["A1", "B1", "C1"]) + + assert payload == { + "p1": ["A1", "B1"], + "p2": ["C1"], + } From 03c6519d370a0f4dd6b35f47bc4570c0561b4503 Mon Sep 17 00:00:00 2001 From: Gonzalo Vidal <35148159+Gonza10V@users.noreply.github.com> Date: Sat, 11 Jul 2026 21:36:52 -0600 Subject: [PATCH 2/4] Format Pudu transformation JSON test --- tests/unit/adapters/pudu/test_transformation_json.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/tests/unit/adapters/pudu/test_transformation_json.py b/tests/unit/adapters/pudu/test_transformation_json.py index d632132..8ad86ce 100644 --- a/tests/unit/adapters/pudu/test_transformation_json.py +++ b/tests/unit/adapters/pudu/test_transformation_json.py @@ -50,7 +50,9 @@ def test_plasmid_locations_to_pudu_json_uses_deterministic_wells(): def test_plasmid_locations_to_pudu_json_accepts_explicit_wells_and_duplicates(): - payload = plasmid_locations_to_pudu_json(["p1", "p1", "p2"], wells=["A1", "B1", "C1"]) + payload = plasmid_locations_to_pudu_json( + ["p1", "p1", "p2"], wells=["A1", "B1", "C1"] + ) assert payload == { "p1": ["A1", "B1"], From 43854b9ae2b9985a407e5b1f7ebd54f97c215bf7 Mon Sep 17 00:00:00 2001 From: Gonzalo Vidal <35148159+Gonza10V@users.noreply.github.com> Date: Sat, 11 Jul 2026 21:53:09 -0600 Subject: [PATCH 3/4] Index domesticated plasmids before assembly retry --- src/buildcompiler/buildcompiler.py | 18 +++++++++++--- tests/test_full_build.py | 39 ++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+), 3 deletions(-) diff --git a/src/buildcompiler/buildcompiler.py b/src/buildcompiler/buildcompiler.py index 44bab10..e89a9fd 100644 --- a/src/buildcompiler/buildcompiler.py +++ b/src/buildcompiler/buildcompiler.py @@ -1463,9 +1463,7 @@ def _run_domestication( ) return [] - for product in products: - if isinstance(product, sbol2.ComponentDefinition): - self._sort_plasmid_components(product, self.sbol_doc) + self._index_domestication_products(products) result["domestication"]["successful"].append( { @@ -1487,6 +1485,20 @@ def _run_domestication( ) return products + + def _index_domestication_products(self, products: list[Any]) -> None: + """Make domesticated plasmids available to subsequent assembly retries.""" + for product in products: + if isinstance(product, Plasmid): + if not self._get_indexed_plasmid( + self.indexed_plasmids, product.plasmid_definition + ): + self.indexed_plasmids.append(product) + continue + + if isinstance(product, sbol2.ComponentDefinition): + self._sort_plasmid_components(product, self.sbol_doc) + def _run_transformation_and_plating( self, products: list[Any], diff --git a/tests/test_full_build.py b/tests/test_full_build.py index 7758877..043be01 100644 --- a/tests/test_full_build.py +++ b/tests/test_full_build.py @@ -11,6 +11,7 @@ sys.path.insert(0, os.path.abspath(os.path.join(os.path.dirname(__file__), "../src"))) from buildcompiler.buildcompiler import BuildCompiler +from buildcompiler.plasmid import Plasmid from buildcompiler.constants import ENGINEERED_PLASMID @@ -118,6 +119,44 @@ def test_find_missing_parts_reports_missing_and_present(self): self.assertEqual(missing[0]["part"].displayId, "part_y") self.assertEqual(missing[0]["reason"], "no implemented plasmid") + def test_run_domestication_indexes_products_before_retry(self): + missing_part = self._make_part("missing_for_retry") + domesticated = self._make_plasmid("domesticated_for_retry") + + with tempfile.TemporaryDirectory() as tmpdir, patch.object( + self.compiler, "domestication", return_value=[domesticated] + ), patch.object( + self.compiler, "_sort_plasmid_components" + ) as mock_sort, patch.object( + self.compiler, "_run_transformation_and_plating" + ): + self.compiler._run_domestication( + [missing_part], + result={ + "domestication": {"successful": [], "failed": []}, + "transformation": {"successful": [], "failed": []}, + "plating": {"successful": [], "failed": []}, + }, + assembly_payloads={}, + results_path=Path(tmpdir), + chassis_name="E_coli_DH5alpha", + plating_protocol_type="manual", + plating_advanced_params=None, + overwrite=True, + ) + + mock_sort.assert_called_once_with(domesticated, self.compiler.sbol_doc) + + def test_index_domestication_products_adds_plasmid_routes_once(self): + domesticated = self._make_plasmid("domesticated_route_for_retry") + route = object.__new__(Plasmid) + route.plasmid_definition = domesticated + + self.compiler._index_domestication_products([route]) + self.compiler._index_domestication_products([route]) + + self.assertEqual(self.compiler.indexed_plasmids, [route]) + def test_full_build_orchestration_and_stage_skip(self): design_a = self._make_design("dA", ["pa"]) design_b = self._make_design("dB", ["pb"]) From 7eea8f0a00602ee144449c51d89509b9484aff53 Mon Sep 17 00:00:00 2001 From: Gonzalo Vidal <35148159+Gonza10V@users.noreply.github.com> Date: Sat, 11 Jul 2026 22:00:35 -0600 Subject: [PATCH 4/4] Pair transformed strains with individual plasmids --- src/buildcompiler/buildcompiler.py | 12 +++++++- tests/test_full_build.py | 49 ++++++++++++++++++++++++++++++ 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/src/buildcompiler/buildcompiler.py b/src/buildcompiler/buildcompiler.py index e89a9fd..e49417d 100644 --- a/src/buildcompiler/buildcompiler.py +++ b/src/buildcompiler/buildcompiler.py @@ -1724,7 +1724,9 @@ def _write_full_build_artifacts( transformations_to_pudu_json( strain_identities=strain_ids, chassis_identities=[chassis for _ in strain_ids], - plasmid_sets=[products for _ in strain_ids], + plasmid_sets=self._plasmid_sets_for_transformed_strains( + products, strain_ids + ), ) ) plasmid_location_inputs.extend(products) @@ -1776,6 +1778,14 @@ def _write_full_build_artifacts( return written + def _plasmid_sets_for_transformed_strains( + self, products: list[Any], strain_ids: list[str] + ) -> list[list[str]]: + product_ids = self._product_identities(products) + if len(product_ids) == len(strain_ids): + return [[product_id] for product_id in product_ids] + return [product_ids for _ in strain_ids] + def _write_pudu_assembly_protocol_script( self, path: Path, payload: list[dict[str, object]], protocol_name: str ) -> Path: diff --git a/tests/test_full_build.py b/tests/test_full_build.py index 043be01..071d9ae 100644 --- a/tests/test_full_build.py +++ b/tests/test_full_build.py @@ -1,3 +1,4 @@ +import json import os import sys import tempfile @@ -222,6 +223,54 @@ def test_full_build_writes_manifest_and_zip_and_return_shape(self): names = archive.namelist() self.assertIn("full_build_manifest.json", names) + def test_full_build_pudu_transformation_pairs_each_strain_with_own_product(self): + result = { + "transformation": { + "successful": [ + { + "stage_label": "assembly_lvl1", + "products": ["plasmid_a", "plasmid_b"], + "result": { + "chassis": "E_coli_DH5alpha", + "sbol_artifacts": [ + {"transformed_strain_module": "strain_a"}, + {"transformed_strain_module": "strain_b"}, + ], + }, + } + ] + }, + "plating": {"successful": []}, + } + + with tempfile.TemporaryDirectory() as tmpdir: + self.compiler._write_full_build_artifacts( + result=result, + assembly_payloads={}, + results_path=Path(tmpdir), + ) + payload = json.loads( + (Path(tmpdir) / "transformation_pudu_input.json").read_text( + encoding="utf-8" + ) + ) + + self.assertEqual( + payload, + [ + { + "Strain": "strain_a", + "Chassis": "E_coli_DH5alpha", + "Plasmids": ["plasmid_a"], + }, + { + "Strain": "strain_b", + "Chassis": "E_coli_DH5alpha", + "Plasmids": ["plasmid_b"], + }, + ], + ) + def test_full_build_lvl2_example_packages_pudu_protocols_for_recovery_stack(self): lvl2_doc, _ = self._make_lvl2_document() missing_part = self._make_part("missing_promoter")