diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..f277d8b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,111 @@ +name: CI + +# Replaces the old conda-build workflow, which still pointed at +# `modules/quest/**` — the path QuEst has when it is vendored inside ChiSurf, +# not the layout of this repository — so it had stopped matching anything. + +on: + workflow_dispatch: + push: + branches: [main] + pull_request: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +env: + # ChiSurf brings tttrlib with its own OpenMP runtime; numba's `workqueue` + # layer aborts the interpreter alongside it. See okf/workflows/testing.md. + NUMBA_THREADING_LAYER: omp + +jobs: + test: + name: Library & web backend (${{ matrix.os }}) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + steps: + - uses: actions/checkout@v4 + + - uses: prefix-dev/setup-pixi@v0.8.1 + with: + pixi-version: latest + cache: true + environments: default + + # The browser suite skips itself unless the servers are up; it runs in the + # `e2e` job below, so it is excluded here rather than silently skipped. + - name: Library + run: pixi run -e default test + + - name: Web backend + run: pixi run -e default test-web + + gui: + name: Qt GUI (offscreen) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: prefix-dev/setup-pixi@v0.8.1 + with: + pixi-version: latest + cache: true + environments: desktop + + # A Qt binding needs an X stack even offscreen. + - name: System Qt dependencies + run: | + sudo apt-get update + sudo apt-get install -y libegl1 libgl1 libxkbcommon-x11-0 \ + libxcb-icccm4 libxcb-image0 libxcb-keysyms1 libxcb-randr0 \ + libxcb-render-util0 libxcb-shape0 libxcb-xinerama0 + + - name: Widget tests + run: pixi run -e desktop test-gui + + frontend: + name: Web UI (typecheck & build) + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: prefix-dev/setup-pixi@v0.8.1 + with: + pixi-version: latest + cache: true + environments: frontend + + - run: pixi run -e frontend typecheck + - run: pixi run -e frontend build + + package: + name: Conda package (rattler-build) + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-latest, macos-latest, windows-latest] + steps: + - uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - uses: prefix-dev/setup-pixi@v0.8.1 + with: + pixi-version: latest + cache: true + environments: build + + - name: Build + run: pixi run -e build build-pkg + + - uses: actions/upload-artifact@v4 + with: + name: quest-conda-${{ matrix.os }} + path: build/pkg/**/*.conda + if-no-files-found: error diff --git a/.github/workflows/quest-conda.yml b/.github/workflows/quest-conda.yml deleted file mode 100644 index abce6a6..0000000 --- a/.github/workflows/quest-conda.yml +++ /dev/null @@ -1,97 +0,0 @@ -name: QuEst Conda CI - -on: - workflow_dispatch: - push: - paths: - - "modules/quest/**" - - "modules/quest/.github/workflows/quest-conda.yml" - pull_request: - paths: - - "modules/quest/**" - - "modules/quest/.github/workflows/quest-conda.yml" - -jobs: - build-and-test: - name: Build & Test (py${{ matrix.python-version }}, ${{ matrix.os }}) - runs-on: ${{ matrix.os }} - strategy: - fail-fast: false - matrix: - os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.10"] - - env: - OUT_DIR: conda-bld - NUMBA_DISABLE_JIT: "1" - QT_QPA_PLATFORM: "offscreen" - - steps: - - name: Free Disk Space (Ubuntu) - if: startsWith(matrix.os, 'ubuntu') - uses: jlumbroso/free-disk-space@main - with: - tool-cache: false - android: true - dotnet: true - haskell: true - large-packages: true - docker-images: true - swap-storage: true - - - name: Checkout (with submodules) - uses: actions/checkout@v4 - with: - fetch-depth: 0 - submodules: recursive - - - name: Set up micromamba - uses: mamba-org/setup-micromamba@v2 - with: - environment-name: build - create-args: >- - python=${{ matrix.python-version }} - boa - conda-build - anaconda-client - pytest - cache-downloads: true - condarc: | - channels: - - conda-forge - channel_priority: strict - - - name: Build conda package (mambabuild) - shell: bash -l {0} - working-directory: modules/quest/conda-recipe - run: | - micromamba run -n build conda mambabuild . \ - --output-folder "${GITHUB_WORKSPACE}/${OUT_DIR}" - - - name: Index built packages - shell: bash -l {0} - run: | - micromamba run -n build conda index "${GITHUB_WORKSPACE}/${OUT_DIR}" - - - name: Create test env from local channel - shell: bash -l {0} - run: | - micromamba run -n build conda create -y -n test \ - -c "file://${GITHUB_WORKSPACE}/${OUT_DIR}" \ - -c conda-forge \ - python=${{ matrix.python-version }} \ - quest \ - pytest \ - click - - - name: Run tests - shell: bash -l {0} - working-directory: ${{ github.workspace }} - run: | - micromamba run -n test pytest modules/quest/tests - - - name: Upload built artifacts - uses: actions/upload-artifact@v4 - with: - name: quest-conda-${{ matrix.os }}-py${{ matrix.python-version }} - path: ${{ env.OUT_DIR }}/**/*.tar.bz2 diff --git a/.gitignore b/.gitignore index 96f17b1..7bf9b3a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,22 +1,151 @@ -build +# ========================================== +# Python build, distribution and packaging +# ========================================== +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +# Anchored to the repository root: an unanchored `lib/` also swallowed +# webui/frontend/src/lib/, whose sources went uncommitted for weeks. +/lib/ +/lib64/ +parts/ +sdist/ +var/ +wheels/ +share/python-wheels/ +*.egg-info/ +.installed.cfg +*.egg +MANIFEST + +# ========================================== +# Compiled binaries, shared libraries, Cython +# ========================================== +# Global ignores for dynamic libraries +*.so +*.dylib +*.dll +*.pyd +*.o +*.obj +*.a +*.lib + +# Cython generated C/C++ sources in quest package +quest/**/*.c +quest/**/*.cpp + +# Older specific compiled targets (kept for safety) +_*-darwin.so +_64-linux-gnu.so + +# ========================================== +# Caches, testing, and coverage +# ========================================== +__pycache__/ +*.pyc +*.pyo +.pytest_cache/ +.coverage +.coverage.* +htmlcov/ +.nosetests +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.mypy_cache/ +.dmypy.json +dmypy.json + +# ========================================== +# WebUI & Frontend (Node, Next.js) +# ========================================== +# Next.js build output +.next/ +out/ +*.tsbuildinfo + +# Node dependencies +node_modules/ + +# Local env files +.env +.env.local +.env.development.local +.env.test.local +.env.production.local + +# npm log files +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* + +# ========================================== +# Virtual environments +# ========================================== +.venv/ +venv/ +env/ +.env/ +ENV/ +env.bak/ +venv.bak/ + +# ========================================== +# IDEs, Editors, and OS-specific files +# ========================================== +.DS_Store +Thumbs.db +.vscode/ +.idea/ +*.suo +*.ntvs* +*.njsproj +*.sln +*.swp *.pro.user *.pro.user.* CMakeLists.txt.user CMakeLists.txt.user.* cmake-build-* -_*-darwin.so -_64-linux-gnu.so -__pycache__ - -quest/lib/fps/fps.cpp -quest/lib/math/functions/rdf.cpp -quest/lib/math/functions/small.cpp -quest/lib/math/functions/rdf.cpython-39-x86_64-linux-gnu.so -quest/lib/fps/fps.cpython-39-x86_64-linux-gnu.so -quest/lib/math/functions/small.cpython-39-x86_64-linux-gnu.so -quest/lib/math/linalg/vector.cpp -quest/lib/tools/dye_diffusion/photon.cpython-39-x86_64-linux-gnu.so -quest/lib/tools/dye_diffusion/photon.cpp -quest/lib/structure/cStructure.cpython-39-x86_64-linux-gnu.so -quest/lib/structure/cStructure.cpp -quest/lib/math/linalg/vector.cpython-39-x86_64-linux-gnu.so + +# ========================================== +# Jupyter Notebooks +# ========================================== +.ipynb_checkpoints/ + +# ========================================== +# Project-specific ignores +# ========================================== +.kilocode/ +.omx/ +.webui-data/ +.antigravity/ +.antigravitycli/ + +# Simulation output. `simulate_project` writes `jobs//` under the current +# working directory whenever `save_outputs` is true, so anything run from the +# repo root leaves a directory behind. Tests should pass `save_outputs=False` +# or a temporary `project_dir` rather than rely on this. +jobs/ + +# Scratch left behind by manual runs and by the molecule viewer. +/out.xyz +/out_slow.xyz +/test.pdb +/test.cif +/webui-viewer-testpdb.png +tests/sim_test.log + + +# ========================================== +# Pixi +# ========================================== +# Environments are reproducible from pixi.toml + pixi.lock, both of which are +# committed. The materialised environment is not. +.pixi/ diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..5300550 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,196 @@ +# AGENTS.md + +This file provides guidance to AI coding agents working in this repository. + +QuEst (QUenching ESTimation) predicts the fluorescence decay of a dye tethered +to a protein by a flexible linker, from the structure alone — PET quenching by +nearby amino acids, plus optional FRET. + +## Both surfaces must stay in sync + +QuEst has **two user-facing surfaces**: the **PyQt desktop GUI** (`quest/gui/`) +and the **Web UI** (`webui/`). Every feature must work on both. A change that +only reaches one surface is a bug. When adding or changing a feature: + +1. **Identify both surfaces.** Search for the feature in both `quest/gui/` and + `webui/frontend/src/`. If it exists in one, it must exist in the other. +2. **Implement on both.** Do not defer the second surface to a later commit. +3. **Test on both.** The PyQt tests (`tests/test_pyqt_*.py`) and the browser + e2e (`tests/test_webui_e2e.py`) must both pass. +4. **The sequence viewer, 3D structure viewer, and AA selection** are the most + common divergence points. Click-to-select a residue in the 3D viewer, the + sequence bar, or the autoform dropdowns must update the same model state on + both surfaces. + +## Read the OKF bundle first — it is this project's memory + +`okf/` is an **Open Knowledge Format v0.2** bundle: plain-markdown concepts with +YAML frontmatter, grouped as `architecture/`, `subsystems/`, `specs/`, +`workflows/` and `references/` under a root `okf/index.md`, plus an append-only +`okf/log.md`. It is the durable, agent-readable knowledge layer that sits beside +the code, and it is where what has been learned about this repository lives. + +**Start at [`okf/index.md`](okf/index.md)**, and read the concept that owns the +area you are about to touch, before reading the source. On a conflict between a +code comment and an OKF concept, OKF wins — it is newer. + +Since 2026-08-06 every concept carries `status`, `generated`, `stale_after` and +`sources`. Three rules follow, and they are not optional: + +- **`stale_after` is a promise to re-read.** When it has passed, the concept is + not wrong — it is unreviewed. Re-read it against the code, then re-date or fix. +- **`verified` is earned.** Add it only when a human or a named process actually + checked the concept; the trust tier is derived from it mechanically. +- **Validate before finishing:** + `python3 okf/references/tools/okf_validate.py okf --version 0.2 + --check-paths "quest/,webui/,tests/,doc/"` — the second flag catches the + bundle drifting behind a refactor, which is exactly what happened to + `quest/lib/` ([`okf/references/known-issues.md`](okf/references/known-issues.md)). + +Format and shared conventions: [`okf/references/okf-format.md`](okf/references/okf-format.md), +and FPSIMP's [`okf/references/okf-conventions.md`](../fpsimp/okf/references/okf-conventions.md), +which is the canonical copy of the rule set the two share. +The rules are shared with the sibling project **FPSIMP** (`../fpsimp`), whose +agent entry point is [`../fpsimp/AGENTS.md`](../fpsimp/AGENTS.md) — same file, +same role. Every repository in this family uses `AGENTS.md` and no per-tool +instruction file; FPSIMP finished that rename on 2026-08-11. It runs the same +taxonomy and the same validator (vendored into each repository, FPSIMP's copy +canonical, `diff` the sync check) — the two are heading for one server, so keep +them shaped alike. + +Fast paths: + +- What actually runs during a simulation → [`okf/architecture/simulation-pipeline.md`](okf/architecture/simulation-pipeline.md) +- Where the architecture is heading, and the gap backlog → [`okf/specs/plugin-integration.md`](okf/specs/plugin-integration.md), [`okf/specs/assessment.md`](okf/specs/assessment.md) +- The project-JSON contract every surface shares → [`okf/architecture/project-schema.md`](okf/architecture/project-schema.md) +- The physics and its approximations → [`okf/references/pet-quenching-theory.md`](okf/references/pet-quenching-theory.md) +- Why something is broken → [`okf/references/known-issues.md`](okf/references/known-issues.md) +- What changed recently and why → [`okf/log.md`](okf/log.md) + +## Working practices + +- **Track everything in OKF — no exceptions.** Every change, finding, decision + and dead end goes into the owning concept *and* `okf/log.md`, in the same + change that makes it. That includes packaging, CI, environments and + documentation, not just code: if it is not in OKF it did not happen, because + the next session starts from OKF and nothing else. +- **Keep OKF up to date — always, not at the end.** `okf/` is only worth reading + if it matches the tree, so it is updated *in the same change* as the code, not + in a later cleanup pass. That includes correcting entries that turn out to be + wrong: a confident but stale concept is worse than a missing one. +- **Use the `arm64` conda environment — it is the only one.** + `/Users/tpeulen/mambaforge/envs/arm64/bin/python` runs everything: Python + 3.12, numpy 2.4.6, PyQt5, LabelLib, a **compiled `IMP.bff`**, and (since + 2026-07-28) fastapi, uvicorn and playwright. The mambaforge base interpreter + is **retired**; the two-environment split and the `-p no:pytest-qt` flag that + went with it are gone. See + [`okf/workflows/environment.md`](okf/workflows/environment.md). +- **Write to memory as you go.** Every material change updates the OKF concept + that owns the behaviour **and** appends a dated bullet to `okf/log.md`, in the + same change. Anything you *learn* that was not obvious from the code — a + missing dependency, a default chosen by measurement, a kernel that must stay + sequential, a physical assumption — goes into the owning concept, or into + `okf/references/known-issues.md` if it is a defect you cannot fix now. Never + leave a finding only in the chat. Full loop: + [`okf/workflows/change-tracking.md`](okf/workflows/change-tracking.md). +- **Docs are part of the change.** `okf/` is for agents; `doc/` and `README.md` + are for people. Parameter help text is edited in + `quest/settings/parameter_catalog.json` (translations in + `quest/settings/locales/*.json`) and regenerated with **both** + `python doc/generate_parameter_docs.py` and + `python -m quest.gui.generate_view_spec` — the second writes the Qt form's + view spec from the same catalog. Never hand-edit `doc/parameters*.md` or + `quest/gui/quest.view*.json`. Locale files are cached per process, so restart + uvicorn after editing one. +- **Test all three surfaces, every time — library, web UI, and Qt GUI.** They + have diverged before (the GUI shipped different quenching chemistry than the + CLI for as long as nobody looked), so a green unit suite is not verification. + One command covers library, GUI and backend: + `QT_QPA_PLATFORM=offscreen /bin/python -m pytest tests/ webui/backend/tests -q --ignore=tests/test_webui_e2e.py` + — **do not pass `-p no:pytest-qt`**, it now removes the `qtbot` fixture. Start + the backend and frontend so `test_webui_e2e.py` runs instead of skipping. + **Render the GUI and the charts and look at the images yourself** — a missing + control or an acceptor defaulting to a water molecule is invisible to + assertions. uvicorn does not reload: restart it before re-running the browser + suite. Baseline 2026-07-28: **404 passed, 1 skipped**, plus 16 for + `-m notebooks`. See [`okf/workflows/testing.md`](okf/workflows/testing.md). +- **A number-moving change is verified against `tests/baselines/`, not against a + green suite** — and every fix must be *seen to fail* before it is believed. + [`okf/specs/programme-2026-07.md`](okf/specs/programme-2026-07.md), decision 13. +- **General fluorescence machinery belongs under `IMP.bff`.** QuEst is the + application — project schema, PET workflow, surfaces, scanning. Accessible + volumes, dye distributions and FRET distance/rate math are general; before + writing any of that here, check whether `IMP.bff` already has it (it usually + does) and prefer depending on it to adding a second copy. Direction and + migration map: [`okf/specs/imp-tricks-dedup.md`](okf/specs/imp-tricks-dedup.md). + Note `IMP.bff` no longer lives in imp-tricks: it was handed to `../imp.bff` on + 2026-08-10, so the shim's `~/dev/imp-tricks` path names a checkout that no + longer carries it. + **Scoped by the dependency policy** (owner, 2026-08-11, canonical copy in + [`../fpsimp/okf/references/dependency-policy.md`](../fpsimp/okf/references/dependency-policy.md)): + a *simple* method reachable only through a *complex* package gets transcribed + here and A/B'd against the reference, not depended on. That question is asked + when a dependency would be **added** — QuEst already depends on `IMP.bff` for + `compute_av`, which is real machinery, so the smaller kernels adopted beside + it are not up for re-litigation. It binds when something new would pull in a + new package. +- **Keep the optional dependencies optional.** Qt, LabelLib and IMP are all + imported behind `try`/`except` with fallbacks. That is what lets the CLI, the + API and the web backend run in this environment, which has no Qt bindings and + no `IMP.bff`. Do not make any of those imports unconditional. +- **Logic goes in the service layer, not in a surface.** The CLI, the web + backend, the GUI and notebooks are thin wrappers over `quest/core.py` (exposed + as `quest.api`). A feature that exists only in the web UI is a design error. + See [`okf/architecture/surfaces.md`](okf/architecture/surfaces.md). The target + is the ChiSurf plugin split — core / rpc / api / cli / gui, one method + registry behind every surface — so prefer changes that move the tree toward + [`okf/specs/plugin-integration.md`](okf/specs/plugin-integration.md) and close + a row in [`okf/specs/assessment.md`](okf/specs/assessment.md). +- **Do not leave run artefacts in the tree.** `simulate_project` writes + `jobs//` under the current directory; pass `save_outputs=False` or a + temp `project_dir` for tests and bulk work. +- **Change policy.** QuEst is **unreleased** — nothing depends on a published + build, so prefer the clean change over the compatible one: rename freely, + delete unused shims, reshape file formats. This does *not* extend to silently + changing what the science computes, to breaking ChiSurf without recording it, + or to skipping OKF. Full rule: + [`okf/references/release-state.md`](okf/references/release-state.md). +- **Commit in between, not at the end.** As soon as a coherent piece is made + *and verified* — suite green, `okf_validate.py` clean — commit it, then start + the next. Do not batch a session's work into a final commit: an uncommitted + stretch cannot be reverted selectively, is invisible to anyone else reading + the tree, and yields messages that describe *what* was done because the *why* + has already faded. The concept update and the `okf/log.md` bullet ride in that + same commit. If a piece cannot be committed because it shares a file with + other in-flight work, say so when you reach it, not in a closing summary. + Same rule in FPSIMP ([`okf/references/okf-format.md`](okf/references/okf-format.md)). +- **Git.** Commit locally; do not push. No commit trailers of any kind — no + `Co-Authored-By`, no tool attribution. The working tree carries other + in-flight work: never `git add -A` / `git commit -a`, and never run + destructive git (`reset --hard`, `restore`, `clean -f`, `stash`, `--force`) + that could discard changes you did not make. + +## Environment and packaging + +**pixi drives everything**, Python included: + +| environment | holds | tasks | +|---|---|---| +| `default` | library, CLI, web backend | `test`, `test-web`, `serve` | +| `desktop` | the above plus Qt | `gui`, `test-gui` | +| `frontend` | the Node toolchain | `dev`, `build`, `typecheck` | +| `build` | rattler-build only | `build-pkg` | + +The conda package is built by **rattler-build** from +`rattler-recipe/recipe.yaml`; the old `conda-recipe/meta.yaml` and its +`conda mambabuild` workflow are gone. CI (`.github/workflows/ci.yml`) runs the +library, backend, GUI, frontend and packaging jobs from those same pixi tasks. + +For day-to-day work on this machine the `arm64` conda environment is still the +canonical interpreter (it has the compiled `IMP.bff`); see +[`okf/workflows/environment.md`](okf/workflows/environment.md). + +## Contact + +Author: Thomas-Otavio Peulen. Repository: +`github.com/Fluorescence-Tools/quest`. diff --git a/README.md b/README.md index 0ad7b90..e180248 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,8 @@ -[![Build Status](https://travis-ci.org/Fluorescence-Tools/quest.svg?branch=master)](https://travis-ci.org/Fluorescence-Tools/ques) +[![CI](https://github.com/Fluorescence-Tools/quest/actions/workflows/ci.yml/badge.svg)](https://github.com/Fluorescence-Tools/quest/actions/workflows/ci.yml) + +

+ QuEst Logo +

# QuEst - Quenching Estimator @@ -6,7 +10,7 @@ QUEST (QUenching ESTimation) simulates the dynamic quenching of xanthene dyes tethers to proteins by flexible linkers by simulating PET and the -diffusion of dyes. +diffusion of dyes (see [Peulen et al., 2017](https://doi.org/10.1021/acs.jpcb.7b03441)). The dynamic quenching of a fluorescent dye coupled to a protein is simulated in three steps: @@ -27,10 +31,34 @@ to calculate the dye's fluorescence decay. In QUEST the dyes are approximated by a sphere diffusing within their accessible volume (AV) (see [labellib](https://github.com/Fluorescence-Tools/LabelLib)). -PET-quenching of the dye by MET, HIS, TYR and TRP residues is -approximated by a step function where the dye is quenched with a -provided rate contestant if it is closer than a given threshold -distance. +### Amino-acid specific quenching + +PET-quenching is resolved per residue type. Each residue is described by four +quantities, editable per dye in the web UI (*Adv. Settings -> Amino-acid +specific quenching*) or under `amino_acid_interactions` in a project file: + +| Field | Meaning | +| --- | --- | +| `kQ` | Quenching rate (1/ns) applied while the dye is in contact. | +| `quench_radius` | Contact radius (Å), measured from the **dye centre** to the residue's quenching centre. `null` inherits the project-wide `critical_distance`. | +| `quench_atoms` | Atom names whose centroid defines the **quenching centre**. | +| `slow_factor` | Diffusion scaling (0–1) modelling unspecific stickiness near the residue. | + +The quenching centre sits on the residue's redox-active moiety rather than on +CB: the indole ring for TRP, the phenol ring for TYR, the imidazole ring for +HIS, SD for MET and SG for CYS. For tryptophan this moves the quencher ~3.3 Å +away from CB, which matters at contact distances of a few Ångström. + +Quenching rates from residues whose contact spheres overlap **add up**; +stickiness factors **multiply**. Every simulation reports how much each residue +type contributed to the total quenching rate (`quench_rate_fraction` in +`result.json` and `aa_residence.csv`, and the *Quenching by residue type* panel +in the web UI). + +The shipped dye presets start from reference PET parameters for a xanthene dye +(TRP > PRO ≈ TYR > MET > HIS > CYS), scaled to each dye's radius. These are +starting values intended to be calibrated against measured lifetimes, not fixed +constants. The relevant simulation parameters can be adjusted either in a graphical user interface `quest_gui` or QuEst can be controlled @@ -115,9 +143,15 @@ if result.fret_counts is not None: The API is designed so that it does not depend on any GUI widgets and can therefore be safely imported and used in headless environments. -Notebook examples: -- `modules/quest/notebooks/quest_core_headless_demo.ipynb` – minimal headless API usage. -- (Legacy) other notebooks for diffusion/quenching/FRET remain available in the same folder. +Notebook examples (each one is executed by `tests/test_notebooks.py`, so they +run rather than merely parse): +- [`notebooks/01_quenching.ipynb`](notebooks/01_quenching.ipynb) – PET quenching of a tethered donor. +- [`notebooks/02_fret.ipynb`](notebooks/02_fret.ipynb) – adding a FRET acceptor. +- [`notebooks/03_et_distance_distribution.ipynb`](notebooks/03_et_distance_distribution.ipynb) – donor–acceptor distance distributions. +- [`notebooks/04_diffusion_modulated_fret.ipynb`](notebooks/04_diffusion_modulated_fret.ipynb) – how dye diffusion changes the transfer. + +Scripted equivalents live in [`examples/`](examples/) and are run by +`tests/test_examples.py`. ### Command-QuEST (Click CLI) @@ -145,6 +179,65 @@ Notes: - Use `--grid key=val1,val2` to sweep multiple values; outputs are tagged per run. - Output format chosen by extension (.csv or .json). +## Webapp and Electron + +QuEst now includes a hostable web surface and a local Electron shell in `webui/`. + +### Hostable web app (FastAPI + Next.js) + +The frontend needs **Node.js 20.9 or newer** (Next.js 16). The repository ships +a [pixi](https://pixi.sh) manifest that provides a pinned Node toolchain in its +own `frontend` environment, so you do not need Node installed system-wide: + +```bash +python -m pip install -e ".[web]" +python -m uvicorn webui.backend.app.main:app --host 127.0.0.1 --port 8000 +# new terminal +pixi run -e frontend dev +``` + +`pixi.toml` and `pixi.lock` are committed, so `pixi install -e frontend` +reproduces the exact toolchain. Available tasks: + +| Task | Does | +| --- | --- | +| `pixi run -e frontend install` | `npm install` in `webui/frontend` | +| `pixi run -e frontend dev` | Next.js dev server on :3000 | +| `pixi run -e frontend build` | Production build (+ standalone assets) | +| `pixi run -e frontend start` | Serve the production build | +| `pixi run -e frontend typecheck` | `tsc --noEmit` | +| `pixi run -e frontend node` | Print the environment's Node version | + +If you prefer your own Node, the plain npm workflow still works — check +`node -v` first, since an older Node fails at startup with a version error: + +```bash +npm --prefix webui/frontend install +npm --prefix webui/frontend run dev +``` + +For production-style frontend: + +```bash +pixi run -e frontend build +pixi run -e frontend start +``` + +Use `QUEST_BACKEND_URL` to point frontend runtime to a hosted backend target. + +### Electron app (local desktop shell) + +```bash +npm --prefix webui/desktop install +npm --prefix webui/desktop run start +``` + +Optional Python override: + +```bash +QUEST_PYTHON=/path/to/python npm --prefix webui/desktop run start +``` + ## Warnings 1. QuEST determines precise values that are not necessary accurate. 2. QuEST was the first software to implement the ACVs. ACVs were later described in more detail (see: [COSB2016](https://doi.org/10.1016/j.sbi.2016.11.012). Differencies in the ACV implementation, may produce slightly different results. @@ -155,13 +248,13 @@ Notes: ## Citation If you have used QuEST in a scientific publication, we would appreciate citations to the following paper: -[![DOI for citing QuEST](https://img.shields.io/badge/https://doi.org/10.1021/acs.jpcb.7b03441-blue.svg)](https://pubs.acs.org/doi/abs/10.1021/acs.jpcb.7b03441) +[![DOI](https://img.shields.io/badge/DOI-10.1021%2Facs.jpcb.7b03441-blue.svg)](https://doi.org/10.1021/acs.jpcb.7b03441) > Peulen, T.O., Opanasyuk, O., and Seidel, C.A., 2017. Combining Graphical and Analytical Methods with Molecular Simulations To Analyze Time-Resolved FRET Measurements of Labeled Macromolecules Accurately. The Journal of Physical Chemistry B 2017, 121, 35, 8211-8241 (Feature Article) For more informations on accessible contact volumes (ACVs) see: -[![DOI for citing LabelLib](https://img.shields.io/badge/DOI-10.1016%2Fj.sbi.2016.11.012-blue.svg)](https://doi.org/10.1016/j.sbi.2016.11.012) +[![DOI](https://img.shields.io/badge/DOI-10.1016%2Fj.sbi.2016.11.012-blue.svg)](https://doi.org/10.1016/j.sbi.2016.11.012) > Dimura, M., Peulen, T.O., Hanke, C.A., Prakash, A., Gohlke, H. and Seidel, C.A., 2016. Quantitative FRET studies and integrative modeling unravel the structure and dynamics of biomolecular systems. Current opinion in structural biology, 40, pp.163-185. diff --git a/conda-recipe/bld.bat b/conda-recipe/bld.bat deleted file mode 100644 index e3e48e0..0000000 --- a/conda-recipe/bld.bat +++ /dev/null @@ -1 +0,0 @@ -"%PYTHON%" -m pip install . --no-deps -vv diff --git a/conda-recipe/build.sh b/conda-recipe/build.sh deleted file mode 100644 index 88fde13..0000000 --- a/conda-recipe/build.sh +++ /dev/null @@ -1,3 +0,0 @@ -#!/usr/bin/env bash -# Build/install via PEP 517 (pyproject.toml) -$PYTHON -m pip install . --no-deps -vv \ No newline at end of file diff --git a/conda-recipe/meta.yaml b/conda-recipe/meta.yaml deleted file mode 100644 index ad556d8..0000000 --- a/conda-recipe/meta.yaml +++ /dev/null @@ -1,53 +0,0 @@ -{% set name = "quest" %} -{% set version = "latest" %} - -package: - name: {{ name|lower }} - version: {{ version|lower }} - # version: {{ GIT_DESCRIBE_TAG }} - -source: - git_url: .. - -build: - number: {{ GIT_DESCRIBE_NUMBER|int }} - string: np{{ CONDA_NPY }}py{{ CONDA_PY }}_{{ GIT_BUILD_STR }} - entry_points: - - quest=quest.quest_gui:start_gui - -requirements: - host: - - python {{ python }} - - setuptools - - numpy - - numexpr - - click - run: - - python {{ python }} - - numpy - - numexpr - - click - - pyopengl - - labellib - - pyyaml - - pyqt - - pyqtgraph - - pytables - - numba - - qtpy <2.0.0 - - libstdcxx-ng # [linux] - -about: - home: https://github.com/Fluorescence-Tools/quest - license: MIT - license_file: LICENSE - summary: QuEst is a protein structure based fluorescence quenching estimator - description: - QuEst is a structure based fluorescence quenching estimator that simulates dynamic - quenching of fluorescence decays of dyes that are coupled to the surface of a proteins. - Dynamic fluorescence quenching is simulated by modelling (i) the diffusion of the dye - and (ii) the quenching of the dye by surface exposed aromatic amino-acids. - -extra: - recipe-maintainers: - - tpeulen diff --git a/doc/cli.md b/doc/cli.md index 5fe64c5..84c472a 100644 --- a/doc/cli.md +++ b/doc/cli.md @@ -5,7 +5,7 @@ The Click-based `quest` command exposes validation, simulation, and template gen ## Common options - `-p, --project PATH`: project JSON file. -- `--pdb PATH`: override PDB path without editing the project file. +- `--pdb PATH_OR_ID`: override structure path or load a bare four-character PDB ID from RCSB without editing the project file. - `--set key=value`: override a project field (dotted paths supported). - `--grid key=v1,v2,...`: sweep multiple values (Cartesian product across grids). - `-o, --output PATH`: output file; extension selects format (`.csv` or `.json`). @@ -27,6 +27,12 @@ Simulate with overrides and CSV output: quest simulate -p project.quest.json --set tau0=3.8 --set attachment.residue=42 -o decay.csv ``` +Simulate directly from an RCSB PDB ID: + +```bash +quest simulate -p project.quest.json --pdb 148l -o decay.csv +``` + Sweep residues and linker lengths (tagged outputs): ```bash @@ -69,6 +75,6 @@ Starts the GUI if the Qt dependencies are installed. ## Troubleshooting -- Provide a valid `pdb` path or pass `--pdb`. +- Provide a valid `pdb` path/PDB ID or pass `--pdb`. - Ensure donor dye has `D`; otherwise validation fails. - For FRET runs, include two dyes and `fret.enabled: true`. diff --git a/doc/generate_parameter_docs.py b/doc/generate_parameter_docs.py new file mode 100644 index 0000000..bf5ccc2 --- /dev/null +++ b/doc/generate_parameter_docs.py @@ -0,0 +1,146 @@ +"""Generate the parameter reference Markdown from the central JSON catalog. + +One page per language: `doc/parameters.md` (English) and +`doc/parameters..md` for every locale in `quest/settings/locales/`. Run + + python doc/generate_parameter_docs.py + +after editing `quest/settings/parameter_catalog.json` or any locale file. Never +hand-edit the output. +""" + +import json +import sys +from collections import defaultdict +from pathlib import Path + +DOCS_DIR = Path(__file__).resolve().parent +REPO_ROOT = DOCS_DIR.parent +CATALOG_PATH = REPO_ROOT / "quest" / "settings" / "parameter_catalog.json" +OUTPUT_PATH = DOCS_DIR / "parameters.md" + +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + +from quest.i18n import ( # noqa: E402 + DEFAULT_LOCALE, + available_locales, + translate_catalog, + ui_strings, +) + + +def output_path(locale: str = DEFAULT_LOCALE) -> Path: + """English keeps the unsuffixed filename; every other language is suffixed.""" + if locale == DEFAULT_LOCALE: + return OUTPUT_PATH + return DOCS_DIR / f"parameters.{locale}.md" + + +def generate(locale: str = DEFAULT_LOCALE) -> Path: + catalog = translate_catalog(locale) + parameters = catalog["parameters"] + strings = ui_strings(locale) + output = output_path(locale) + # A comma-joined list, not "a and b": the conjunction would be English in + # every language, and the one thing this file must not do is leak English. + source_files = ["`parameter_catalog.json`"] + if locale != DEFAULT_LOCALE: + source_files.append(f"`quest/settings/locales/{locale}.json`") + sources = ", ".join(source_files) + + grouped = defaultdict(list) + for parameter_id, meta in sorted(parameters.items()): + grouped[meta.get("category", "Other")].append((parameter_id, meta)) + + lines = [ + f"# {strings['doc.title']}", + "", + strings["doc.generated"].format(sources=sources), + "", + f"## {strings['doc.summary']}", + "", + "| {key} | {category} | {type} | {unit} | {description} |".format( + key=strings["doc.col.key"], + category=strings["doc.col.category"], + type=strings["doc.col.type"], + unit=strings["doc.col.unit"], + description=strings["doc.col.description"], + ), + "| --- | --- | --- | --- | --- |", + ] + + for parameter_id, meta in sorted(parameters.items()): + unit = meta.get("unit", "-") + desc = meta.get("description", "") + category = meta.get("category_label", meta.get("category", "")) + lines.append( + f"| `{parameter_id}` | {category} | {meta.get('type', '')} | {unit} | {desc} |" + ) + + lines.append("") + + # Detailed descriptions by category + category_order = ["Structure", "Labeling site", "Accessible volume", "Simulation", "Quenchers", "Advanced", "FRET Acceptor"] + # Add any categories that might not be in the list + for cat in sorted(grouped.keys()): + if cat not in category_order: + category_order.append(cat) + + for category in category_order: + if category not in grouped: + continue + # `category_label` is set by translate_catalog; the English key stays so + # ordering and grouping do not depend on the language. + heading = grouped[category][0][1].get("category_label", category) + lines.extend([f"## {heading}", ""]) + for parameter_id, meta in grouped[category]: + label = meta.get("label", parameter_id) + lines.extend([ + f"### `{parameter_id}`", + "", + f"**{strings['doc.label']}:** {label} ", + f"**{strings['doc.type']}:** `{meta.get('type', 'unspecified')}`", + ]) + if "unit" in meta: + lines.append(f"**{strings['doc.unit']}:** `{meta['unit']}`") + lines.extend([ + "", + meta.get("description", ""), + "" + ]) + + # Append static documentation sections + lines.extend([ + "## CLI override examples", + "", + "- Set donor lifetime and attachment residue:", + " ```bash", + " quest simulate -p project.quest.json --set tau0=3.8 --set attachment.residue=55", + " ```", + "- Sweep linker length and residue:", + " ```bash", + " quest simulate -p project.quest.json \\", + " --grid av_parameter.linker_length=10.0,12.5 \\", + " --grid attachment.residue=25,30,35", + " ```", + "", + "## Validation tips", + "", + "- Ensure donor dye has `D` set; otherwise the API raises a `KeyError`.", + "- Provide a valid `pdb` path (or pass `--pdb`/`pdb_path`).", + "- When enabling FRET, include two dyes and an `R0_matrix` entry for donor→acceptor.", + "" + ]) + + output.write_text("\n".join(lines).rstrip() + "\n") + return output + + +def generate_all() -> list[Path]: + return [generate(code) for code in sorted(available_locales())] + + +if __name__ == "__main__": + for written in generate_all(): + print(f"Generated {written}") diff --git a/doc/index.md b/doc/index.md index c84cd86..1e1baed 100644 --- a/doc/index.md +++ b/doc/index.md @@ -70,7 +70,7 @@ Project files are JSON. Key blocks: - `quencher`: mapping of residue name to atom list and `kQ` per quencher. - `fret` (optional): `enabled`, `dyes` (donor first, acceptor second), `R0_matrix`. - `av_parameter`: `{linker_length, linker_width, radius1}`. -- `pdb`: path to the structure file. +- `pdb`: path to the structure file, or a bare four-character RCSB PDB ID such as `148l`. The CLI accepts dotted overrides (e.g., `--set attachment.residue=42`). @@ -115,7 +115,8 @@ Use this when simulating PET quenching with Brownian dynamics: - Quenchers: list of amino-acid names (3-letter codes) and atoms; atoms in the exclude list are ignored. - `quench_radius`: distance threshold for quenching. - `kQ`: quenching rate constant. - - `slow_fact`: scaling factor for diffusion near sticks; `critical_distance`/`slow_radius` define where it applies. + - `stickiness_mode`: defaults to amino-acid-specific slowing, with ASP/GLU using the configured `amino_acid_slow_facts`. + - `slow_fact`: global scaling factor for diffusion near sticks; `critical_distance`/`slow_radius` define where it applies. 4. **Simulation controls** - Time: `sim_time`, timestep `dt`. - Photons/frames: `n_photons`, `frames`. diff --git a/doc/logo.png b/doc/logo.png new file mode 100644 index 0000000..e8049f4 Binary files /dev/null and b/doc/logo.png differ diff --git a/doc/parameters.de.md b/doc/parameters.de.md new file mode 100644 index 0000000..04fa964 --- /dev/null +++ b/doc/parameters.de.md @@ -0,0 +1,379 @@ +# QuEst-Parameterreferenz + +Diese Seite wird aus `parameter_catalog.json`, `quest/settings/locales/de.json` erzeugt. Ändern Sie zuerst dort den Hilfetext eines Parameters — Weboberfläche, diese Seite und das Desktop-Formular lesen dieselben Dateien. + +## Übersicht des Katalogs + +| Schlüssel | Kategorie | Typ | Einheit | Beschreibung | +| --- | --- | --- | --- | --- | +| `amino_acid_interactions` | Löschung | table | - | Tabelle der Wechselwirkungen je Resttyp. Jeder Eintrag enthält slow_factor (0–1, wie stark der Rest den diffundierenden Farbstoff verlangsamt), kQ (Löschrate in 1/ns bei Kontakt), quench_radius (Kontaktradius in Ångström vom Farbstoffmittelpunkt; null übernimmt critical_distance) und quench_atoms (Atomnamen, deren Schwerpunkt das Löschzentrum bildet). Standardmäßig löschen nur Reste mit redoxaktiver Seitenkette: TRP, TYR, MET, HIS, CYS und PRO. | +| `amino_acid_interactions.kQ` | Löschung | number | 1/ns | Rate, mit der dieser Resttyp den Farbstoff bei Kontakt löscht. Beiträge von Resten mit überlappenden Kontaktsphären addieren sich. | +| `amino_acid_interactions.quench_atoms` | Löschung | list | - | Atomnamen, deren Schwerpunkt das Löschzentrum dieses Rests bildet. Die Voreinstellungen folgen der redoxaktiven Gruppe, die den photoinduzierten Elektronentransfer vermittelt: der Indolring bei TRP, der Phenolring bei TYR, der Imidazolring bei HIS, SD bei MET und SG bei CYS – nicht CB. | +| `amino_acid_interactions.quench_radius` | Löschung | number | Å | Abstand vom Farbstoffmittelpunkt zum Löschzentrum dieses Rests, innerhalb dessen Löschung stattfindet. Leer lassen, um die projektweite critical_distance zu übernehmen. | +| `amino_acid_interactions.slow_factor` | Löschung | number | - | Faktor zwischen 0 und 1, der den Diffusionskoeffizienten des Farbstoffs in der Nähe dieses Resttyps skaliert und unspezifische Haftung beschreibt. Überlappende Reste multiplizieren ihre Faktoren. | +| `attachment.atom` | Markierungsstelle | text | - | Atomname (z. B. CB, CA), der als Anbindungspunkt des Farbstoffs dient. | +| `attachment.chain` | Markierungsstelle | text | - | Kettenbezeichner der Aminosäure, an die der Farbstoff gebunden ist. | +| `attachment.residue` | Markierungsstelle | integer | - | Sequenznummer der Aminosäure, an die der Farbstoff gebunden ist. | +| `av_parameter.linker_length` | Zugängliches Volumen | number | Å | Maximaler Abstand vom Anbindungspunkt zum Mittelpunkt des Farbstoffs. | +| `av_parameter.linker_width` | Zugängliches Volumen | number | Å | Breite des Linkers, der den Farbstoff hält. | +| `av_parameter.radius1` | Zugängliches Volumen | number | Å | Ausschlussradius, der den Farbstoff als Kugel beschreibt (Ein-Kugel-Näherung). | +| `coarse_grained` | Simulation | boolean | - | Reduziert die Struktur vor der Simulation auf das Rückgrat samt CB, wobei CB in den Schwerpunkt der Seitenkette verschoben wird. Seitenkettenatome fehlen dann, sodass das Löschzentrum jedes Rests auf dieses CB-Pseudoatom zurückfällt und das zugängliche Volumen wächst, weil die Seitenketten es nicht mehr versperren. Das ist eine Modellierungsentscheidung, keine Beschleunigung: Der Aufwand von QuEst wird vom AV-Gitter bestimmt, nicht von der Atomzahl. | +| `critical_distance` | Löschung | number | Å | Kontaktradius für Resttypen, die keinen eigenen quench_radius festlegen. Er wird vom Farbstoffmittelpunkt bis zum Löschzentrum des Rests gemessen und muss daher größer sein als der Farbstoffradius zuzüglich des Van-der-Waals-Kontakts (typischerweise 7–9 Å bei einem Farbstoff von 3,5 Å). | +| `dg` | Zugängliches Volumen | number | Å | Gitterauflösung für die Berechnung des zugänglichen Volumens (AV) und des Diffusionsraums. | +| `fret.R0_matrix` | FRET-Akzeptor | number | Å | Förster-Radius R0 des Donor-Akzeptor-Paares, in Ångström wie jede andere Länge im Projekt. Gespeichert wird die Zelle Donor→Akzeptor von fret.R0_matrix; die Transferrate skaliert mit (R0/r)^6, sodass eine Eingabe in Nanometern FRET verschwinden lässt. Typische Xanthen-Paare liegen bei 45–65 Å. | +| `fret.acceptor_dynamics` | FRET-Akzeptor | choice | - | Wie der Akzeptor behandelt wird: „trajectory“ simuliert seine Brownsche Bewegung mit eigenem Diffusionskoeffizienten und eigener Haftung und verwendet den momentanen Donor-Akzeptor-Abstand, „averaged“ mittelt über sein statisches zugängliches Volumen (Grenzfall des schnellen Akzeptors, nur gültig, wenn er dieses Volumen schnell im Vergleich zur Donorlebensdauer durchläuft). Beide unterscheiden sich, weil eine Punktwolke gleichmäßig gewichtet wird, eine Trajektorie hingegen danach, wo sich der Farbstoff tatsächlich aufhält. | +| `fret.dyes.0.D` | Simulation | number | Ų/ns | Diffusionskoeffizient des Donorfarbstoffs in Lösung, ohne Wechselwirkung mit der Proteinoberfläche. | +| `fret.dyes.1.D` | FRET-Akzeptor | number | Ų/ns | Diffusionskoeffizient des FRET-Akzeptorfarbstoffs ohne Wechselwirkung mit der Proteinoberfläche. | +| `fret.dyes.1.amino_acid_interactions` | FRET-Akzeptor | table | - | Tabelle der Wechselwirkungen je Resttyp für den Akzeptor, gleiche Form wie amino_acid_interactions des Donors. Verwendet wird nur slow_factor, denn QuEst berichtet das Abklingen des Donors; die eigene PET-Löschung des Akzeptors würde dessen Helligkeit ändern, nicht die des Donors. Voreinstellung ist die Tabelle des Donors. | +| `fret.dyes.1.attachment.atom` | FRET-Akzeptor | text | - | Atomname, an dem der FRET-Akzeptorfarbstoff gebunden ist. | +| `fret.dyes.1.attachment.chain` | FRET-Akzeptor | text | - | Kettenbezeichner des Rests, an den der FRET-Akzeptorfarbstoff gebunden ist. | +| `fret.dyes.1.attachment.residue` | FRET-Akzeptor | integer | - | Sequenznummer des Rests, an den der FRET-Akzeptorfarbstoff gebunden ist. | +| `fret.dyes.1.av_parameter.linker_length` | FRET-Akzeptor | number | Å | Maximaler Abstand vom Anbindungspunkt zum Mittelpunkt des FRET-Akzeptorfarbstoffs. | +| `fret.dyes.1.av_parameter.linker_width` | FRET-Akzeptor | number | Å | Breite des Linkers, der den FRET-Akzeptorfarbstoff hält. | +| `fret.dyes.1.av_parameter.radius1` | FRET-Akzeptor | number | Å | Ausschlussradius, der den FRET-Akzeptorfarbstoff als Kugel beschreibt. | +| `fret.dyes.1.slow_radius` | FRET-Akzeptor | number | Å | Radius um jedes Aminosäurezentrum, innerhalb dessen dieser Rest den Akzeptor verlangsamt. Getrennt vom Donor: Ein Cyanin und ein Rhodamin haften nicht in gleicher Weise an einer Proteinoberfläche. Voreinstellung ist der Wert des Donors. | +| `fret.enabled` | FRET-Akzeptor | boolean | - | Legt fest, ob ein FRET-Akzeptorfarbstoff simuliert wird, um FRET-Effizienz und Abklingkurven zu berechnen. | +| `fret.kappa2` | FRET-Akzeptor | number | - | Orientierungsfaktor κ² des Transfers, zwischen 0 (senkrecht zueinander stehende Übergangsdipole) und 4 (kollinear). QuEst modelliert ihn nicht: der Farbstoff ist ein Punkt, der in einem Volumen diffundiert, und besitzt keinen Dipol, der sich ausrichten könnte — dieser Wert ist also die Mittelungsannahme, die Sie treffen. Der Standardwert 2/3 ist das isotrope dynamische Mittel, das ein publizierter Förster-Radius bereits voraussetzt; ihn stehen zu lassen reproduziert die Rate exakt. Erhöhen Sie ihn nur, wenn belegt ist, dass beide Farbstoffe in ihrer Orientierung eingeschränkt sind. | +| `n_bins` | Simulation | integer | - | Anzahl der Zeitkanäle des ausgegebenen Abklinghistogramms. | +| `n_photons` | Simulation | integer | - | Anzahl der simulierten Anregungsphotonen zur Rekonstruktion des Fluoreszenzabklingens. | +| `output_file` | Erweitert | text | - | Namenspräfix für gespeicherte Simulationsergebnisse, Trajektorien und Abklingkurven. | +| `parallel_trajectories` | Erweitert | integer | - | Anzahl unabhängiger Brownscher Trajektorien, die gleichzeitig gerechnet und vor der Photonensimulation zusammengeführt werden. −1 nutzt alle CPU-Kerne, höchstens jedoch 8. | +| `pdb` | Struktur | file | - | Pfad zur Strukturdatei (PDB/CIF) oder eine vierstellige RCSB-PDB-Kennung; wird für die AV-Berechnung verwendet. | +| `random_seed` | Erweitert | integer | - | Startwert der Monte-Carlo-Simulation. Ist er gesetzt, werden sowohl die Diffusionstrajektorie als auch die Photonenspur initialisiert, sodass wiederholte Läufe desselben Projekts genau dasselbe Abklingen und dieselbe Quantenausbeute liefern. Ohne Startwert läuft die Simulation unabhängig zufällig; die Photonenspur nutzt dann einen schnelleren, mehrfädigen Kern. | +| `save_avs` | Erweitert | boolean | - | Legt fest, ob die berechneten Gitter des zugänglichen Volumens als XYZ-Dateien gespeichert werden. | +| `skip_frame` | Erweitert | integer | - | Unterabtastungsfaktor beim Schreiben von Trajektorienbildern in Koordinatendateien. | +| `slow_radius` | Erweitert | number | Å | Radius um jedes Aminosäurezentrum des gesamten Proteins, innerhalb dessen dieser Resttyp seinen slow_factor zum Gitter der Diffusionskoeffizienten beiträgt. | +| `t_max` | Simulation | number | ns | Gesamtlänge der simulierten Brownschen Trajektorie. | +| `t_step` | Simulation | number | ns | Schrittweite für die Berechnung der Brownschen Trajektorie. | +| `tau0` | Simulation | number | ns | Fluoreszenzlebensdauer des Donorfarbstoffs ohne Löschung. | + +## Struktur + +### `pdb` + +**Bezeichnung:** Strukturdatei +**Typ:** `file` + +Pfad zur Strukturdatei (PDB/CIF) oder eine vierstellige RCSB-PDB-Kennung; wird für die AV-Berechnung verwendet. + +## Markierungsstelle + +### `attachment.atom` + +**Bezeichnung:** Atom der Anbindung +**Typ:** `text` + +Atomname (z. B. CB, CA), der als Anbindungspunkt des Farbstoffs dient. + +### `attachment.chain` + +**Bezeichnung:** Kette der Anbindung +**Typ:** `text` + +Kettenbezeichner der Aminosäure, an die der Farbstoff gebunden ist. + +### `attachment.residue` + +**Bezeichnung:** Rest der Anbindung +**Typ:** `integer` + +Sequenznummer der Aminosäure, an die der Farbstoff gebunden ist. + +## Zugängliches Volumen + +### `av_parameter.linker_length` + +**Bezeichnung:** Linkerlänge +**Typ:** `number` +**Einheit:** `Å` + +Maximaler Abstand vom Anbindungspunkt zum Mittelpunkt des Farbstoffs. + +### `av_parameter.linker_width` + +**Bezeichnung:** Linkerbreite +**Typ:** `number` +**Einheit:** `Å` + +Breite des Linkers, der den Farbstoff hält. + +### `av_parameter.radius1` + +**Bezeichnung:** Farbstoffradius +**Typ:** `number` +**Einheit:** `Å` + +Ausschlussradius, der den Farbstoff als Kugel beschreibt (Ein-Kugel-Näherung). + +### `dg` + +**Bezeichnung:** Gitterauflösung +**Typ:** `number` +**Einheit:** `Å` + +Gitterauflösung für die Berechnung des zugänglichen Volumens (AV) und des Diffusionsraums. + +## Simulation + +### `coarse_grained` + +**Bezeichnung:** Grobkörnige Struktur +**Typ:** `boolean` + +Reduziert die Struktur vor der Simulation auf das Rückgrat samt CB, wobei CB in den Schwerpunkt der Seitenkette verschoben wird. Seitenkettenatome fehlen dann, sodass das Löschzentrum jedes Rests auf dieses CB-Pseudoatom zurückfällt und das zugängliche Volumen wächst, weil die Seitenketten es nicht mehr versperren. Das ist eine Modellierungsentscheidung, keine Beschleunigung: Der Aufwand von QuEst wird vom AV-Gitter bestimmt, nicht von der Atomzahl. + +### `fret.dyes.0.D` + +**Bezeichnung:** Diffusionskoeffizient des Donors +**Typ:** `number` +**Einheit:** `Ų/ns` + +Diffusionskoeffizient des Donorfarbstoffs in Lösung, ohne Wechselwirkung mit der Proteinoberfläche. + +### `n_bins` + +**Bezeichnung:** Kanäle des Abklingens +**Typ:** `integer` + +Anzahl der Zeitkanäle des ausgegebenen Abklinghistogramms. + +### `n_photons` + +**Bezeichnung:** Simulierte Photonen +**Typ:** `integer` + +Anzahl der simulierten Anregungsphotonen zur Rekonstruktion des Fluoreszenzabklingens. + +### `t_max` + +**Bezeichnung:** Simulationsdauer +**Typ:** `number` +**Einheit:** `ns` + +Gesamtlänge der simulierten Brownschen Trajektorie. + +### `t_step` + +**Bezeichnung:** Zeitschritt +**Typ:** `number` +**Einheit:** `ns` + +Schrittweite für die Berechnung der Brownschen Trajektorie. + +### `tau0` + +**Bezeichnung:** Ungelöschte Lebensdauer +**Typ:** `number` +**Einheit:** `ns` + +Fluoreszenzlebensdauer des Donorfarbstoffs ohne Löschung. + +## Erweitert + +### `output_file` + +**Bezeichnung:** Präfix der Ausgabedateien +**Typ:** `text` + +Namenspräfix für gespeicherte Simulationsergebnisse, Trajektorien und Abklingkurven. + +### `parallel_trajectories` + +**Bezeichnung:** Parallele Trajektorien +**Typ:** `integer` + +Anzahl unabhängiger Brownscher Trajektorien, die gleichzeitig gerechnet und vor der Photonensimulation zusammengeführt werden. −1 nutzt alle CPU-Kerne, höchstens jedoch 8. + +### `random_seed` + +**Bezeichnung:** Zufallsstartwert +**Typ:** `integer` + +Startwert der Monte-Carlo-Simulation. Ist er gesetzt, werden sowohl die Diffusionstrajektorie als auch die Photonenspur initialisiert, sodass wiederholte Läufe desselben Projekts genau dasselbe Abklingen und dieselbe Quantenausbeute liefern. Ohne Startwert läuft die Simulation unabhängig zufällig; die Photonenspur nutzt dann einen schnelleren, mehrfädigen Kern. + +### `save_avs` + +**Bezeichnung:** AV-Dateien speichern +**Typ:** `boolean` + +Legt fest, ob die berechneten Gitter des zugänglichen Volumens als XYZ-Dateien gespeichert werden. + +### `skip_frame` + +**Bezeichnung:** Übersprungene Trajektorienbilder +**Typ:** `integer` + +Unterabtastungsfaktor beim Schreiben von Trajektorienbildern in Koordinatendateien. + +### `slow_radius` + +**Bezeichnung:** Verlangsamungsradius +**Typ:** `number` +**Einheit:** `Å` + +Radius um jedes Aminosäurezentrum des gesamten Proteins, innerhalb dessen dieser Resttyp seinen slow_factor zum Gitter der Diffusionskoeffizienten beiträgt. + +## FRET-Akzeptor + +### `fret.R0_matrix` + +**Bezeichnung:** Förster-Radius +**Typ:** `number` +**Einheit:** `Å` + +Förster-Radius R0 des Donor-Akzeptor-Paares, in Ångström wie jede andere Länge im Projekt. Gespeichert wird die Zelle Donor→Akzeptor von fret.R0_matrix; die Transferrate skaliert mit (R0/r)^6, sodass eine Eingabe in Nanometern FRET verschwinden lässt. Typische Xanthen-Paare liegen bei 45–65 Å. + +### `fret.acceptor_dynamics` + +**Bezeichnung:** Akzeptordynamik +**Typ:** `choice` + +Wie der Akzeptor behandelt wird: „trajectory“ simuliert seine Brownsche Bewegung mit eigenem Diffusionskoeffizienten und eigener Haftung und verwendet den momentanen Donor-Akzeptor-Abstand, „averaged“ mittelt über sein statisches zugängliches Volumen (Grenzfall des schnellen Akzeptors, nur gültig, wenn er dieses Volumen schnell im Vergleich zur Donorlebensdauer durchläuft). Beide unterscheiden sich, weil eine Punktwolke gleichmäßig gewichtet wird, eine Trajektorie hingegen danach, wo sich der Farbstoff tatsächlich aufhält. + +### `fret.dyes.1.D` + +**Bezeichnung:** Diffusionskoeffizient des Akzeptors +**Typ:** `number` +**Einheit:** `Ų/ns` + +Diffusionskoeffizient des FRET-Akzeptorfarbstoffs ohne Wechselwirkung mit der Proteinoberfläche. + +### `fret.dyes.1.amino_acid_interactions` + +**Bezeichnung:** Wechselwirkungen des Akzeptors +**Typ:** `table` + +Tabelle der Wechselwirkungen je Resttyp für den Akzeptor, gleiche Form wie amino_acid_interactions des Donors. Verwendet wird nur slow_factor, denn QuEst berichtet das Abklingen des Donors; die eigene PET-Löschung des Akzeptors würde dessen Helligkeit ändern, nicht die des Donors. Voreinstellung ist die Tabelle des Donors. + +### `fret.dyes.1.attachment.atom` + +**Bezeichnung:** Atom des Akzeptors +**Typ:** `text` + +Atomname, an dem der FRET-Akzeptorfarbstoff gebunden ist. + +### `fret.dyes.1.attachment.chain` + +**Bezeichnung:** Kette des Akzeptors +**Typ:** `text` + +Kettenbezeichner des Rests, an den der FRET-Akzeptorfarbstoff gebunden ist. + +### `fret.dyes.1.attachment.residue` + +**Bezeichnung:** Rest des Akzeptors +**Typ:** `integer` + +Sequenznummer des Rests, an den der FRET-Akzeptorfarbstoff gebunden ist. + +### `fret.dyes.1.av_parameter.linker_length` + +**Bezeichnung:** Linkerlänge des Akzeptors +**Typ:** `number` +**Einheit:** `Å` + +Maximaler Abstand vom Anbindungspunkt zum Mittelpunkt des FRET-Akzeptorfarbstoffs. + +### `fret.dyes.1.av_parameter.linker_width` + +**Bezeichnung:** Linkerbreite des Akzeptors +**Typ:** `number` +**Einheit:** `Å` + +Breite des Linkers, der den FRET-Akzeptorfarbstoff hält. + +### `fret.dyes.1.av_parameter.radius1` + +**Bezeichnung:** Radius des Akzeptorfarbstoffs +**Typ:** `number` +**Einheit:** `Å` + +Ausschlussradius, der den FRET-Akzeptorfarbstoff als Kugel beschreibt. + +### `fret.dyes.1.slow_radius` + +**Bezeichnung:** Verlangsamungsradius des Akzeptors +**Typ:** `number` +**Einheit:** `Å` + +Radius um jedes Aminosäurezentrum, innerhalb dessen dieser Rest den Akzeptor verlangsamt. Getrennt vom Donor: Ein Cyanin und ein Rhodamin haften nicht in gleicher Weise an einer Proteinoberfläche. Voreinstellung ist der Wert des Donors. + +### `fret.enabled` + +**Bezeichnung:** FRET aktiviert +**Typ:** `boolean` + +Legt fest, ob ein FRET-Akzeptorfarbstoff simuliert wird, um FRET-Effizienz und Abklingkurven zu berechnen. + +### `fret.kappa2` + +**Bezeichnung:** Orientierungsfaktor κ² +**Typ:** `number` + +Orientierungsfaktor κ² des Transfers, zwischen 0 (senkrecht zueinander stehende Übergangsdipole) und 4 (kollinear). QuEst modelliert ihn nicht: der Farbstoff ist ein Punkt, der in einem Volumen diffundiert, und besitzt keinen Dipol, der sich ausrichten könnte — dieser Wert ist also die Mittelungsannahme, die Sie treffen. Der Standardwert 2/3 ist das isotrope dynamische Mittel, das ein publizierter Förster-Radius bereits voraussetzt; ihn stehen zu lassen reproduziert die Rate exakt. Erhöhen Sie ihn nur, wenn belegt ist, dass beide Farbstoffe in ihrer Orientierung eingeschränkt sind. + +## Löschung + +### `amino_acid_interactions` + +**Bezeichnung:** Aminosäure-Wechselwirkungen +**Typ:** `table` + +Tabelle der Wechselwirkungen je Resttyp. Jeder Eintrag enthält slow_factor (0–1, wie stark der Rest den diffundierenden Farbstoff verlangsamt), kQ (Löschrate in 1/ns bei Kontakt), quench_radius (Kontaktradius in Ångström vom Farbstoffmittelpunkt; null übernimmt critical_distance) und quench_atoms (Atomnamen, deren Schwerpunkt das Löschzentrum bildet). Standardmäßig löschen nur Reste mit redoxaktiver Seitenkette: TRP, TYR, MET, HIS, CYS und PRO. + +### `amino_acid_interactions.kQ` + +**Bezeichnung:** Löschrate kQ +**Typ:** `number` +**Einheit:** `1/ns` + +Rate, mit der dieser Resttyp den Farbstoff bei Kontakt löscht. Beiträge von Resten mit überlappenden Kontaktsphären addieren sich. + +### `amino_acid_interactions.quench_atoms` + +**Bezeichnung:** Atome des Löschzentrums +**Typ:** `list` + +Atomnamen, deren Schwerpunkt das Löschzentrum dieses Rests bildet. Die Voreinstellungen folgen der redoxaktiven Gruppe, die den photoinduzierten Elektronentransfer vermittelt: der Indolring bei TRP, der Phenolring bei TYR, der Imidazolring bei HIS, SD bei MET und SG bei CYS – nicht CB. + +### `amino_acid_interactions.quench_radius` + +**Bezeichnung:** Kontaktradius +**Typ:** `number` +**Einheit:** `Å` + +Abstand vom Farbstoffmittelpunkt zum Löschzentrum dieses Rests, innerhalb dessen Löschung stattfindet. Leer lassen, um die projektweite critical_distance zu übernehmen. + +### `amino_acid_interactions.slow_factor` + +**Bezeichnung:** Verlangsamungsfaktor +**Typ:** `number` + +Faktor zwischen 0 und 1, der den Diffusionskoeffizienten des Farbstoffs in der Nähe dieses Resttyps skaliert und unspezifische Haftung beschreibt. Überlappende Reste multiplizieren ihre Faktoren. + +### `critical_distance` + +**Bezeichnung:** Voreingestellter Kontaktradius +**Typ:** `number` +**Einheit:** `Å` + +Kontaktradius für Resttypen, die keinen eigenen quench_radius festlegen. Er wird vom Farbstoffmittelpunkt bis zum Löschzentrum des Rests gemessen und muss daher größer sein als der Farbstoffradius zuzüglich des Van-der-Waals-Kontakts (typischerweise 7–9 Å bei einem Farbstoff von 3,5 Å). + +## CLI override examples + +- Set donor lifetime and attachment residue: + ```bash + quest simulate -p project.quest.json --set tau0=3.8 --set attachment.residue=55 + ``` +- Sweep linker length and residue: + ```bash + quest simulate -p project.quest.json \ + --grid av_parameter.linker_length=10.0,12.5 \ + --grid attachment.residue=25,30,35 + ``` + +## Validation tips + +- Ensure donor dye has `D` set; otherwise the API raises a `KeyError`. +- Provide a valid `pdb` path (or pass `--pdb`/`pdb_path`). +- When enabling FRET, include two dyes and an `R0_matrix` entry for donor→acceptor. diff --git a/doc/parameters.fr.md b/doc/parameters.fr.md new file mode 100644 index 0000000..b006c68 --- /dev/null +++ b/doc/parameters.fr.md @@ -0,0 +1,379 @@ +# Référence des paramètres QuEst + +Cette page est générée à partir de `parameter_catalog.json`, `quest/settings/locales/fr.json`. Modifiez-les d'abord pour changer le texte d'aide d'un paramètre — l'interface web, cette page et le formulaire de bureau lisent les mêmes fichiers. + +## Résumé du catalogue + +| Clé | Catégorie | Type | Unité | Description | +| --- | --- | --- | --- | --- | +| `amino_acid_interactions` | Extinction | table | - | Table d'interaction par type de résidu. Chaque entrée contient slow_factor (0–1, mesure du ralentissement du fluorophore par le résidu), kQ (taux d'extinction en 1/ns appliqué au contact), quench_radius (rayon de contact en ångströms depuis le centre du fluorophore ; null hérite de critical_distance) et quench_atoms (noms des atomes dont le barycentre définit le centre d'extinction). Par défaut, seuls les résidus à chaîne latérale rédox-active éteignent la fluorescence : TRP, TYR, MET, HIS, CYS et PRO. | +| `amino_acid_interactions.kQ` | Extinction | number | 1/ns | Taux auquel ce type de résidu éteint le fluorophore tant que les deux sont en contact. Les contributions des résidus dont les sphères de contact se recouvrent s'additionnent. | +| `amino_acid_interactions.quench_atoms` | Extinction | list | - | Noms des atomes dont le barycentre définit le centre d'extinction de ce résidu. Les valeurs par défaut suivent le groupement rédox-actif qui assure le transfert d'électron photo-induit : le cycle indole pour TRP, le cycle phénol pour TYR, le cycle imidazole pour HIS, SD pour MET et SG pour CYS — et non CB. | +| `amino_acid_interactions.quench_radius` | Extinction | number | Å | Distance entre le centre du fluorophore et le centre d'extinction de ce résidu en deçà de laquelle l'extinction se produit. Laisser vide pour hériter du critical_distance du projet. | +| `amino_acid_interactions.slow_factor` | Extinction | number | - | Facteur compris entre 0 et 1 qui met à l'échelle le coefficient de diffusion du fluorophore au voisinage de ce type de résidu, modélisant une adhérence non spécifique. Les résidus qui se recouvrent multiplient leurs facteurs. | +| `attachment.atom` | Site de marquage | text | - | Nom de l'atome (par ex. CB, CA) servant de point d'attache au fluorophore. | +| `attachment.chain` | Site de marquage | text | - | Identifiant de chaîne du résidu sur lequel le fluorophore est attaché. | +| `attachment.residue` | Site de marquage | integer | - | Numéro de séquence du résidu sur lequel le fluorophore est attaché. | +| `av_parameter.linker_length` | Volume accessible | number | Å | Distance maximale entre le point d'attache et le centre du fluorophore. | +| `av_parameter.linker_width` | Volume accessible | number | Å | Largeur du bras espaceur qui retient le fluorophore. | +| `av_parameter.radius1` | Volume accessible | number | Å | Rayon d'exclusion représentant le fluorophore comme une sphère (approximation à une sphère). | +| `coarse_grained` | Simulation | boolean | - | Réduit la structure au squelette et aux CB avant la simulation, chaque CB étant déplacé au centre de masse de sa chaîne latérale. Les atomes de chaîne latérale sont alors absents : le centre d'extinction de chaque résidu se rabat sur ce pseudo-atome CB, et le volume accessible augmente puisque les chaînes latérales ne l'obstruent plus. C'est un choix de modélisation, non une optimisation : le coût de QuEst tient à la grille du volume accessible, pas au nombre d'atomes. | +| `critical_distance` | Extinction | number | Å | Rayon de contact employé par les types de résidus qui ne définissent pas leur propre quench_radius. Il se mesure du centre du fluorophore au centre d'extinction du résidu et doit donc dépasser le rayon du fluorophore augmenté du contact de van der Waals (typiquement 7 à 9 Å pour un fluorophore de 3,5 Å). | +| `dg` | Volume accessible | number | Å | Résolution de la grille utilisée pour calculer le volume accessible (AV) et l'espace de diffusion. | +| `fret.R0_matrix` | Accepteur FRET | number | Å | Rayon de Förster R0 du couple donneur–accepteur, en ångströms comme toute autre longueur du projet. Il est stocké dans la case donneur→accepteur de fret.R0_matrix ; le taux de transfert varie en (R0/r)^6, si bien qu'une saisie en nanomètres fait disparaître le FRET. Les couples xanthènes usuels se situent entre 45 et 65 Å. | +| `fret.acceptor_dynamics` | Accepteur FRET | choice | - | Traitement de l'accepteur : « trajectory » simule sa marche brownienne avec son propre coefficient de diffusion et sa propre adhérence, et utilise la distance donneur-accepteur instantanée ; « averaged » moyenne sur son volume accessible statique (limite de l'accepteur rapide, valable seulement s'il parcourt ce volume rapidement devant la durée de vie du donneur). Les deux diffèrent parce qu'un nuage est pondéré uniformément alors qu'une trajectoire l'est par les endroits où le fluorophore séjourne. | +| `fret.dyes.0.D` | Simulation | number | Ų/ns | Coefficient de diffusion du donneur en solution, hors interaction avec la surface de la protéine. | +| `fret.dyes.1.D` | Accepteur FRET | number | Ų/ns | Coefficient de diffusion de l'accepteur FRET hors interaction avec la surface de la protéine. | +| `fret.dyes.1.amino_acid_interactions` | Accepteur FRET | table | - | Table d'interaction par type de résidu pour l'accepteur, de même forme que l'amino_acid_interactions du donneur. Seul slow_factor est utilisé, car QuEst rapporte le déclin du donneur : l'extinction PET propre à l'accepteur modifierait sa brillance, pas celle du donneur. Par défaut, la table du donneur. | +| `fret.dyes.1.attachment.atom` | Accepteur FRET | text | - | Nom de l'atome sur lequel l'accepteur FRET est attaché. | +| `fret.dyes.1.attachment.chain` | Accepteur FRET | text | - | Identifiant de chaîne du résidu sur lequel l'accepteur FRET est attaché. | +| `fret.dyes.1.attachment.residue` | Accepteur FRET | integer | - | Numéro de séquence du résidu sur lequel l'accepteur FRET est attaché. | +| `fret.dyes.1.av_parameter.linker_length` | Accepteur FRET | number | Å | Distance maximale entre le point d'attache et le centre de l'accepteur FRET. | +| `fret.dyes.1.av_parameter.linker_width` | Accepteur FRET | number | Å | Largeur du bras espaceur qui retient l'accepteur FRET. | +| `fret.dyes.1.av_parameter.radius1` | Accepteur FRET | number | Å | Rayon d'exclusion représentant l'accepteur FRET comme une sphère. | +| `fret.dyes.1.slow_radius` | Accepteur FRET | number | Å | Rayon autour de chaque centre d'acide aminé à l'intérieur duquel ce résidu ralentit l'accepteur. Distinct de celui du donneur : une cyanine et une rhodamine n'adhèrent pas de la même façon à une surface protéique. Par défaut, la valeur du donneur. | +| `fret.enabled` | Accepteur FRET | boolean | - | Indique si un accepteur FRET est simulé afin de calculer l'efficacité de FRET et les courbes de déclin. | +| `fret.kappa2` | Accepteur FRET | number | - | Facteur d'orientation κ² du transfert, entre 0 (dipôles de transition perpendiculaires) et 4 (colinéaires). QuEst ne le modélise pas : le fluorophore est un point diffusant dans un volume et n'a aucun dipôle à orienter — cette valeur est donc le régime de moyenne que vous postulez. La valeur par défaut 2/3 est la moyenne dynamique isotrope, que suppose déjà tout rayon de Förster publié ; la conserver reproduit exactement la vitesse de transfert. Ne l'augmentez qu'avec la preuve que les deux fluorophores sont contraints en orientation. | +| `n_bins` | Simulation | integer | - | Nombre de canaux temporels de l'histogramme de déclin produit. | +| `n_photons` | Simulation | integer | - | Nombre de photons d'excitation simulés pour reconstruire l'histogramme de déclin de fluorescence. | +| `output_file` | Avancé | text | - | Préfixe de nom employé pour enregistrer les résultats, les trajectoires et les déclins. | +| `parallel_trajectories` | Avancé | integer | - | Nombre de trajectoires browniennes indépendantes calculées simultanément et réunies avant l'échantillonnage des photons. −1 utilise tous les cœurs du processeur, dans la limite de 8. | +| `pdb` | Structure | file | - | Chemin du fichier de structure (PDB/CIF), ou identifiant RCSB PDB à quatre caractères, utilisé pour le calcul du volume accessible. | +| `random_seed` | Avancé | integer | - | Graine de la simulation Monte-Carlo. Lorsqu'elle est fixée, la trajectoire de diffusion et le tirage des photons sont tous deux initialisés : deux exécutions du même projet reproduisent exactement le même déclin et le même rendement quantique. Sans graine, chaque exécution est indépendante et le tirage des photons emploie un noyau multithread plus rapide. | +| `save_avs` | Avancé | boolean | - | Indique si les grilles de volume accessible calculées sont enregistrées au format XYZ. | +| `skip_frame` | Avancé | integer | - | Facteur de sous-échantillonnage lors de l'écriture des images de trajectoire dans les fichiers de coordonnées. | +| `slow_radius` | Avancé | number | Å | Rayon autour de chaque centre d'acide aminé de la protéine entière à l'intérieur duquel ce type de résidu applique son slow_factor à la grille des coefficients de diffusion. | +| `t_max` | Simulation | number | ns | Durée totale de la trajectoire de dynamique brownienne simulée. | +| `t_step` | Simulation | number | ns | Pas de temps du calcul de la trajectoire de dynamique brownienne. | +| `tau0` | Simulation | number | ns | Durée de vie de fluorescence du donneur en l'absence d'extinction. | + +## Structure + +### `pdb` + +**Libellé:** Fichier de structure +**Type:** `file` + +Chemin du fichier de structure (PDB/CIF), ou identifiant RCSB PDB à quatre caractères, utilisé pour le calcul du volume accessible. + +## Site de marquage + +### `attachment.atom` + +**Libellé:** Atome d'attache +**Type:** `text` + +Nom de l'atome (par ex. CB, CA) servant de point d'attache au fluorophore. + +### `attachment.chain` + +**Libellé:** Chaîne d'attache +**Type:** `text` + +Identifiant de chaîne du résidu sur lequel le fluorophore est attaché. + +### `attachment.residue` + +**Libellé:** Résidu d'attache +**Type:** `integer` + +Numéro de séquence du résidu sur lequel le fluorophore est attaché. + +## Volume accessible + +### `av_parameter.linker_length` + +**Libellé:** Longueur du bras espaceur +**Type:** `number` +**Unité:** `Å` + +Distance maximale entre le point d'attache et le centre du fluorophore. + +### `av_parameter.linker_width` + +**Libellé:** Largeur du bras espaceur +**Type:** `number` +**Unité:** `Å` + +Largeur du bras espaceur qui retient le fluorophore. + +### `av_parameter.radius1` + +**Libellé:** Rayon du fluorophore +**Type:** `number` +**Unité:** `Å` + +Rayon d'exclusion représentant le fluorophore comme une sphère (approximation à une sphère). + +### `dg` + +**Libellé:** Résolution de la grille +**Type:** `number` +**Unité:** `Å` + +Résolution de la grille utilisée pour calculer le volume accessible (AV) et l'espace de diffusion. + +## Simulation + +### `coarse_grained` + +**Libellé:** Structure gros grains +**Type:** `boolean` + +Réduit la structure au squelette et aux CB avant la simulation, chaque CB étant déplacé au centre de masse de sa chaîne latérale. Les atomes de chaîne latérale sont alors absents : le centre d'extinction de chaque résidu se rabat sur ce pseudo-atome CB, et le volume accessible augmente puisque les chaînes latérales ne l'obstruent plus. C'est un choix de modélisation, non une optimisation : le coût de QuEst tient à la grille du volume accessible, pas au nombre d'atomes. + +### `fret.dyes.0.D` + +**Libellé:** Coefficient de diffusion du donneur +**Type:** `number` +**Unité:** `Ų/ns` + +Coefficient de diffusion du donneur en solution, hors interaction avec la surface de la protéine. + +### `n_bins` + +**Libellé:** Canaux du déclin +**Type:** `integer` + +Nombre de canaux temporels de l'histogramme de déclin produit. + +### `n_photons` + +**Libellé:** Photons simulés +**Type:** `integer` + +Nombre de photons d'excitation simulés pour reconstruire l'histogramme de déclin de fluorescence. + +### `t_max` + +**Libellé:** Durée de simulation +**Type:** `number` +**Unité:** `ns` + +Durée totale de la trajectoire de dynamique brownienne simulée. + +### `t_step` + +**Libellé:** Pas de temps +**Type:** `number` +**Unité:** `ns` + +Pas de temps du calcul de la trajectoire de dynamique brownienne. + +### `tau0` + +**Libellé:** Durée de vie non éteinte +**Type:** `number` +**Unité:** `ns` + +Durée de vie de fluorescence du donneur en l'absence d'extinction. + +## Avancé + +### `output_file` + +**Libellé:** Préfixe des fichiers de sortie +**Type:** `text` + +Préfixe de nom employé pour enregistrer les résultats, les trajectoires et les déclins. + +### `parallel_trajectories` + +**Libellé:** Trajectoires parallèles +**Type:** `integer` + +Nombre de trajectoires browniennes indépendantes calculées simultanément et réunies avant l'échantillonnage des photons. −1 utilise tous les cœurs du processeur, dans la limite de 8. + +### `random_seed` + +**Libellé:** Graine aléatoire +**Type:** `integer` + +Graine de la simulation Monte-Carlo. Lorsqu'elle est fixée, la trajectoire de diffusion et le tirage des photons sont tous deux initialisés : deux exécutions du même projet reproduisent exactement le même déclin et le même rendement quantique. Sans graine, chaque exécution est indépendante et le tirage des photons emploie un noyau multithread plus rapide. + +### `save_avs` + +**Libellé:** Enregistrer les fichiers AV +**Type:** `boolean` + +Indique si les grilles de volume accessible calculées sont enregistrées au format XYZ. + +### `skip_frame` + +**Libellé:** Images de trajectoire ignorées +**Type:** `integer` + +Facteur de sous-échantillonnage lors de l'écriture des images de trajectoire dans les fichiers de coordonnées. + +### `slow_radius` + +**Libellé:** Rayon de ralentissement +**Type:** `number` +**Unité:** `Å` + +Rayon autour de chaque centre d'acide aminé de la protéine entière à l'intérieur duquel ce type de résidu applique son slow_factor à la grille des coefficients de diffusion. + +## Accepteur FRET + +### `fret.R0_matrix` + +**Libellé:** Rayon de Förster +**Type:** `number` +**Unité:** `Å` + +Rayon de Förster R0 du couple donneur–accepteur, en ångströms comme toute autre longueur du projet. Il est stocké dans la case donneur→accepteur de fret.R0_matrix ; le taux de transfert varie en (R0/r)^6, si bien qu'une saisie en nanomètres fait disparaître le FRET. Les couples xanthènes usuels se situent entre 45 et 65 Å. + +### `fret.acceptor_dynamics` + +**Libellé:** Dynamique de l'accepteur +**Type:** `choice` + +Traitement de l'accepteur : « trajectory » simule sa marche brownienne avec son propre coefficient de diffusion et sa propre adhérence, et utilise la distance donneur-accepteur instantanée ; « averaged » moyenne sur son volume accessible statique (limite de l'accepteur rapide, valable seulement s'il parcourt ce volume rapidement devant la durée de vie du donneur). Les deux diffèrent parce qu'un nuage est pondéré uniformément alors qu'une trajectoire l'est par les endroits où le fluorophore séjourne. + +### `fret.dyes.1.D` + +**Libellé:** Coefficient de diffusion de l'accepteur +**Type:** `number` +**Unité:** `Ų/ns` + +Coefficient de diffusion de l'accepteur FRET hors interaction avec la surface de la protéine. + +### `fret.dyes.1.amino_acid_interactions` + +**Libellé:** Interactions de l'accepteur +**Type:** `table` + +Table d'interaction par type de résidu pour l'accepteur, de même forme que l'amino_acid_interactions du donneur. Seul slow_factor est utilisé, car QuEst rapporte le déclin du donneur : l'extinction PET propre à l'accepteur modifierait sa brillance, pas celle du donneur. Par défaut, la table du donneur. + +### `fret.dyes.1.attachment.atom` + +**Libellé:** Atome de l'accepteur +**Type:** `text` + +Nom de l'atome sur lequel l'accepteur FRET est attaché. + +### `fret.dyes.1.attachment.chain` + +**Libellé:** Chaîne de l'accepteur +**Type:** `text` + +Identifiant de chaîne du résidu sur lequel l'accepteur FRET est attaché. + +### `fret.dyes.1.attachment.residue` + +**Libellé:** Résidu de l'accepteur +**Type:** `integer` + +Numéro de séquence du résidu sur lequel l'accepteur FRET est attaché. + +### `fret.dyes.1.av_parameter.linker_length` + +**Libellé:** Longueur du bras de l'accepteur +**Type:** `number` +**Unité:** `Å` + +Distance maximale entre le point d'attache et le centre de l'accepteur FRET. + +### `fret.dyes.1.av_parameter.linker_width` + +**Libellé:** Largeur du bras de l'accepteur +**Type:** `number` +**Unité:** `Å` + +Largeur du bras espaceur qui retient l'accepteur FRET. + +### `fret.dyes.1.av_parameter.radius1` + +**Libellé:** Rayon de l'accepteur +**Type:** `number` +**Unité:** `Å` + +Rayon d'exclusion représentant l'accepteur FRET comme une sphère. + +### `fret.dyes.1.slow_radius` + +**Libellé:** Rayon de ralentissement de l'accepteur +**Type:** `number` +**Unité:** `Å` + +Rayon autour de chaque centre d'acide aminé à l'intérieur duquel ce résidu ralentit l'accepteur. Distinct de celui du donneur : une cyanine et une rhodamine n'adhèrent pas de la même façon à une surface protéique. Par défaut, la valeur du donneur. + +### `fret.enabled` + +**Libellé:** FRET activé +**Type:** `boolean` + +Indique si un accepteur FRET est simulé afin de calculer l'efficacité de FRET et les courbes de déclin. + +### `fret.kappa2` + +**Libellé:** Facteur d'orientation κ² +**Type:** `number` + +Facteur d'orientation κ² du transfert, entre 0 (dipôles de transition perpendiculaires) et 4 (colinéaires). QuEst ne le modélise pas : le fluorophore est un point diffusant dans un volume et n'a aucun dipôle à orienter — cette valeur est donc le régime de moyenne que vous postulez. La valeur par défaut 2/3 est la moyenne dynamique isotrope, que suppose déjà tout rayon de Förster publié ; la conserver reproduit exactement la vitesse de transfert. Ne l'augmentez qu'avec la preuve que les deux fluorophores sont contraints en orientation. + +## Extinction + +### `amino_acid_interactions` + +**Libellé:** Interactions avec les acides aminés +**Type:** `table` + +Table d'interaction par type de résidu. Chaque entrée contient slow_factor (0–1, mesure du ralentissement du fluorophore par le résidu), kQ (taux d'extinction en 1/ns appliqué au contact), quench_radius (rayon de contact en ångströms depuis le centre du fluorophore ; null hérite de critical_distance) et quench_atoms (noms des atomes dont le barycentre définit le centre d'extinction). Par défaut, seuls les résidus à chaîne latérale rédox-active éteignent la fluorescence : TRP, TYR, MET, HIS, CYS et PRO. + +### `amino_acid_interactions.kQ` + +**Libellé:** Taux d'extinction kQ +**Type:** `number` +**Unité:** `1/ns` + +Taux auquel ce type de résidu éteint le fluorophore tant que les deux sont en contact. Les contributions des résidus dont les sphères de contact se recouvrent s'additionnent. + +### `amino_acid_interactions.quench_atoms` + +**Libellé:** Atomes du centre d'extinction +**Type:** `list` + +Noms des atomes dont le barycentre définit le centre d'extinction de ce résidu. Les valeurs par défaut suivent le groupement rédox-actif qui assure le transfert d'électron photo-induit : le cycle indole pour TRP, le cycle phénol pour TYR, le cycle imidazole pour HIS, SD pour MET et SG pour CYS — et non CB. + +### `amino_acid_interactions.quench_radius` + +**Libellé:** Rayon de contact +**Type:** `number` +**Unité:** `Å` + +Distance entre le centre du fluorophore et le centre d'extinction de ce résidu en deçà de laquelle l'extinction se produit. Laisser vide pour hériter du critical_distance du projet. + +### `amino_acid_interactions.slow_factor` + +**Libellé:** Facteur de ralentissement +**Type:** `number` + +Facteur compris entre 0 et 1 qui met à l'échelle le coefficient de diffusion du fluorophore au voisinage de ce type de résidu, modélisant une adhérence non spécifique. Les résidus qui se recouvrent multiplient leurs facteurs. + +### `critical_distance` + +**Libellé:** Rayon de contact par défaut +**Type:** `number` +**Unité:** `Å` + +Rayon de contact employé par les types de résidus qui ne définissent pas leur propre quench_radius. Il se mesure du centre du fluorophore au centre d'extinction du résidu et doit donc dépasser le rayon du fluorophore augmenté du contact de van der Waals (typiquement 7 à 9 Å pour un fluorophore de 3,5 Å). + +## CLI override examples + +- Set donor lifetime and attachment residue: + ```bash + quest simulate -p project.quest.json --set tau0=3.8 --set attachment.residue=55 + ``` +- Sweep linker length and residue: + ```bash + quest simulate -p project.quest.json \ + --grid av_parameter.linker_length=10.0,12.5 \ + --grid attachment.residue=25,30,35 + ``` + +## Validation tips + +- Ensure donor dye has `D` set; otherwise the API raises a `KeyError`. +- Provide a valid `pdb` path (or pass `--pdb`/`pdb_path`). +- When enabling FRET, include two dyes and an `R0_matrix` entry for donor→acceptor. diff --git a/doc/parameters.md b/doc/parameters.md index a51f490..7f1834a 100644 --- a/doc/parameters.md +++ b/doc/parameters.md @@ -1,108 +1,363 @@ # QuEst parameters reference -This page summarizes the project JSON keys and their meaning. The same fields are surfaced in the GUI, CLI overrides (`--set key=value`, `--grid key=...`) and the Python API. - -## Project-level fields - -| Key | Description | -| --- | --- | -| `pdb` | Path to the structure file used for AV calculation. | -| `tau0` | Fluorescence lifetime in the absence of quenching (ns). | -| `kQ` | Default quenching rate constant (1/ns) applied to quencher residues. | -| `n_photons` | Number of simulated photons. | -| `dg` | Grid resolution for dye diffusion. | -| `slow_fact` | Factor by which the dye diffusion slows near the surface. | -| `critical_distance` | Distance threshold for counting collisions/quenching. | -| `slow_radius` | Interaction radius (Å) within which the dye experiences slowed diffusion. | -| `sticky_mode` | `"surface"` to slow near all surface atoms, `"quencher"` to slow only near quencher residues. | -| `save_avs` | Whether to persist accessible volume grids. | -| `output_file` | Base name for saved outputs. | -| `n_bins` | Histogram bin count for decay outputs (CLI/API default: 4096 if omitted). | - -## Attachment block - -```json -"attachment": { - "chain": "A", - "residue": 42, - "atom": "CA" -} -``` - -Defines where the donor dye is tethered. +This page is generated from `parameter_catalog.json`. Update those first when changing parameter help text — the web UI, this page and the desktop form all read them. + +## Catalog summary + +| Key | Category | Type | Unit | Description | +| --- | --- | --- | --- | --- | +| `amino_acid_interactions` | Quenching | table | - | Per-residue-type interaction table. Each entry holds slow_factor (0-1, how much the residue slows the diffusing dye), kQ (quenching rate in 1/ns applied on contact), quench_radius (contact radius in Angstrom from the dye centre; null inherits critical_distance) and quench_atoms (atom names whose centroid defines the quenching centre). Only residues with a redox-active side chain quench by default: TRP, TYR, MET, HIS, CYS and PRO. | +| `amino_acid_interactions.kQ` | Quenching | number | 1/ns | Rate at which this residue type quenches the dye while the two are in contact. Contributions from residues whose contact spheres overlap add up. | +| `amino_acid_interactions.quench_atoms` | Quenching | list | - | Atom names whose centroid defines this residue's quenching centre. The defaults follow the redox-active moiety that mediates photo-induced electron transfer: the indole ring for TRP, the phenol ring for TYR, the imidazole ring for HIS, SD for MET and SG for CYS - not CB. | +| `amino_acid_interactions.quench_radius` | Quenching | number | Å | Distance from the dye centre to this residue's quenching centre within which quenching occurs. Leave empty to inherit the project-wide critical_distance. | +| `amino_acid_interactions.slow_factor` | Quenching | number | - | Factor between 0 and 1 scaling the dye's diffusion coefficient near this residue type, modelling unspecific stickiness. Overlapping residues multiply their factors. | +| `attachment.atom` | Labeling site | text | - | Atom name (e.g., CB, CA) used as the tethering point for the dye. | +| `attachment.chain` | Labeling site | text | - | Chain identifier of the amino acid residue where the dye is tethered. | +| `attachment.residue` | Labeling site | integer | - | Residue sequence number of the amino acid where the dye is tethered. | +| `av_parameter.linker_length` | Accessible volume | number | Å | Maximum distance from attachment point to the center of the dye. | +| `av_parameter.linker_width` | Accessible volume | number | Å | Width of the linker tethering the dye. | +| `av_parameter.radius1` | Accessible volume | number | Å | Exclusion radius representing the dye sphere (single-sphere approximation). | +| `coarse_grained` | Simulation | boolean | - | Reduce the structure to backbone plus CB before simulating, with CB moved to the side-chain centre of mass. Side-chain atoms are then absent, so every residue's quenching centre falls back to that CB pseudo-atom, and the accessible volume grows because side chains no longer block it. This is a modelling choice, not a speed optimisation: QuEst's cost is dominated by the AV grid rather than the atom count. | +| `critical_distance` | Quenching | number | Å | Contact radius used by residue types that do not define their own quench_radius. It is measured from the dye centre to the residue's quenching centre, so it must exceed the dye radius plus van der Waals contact (typically 7-9 A for a 3.5 A dye). | +| `dg` | Accessible volume | number | Å | Grid resolution used to compute the accessible volume (AV) and diffusion search space. | +| `fret.R0_matrix` | FRET Acceptor | number | Å | Förster radius R0 of the donor–acceptor pair, in Ångström like every other length in a project. Stored as the donor→acceptor cell of fret.R0_matrix; the transfer rate scales as (R0/r)^6, so entering nanometres makes FRET vanish. Typical xanthene pairs are 45–65 Å. | +| `fret.acceptor_dynamics` | FRET Acceptor | choice | - | How the acceptor is treated: 'trajectory' simulates its Brownian walk with its own diffusion coefficient and stickiness and uses the instantaneous donor-acceptor distance, 'averaged' averages over its static accessible volume (the fast-acceptor limit, valid only when it explores that volume quickly compared with the donor lifetime). The two disagree because a cloud is weighted uniformly while a trajectory is weighted by where the dye dwells. | +| `fret.dyes.0.D` | Simulation | number | Ų/ns | Diffusion coefficient of the donor dye in solution, when not interacting with the protein surface. | +| `fret.dyes.1.D` | FRET Acceptor | number | Ų/ns | Diffusion coefficient of the FRET acceptor dye when not interacting with the protein surface. | +| `fret.dyes.1.amino_acid_interactions` | FRET Acceptor | table | - | Per-residue-type interaction table for the acceptor, same shape as the donor's amino_acid_interactions. Only slow_factor is used, since QuEst reports the donor's decay and the acceptor's own PET quenching would change how bright the acceptor is, not the donor. Defaults to the donor's table. | +| `fret.dyes.1.attachment.atom` | FRET Acceptor | text | - | Atom name where the FRET acceptor dye is attached. | +| `fret.dyes.1.attachment.chain` | FRET Acceptor | text | - | Chain identifier of the residue where the FRET acceptor dye is attached. | +| `fret.dyes.1.attachment.residue` | FRET Acceptor | integer | - | Residue sequence number where the FRET acceptor dye is attached. | +| `fret.dyes.1.av_parameter.linker_length` | FRET Acceptor | number | Å | Maximum distance from attachment point to the center of the FRET acceptor dye. | +| `fret.dyes.1.av_parameter.linker_width` | FRET Acceptor | number | Å | Width of the linker tethering the FRET acceptor dye. | +| `fret.dyes.1.av_parameter.radius1` | FRET Acceptor | number | Å | Exclusion radius representing the FRET acceptor dye sphere. | +| `fret.dyes.1.slow_radius` | FRET Acceptor | number | Å | Radius around each amino-acid centre within which that residue slows the acceptor. Separate from the donor's: a cyanine and a rhodamine do not adhere to a protein surface in the same way. Defaults to the donor's value. | +| `fret.enabled` | FRET Acceptor | boolean | - | Whether a FRET acceptor dye is simulated to compute FRET efficiency and decay curves. | +| `fret.kappa2` | FRET Acceptor | number | - | Orientation factor κ² of the transfer, between 0 (perpendicular transition dipoles) and 4 (collinear). QuEst does not model it: the dye is a point diffusing in a volume and has no dipole to orient, so this is the averaging regime you are asserting. The default 2/3 is the isotropic dynamic average, which is what a published Förster radius already assumes — leaving it there reproduces the rate exactly. Raise it only with evidence that both dyes are orientationally restricted. | +| `n_bins` | Simulation | integer | - | Number of time channels/bins used to construct the output decay histogram. | +| `n_photons` | Simulation | integer | - | Number of excitation photons simulated to reconstruct the fluorescence decay histogram. | +| `output_file` | Advanced | text | - | Base filename prefix used when saving simulation outputs, trajectories, and decays. | +| `parallel_trajectories` | Advanced | integer | - | Number of independent Brownian dynamics trajectories run concurrently and combined before photon sampling. Use -1 to use all CPU cores, capped at 8. | +| `pdb` | Structure | file | - | Path to the structure file (PDB/CIF), or a bare four-character RCSB PDB ID used for AV calculation. | +| `random_seed` | Advanced | integer | - | Seed for the Monte-Carlo simulation. When set, both the diffusion trajectory and the photon trace are seeded, so repeated runs of the same project reproduce the same decay and quantum yield exactly. Leave unset for an independent random run; the photon trace then uses a faster multi-threaded kernel. | +| `save_avs` | Advanced | boolean | - | Whether to save the calculated accessible volume grids as XYZ files. | +| `skip_frame` | Advanced | integer | - | Subsampling factor for writing trajectory frames to coordinates files. | +| `slow_radius` | Advanced | number | Å | Radius around each whole-protein amino-acid center where that residue type contributes its slow_factor to the diffusion coefficient grid. | +| `t_max` | Simulation | number | ns | Total length of the simulated Brownian dynamics trajectory. | +| `t_step` | Simulation | number | ns | Time step size for the Brownian dynamics trajectory calculation. | +| `tau0` | Simulation | number | ns | Fluorescence lifetime of the donor dye in the absence of quenching. | + +## Structure + +### `pdb` + +**Label:** Structure file +**Type:** `file` + +Path to the structure file (PDB/CIF), or a bare four-character RCSB PDB ID used for AV calculation. + +## Labeling site + +### `attachment.atom` + +**Label:** Attachment atom +**Type:** `text` + +Atom name (e.g., CB, CA) used as the tethering point for the dye. + +### `attachment.chain` + +**Label:** Attachment chain +**Type:** `text` + +Chain identifier of the amino acid residue where the dye is tethered. + +### `attachment.residue` + +**Label:** Attachment residue +**Type:** `integer` + +Residue sequence number of the amino acid where the dye is tethered. ## Accessible volume -```json -"av_parameter": { - "linker_length": 20.0, - "linker_width": 0.5, - "radius1": 5.0 -} -``` - -- `linker_length`: Maximum distance from attachment point to dye center. -- `linker_width`: Width of the linker. -- `radius1`: Dye radius (single-sphere approximation). - -## Dye block (FRET dyes list) - -Located under `fret.dyes`. The first entry is the donor; the second (optional) is the acceptor. - -| Key | Description | -| --- | --- | -| `D` | Diffusion coefficient of the dye when not interacting with the surface (Ų/ns). **Required for donor.** | -| `attachment` | Same structure as the top-level `attachment` (chain/residue/atom). | -| `av_parameter` | Optional AV parameters for acceptor (when FRET). | - -## Quencher block - -```json -"quencher": { - "TRP": ["CB"], - "TYR": ["CB"], - "HIS": ["CB"] -} -``` - -- Keys are quenching residue names (3-letter codes). -- Values list atom names that act as quenchers. -- `kQ` at the project root sets the rate constant applied when within `critical_distance`. -- `all_quencher_atoms` (bool, default `true`): use all atoms of quencher residues if `true`, otherwise only the listed atoms. - -## FRET block (optional) - -```json -"fret": { - "enabled": true, - "dyes": [... donor, acceptor ...], - "R0_matrix": [[null, 52.0], [52.0, null]] -} -``` - -- `enabled`: turn FRET on/off. -- `dyes`: list of dye entries (donor first). Provide acceptor when FRET is enabled. -- `R0_matrix`: Förster distances (nm); donor→acceptor entry is used (row 0, col 1). - -## Simulation controls - -| Key | Description | -| --- | --- | -| `t_max` | Total simulation time (µs). | -| `t_step` | Time step (ps) for Brownian dynamics. | -| `frames` | Derived: total number of frames (from `t_max` and `t_step`). | -| `n_photons` | Number of photons generated. | -| `show_av` | Show full AV in 3D illustration (GUI). | - -## Results fields (outputs) - -| Field | Meaning | -| --- | --- | -| `QY(F)` | Simulated fluorescence quantum yield of the bright species. | -| `collisions_fraction` | Fraction of frames where dye is within quench radius. | -| `nBins` / `n_bins` | Bin count used for decay histogram. | -| `range` | Time axis range for decay histogram (tac_range in API/CLI). | -| `skip` | GUI-only: subsampling factor for 3D illustration frames. | +### `av_parameter.linker_length` + +**Label:** Linker length +**Type:** `number` +**Unit:** `Å` + +Maximum distance from attachment point to the center of the dye. + +### `av_parameter.linker_width` + +**Label:** Linker width +**Type:** `number` +**Unit:** `Å` + +Width of the linker tethering the dye. + +### `av_parameter.radius1` + +**Label:** Dye radius +**Type:** `number` +**Unit:** `Å` + +Exclusion radius representing the dye sphere (single-sphere approximation). + +### `dg` + +**Label:** Grid resolution +**Type:** `number` +**Unit:** `Å` + +Grid resolution used to compute the accessible volume (AV) and diffusion search space. + +## Simulation + +### `coarse_grained` + +**Label:** Coarse-grained structure +**Type:** `boolean` + +Reduce the structure to backbone plus CB before simulating, with CB moved to the side-chain centre of mass. Side-chain atoms are then absent, so every residue's quenching centre falls back to that CB pseudo-atom, and the accessible volume grows because side chains no longer block it. This is a modelling choice, not a speed optimisation: QuEst's cost is dominated by the AV grid rather than the atom count. + +### `fret.dyes.0.D` + +**Label:** Donor diffusion coefficient +**Type:** `number` +**Unit:** `Ų/ns` + +Diffusion coefficient of the donor dye in solution, when not interacting with the protein surface. + +### `n_bins` + +**Label:** Decay bins +**Type:** `integer` + +Number of time channels/bins used to construct the output decay histogram. + +### `n_photons` + +**Label:** Simulated photons +**Type:** `integer` + +Number of excitation photons simulated to reconstruct the fluorescence decay histogram. + +### `t_max` + +**Label:** Simulation time +**Type:** `number` +**Unit:** `ns` + +Total length of the simulated Brownian dynamics trajectory. + +### `t_step` + +**Label:** Time step +**Type:** `number` +**Unit:** `ns` + +Time step size for the Brownian dynamics trajectory calculation. + +### `tau0` + +**Label:** Unquenched lifetime +**Type:** `number` +**Unit:** `ns` + +Fluorescence lifetime of the donor dye in the absence of quenching. + +## Advanced + +### `output_file` + +**Label:** Output file prefix +**Type:** `text` + +Base filename prefix used when saving simulation outputs, trajectories, and decays. + +### `parallel_trajectories` + +**Label:** Parallel trajectories +**Type:** `integer` + +Number of independent Brownian dynamics trajectories run concurrently and combined before photon sampling. Use -1 to use all CPU cores, capped at 8. + +### `random_seed` + +**Label:** Random seed +**Type:** `integer` + +Seed for the Monte-Carlo simulation. When set, both the diffusion trajectory and the photon trace are seeded, so repeated runs of the same project reproduce the same decay and quantum yield exactly. Leave unset for an independent random run; the photon trace then uses a faster multi-threaded kernel. + +### `save_avs` + +**Label:** Save AV files +**Type:** `boolean` + +Whether to save the calculated accessible volume grids as XYZ files. + +### `skip_frame` + +**Label:** Trajectory skip frames +**Type:** `integer` + +Subsampling factor for writing trajectory frames to coordinates files. + +### `slow_radius` + +**Label:** Slowing radius +**Type:** `number` +**Unit:** `Å` + +Radius around each whole-protein amino-acid center where that residue type contributes its slow_factor to the diffusion coefficient grid. + +## FRET Acceptor + +### `fret.R0_matrix` + +**Label:** Förster radius +**Type:** `number` +**Unit:** `Å` + +Förster radius R0 of the donor–acceptor pair, in Ångström like every other length in a project. Stored as the donor→acceptor cell of fret.R0_matrix; the transfer rate scales as (R0/r)^6, so entering nanometres makes FRET vanish. Typical xanthene pairs are 45–65 Å. + +### `fret.acceptor_dynamics` + +**Label:** Acceptor dynamics +**Type:** `choice` + +How the acceptor is treated: 'trajectory' simulates its Brownian walk with its own diffusion coefficient and stickiness and uses the instantaneous donor-acceptor distance, 'averaged' averages over its static accessible volume (the fast-acceptor limit, valid only when it explores that volume quickly compared with the donor lifetime). The two disagree because a cloud is weighted uniformly while a trajectory is weighted by where the dye dwells. + +### `fret.dyes.1.D` + +**Label:** Acceptor diffusion coefficient +**Type:** `number` +**Unit:** `Ų/ns` + +Diffusion coefficient of the FRET acceptor dye when not interacting with the protein surface. + +### `fret.dyes.1.amino_acid_interactions` + +**Label:** Acceptor interactions +**Type:** `table` + +Per-residue-type interaction table for the acceptor, same shape as the donor's amino_acid_interactions. Only slow_factor is used, since QuEst reports the donor's decay and the acceptor's own PET quenching would change how bright the acceptor is, not the donor. Defaults to the donor's table. + +### `fret.dyes.1.attachment.atom` + +**Label:** Acceptor atom +**Type:** `text` + +Atom name where the FRET acceptor dye is attached. + +### `fret.dyes.1.attachment.chain` + +**Label:** Acceptor chain +**Type:** `text` + +Chain identifier of the residue where the FRET acceptor dye is attached. + +### `fret.dyes.1.attachment.residue` + +**Label:** Acceptor residue +**Type:** `integer` + +Residue sequence number where the FRET acceptor dye is attached. + +### `fret.dyes.1.av_parameter.linker_length` + +**Label:** Acceptor linker length +**Type:** `number` +**Unit:** `Å` + +Maximum distance from attachment point to the center of the FRET acceptor dye. + +### `fret.dyes.1.av_parameter.linker_width` + +**Label:** Acceptor linker width +**Type:** `number` +**Unit:** `Å` + +Width of the linker tethering the FRET acceptor dye. + +### `fret.dyes.1.av_parameter.radius1` + +**Label:** Acceptor dye radius +**Type:** `number` +**Unit:** `Å` + +Exclusion radius representing the FRET acceptor dye sphere. + +### `fret.dyes.1.slow_radius` + +**Label:** Acceptor slowing radius +**Type:** `number` +**Unit:** `Å` + +Radius around each amino-acid centre within which that residue slows the acceptor. Separate from the donor's: a cyanine and a rhodamine do not adhere to a protein surface in the same way. Defaults to the donor's value. + +### `fret.enabled` + +**Label:** FRET enabled +**Type:** `boolean` + +Whether a FRET acceptor dye is simulated to compute FRET efficiency and decay curves. + +### `fret.kappa2` + +**Label:** Orientation factor κ² +**Type:** `number` + +Orientation factor κ² of the transfer, between 0 (perpendicular transition dipoles) and 4 (collinear). QuEst does not model it: the dye is a point diffusing in a volume and has no dipole to orient, so this is the averaging regime you are asserting. The default 2/3 is the isotropic dynamic average, which is what a published Förster radius already assumes — leaving it there reproduces the rate exactly. Raise it only with evidence that both dyes are orientationally restricted. + +## Quenching + +### `amino_acid_interactions` + +**Label:** Amino-acid interactions +**Type:** `table` + +Per-residue-type interaction table. Each entry holds slow_factor (0-1, how much the residue slows the diffusing dye), kQ (quenching rate in 1/ns applied on contact), quench_radius (contact radius in Angstrom from the dye centre; null inherits critical_distance) and quench_atoms (atom names whose centroid defines the quenching centre). Only residues with a redox-active side chain quench by default: TRP, TYR, MET, HIS, CYS and PRO. + +### `amino_acid_interactions.kQ` + +**Label:** Quenching rate kQ +**Type:** `number` +**Unit:** `1/ns` + +Rate at which this residue type quenches the dye while the two are in contact. Contributions from residues whose contact spheres overlap add up. + +### `amino_acid_interactions.quench_atoms` + +**Label:** Quenching centre atoms +**Type:** `list` + +Atom names whose centroid defines this residue's quenching centre. The defaults follow the redox-active moiety that mediates photo-induced electron transfer: the indole ring for TRP, the phenol ring for TYR, the imidazole ring for HIS, SD for MET and SG for CYS - not CB. + +### `amino_acid_interactions.quench_radius` + +**Label:** Contact radius +**Type:** `number` +**Unit:** `Å` + +Distance from the dye centre to this residue's quenching centre within which quenching occurs. Leave empty to inherit the project-wide critical_distance. + +### `amino_acid_interactions.slow_factor` + +**Label:** Slow factor +**Type:** `number` + +Factor between 0 and 1 scaling the dye's diffusion coefficient near this residue type, modelling unspecific stickiness. Overlapping residues multiply their factors. + +### `critical_distance` + +**Label:** Fallback contact radius +**Type:** `number` +**Unit:** `Å` + +Contact radius used by residue types that do not define their own quench_radius. It is measured from the dye centre to the residue's quenching centre, so it must exceed the dye radius plus van der Waals contact (typically 7-9 A for a 3.5 A dye). ## CLI override examples @@ -113,7 +368,7 @@ Located under `fret.dyes`. The first entry is the donor; the second (optional) i - Sweep linker length and residue: ```bash quest simulate -p project.quest.json \ - --grid linker.length=10.0,12.5 \ + --grid av_parameter.linker_length=10.0,12.5 \ --grid attachment.residue=25,30,35 ``` diff --git a/examples/01_donor_quenching.py b/examples/01_donor_quenching.py new file mode 100644 index 0000000..f337b30 --- /dev/null +++ b/examples/01_donor_quenching.py @@ -0,0 +1,75 @@ +"""Simulate the fluorescence decay of a dye tethered to a protein. + +What QuEst does, in one run: build the dye's accessible volume, diffuse it there +under Brownian dynamics, and let photo-induced electron transfer from nearby +amino acids quench it. The output is a decay curve you could compare with a +TCSPC measurement, plus the numbers that summarise it. + + python examples/01_donor_quenching.py +""" + +from __future__ import annotations + +import numpy as np + +from _common import example_project +from quest.api import simulate_project, top_quenchers + + +def main() -> int: + # Residue 100 of T4 lysozyme sits next to a tryptophan, so the quenching is + # unmistakable. Try 55 for a site the dye barely quenches at. + project = example_project(chain="E", residue=100) + print(f"Structure : {project['pdb']}") + site = project["attachment"] + print(f"Labeling : chain {site['chain']}, residue {site['residue']}, atom {site['atom']}") + + # save_outputs=False keeps the run in memory; set it True to get a + # jobs// directory with the decay, the volumes and the point clouds. + result = simulate_project(project, save_outputs=False) + + print("\n--- Decay -------------------------------------------------------") + print(f" bins {result.time.size} over {result.time[-1]:.1f} ns") + print(f" photons collected {int(result.donor_counts.sum()):,}") + + print("\n--- Derived quantities ------------------------------------------") + print(f" quantum yield {result.quantum_yield_donor:.4f}") + print(f" mean lifetime {result.lifetime_donor:.3f} ns (tau0 = {project['tau0']} ns)") + print(f" contact fraction {result.collisions_fraction * 100:.2f} %") + print(f" accessible volume {result.av_volume:.0f} A^3") + print(f" contact volume {result.contact_volume:.0f} A^3") + + # Quenching is resolved per residue type: this is what makes the answer + # interpretable rather than just a number. + print("\n--- What quenches the dye ---------------------------------------") + ranked = top_quenchers(result.aa_residence, limit=5) + if not ranked: + print(" nothing: the dye never reaches a quenching residue from here") + # top_quenchers is the summary; result.aa_residence has the full table, + # including how long the dye spent near each residue type. + residence = {row["residue_name"]: row for row in (result.aa_residence or [])} + for entry in ranked: + row = residence.get(entry["residue_name"], {}) + print( + f" {entry['residue_name']:>4s}" + f" {entry['quench_rate_fraction'] * 100:5.1f} % of the quenching" + f" in contact {row.get('fraction_near', 0.0) * 100:6.3f} % of frames" + f" ({row.get('event_count', 0)} visits)" + ) + + # The decay is multi-exponential even though the dye has one unquenched + # lifetime: the dye samples environments that quench it differently. + counts = result.donor_counts + peak = int(np.argmax(counts)) + tail = counts[peak:] + positive = tail > 0 + if positive.sum() > 10: + slope = np.polyfit(result.time[peak:][positive], np.log(tail[positive]), 1)[0] + print(f"\n single-exponential fit of the tail: {-1 / slope:.2f} ns") + print(" (compare with the mean lifetime above; they differ because the") + print(" decay is not single-exponential)") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/examples/02_fret_pair.py b/examples/02_fret_pair.py new file mode 100644 index 0000000..50987e1 --- /dev/null +++ b/examples/02_fret_pair.py @@ -0,0 +1,66 @@ +"""Simulate a FRET pair: donor, acceptor, and the transfer between them. + +The donor diffuses through its accessible volume while the transfer rate is +evaluated *per frame*, so FRET responds to where the dye actually is rather +than to one averaged distance. + + python examples/02_fret_pair.py +""" + +from __future__ import annotations + +import numpy as np + +from _common import example_project +from quest.api import simulate_project +from quest.project import DEFAULT_FORSTER_RADIUS + + +def fret_project(donor: int, acceptor: int, r0: float = DEFAULT_FORSTER_RADIUS): + """A donor/acceptor project. `r0` is a Forster radius in **Angstrom**.""" + project = example_project(with_fret=True, residue=donor) + project["fret"]["dyes"][1]["attachment"] = { + "chain": "E", "residue": acceptor, "atom": "CB", + } + project["fret"]["R0_matrix"] = [[None, r0], [r0, None]] + return project + + +def main() -> int: + donor, acceptor = 55, 132 + result = simulate_project(fret_project(donor, acceptor), save_outputs=False) + + print(f"donor site E:{donor}") + print(f"acceptor site E:{acceptor}") + print(f"Forster radius {DEFAULT_FORSTER_RADIUS} A (Angstrom — a value in nm switches FRET off)") + + print("\n--- Yields -------------------------------------------------------") + print(f" donor alone {result.quantum_yield_donor:.4f}") + print(f" donor + acceptor {result.quantum_yield_fret:.4f}") + print(f" transfer efficiency {result.fret_efficiency:.4f}") + + # E(t) = f_DA(t) / f_D0(t): the time-resolved transfer efficiency, which is + # what a distance distribution is deconvolved from (notebook 03). + t = result.time + fd0 = result.donor_counts.astype(float) + fda = result.fret_counts.astype(float) + # Skip the first nanosecond: the histogram's leading bins carry the + # excitation spike, where the ratio of two decays is meaningless. + usable = (fd0 > 20.0) & (t > 1.0) & (t < 20.0) + et = 1.0 - fda[usable] / fd0[usable] + print("\n--- E(t) ---------------------------------------------------------") + print(f" early ({t[usable][0]:.1f} ns) {et[0]:.3f}") + print(f" late ({t[usable][-1]:.1f} ns) {et[-1]:.3f}") + + # A smaller Forster radius must transfer less. Cheap, and it catches a unit + # mistake immediately. + weak = simulate_project(fret_project(donor, acceptor, r0=35.0), save_outputs=False) + print("\n--- Sanity: efficiency follows R0 --------------------------------") + print(f" R0 = 52 A -> E = {result.fret_efficiency:.3f}") + print(f" R0 = 35 A -> E = {weak.fret_efficiency:.3f}") + assert weak.fret_efficiency < result.fret_efficiency + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/examples/03_labeling_scan.py b/examples/03_labeling_scan.py new file mode 100644 index 0000000..9f65ede --- /dev/null +++ b/examples/03_labeling_scan.py @@ -0,0 +1,54 @@ +"""Choose a labeling site: simulate several, compare what quenches them. + +This is the question QuEst exists to answer before an experiment — which +position gives a dye that is bright, or deliberately quenched. + + python examples/03_labeling_scan.py +""" + +from __future__ import annotations + +from _common import example_project +from quest.scan import scan_positions + + +def main() -> int: + # Candidate sites on chain E of T4 lysozyme. + candidates = { + f"E:{residue}": { + "chain_identifier": "E", + "residue_seq_number": residue, + "atom_name": "CB", + } + for residue in (15, 55, 100, 132) + } + + project = example_project() + print(f"scanning {len(candidates)} sites on {project['pdb']}\n") + + header = f"{'site':>8s} {'QY':>6s} {'tau [ns]':>8s} {'contact':>8s} quenched by" + print(header) + print("-" * len(header)) + + # scan_positions never raises: a buried or unlabelable site is reported as + # data, so one bad candidate cannot abort the scan. + for record in scan_positions(project, candidates): + if record["status"] != "success": + print(f"{record['name']:>8s} failed: {record['error'][:48]}") + continue + quencher = record["dominant_quencher"] or "-" + share = record["dominant_quencher_fraction"] + share_text = f"{share * 100:.0f}%" if share else "" + print( + f"{record['name']:>8s} {record['quantum_yield']:6.3f} " + f"{record['lifetime']:8.2f} {record['contact_fraction'] * 100:7.1f}% " + f"{quencher} {share_text}" + ) + + print("\nA bright site (high QY) reports the dye faithfully; a quenched one") + print("is sensitive to its environment. Which you want depends on the experiment.") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/examples/_common.py b/examples/_common.py new file mode 100644 index 0000000..34f3376 --- /dev/null +++ b/examples/_common.py @@ -0,0 +1,79 @@ +"""Shared setup for the examples. + +The examples are meant to run in a few seconds each, so they use a small test +protein and short trajectories. Real work uses longer ones -- every example says +where to turn the knobs up. +""" + +from __future__ import annotations + +import os +import sys +from pathlib import Path + +__all__ = ["example_structure", "example_project"] + +REPO_ROOT = Path(__file__).resolve().parents[1] + +# Run *this* checkout, whatever the current directory is. Without this an +# editable install elsewhere on the machine can win -- on this machine the +# `quest` distribution is installed editable from a different checkout, so an +# example run from `examples/` would silently exercise that one instead. +if str(REPO_ROOT) not in sys.path: + sys.path.insert(0, str(REPO_ROOT)) + + +def example_structure() -> Path: + """Return the structure the examples label: T4 lysozyme (PDB 148L). + + Override with ``QUEST_EXAMPLE_STRUCTURE`` to run any example against your + own structure. + """ + + override = os.environ.get("QUEST_EXAMPLE_STRUCTURE") + if override: + return Path(override).expanduser() + + for candidate in ( + REPO_ROOT / "examples" / "data" / "148l.pdb", + REPO_ROOT / "tests" / "148l.pdb", + ): + if candidate.exists(): + return candidate + raise FileNotFoundError( + "No example structure found. Set QUEST_EXAMPLE_STRUCTURE to a PDB/CIF " + "file, or run from a source checkout." + ) + + +def example_project(*, with_fret: bool = False, chain: str = "E", residue: int = 100): + """A small, fast QuEst project on the example structure. + + Parameters are deliberately modest so an example finishes in seconds: + + ============ ======== =============================================== + parameter here production + ============ ======== =============================================== + ``t_max`` 400 ns tens of microseconds, so the dye samples its + whole accessible volume many times over + ``n_photons`` 200 000 millions, for smooth decay statistics + ``dg`` 0.5 Å 0.5 Å is already fine; coarser trades accuracy + ============ ======== =============================================== + """ + + from quest.project import template_project + + project = template_project(with_fret=with_fret) + project["pdb"] = str(example_structure()) + project["attachment"] = {"chain": chain, "residue": residue, "atom": "CB"} + project["fret"]["dyes"][0]["attachment"] = dict(project["attachment"]) + + project.update( + t_max=400.0, + t_step=0.02, + n_photons=200_000, + n_bins=256, + # Reproducible output: drop this for an independent Monte-Carlo sample. + random_seed=2026, + ) + return project diff --git a/notebooks/01_quenching.ipynb b/notebooks/01_quenching.ipynb new file mode 100644 index 0000000..fa553e1 --- /dev/null +++ b/notebooks/01_quenching.ipynb @@ -0,0 +1,111 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Dynamic PET quenching of a tethered dye\n", + "\n", + "The decay of a dye on a flexible linker, from the structure alone. QuEst builds\n", + "the dye's accessible volume, diffuses it there, and quenches it by\n", + "photo-induced electron transfer whenever it touches an electron-rich side\n", + "chain.\n", + "\n", + "This replaces the old `mfm`-based notebooks: same science, current API." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "from pathlib import Path\n", + "\n", + "sys.path.insert(0, str(Path.cwd() if (Path.cwd() / \"quest_notebook.py\").exists() else Path.cwd() / \"notebooks\"))\n", + "from quest_notebook import REPO, STRUCTURE, quick_project, fret_project\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "print(\"structure:\", STRUCTURE.name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from quest.api import simulate_project, top_quenchers\n", + "\n", + "result = simulate_project(quick_project(residue=100), save_outputs=False)\n", + "print(f\"quantum yield {result.quantum_yield_donor:.4f}\")\n", + "print(f\"mean lifetime {result.lifetime_donor:.3f} ns (tau0 = 4.2 ns)\")\n", + "print(f\"contact {result.collisions_fraction * 100:.1f} % of frames\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Which residues do the quenching\n", + "\n", + "Every run reports the contribution per residue type. Residue 100 sits next to a\n", + "tryptophan, and the attribution says so." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "for entry in top_quenchers(result.aa_residence, limit=5):\n", + " print(f\"{entry['residue_name']:>4s} {entry['quench_rate_fraction'] * 100:5.1f} % of the quenching\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## The decay is not single-exponential\n", + "\n", + "The dye has one unquenched lifetime, but it samples environments that quench it\n", + "differently \u2014 so the observable decay is a superposition." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "quenched = simulate_project(quick_project(100), save_outputs=False)\n", + "free = simulate_project(quick_project(15), save_outputs=False)\n", + "\n", + "fig, ax = plt.subplots(figsize=(6, 4))\n", + "for label, r in ((\"residue 100 (next to TRP)\", quenched), (\"residue 15 (little quenching)\", free)):\n", + " counts = np.clip(r.donor_counts, 1e-1, None)\n", + " ax.semilogy(r.time, counts / counts.max(), label=f\"{label}: QY {r.quantum_yield_donor:.2f}\")\n", + "ax.set_xlabel(\"time [ns]\"); ax.set_ylabel(\"normalised counts\")\n", + "ax.set_xlim(0, 25); ax.legend(); ax.set_title(\"Donor decay at two labelling sites\")\n", + "plt.tight_layout()\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/02_fret.ipynb b/notebooks/02_fret.ipynb new file mode 100644 index 0000000..14100ee --- /dev/null +++ b/notebooks/02_fret.ipynb @@ -0,0 +1,120 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# FRET: donor, acceptor, and the time-resolved efficiency\n", + "\n", + "Two dyes on the same protein. QuEst simulates the donor's diffusion and\n", + "evaluates the transfer rate **per trajectory frame**, so the FRET channel\n", + "responds to where the dye actually is.\n", + "\n", + "Reproduces the FRET part of the old `simulate_decays_for_structure` notebook." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "from pathlib import Path\n", + "\n", + "sys.path.insert(0, str(Path.cwd() if (Path.cwd() / \"quest_notebook.py\").exists() else Path.cwd() / \"notebooks\"))\n", + "from quest_notebook import REPO, STRUCTURE, quick_project, fret_project\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "print(\"structure:\", STRUCTURE.name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from quest.api import simulate_project\n", + "\n", + "# R0 is in Angstrom, like every length in a project. A value in\n", + "# nanometres (~5.5) is ten times too small and switches FRET off silently.\n", + "pair = fret_project(donor=55, acceptor=132)\n", + "result = simulate_project(pair, save_outputs=False)\n", + "\n", + "print(f\"donor QY {result.quantum_yield_donor:.4f}\")\n", + "print(f\"donor QY with A {result.quantum_yield_fret:.4f}\")\n", + "print(f\"transfer efficiency {result.fret_efficiency:.4f}\")\n" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Both decays, and E(t)\n", + "\n", + "The FRET channel decays faster; the ratio of the two is the time-resolved\n", + "transfer efficiency, which is what the E(t) analysis works on." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "t = result.time\n", + "fd0 = np.clip(result.donor_counts.astype(float), 1e-9, None)\n", + "fda = np.clip(result.fret_counts.astype(float), 1e-9, None)\n", + "\n", + "fig, (ax, bx) = plt.subplots(1, 2, figsize=(11, 4))\n", + "ax.semilogy(t, fd0 / fd0.max(), label=\"donor only\")\n", + "ax.semilogy(t, fda / fda.max(), label=\"donor + acceptor\")\n", + "ax.set_xlim(0, 25); ax.set_xlabel(\"time [ns]\"); ax.set_ylabel(\"normalised counts\")\n", + "ax.legend(); ax.set_title(\"Decays\")\n", + "\n", + "valid = (fd0 > 1.0) & (t < 20)\n", + "bx.plot(t[valid], 1.0 - fda[valid] / fd0[valid])\n", + "bx.set_xlabel(\"time [ns]\"); bx.set_ylabel(\"E(t)\"); bx.set_ylim(0, 1)\n", + "bx.set_title(\"Time-resolved transfer efficiency\")\n", + "plt.tight_layout()" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Efficiency responds to the F\u00f6rster radius\n", + "\n", + "A sanity check that costs one more run: a smaller R0 must transfer less." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "weak = simulate_project(fret_project(55, 132, r0=35.0), save_outputs=False)\n", + "print(f\"R0 = 52 A -> E = {result.fret_efficiency:.3f}\")\n", + "print(f\"R0 = 35 A -> E = {weak.fret_efficiency:.3f}\")\n", + "assert weak.fret_efficiency < result.fret_efficiency\n" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/03_et_distance_distribution.ipynb b/notebooks/03_et_distance_distribution.ipynb new file mode 100644 index 0000000..e34f768 --- /dev/null +++ b/notebooks/03_et_distance_distribution.ipynb @@ -0,0 +1,143 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# From E(t) to a donor\u2013acceptor distance distribution\n", + "\n", + "The analysis at the heart of the E(t) paper, rebuilt on the current API: take\n", + "the time-resolved transfer efficiency, and deconvolve it into a distribution of\n", + "donor\u2013acceptor distances.\n", + "\n", + "A donor at distance $R$ decays as $\\exp[-t/\\tau_0 (1 + (R_0/R)^6)]$, so a\n", + "mixture of distances gives\n", + "\n", + "$$ f_{DA}(t) / f_{D0}(t) = \\int p(R)\\, e^{-t/\\tau_0 (R_0/R)^6} \\, dR $$\n", + "\n", + "which is a linear problem in $p(R)$ \u2014 solved here with non-negative least\n", + "squares and a smoothness penalty. The old notebook used `mfm`'s\n", + "`calc_transfer_matrix` and `solve_nnls`; both are a few lines of NumPy/SciPy." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "import sys\n", + "from pathlib import Path\n", + "\n", + "sys.path.insert(0, str(Path.cwd() if (Path.cwd() / \"quest_notebook.py\").exists() else Path.cwd() / \"notebooks\"))\n", + "from quest_notebook import REPO, STRUCTURE, quick_project, fret_project\n", + "\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "\n", + "print(\"structure:\", STRUCTURE.name)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from scipy.optimize import nnls\n", + "from quest.project import DEFAULT_FORSTER_RADIUS\n", + "from quest.api import simulate_project\n", + "\n", + "R0 = DEFAULT_FORSTER_RADIUS\n", + "TAU0 = 4.2\n", + "\n", + "p = fret_project(donor=55, acceptor=132, r0=R0, n_photons=400_000, tau0=TAU0, random_seed=11)\n", + "result = simulate_project(p, save_outputs=False)\n", + "print(\"E =\", round(result.fret_efficiency, 3))\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "def transfer_matrix(t, r_axis, r0=R0, tau0=TAU0):\n", + " \"\"\"Column j is the FRET-induced decay of a pair at distance r_axis[j].\"\"\"\n", + " k = (1.0 / tau0) * (r0 / r_axis[None, :]) ** 6\n", + " return np.exp(-t[:, None] * k)\n", + "\n", + "t = result.time\n", + "fd0 = result.donor_counts.astype(float)\n", + "fda = result.fret_counts.astype(float)\n", + "\n", + "# Use the part of the decay with real statistics.\n", + "usable = (fd0 > 20.0) & (t < 20.0)\n", + "t_fit = t[usable]\n", + "et = fda[usable] / fd0[usable]\n", + "\n", + "r_axis = np.linspace(20.0, 90.0, 96)\n", + "A = transfer_matrix(t_fit, r_axis)\n", + "\n", + "# Second-difference smoothness penalty: without it NNLS answers with spikes.\n", + "penalty = 0.05 * np.sqrt(len(t_fit))\n", + "D = np.diff(np.eye(len(r_axis)), n=2, axis=0)\n", + "A_reg = np.vstack([A, penalty * D])\n", + "b_reg = np.concatenate([et, np.zeros(D.shape[0])])\n", + "\n", + "p_r, residual = nnls(A_reg, b_reg)\n", + "p_r = p_r / p_r.sum()\n", + "mean_r = float((p_r * r_axis).sum())\n", + "print(f\"recovered = {mean_r:.1f} A\")" + ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "## Cross-check against the accessible volumes\n", + "\n", + "The distance distribution came from the *decay*. The accessible volumes give an\n", + "independent estimate of the same quantity \u2014 the F\u00f6rster-averaged distance\n", + "\u27e8R_DA\u27e9_E \u2014 so the two should agree to within a few \u00c5ngstr\u00f6m." + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from quest.core import build_donor_from_project\n", + "\n", + "model = build_donor_from_project(p)\n", + "model.update_all(verbose=False)\n", + "rda_e = model.rda_mean_e(n_samples=20000)\n", + "print(f\"from the AV clouds : _E = {rda_e:.1f} A\")\n", + "print(f\"from the decay : = {mean_r:.1f} A\")\n", + "print(f\"difference : {abs(rda_e - mean_r):.1f} A\")\n", + "\n", + "fig, ax = plt.subplots(figsize=(6, 4))\n", + "ax.plot(r_axis, p_r, lw=2)\n", + "ax.axvline(rda_e, color=\"k\", ls=\"--\", label=f\"$\\\\langle R_{{DA}}\\\\rangle_E$ from AVs = {rda_e:.0f} A\")\n", + "ax.axvline(mean_r, color=\"C3\", ls=\":\", label=f\"mean of p(R) = {mean_r:.0f} A\")\n", + "ax.set_xlabel(\"$R_{DA}$ [A]\"); ax.set_ylabel(\"p(R)\")\n", + "ax.set_title(\"Distance distribution deconvolved from E(t)\")\n", + "ax.legend(); plt.tight_layout()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "name": "python", + "version": "3.12" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/Laplace-diffusion_fret.ipynb b/notebooks/04_diffusion_modulated_fret.ipynb similarity index 91% rename from notebooks/Laplace-diffusion_fret.ipynb rename to notebooks/04_diffusion_modulated_fret.ipynb index a10d621..87e77c4 100644 --- a/notebooks/Laplace-diffusion_fret.ipynb +++ b/notebooks/04_diffusion_modulated_fret.ipynb @@ -19,10 +19,17 @@ "cell_type": "markdown", "metadata": {}, "source": [ - "# Laplace diffusion FRET demo (updated)\n", + "# Diffusion-modulated FRET, solved as a PDE\n", "\n", - "This notebook solves a 1D Laplace diffusion equation with distance-dependent FRET,\n", - "ported from the original nbformat 3 / Python 2 version to nbformat 4 / Python 3.\n" + "The Haas-Steinberg equation: donor-acceptor distance diffusion and FRET treated\n", + "analytically on a 1D distance coordinate, rather than by simulating a\n", + "trajectory.\n", + "\n", + "It is the companion to notebook 02. QuEst answers the same question by Monte\n", + "Carlo \u2014 diffusing the dye through its accessible volume and generating photons \u2014\n", + "which needs no assumed p(R) but costs a simulation. This one takes p(R) and the\n", + "mutual diffusion coefficient as given and integrates the population directly, so\n", + "it is the faster way to see *how* diffusion reshapes a FRET decay.\n" ] }, { @@ -233,4 +240,4 @@ ] } ] -} \ No newline at end of file +} diff --git a/notebooks/dye_quenching_simulation.ipynb b/notebooks/dye_quenching_simulation.ipynb deleted file mode 100644 index 9622a6d..0000000 --- a/notebooks/dye_quenching_simulation.ipynb +++ /dev/null @@ -1,213 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# QuEst dye quenching and FRET demo (headless)\n", - "\n", - "This notebook is a port of the legacy `mfm`-based *Dye-quenching* example to the current QuEst backend.\n", - "\n", - "It reproduces the same conceptual steps as the original notebook:\n", - "\n", - "- **Structure-based accessible volume (AV)** around a labeled residue on hGBP1.\n", - "- **Diffusion-based dye quenching** by protein residues within a critical distance.\n", - "- **Photon-based donor decay simulation** and quantum yield estimate.\n", - "- **Optional FRET channel** using an acceptor dye on the same structure and a Förster radius.\n", - "\n", - "All calculations are performed via the GUI-free `quest.lib.tools.dye_diffusion.dye_diffusion.DonorDecay` API so the notebook can run headless." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "import sys\n", - "from pathlib import Path\n", - "\n", - "import numpy as np\n", - "import matplotlib.pyplot as p\n", - "\n", - "# Resolve repository root when running from repo root or this notebook folder\n", - "try:\n", - " ROOT = Path(__file__).resolve().parents[2]\n", - "except NameError:\n", - " ROOT = Path().resolve()\n", - " if not (ROOT / \"modules\" / \"quest\").exists():\n", - " ROOT = Path().resolve().parents[2]\n", - "\n", - "QUEST_ROOT = ROOT / \"modules\" / \"quest\"\n", - "if str(QUEST_ROOT) not in sys.path:\n", - " sys.path.insert(0, str(QUEST_ROOT))\n", - "\n", - "from quest.lib.tools.dye_diffusion.dye_diffusion import DonorDecay\n", - "\n", - "PDB_HGBP1_CLOSED = ROOT / \"test\" / \"data\" / \"atomic_coordinates\" / \"pdb_files\" / \"hGBP1_closed.pdb\"\n", - "\n", - "\n", - "# --- Donor-only dye quenching -------------------------------------------------\n", - "\n", - "# Parameters chosen to mirror the original legacy example as closely as possible.\n", - "# - hGBP1 closed structure\n", - "# - Attachment at residue 344 CB\n", - "# - Surface sticking with slow_radius / slow_fact\n", - "# - All quenching residues treated as potential quenchers within critical_distance\n", - "\n", - "donor = DonorDecay(\n", - " tau0=4.0,\n", - " kQ=0.5,\n", - " nph=24_000_000, # photons for \"photon\"-style decay\n", - " verbose=False,\n", - " auto_update=False,\n", - " pdb=None,\n", - " attachment_residue=344,\n", - " attachment_atom=\"CB\",\n", - " attachment_chain=None, # no explicit chain in hGBP1_closed.pdb\n", - " dg=0.5,\n", - " sticky_mode=\"surface\",\n", - " save_avs=False,\n", - " D=23.0,\n", - " slow_fact=0.6,\n", - " critical_distance=5.1,\n", - " output_file=\"dye_quenching_demo\",\n", - " av_parameter={\"linker_length\": 20.0, \"linker_width\": 0.5, \"radius1\": 2.0},\n", - " quencher={\"TRP\": [\"CB\"], \"TYR\": [\"CB\"], \"HIS\": [\"CB\"]},\n", - " t_max=500.0,\n", - " t_step=0.032,\n", - " slow_radius=8.5,\n", - " all_quencher_atoms=True,\n", - ")\n", - "\n", - "donor.structure = str(PDB_HGBP1_CLOSED)\n", - "\n", - "# One full update performs: AV -> slow AV -> diffusion -> photon trace\n", - "success = donor.update_all(verbose=False)\n", - "if not success:\n", - " raise RuntimeError(\"Diffusion trajectory simulation failed for donor dye.\")\n", - "\n", - "# \"Curve\" vs \"photon\" styles: reuse the same diffusion but vary photon statistics.\n", - "# First, a moderate-photon curve-style decay.\n", - "\n", - "donor.n_photons = 1_000_000\n", - "# Reset photon trace so it will be recomputed\n", - "try:\n", - " donor._photon_trace = None # type: ignore[attr-defined]\n", - "except Exception:\n", - " pass\n", - "x_curve, y_curve = donor.get_histogram(nbins=4096, range=(0, 50))\n", - "y_curve = y_curve.astype(float)\n", - "y_curve_norm = y_curve / (y_curve.max() if y_curve.max() > 0 else 1.0)\n", - "\n", - "# Now a high-statistics \"photon\"-style decay.\n", - "\n", - "donor.n_photons = 24_000_000\n", - "try:\n", - " donor._photon_trace = None # type: ignore[attr-defined]\n", - "except Exception:\n", - " pass\n", - "x_photon, y_photon = donor.get_histogram(nbins=4096, range=(0, 50))\n", - "y_photon = y_photon.astype(float)\n", - "y_photon_norm = y_photon / (y_photon.max() if y_photon.max() > 0 else 1.0)\n", - "\n", - "print(f\"Quantum yield (donor): {donor.quantum_yield:.3f}\")\n", - "print(f\"Collisions fraction: {donor.collisions:.3f}\")\n", - "\n", - "# Plot donor curve vs photon decays on a semilogarithmic scale\n", - "p.figure(figsize=(6, 4))\n", - "p.semilogy(x_curve, y_curve_norm + 1e-4, label=\"curve-style\")\n", - "p.semilogy(x_photon, y_photon_norm + 1e-4, label=\"photon-style\")\n", - "p.xlabel(\"time (ns)\")\n", - "p.ylabel(\"normalized counts\")\n", - "p.legend()\n", - "p.tight_layout()\n", - "p.show()\n", - "\n", - "# Time axis for the underlying diffusion trajectory (analogous to diffusion_donor.time)\n", - "traj = donor.diffusion._traj # type: ignore[attr-defined]\n", - "time_axis = np.arange(traj.shape[0]) * donor.diffusion.t_step\n", - "\n", - "\n", - "# --- FRET-decay (optional) ----------------------------------------------------\n", - "\n", - "# Set up a donor/acceptor pair on the same structure, approximating the\n", - "# legacy example (donor at residue 254, acceptor at residue 577, both CB).\n", - "\n", - "fret = DonorDecay(\n", - " tau0=4.0,\n", - " kQ=0.5,\n", - " nph=1_000_000,\n", - " verbose=False,\n", - " auto_update=False,\n", - " pdb=None,\n", - " attachment_residue=254,\n", - " attachment_atom=\"CB\",\n", - " attachment_chain=None,\n", - " dg=0.5,\n", - " sticky_mode=\"surface\",\n", - " save_avs=False,\n", - " D=23.0,\n", - " slow_fact=0.6,\n", - " critical_distance=5.1,\n", - " output_file=\"dye_quenching_fret_demo\",\n", - " av_parameter={\"linker_length\": 20.0, \"linker_width\": 0.5, \"radius1\": 2.0},\n", - " quencher={\"TRP\": [\"CB\"], \"TYR\": [\"CB\"], \"HIS\": [\"CB\"]},\n", - " t_max=500.0,\n", - " t_step=0.032,\n", - " slow_radius=8.5,\n", - " all_quencher_atoms=True,\n", - ")\n", - "\n", - "fret.structure = str(PDB_HGBP1_CLOSED)\n", - "\n", - "# Enable FRET: acceptor AV, Förster radius, and acceptor attachment site.\n", - "fret.fret_enabled = True\n", - "fret.fret_R0 = 52.0\n", - "fret.acceptor_chain = None\n", - "fret.acceptor_residue = 577\n", - "fret.acceptor_atom = \"CB\"\n", - "\n", - "success_fret = fret.update_all(verbose=False)\n", - "if not success_fret:\n", - " raise RuntimeError(\"Diffusion trajectory simulation failed for FRET pair.\")\n", - "\n", - "x_fret, y_fret = fret.get_histogram_fret(nbins=4096, range=(0, 50))\n", - "if x_fret is not None and y_fret is not None:\n", - " y_fret = y_fret.astype(float)\n", - " y_fret_norm = y_fret / (y_fret.max() if y_fret.max() > 0 else 1.0)\n", - "\n", - " print(f\"Quantum yield (FRET channel): {fret.quantum_yield_fret:.3f}\")\n", - " print(f\"FRET efficiency (Donor->Acceptor): {fret.fret_efficiency:.3f}\")\n", - "\n", - " p.figure(figsize=(6, 4))\n", - " p.semilogy(x_curve, y_curve_norm + 1e-4, label=\"donor (no FRET)\")\n", - " p.semilogy(x_fret, y_fret_norm + 1e-4, label=\"FRET channel\")\n", - " p.xlabel(\"time (ns)\")\n", - " p.ylabel(\"normalized counts\")\n", - " p.legend()\n", - " p.tight_layout()\n", - " p.show()\n", - "else:\n", - " print(\"FRET decay could not be computed (no acceptor AV or invalid geometry).\")\n" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "pygments_lexer": "ipython3" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} diff --git a/notebooks/quenching_and_fret (2).ipynb b/notebooks/quenching_and_fret (2).ipynb deleted file mode 100644 index c2055c6..0000000 --- a/notebooks/quenching_and_fret (2).ipynb +++ /dev/null @@ -1,679 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "W:\\User\\Papers\\E(t)-paper\\Software\\141216\n" - ] - } - ], - "source": [ - "cd W:\\User\\Papers\\E(t)-paper\\Software\\141216" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "import mfm\n", - "from mfm.fluorescence.fps.dynamic import Sticking, Dye, ProteinQuenching, DiffusionSimulationParameter, \\\n", - " DiffusionSimulation\n", - "from mfm.fluorescence.simulation.dye_diffusion import DyeDecay, DecaySimulationParameter, FRETDecay\n", - "from mfm.fitting.models.tcspc.tcspc import FretParameter\n", - "from mfm.fitting.optimization import solve_nnls, maxent\n", - "import numpy as np\n", - "import itertools\n", - "import pylab as p\n", - "\n", - "mfm.verbose = False" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Custom functions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First I define some custom function for batch processing of decays." - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def simulate_decays(dyes, decay_parameter, simulation_parameter, quenching_parameter, save_decays=True,\n", - " directory=\"./\"):\n", - " dye_decays = dict()\n", - "\n", - " for dye_key in dyes:\n", - " print \"Simulating decay: %s\" % dye_key\n", - " dye = dyes[dye_key]\n", - " diffusion_simulation = DiffusionSimulation(dye,\n", - " quenching_parameter,\n", - " simulation_parameter)\n", - " diffusion_simulation.update()\n", - " diffusion_simulation.save('%sD_diffusion.xyz' % dye_key, mode='xyz', skip=5)\n", - " av = diffusion_simulation.av\n", - " av.save('%sD' % dye_key)\n", - "\n", - " fd0_sim_curve = DyeDecay(decay_parameter, diffusion_simulation)\n", - " fd0_sim_curve.update()\n", - " decay = fd0_sim_curve.get_histogram()\n", - " print \"QY: %s\" % fd0_sim_curve.quantum_yield\n", - " filename = \"Donor-%s.txt\" % dye_key\n", - " decay = np.vstack(decay)\n", - " if save_decays:\n", - " np.savetxt(directory+filename, decay.T)\n", - " dye_decays[dye_key] = decay\n", - " return dye_decays" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "def simulate_fret_decays(donors, acceptors, decay_parameter, simulation_parameter, donor_quenching, acceptor_quenching,\n", - " fret_parameter, save=True, directory=\"./\"):\n", - " donor_keys = donors.keys()\n", - " acceptor_keys = acceptors.keys()\n", - " fret_decays = dict(\n", - " (donor_key, dict()) for donor_key in donor_keys\n", - " )\n", - " \n", - " distances = dict(\n", - " (donor_key, dict()) for donor_key in donor_keys\n", - " )\n", - " \n", - " dye_combinations = itertools.product(donor_keys, acceptor_keys)\n", - " for donor_key, acceptor_key in dye_combinations:\n", - " print \"Simulating: %sD-%sA\" % (donor_key, acceptor_key)\n", - " donor = donors[donor_key]\n", - " acceptor = acceptors[acceptor_key]\n", - "\n", - " donor_diffusion_simulation = DiffusionSimulation(donor,\n", - " donor_quenching,\n", - " simulation_parameter)\n", - " donor_diffusion_simulation.update()\n", - "\n", - " acceptor_diffusion_simulation = DiffusionSimulation(acceptor,\n", - " acceptor_quenching,\n", - " simulation_parameter)\n", - " acceptor_diffusion_simulation.update()\n", - "\n", - " fret_sim = FRETDecay(donor_diffusion_simulation, acceptor_diffusion_simulation,\n", - " fret_parameter, decay_parameter)\n", - " fret_sim.update()\n", - " decay = fret_sim.get_histogram()\n", - " decay = np.vstack(decay)\n", - " if save:\n", - " np.savetxt(directory+\"FRET-%sD-%sA-dRDA.txt\" % (donor_key, acceptor_key), fret_sim.dRDA.T)\n", - " np.savetxt(directory+\"FRET-%sD-%sA.txt\" % (donor_key, acceptor_key), decay.T)\n", - " fret_decays[donor_key][acceptor_key] = decay\n", - " distances[donor_key][acceptor_key] = np.histogram(fret_sim.dRDA, bins=np.linspace(0, 150, 150), density=True)\n", - " return fret_decays, distances" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Simulation parameters" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Structure" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are two PDBs of hGBP1. Both PDBs are coarse grained models of hGBP1. In the coarse model the sidechains are stripped. Instead of the stripped sidechain are pseudo atom was placed at the center of mass of the side-chain. The program identifies the type of the sidechain by the name of the amino-acid. In one PDB the names of the natural amino-acids were used. In the second PDB the names of the natural quenchers (TYR, TRP, HIS, PRO, MET) were replaced by ALA.\n", - "\n", - "Given the PDB-files now a new structure object is generated and the simulation parameters are set." - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "#pdb_file = '../sample_data/model/hgbp1/hGBP1.pdb' # This PDB quenched the dye\n", - "pdb_file = 'W:/User/Papers/E(t)-paper/Figures/old/Diffusion_simulation/Diffusion_simulation/PDBs/All_Ala_hGBP1/hGBP1_coarse_all_ala.pdb' # This PDB does not quench the dye\n", - "structure = mfm.Structure(pdb_file)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## General Parameters" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "save_directory = \"./tmp/\"" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## FRET-parameter" - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "tau0 = 4.1\n", - "forster_radius = 52.0\n", - "kappa2 = 0.667\n", - "\n", - "fret_parameter = FretParameter(tau0=tau0,\n", - " forster_radius=forster_radius,\n", - " kappa2=kappa2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Dye-definitions" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "diffusion_coefficient_donor = 30.0 # A2/ns - Stas-paper 7.0 A2/ns\n", - "diffusion_coefficient_acceptor = diffusion_coefficient_donor * 0.5 # A2/ns - Stas-paper 1.5 A2/ns\n", - "slow_factor = 0.1 # Diffusion multiplier in boundary - best 0.1\n", - "slow_radius = 8.5 # Defines surface area - best 8.5\n", - "directory = \"./tmp/\" # This directory is used for saving" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Donor" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "#donor_labeling_positions = [18, 254, 577, 344, 481, 496, 525, 540, 577]\n", - "donor_labeling_positions = [379]\n", - "donor_chains = ['A']*len(donor_labeling_positions)\n", - "\n", - "donor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=1.0,\n", - ")\n", - "\n", - "donor_sticking = Sticking(structure, donor_quenching,\n", - " sticky_mode='surface',\n", - " slow_radius=slow_radius,\n", - " slow_fact=slow_factor) # Stas-paper Dye-MD (roughly 10%)\n", - "\n", - "donor_dyes = dict(\n", - " [\n", - " (pos,\n", - " Dye(donor_sticking,\n", - " attachment_residue=pos,\n", - " attachment_chain=chain,\n", - " attachment_atom='CB',\n", - " critical_distance=3.0 + 5.5, # 3.0 Ang von AV + 6.0 Ang only C-beta quench (so far best 5.0 + 3.0)\n", - " diffusion_coefficient=diffusion_coefficient_donor, # Stas-paper (Dye-MD 30 A2/ns)\n", - " av_radius=3.0,\n", - " av_length=22.0, # 20 + 5 = 3.5 + 21.5\n", - " tau0=4.2)\n", - " )\n", - " for pos, chain in zip(donor_labeling_positions, donor_chains)\n", - " ]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Acceptor" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "#acceptor_labeling_positions = [18, 254, 577 , 344, 481, 496, 525, 540, 577]\n", - "acceptor_labeling_positions = [467]\n", - "acceptor_chains = ['A']*len(donor_labeling_positions)\n", - "acceptor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=0.8)\n", - "\n", - "acceptor_sticking = Sticking(structure, acceptor_quenching,\n", - " sticky_mode='surface',\n", - " slow_radius=slow_radius,\n", - " slow_fact=slow_factor) # Stas-paper Dye-MD (roughly 10%)\n", - "acceptor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=0.8)\n", - "acceptor_dyes = dict(\n", - " [\n", - " (pos,\n", - " Dye(donor_sticking,\n", - " attachment_residue=pos,\n", - " attachment_chain=chain,\n", - " attachment_atom='CB',\n", - " critical_distance=0.0, # The acceptor dye does not have to be quenched setting this to zero speeds up calulation\n", - " diffusion_coefficient=diffusion_coefficient_acceptor,\n", - " av_radius=3.5,\n", - " tau0=1.0)\n", - " )\n", - " for pos, chain in zip(acceptor_labeling_positions, acceptor_chains)\n", - " ]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Simulation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Donor-decay" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now the simulation parameters are set." - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "simulation_parameter = DiffusionSimulationParameter(t_max=512000,\n", - " t_step=0.064)\n", - "decay_parameter = DecaySimulationParameter(decay_mode='photon',\n", - " n_photons=50.0e6,\n", - " tac_range=(0, 20),\n", - " dt_tac=0.016)\n", - "#decay_parameter = DecaySimulationParameter(decay_mode='curve',\n", - "# n_curves=25000,\n", - "# n_tac = 4096,\n", - "# dt_tac=0.016)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Simulating decay: 379\n", - "QY: 0.998514509716\n" - ] - } - ], - "source": [ - "donor_decays = simulate_decays(donor_dyes, decay_parameter, simulation_parameter, donor_quenching, directory=save_directory)" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "(1249L,)\n" - ] - } - ], - "source": [ - "for k in donor_decays:\n", - " p.semilogy(donor_decays[k][0], donor_decays[k][1], label='%s' % k)\n", - "p.legend()\n", - "p.show()\n", - "print donor_decays[379][0].shape" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## FRET-decay" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Simulating: 379D-467A\n" - ] - } - ], - "source": [ - "fret_decays, distance_distributions = simulate_fret_decays(donor_dyes, acceptor_dyes, decay_parameter, simulation_parameter, \n", - " donor_quenching, acceptor_quenching, fret_parameter,\n", - " directory=save_directory)" - ] - }, - { - "cell_type": "code", - "execution_count": 16, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "for donor_key in donor_decays:\n", - " t, fd0 = donor_decays[donor_key]\n", - " p.semilogy(t, fd0)\n", - " fret = fret_decays[donor_key]\n", - " for acceptor_key in fret:\n", - " t, fda = fret_decays[donor_key][acceptor_key]\n", - " p.semilogy(t, fda)\n", - " p.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## E(t)-decay" - ] - }, - { - "cell_type": "code", - "execution_count": 17, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "et_decays = dict(\n", - " (donor_key, dict(\n", - " (acceptor_key, (fret_decays[donor_key][acceptor_key][0], fret_decays[donor_key][acceptor_key][1]/donor_decays[donor_key][1]))\n", - " for acceptor_key in fret_decays[donor_key].keys()\n", - " )\n", - " ) for donor_key in donor_decays.keys()\n", - ")\n", - "\n", - "for donor_key in donor_decays:\n", - " t, fd0 = donor_decays[donor_key]\n", - " fret = fret_decays[donor_key]\n", - " for acceptor_key in fret:\n", - " t, et = et_decays[donor_key][acceptor_key]\n", - " p.semilogy(t, et)\n", - " p.show()" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Deconvolution of E(t)-decay" - ] - }, - { - "cell_type": "code", - "execution_count": 18, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 18, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "t_matrix, r_DA = mfm.fluorescence.calc_transfer_matrix(t, rDA_min=10.0, rDA_max=128.0, n_steps=1024, space='lin', \n", - " kappa2=kappa2, tau0=tau0, R0=forster_radius)\n", - "p.imshow(t_matrix)" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\nRU5ErkJggg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\nQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Recovered mean: 50.8969465522\n", - "True mean : 54.8252447567\n" - ] - } - ], - "source": [ - "regularization_factor = 1.0\n", - "\n", - "for donor_key in et_decays:\n", - " et_a = fret_decays[donor_key]\n", - " for acceptor_key in et_a:\n", - " t, et = et_decays[donor_key][acceptor_key]\n", - " \n", - " t_matrix, r_DA = mfm.fluorescence.calc_transfer_matrix(t, rDA_min=10.0, rDA_max=100.0, n_steps=128, space='lin', \n", - " kappa2=kappa2, tau0=tau0, R0=forster_radius)\n", - " t_matrix[t_matrix < 0.0] = 0.0\n", - " \n", - " #p_rDA = maxent(t_matrix.T, et, regularization_factor)\n", - " p_rDA = solve_nnls(t_matrix, et, regularization_factor)\n", - " #p_rDA = np.linalg.lstsq(t_matrix.T, et, regularization_factor)[0]\n", - " hist, edges = distance_distributions[donor_key][acceptor_key]\n", - " \n", - " p.plot(r_DA, p_rDA)\n", - " p.plot(edges[:-1], hist)\n", - " p.show()\n", - "\n", - " p.semilogx(forster_radius**6 / r_DA**6, p_rDA)\n", - " p.semilogx(forster_radius**6 / edges[:-1]**6, hist)\n", - " p.show()\n", - "\n", - " print \"Recovered mean: %s\" % (np.dot(r_DA, p_rDA/sum(p_rDA)))\n", - " print \"True mean : %s\" % (np.dot(edges[:-1], hist/sum(hist)))" - ] - }, - { - "cell_type": "code", - "execution_count": 20, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "np.savetxt(\"./tmp/r_axis.txt\", r_DA)\n", - "np.savetxt(\"./tmp/sticking_p_30.0_15.0_rDA.txt\", p_rDA)" - ] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 2", - "language": "python", - "name": "python2" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.11" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/notebooks/quenching_and_fret.ipynb b/notebooks/quenching_and_fret.ipynb deleted file mode 100644 index a5cadb1..0000000 --- a/notebooks/quenching_and_fret.ipynb +++ /dev/null @@ -1,605 +0,0 @@ -{ - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "cd \\\\psf\\Home\\Documents\\ChiSurf\\devel" - ], - "language": "python" - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "%matplotlib inline" - ], - "language": "python" - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "import mfm\n", - "from mfm.fluorescence.fps.dynamic import Sticking, Dye, ProteinQuenching, DiffusionSimulationParameter, \\\n", - " DiffusionSimulation\n", - "from mfm.fluorescence.simulation.dye_diffusion import DyeDecay, DecaySimulationParameter, FRETDecay\n", - "from mfm.fitting.models.tcspc.tcspc import FretParameter\n", - "from mfm.fitting.optimization import solve_nnls\n", - "import numpy as np\n", - "import itertools\n", - "\n", - "mfm.verbose = False" - ], - "language": "python", - "prompt_number": 76 - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 1, - "source": [ - "Custom functions" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "First I define some custom function for batch processing of decays." - ] - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "def simulate_decays(dyes, decay_parameter, simulation_parameter, quenching_parameter, save_decays=True,\n", - " directory=\"./\"):\n", - " dye_decays = dict()\n", - "\n", - " for dye_key in dyes:\n", - " print \"Simulating decay: %s\" % dye_key\n", - " dye = dyes[dye_key]\n", - " diffusion_simulation = DiffusionSimulation(dye,\n", - " quenching_parameter,\n", - " simulation_parameter)\n", - " diffusion_simulation.update()\n", - " diffusion_simulation.save('%sD_diffusion.xyz' % dye_key, mode='xyz', skip=5)\n", - " av = diffusion_simulation.av\n", - " av.save('%sD' % dye_key)\n", - "\n", - " fd0_sim_curve = DyeDecay(decay_parameter, diffusion_simulation)\n", - " fd0_sim_curve.update()\n", - " decay = fd0_sim_curve.get_histogram()\n", - " print fd0_sim_curve.quantum_yield\n", - " filename = \"Donor-%s.txt\" % dye_key\n", - " decay = np.vstack(decay)\n", - " if save_decays:\n", - " np.savetxt(directory+filename, decay.T)\n", - " dye_decays[dye_key] = decay\n", - " return dye_decays" - ], - "language": "python", - "prompt_number": 77 - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "def simulate_fret_decays(donors, acceptors, decay_parameter, simulation_parameter, donor_quenching, acceptor_quenching,\n", - " fret_parameter, save=True, directory=\"./\"):\n", - " donor_keys = donors.keys()\n", - " acceptor_keys = acceptors.keys()\n", - " fret_decays = dict(\n", - " (donor_key, dict()) for donor_key in donor_keys\n", - " )\n", - " \n", - " distances = dict(\n", - " (donor_key, dict()) for donor_key in donor_keys\n", - " )\n", - " \n", - " dye_combinations = itertools.product(donor_keys, acceptor_keys)\n", - " for donor_key, acceptor_key in dye_combinations:\n", - " print \"Simulating: %sD-%sA\" % (donor_key, acceptor_key)\n", - " donor = donors[donor_key]\n", - " acceptor = acceptors[acceptor_key]\n", - "\n", - " donor_diffusion_simulation = DiffusionSimulation(donor,\n", - " donor_quenching,\n", - " simulation_parameter)\n", - " donor_diffusion_simulation.update()\n", - "\n", - " acceptor_diffusion_simulation = DiffusionSimulation(acceptor,\n", - " acceptor_quenching,\n", - " simulation_parameter)\n", - " acceptor_diffusion_simulation.update()\n", - "\n", - " fret_sim = FRETDecay(donor_diffusion_simulation, acceptor_diffusion_simulation,\n", - " fret_parameter, decay_parameter)\n", - " fret_sim.update()\n", - " decay = fret_sim.get_histogram()\n", - " decay = np.vstack(decay)\n", - " if save:\n", - " np.savetxt(directory+\"FRET-%sD-%sA-dRDA.txt\" % (donor_key, acceptor_key), fret_sim.dRDA.T)\n", - " np.savetxt(directory+\"FRET-%sD-%sA.txt\" % (donor_key, acceptor_key), decay.T)\n", - " fret_decays[donor_key][acceptor_key] = decay\n", - " distances[donor_key][acceptor_key] = np.histogram(fret_sim.dRDA, bins=np.linspace(0, 150, 150), density=True)\n", - " return fret_decays, distances" - ], - "language": "python", - "prompt_number": 78 - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 1, - "source": [ - "Simulation parameters" - ] - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 2, - "source": [ - "Structure" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are two PDBs of hGBP1. Both PDBs are coarse grained models of hGBP1. In the coarse model the sidechains are stripped. Instead of the stripped sidechain are pseudo atom was placed at the center of mass of the side-chain. The program identifies the type of the sidechain by the name of the amino-acid. In one PDB the names of the natural amino-acids were used. In the second PDB the names of the natural quenchers (TYR, TRP, HIS, PRO, MET) were replaced by ALA.\n", - "\n", - "Given the PDB-files now a new structure object is generated and the simulation parameters are set." - ] - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "#pdb_file = '../sample_data/model/hgbp1/hGBP1.pdb'\n", - "pdb_file = '../sample_data/model/hgbp1/hGBP1_coarse_all_ala.pdb'\n", - "structure = mfm.Structure(pdb_file)" - ], - "language": "python", - "prompt_number": 79 - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 2, - "source": [ - "FRET-parameter" - ] - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "tau0 = 4.1\n", - "forster_radius = 52.0\n", - "kappa2 = 0.667\n", - "\n", - "fret_parameter = FretParameter(tau0=tau0,\n", - " forster_radius=forster_radius,\n", - " kappa2=kappa2)" - ], - "language": "python", - "prompt_number": 80 - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 2, - "source": [ - "Dye-definitions" - ] - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "diffusion_coefficient_donor = 1.5 # A2/ns\n", - "diffusion_coefficient_acceptor = 1.5 # A2/ns\n", - "directory = \"./tmp/\" # This directory is used for saving" - ], - "language": "python", - "prompt_number": 225 - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 2, - "source": [ - "Donor" - ] - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "#donor_labeling_positions = [18, 254, 577, 344, 481, 496, 525, 540, 577]\n", - "donor_labeling_positions = [379]\n", - "donor_chains = ['A']*len(donor_labeling_positions)\n", - "\n", - "donor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=1.0,\n", - ")\n", - "\n", - "donor_sticking = Sticking(structure, donor_quenching,\n", - " sticky_mode='surface',\n", - " slow_radius=8.5,\n", - " slow_fact=0.1) # Stas-paper Dye-MD (roughly 10%)\n", - "\n", - "donor_dyes = dict(\n", - " [\n", - " (pos,\n", - " Dye(donor_sticking,\n", - " attachment_residue=pos,\n", - " attachment_chain=chain,\n", - " attachment_atom='CB',\n", - " critical_distance=3.0 + 5.5, # 3.0 Ang von AV + 6.0 Ang only C-beta quench (so far best 5.0 + 3.0)\n", - " diffusion_coefficient=diffusion_coefficient_donor, # Stas-paper (Dye-MD 30 A2/ns)\n", - " av_radius=3.0,\n", - " av_length=22.0, # 20 + 5 = 3.5 + 21.5\n", - " tau0=4.2)\n", - " )\n", - " for pos, chain in zip(donor_labeling_positions, donor_chains)\n", - " ]\n", - ")" - ], - "language": "python", - "prompt_number": 226 - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 2, - "source": [ - "Acceptor" - ] - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "#acceptor_labeling_positions = [18, 254, 577 , 344, 481, 496, 525, 540, 577]\n", - "acceptor_labeling_positions = [467]\n", - "acceptor_chains = ['A']*len(donor_labeling_positions)\n", - "acceptor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=0.8)\n", - "\n", - "acceptor_sticking = Sticking(structure, acceptor_quenching,\n", - " sticky_mode='surface',\n", - " slow_radius=8.5,\n", - " slow_fact=0.1) # Stas-paper Dye-MD (roughly 10%)\n", - "acceptor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=0.8)\n", - "acceptor_dyes = dict(\n", - " [\n", - " (pos,\n", - " Dye(donor_sticking,\n", - " attachment_residue=pos,\n", - " attachment_chain=chain,\n", - " attachment_atom='CB',\n", - " critical_distance=0.0, # The acceptor dye does not have to be quenched setting this to zero speeds up calulation\n", - " diffusion_coefficient=diffusion_coefficient_acceptor,\n", - " av_radius=3.5,\n", - " tau0=1.0)\n", - " )\n", - " for pos, chain in zip(acceptor_labeling_positions, acceptor_chains)\n", - " ]\n", - ")" - ], - "language": "python", - "prompt_number": 227 - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 1, - "source": [ - "Simulation" - ] - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 2, - "source": [ - "Donor-decay" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now the simulation parameters are set." - ] - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "simulation_parameter = DiffusionSimulationParameter(t_max=8000,\n", - " t_step=0.016)\n", - "decay_parameter = DecaySimulationParameter(decay_mode='curve',\n", - " n_photons=1.0e6,\n", - " n_curves=250000,\n", - " tac_range=(0, 50),\n", - " dt_tac=0.016)" - ], - "language": "python", - "prompt_number": 228 - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "Simulating decay: 379\n1.0", - "text": [ - "Simulating decay: 379\n1.0" - ] - }, - { - "output_type": "stream", - "stream": "\n", - "text": [ - "\n" - ] - } - ], - "input": [ - "donor_decays = simulate_decays(donor_dyes, decay_parameter, simulation_parameter, donor_quenching)" - ], - "language": "python", - "prompt_number": 229 - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [ - { - "output_type": "display_data", - "png": "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\n/wEoWIpFKCKhQgAAAABJRU5ErkJggg==\n", - "text": [ - "" - ], - "metadata": {} - } - ], - "input": [ - "import pylab as p\n", - "for k in donor_decays:\n", - " p.semilogy(donor_decays[k][0], donor_decays[k][1], label='%s' % k)\n", - "p.legend()\n", - "p.show()" - ], - "language": "python", - "prompt_number": 230 - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 2, - "source": [ - "FRET-decay" - ] - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "Simulating: 379D-467A\n", - "text": [ - "Simulating: 379D-467A\n" - ] - } - ], - "input": [ - "fret_decays, distance_distributions = simulate_fret_decays(donor_dyes, acceptor_dyes, decay_parameter, simulation_parameter, \n", - " donor_quenching, acceptor_quenching, fret_parameter)" - ], - "language": "python", - "prompt_number": 231 - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [ - { - "output_type": "display_data", - "png": "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\nUlnA/wMUFDbsi+nBKwAAAABJRU5ErkJggg==\n", - "text": [ - "" - ], - "metadata": {} - } - ], - "input": [ - "for donor_key in donor_decays:\n", - " t, fd0 = donor_decays[donor_key]\n", - " p.semilogy(t, fd0)\n", - " fret = fret_decays[donor_key]\n", - " for acceptor_key in fret:\n", - " t, fda = fret_decays[donor_key][acceptor_key]\n", - " p.semilogy(t, fda)\n", - " p.show()" - ], - "language": "python", - "prompt_number": 232 - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 2, - "source": [ - "E(t)-decay" - ] - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "et_decays = dict(\n", - " (donor_key, dict(\n", - " (acceptor_key, (fret_decays[donor_key][acceptor_key][0], fret_decays[donor_key][acceptor_key][1]/donor_decays[donor_key][1]))\n", - " for acceptor_key in fret_decays[donor_key].keys()\n", - " )\n", - " ) for donor_key in donor_decays.keys()\n", - ")" - ], - "language": "python", - "prompt_number": 233 - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "" - ], - "language": "python" - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [ - { - "output_type": "display_data", - "png": "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\nULEXEUmB/wN8ld7wdIYJjQAAAABJRU5ErkJggg==\n", - "text": [ - "" - ], - "metadata": {} - } - ], - "input": [ - "for donor_key in donor_decays:\n", - " t, fd0 = donor_decays[donor_key]\n", - " fret = fret_decays[donor_key]\n", - " for acceptor_key in fret:\n", - " t, et = et_decays[donor_key][acceptor_key]\n", - " p.semilogy(t, et)\n", - " p.show()" - ], - "language": "python", - "prompt_number": 234 - }, - { - "cell_type": "heading", - "metadata": {}, - "level": 2, - "source": [ - "Deconvolution of E(t)-decay" - ] - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [ - { - "output_type": "display_data", - "png": "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\n", - "text": [ - "" - ], - "metadata": {} - } - ], - "input": [ - "t_matrix, r_DA = mfm.fluorescence.calc_transfer_matrix(t, rDA_min=10.0, rDA_max=100.0, n_steps=1024, space='lin', \n", - " kappa2=kappa2, tau0=tau0, R0=forster_radius)\n", - "#p.imshow(t_matrix)\n", - "p.plot(t_matrix[500])\n", - "p.show()" - ], - "language": "python", - "prompt_number": 235 - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "et = fda / fd0\n", - "\n", - "regularization_factor = 0.002\n", - "\n", - "for donor_key in et_decays:\n", - " et_a = fret_decays[donor_key]\n", - " for acceptor_key in et_a:\n", - " t, et = et_decays[donor_key][acceptor_key]\n", - " \n", - " t_matrix, r_DA = mfm.fluorescence.calc_transfer_matrix(t, rDA_min=0.0, rDA_max=100.0, n_steps=4096, space='lin', \n", - " kappa2=kappa2, tau0=tau0, R0=forster_radius)\n", - " t_matrix[t_matrix < 0.0] = 0.0\n", - " \n", - " #p_rDA = solve_nnls(t_matrix, et, regularization_factor)\n", - " p_rDA = np.linalg.lstsq(t_matrix.T, et, regularization_factor)[0]\n", - " hist, edges = distance_distributions[donor_key][acceptor_key]\n", - " \n", - " p.plot(r_DA, p_rDA)\n", - " #p.plot(edges[:-1], hist)\n", - " p.show()" - ], - "language": "python" - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "p.plot(r_DA, p_rDA)\n", - "p.show()" - ], - "language": "python" - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "import scipy.sparse\n", - "\n", - "p_rDA = np.linalg.lstsq(t_matrix.T, et, regularization_factor)[0]\n", - "p.plot(r_DA, p_rDA)\n", - "\n", - "p_rDA = scipy.sparse.linalg.gmres(t_matrix.T, et)\n", - "p.plot(r_DA, p_rDA)" - ], - "language": "python" - } - ] - } - ], - "cells": [], - "metadata": { - "name": "", - "signature": "sha256:8a5f9637f1dc498b9d75df265ffc19d5ff769fae1fff099ef5b0d1613c8b30c1" - }, - "nbformat": 3, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/notebooks/quest_core_headless.ipynb b/notebooks/quest_core_headless.ipynb deleted file mode 100644 index d0bb9da..0000000 --- a/notebooks/quest_core_headless.ipynb +++ /dev/null @@ -1,133 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# QuEST headless API demo (quest.core)\n", - "\n", - "This notebook shows how to use the GUI-free QuEST backend in scripts or notebooks via `quest.core` (also re-exported by `quest.api`).\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "import json\n", - "import sys\n", - "from pathlib import Path\n", - "\n", - "# Resolve repository root (works when running from repo root or this notebook folder)\n", - "try:\n", - " ROOT = Path(__file__).resolve().parents[2]\n", - "except NameError:\n", - " ROOT = Path().resolve()\n", - " if not (ROOT / 'modules' / 'quest').exists():\n", - " # If launched from modules/quest/notebooks, go two levels up\n", - " ROOT = Path().resolve().parents[2]\n", - "\n", - "QUEST_ROOT = ROOT / 'modules' / 'quest'\n", - "if str(QUEST_ROOT) not in sys.path:\n", - " sys.path.insert(0, str(QUEST_ROOT))\n", - "\n", - "from quest.core import load_project, simulate_project\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def make_minimal_project(with_fret: bool = False) -> dict:\n", - " project: dict = {}\n", - " project['pdb'] = str(ROOT / 'test' / 'data' / 'atomic_coordinates' / 'pdb_files' / '148l.pdb')\n", - " project['attachment'] = {'chain': 'E', 'residue': 10, 'atom': 'CB'}\n", - " project['av_parameter'] = {'linker_length': 21.5, 'linker_width': 0.5, 'radius1': 3.5}\n", - " project['dg'] = 0.5\n", - " project['slow_radius'] = 8.5\n", - " project['t_max'] = 200.0\n", - " project['t_step'] = 0.05\n", - " project['n_photons'] = 3000\n", - " project['n_bins'] = 128\n", - " project['skip_frame'] = 5\n", - " project['tau0'] = 4.2\n", - " project['kQ'] = 2.0\n", - " project['slow_fact'] = 0.1\n", - " project['critical_distance'] = 6.5\n", - " project['quencher'] = {'TYR': ['CB']}\n", - " project['output_file'] = 'example_out'\n", - " project['save_avs'] = False\n, - " project['all_quencher_atoms'] = True\n", - " project['sticky_mode'] = 'quencher'\n", - " project['fret'] = {'enabled': with_fret, 'dyes': [], 'R0_matrix': []}\n", - "\n", - " if with_fret:\n", - " # Minimal donor+acceptor definition; adjust to your system\n", - " project['fret']['dyes'] = [\n", - " {\n", - " 'name': 'D0',\n", - " 'role': 'donor',\n", - " 'attachment': project['attachment'],\n", - " 'av_parameter': project['av_parameter'],\n", - " 'D': 7.0,\n", - " },\n", - " {\n", - " 'name': 'A0',\n", - " 'role': 'acceptor',\n", - " 'attachment': {'chain': 'A', 'residue': 20, 'atom': 'CA'},\n", - " 'av_parameter': project['av_parameter'],\n", - " 'D': 6.5,\n", - " },\n", - " ]\n", - " project['fret']['R0_matrix'] = [[0.0, 55.0], [55.0, 0.0]]\n", - "\n", - " return project\n", - "\n", - "project = make_minimal_project(with_fret=False)\n", - "result = simulate_project(project)\n", - "\n", - "print(f"Quantum yield (donor): {result.quantum_yield_donor:.3f}")\n", - "print(f"Collisions fraction: {result.collisions_fraction:.3f}")\n", - "print(f"Time bins: {result.time.shape[0]}, counts shape: {result.donor_counts.shape}")\n", - "if result.fret_counts is not None:\n", - " print(f"FRET efficiency: {result.fret_efficiency:.3f}")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tips\n", - "- To override parameters, edit the `project` dictionary before calling `simulate_project`.\n", - "- To persist and reload projects, use `path.write_text(json.dumps(project))` then `load_project(path)`.\n", - "- The `quest.api` module re-exports the same functions if you prefer that import path.\n" - ] - } - ], - "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/quest_core_headless_demo.ipynb b/notebooks/quest_core_headless_demo.ipynb deleted file mode 100644 index 84181fb..0000000 --- a/notebooks/quest_core_headless_demo.ipynb +++ /dev/null @@ -1,130 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# QuEST headless API demo (quest.core)\n", - "\n", - "Use the GUI-free backend from notebooks or scripts. The same objects are re-exported via `quest.api`.\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "from __future__ import annotations\n", - "\n", - "import sys\n", - "from pathlib import Path\n", - "\n", - "# Resolve repository root when running from repo root or this notebook folder\n", - "try:\n", - " ROOT = Path(__file__).resolve().parents[2]\n", - "except NameError:\n", - " ROOT = Path().resolve()\n", - " if not (ROOT / 'modules' / 'quest').exists():\n", - " ROOT = Path().resolve().parents[2]\n", - "\n", - "QUEST_ROOT = ROOT / 'modules' / 'quest'\n", - "if str(QUEST_ROOT) not in sys.path:\n", - " sys.path.insert(0, str(QUEST_ROOT))\n", - "\n", - "from quest.core import load_project, simulate_project\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "def make_minimal_project(with_fret: bool = False) -> dict:\n", - " project: dict = {}\n", - " project['pdb'] = str(ROOT / 'test' / 'data' / 'atomic_coordinates' / 'pdb_files' / '148l.pdb')\n", - " project['attachment'] = {'chain': 'E', 'residue': 10, 'atom': 'CB'}\n", - " project['av_parameter'] = {'linker_length': 21.5, 'linker_width': 0.5, 'radius1': 3.5}\n", - " project['dg'] = 0.5\n", - " project['slow_radius'] = 8.5\n", - " project['t_max'] = 200.0\n", - " project['t_step'] = 0.05\n", - " project['n_photons'] = 3000\n", - " project['n_bins'] = 128\n", - " project['skip_frame'] = 5\n", - " project['tau0'] = 4.2\n", - " project['kQ'] = 2.0\n", - " project['slow_fact'] = 0.1\n", - " project['critical_distance'] = 6.5\n", - " project['quencher'] = {'TYR': ['CB']}\n", - " project['output_file'] = 'example_out'\n", - " project['save_avs'] = False\n", - " project['all_quencher_atoms'] = True\n", - " project['sticky_mode'] = 'quencher'\n", - " project['fret'] = {'enabled': with_fret, 'dyes': [], 'R0_matrix': []}\n", - "\n", - " if with_fret:\n", - " project['fret']['dyes'] = [\n", - " {\n", - " 'name': 'D0',\n", - " 'role': 'donor',\n", - " 'attachment': project['attachment'],\n", - " 'av_parameter': project['av_parameter'],\n", - " 'D': 7.0,\n", - " },\n", - " {\n", - " 'name': 'A0',\n", - " 'role': 'acceptor',\n", - " 'attachment': {'chain': 'A', 'residue': 20, 'atom': 'CA'},\n", - " 'av_parameter': project['av_parameter'],\n", - " 'D': 6.5,\n", - " },\n", - " ]\n", - " project['fret']['R0_matrix'] = [[0.0, 55.0], [55.0, 0.0]]\n", - "\n", - " return project\n", - "\n", - "project = make_minimal_project(with_fret=False)\n", - "result = simulate_project(project)\n", - "\n", - "print(f\"Quantum yield (donor): {result.quantum_yield_donor:.3f}\")\n", - "print(f\"Collisions fraction: {result.collisions_fraction:.3f}\")\n", - "print(f\"Time bins: {result.time.shape[0]}, counts shape: {result.donor_counts.shape}\")\n", - "if result.fret_counts is not None:\n", - " print(f\"FRET efficiency: {result.fret_efficiency:.3f}\")\n" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Tips\n", - "- To override parameters, edit the `project` dictionary before calling `simulate_project`.\n", - "- To persist and reload projects, use `path.write_text(json.dumps(project))` then `load_project(path)`.\n", - "- The `quest.api` module re-exports the same functions if you prefer that import path.\n" - ] - } - ], - "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/quest_notebook.py b/notebooks/quest_notebook.py new file mode 100644 index 0000000..f72d09c --- /dev/null +++ b/notebooks/quest_notebook.py @@ -0,0 +1,67 @@ +"""Shared setup for the QuEst notebooks. + +Keeps the boilerplate — finding the checkout, the example structure, a small +fast project — in one place instead of repeating it in every notebook. +""" + +from __future__ import annotations + +import sys +from pathlib import Path + +__all__ = ["REPO", "STRUCTURE", "quick_project", "fret_project"] + + +def _repo() -> Path: + here = Path.cwd() + for candidate in (here, *here.parents): + if (candidate / "quest" / "__init__.py").exists(): + return candidate + raise RuntimeError("run these notebooks from inside a QuEst checkout") + + +REPO = _repo() +if str(REPO) not in sys.path: + # Ahead of any editable install from another checkout. + sys.path.insert(0, str(REPO)) + +#: T4 lysozyme — small, well studied, and it has the tryptophan that makes +#: PET quenching unmistakable. +STRUCTURE = REPO / "tests" / "148l.pdb" + + +def quick_project(residue: int = 100, chain: str = "E", **overrides): + """A donor-only project that finishes in seconds. + + Production runs use tens of microseconds and millions of photons; these + settings are chosen so a notebook stays interactive. + """ + from quest.project import template_project + + project = template_project(with_fret=False) + project["pdb"] = str(STRUCTURE) + project["attachment"] = {"chain": chain, "residue": residue, "atom": "CB"} + project["fret"]["dyes"][0]["attachment"] = dict(project["attachment"]) + project.update( + t_max=400.0, t_step=0.02, n_photons=200_000, n_bins=256, random_seed=2026 + ) + project.update(overrides) + return project + + +def fret_project(donor: int = 55, acceptor: int = 132, r0: float | None = None, **overrides): + """A donor+acceptor project. ``r0`` is a Forster radius in **Angstrom**.""" + from quest.project import DEFAULT_FORSTER_RADIUS, template_project + + radius = DEFAULT_FORSTER_RADIUS if r0 is None else float(r0) + project = template_project(with_fret=True) + project["pdb"] = str(STRUCTURE) + project["attachment"] = {"chain": "E", "residue": donor, "atom": "CB"} + project["fret"]["dyes"][0]["attachment"] = dict(project["attachment"]) + project["fret"]["dyes"][1]["attachment"] = {"chain": "E", "residue": acceptor, "atom": "CB"} + project["fret"]["R0_matrix"] = [[None, radius], [radius, None]] + project.update( + t_max=400.0, t_step=0.02, n_photons=200_000, n_bins=256, random_seed=7 + ) + project.update(overrides) + return project diff --git a/notebooks/simulate_decays_for_structure(1).ipynb b/notebooks/simulate_decays_for_structure(1).ipynb deleted file mode 100644 index a992d33..0000000 --- a/notebooks/simulate_decays_for_structure(1).ipynb +++ /dev/null @@ -1,817 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "C:\\atlastin\n" - ] - } - ], - "source": [ - "cd C:\\atlastin" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "from collections import OrderedDict\n", - "import mfm\n", - "from mfm.fluorescence.fps.dynamic import Sticking, Dye, ProteinQuenching, DiffusionSimulationParameter, \\\n", - " DiffusionSimulation\n", - "from mfm.fluorescence.simulation.dye_diffusion import DyeDecay, DecaySimulationParameter, FRETDecay\n", - "from mfm.fitting.models.tcspc.tcspc import FretParameter\n", - "from mfm.fitting.optimization import solve_nnls\n", - "import numpy as np\n", - "import itertools\n", - "import os\n", - "mfm.verbose = False\n", - "\n", - "\n", - "def simulate_fret_decays(donors, acceptors, decay_parameter, \n", - " simulation_parameter, donor_quenching, acceptor_quenching,\n", - " fret_parameter, save=True, directory=\"./\", \n", - " dye_combinations=None, donor_decays=None):\n", - " donor_keys = donors.keys()\n", - " acceptor_keys = acceptors.keys()\n", - " fret_decays = list()\n", - " \n", - " distances = list()\n", - " eff = list()\n", - " if dye_combinations is None:\n", - " dye_combinations = itertools.product(donor_keys, acceptor_keys)\n", - " \n", - " for donor_key, acceptor_key in dye_combinations:\n", - " print \"Simulating: %sD-%sA\" % (donor_key, acceptor_key)\n", - " fn = directory+file_prefix+\"_FRET-%sD-%sA_\" % (donor_key, acceptor_key)\n", - "\n", - " donor = donors[donor_key]\n", - " acceptor = acceptors[acceptor_key]\n", - "\n", - " donor_diffusion_simulation = DiffusionSimulation(donor,\n", - " donor_quenching,\n", - " simulation_parameter)\n", - " donor_diffusion_simulation.update()\n", - "\n", - " acceptor_diffusion_simulation = DiffusionSimulation(acceptor,\n", - " acceptor_quenching,\n", - " simulation_parameter)\n", - " acceptor_diffusion_simulation.update()\n", - " if save:\n", - " donor_diffusion_simulation.save(filename=fn+\"_D_diff.xyz\", mode='xyz', skip=10)\n", - " acceptor_diffusion_simulation.save(filename=fn+\"_A_diff.xyz\", mode='xyz', skip=10)\n", - "\n", - " fret_sim = FRETDecay(donor_diffusion_simulation, acceptor_diffusion_simulation,\n", - " fret_parameter, decay_parameter)\n", - " fret_sim.update()\n", - " decay = fret_sim.get_histogram()\n", - " decay = np.vstack(decay)\n", - " if save:\n", - " np.savetxt(fn + \"-dRDA.txt\" , fret_sim.dRDA.T)\n", - " #np.savetxt(fn +\"-decay.txt\" , decay.T, fmt=\"%i\", delimiter=\"\\t\")\n", - " fret_decays.append(decay)\n", - " distances.append(np.histogram(fret_sim.dRDA, bins=np.linspace(0, 150, 150), density=True))\n", - " donor_decay = donor_decays[donor_key][1]\n", - " print donor_decay\n", - " #print sum(donor_decay)\n", - " eff.append( 1. - sum(decay[1])/sum(donor_decay))\n", - " return fret_decays, distances, eff\n", - "\n", - "\n", - "def simulate_decays(dyes, decay_parameter, simulation_parameter, quenching_parameter, save_decays=False,\n", - " directory=\"./\"):\n", - " dye_decays = OrderedDict()\n", - " quantum_yields = list()\n", - " for dye_key in dyes:\n", - " \n", - " dye = dyes[dye_key]\n", - " diffusion_simulation = DiffusionSimulation(dye,\n", - " quenching_parameter,\n", - " simulation_parameter)\n", - " try:\n", - " diffusion_simulation.update()\n", - " #diffusion_simulation.save('%sD_diffusion.xyz' % dye_key, mode='xyz', skip=5)\n", - " av = diffusion_simulation.av\n", - " #av.save('%sD' % dye_key)\n", - "\n", - " fd0_sim_curve = DyeDecay(decay_parameter, diffusion_simulation)\n", - " fd0_sim_curve.update()\n", - " decay = fd0_sim_curve.get_histogram()\n", - " qy = fd0_sim_curve.quantum_yield\n", - " print \"%s\\t%s\" % (dye_key, qy)\n", - " filename = \"Donor-%s.txt\" % dye_key\n", - " decay = np.vstack(decay)\n", - " if save_decays:\n", - " np.savetxt(directory+filename, decay.T, fmt=\"%i\", delimiter=\"\\t\")\n", - " except ValueError:\n", - " decay = np.ones(10)\n", - " \n", - " dye_decays[dye_key] = decay\n", - " quantum_yields.append(qy)\n", - " \n", - " return quantum_yields, dye_decays" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Simulation parameters" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are two PDBs of hGBP1. Both PDBs are coarse grained models of hGBP1. In the coarse model the sidechains are stripped. Instead of the stripped sidechain are pseudo atom was placed at the center of mass of the side-chain. The program identifies the type of the sidechain by the name of the amino-acid. In one PDB the names of the natural amino-acids were used. In the second PDB the names of the natural quenchers (TYR, TRP, HIS, MET) were replaced by ALA.\n", - "\n", - "Given the PDB-files now a new structure object is generated and the simulation parameters are set." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Input\n", - "-----\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "pdb_file = './crystal/4idn_fixed.pdb' # C2\n", - "#pdb_file = './crystal/3q5d_fixed.pdb' # C1\n", - "#pdb_file = './crystal/3q5e_fixed.pdb' # C3\n", - "file_prefix = 'C2_'\n", - "directory = './tmp/'# This directory is used for saving\n", - "\n", - "diffusion_coefficient_donor = 7.5 # A2/ns\n", - "diffusion_coefficient_acceptor = 4.0 # A2/ns\n", - "r_qd_quench = 3.0 + 5.5 # Distance below the Donor is quenched\n", - "\n", - "rs = [0.2, 0.3, 0.38-0.2, 20] # sum should amplitudes should be 0.38 (0.4) anisotropy spectrum, amplitude, rotational time (interleaved) b1, rho1, b2, rho2, ....\n", - "acs = [1.0, 1.5] # This is the lifetime spectrum of the acceptor (interleaved)\n", - "\n", - "# Residue numbers for the attachment of the dyes\n", - "donor_labeling_positions = list(set([176, 401, 301, 393, 301, 339, 13, 401, 176, 339, 305, 401, 10, 339, 289, 339, 301, 382, 13, 397]))\n", - "acceptor_labeling_positions = list(set([176, 401, 301, 393, 301, 339, 13, 401, 176, 339, 305, 401, 10, 339, 289, 339, 301, 382, 13, 397]))\n", - "\n", - "# These are the FRET-pairs which are going to be simulated (first position D, second A)\n", - "dye_combinations = [\n", - " [176, 401], [301, 393], [301, 339], [13, 401], [176, 339], [305, 401], [10, 339], [289, 339], [301, 382], [13, 397],\n", - " [401, 176], [393, 301], [339, 301], [401, 13], [339, 176], [401, 305], [339, 10], [339, 289], [382, 301], [397, 13]\n", - "]\n", - "\n", - "dye_combinations = [\n", - " [13, 401],\n", - " [401, 13]\n", - "]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "structure = mfm.Structure(pdb_file)\n", - "tau0 = 4.1\n", - "forster_radius = 52.0\n", - "kappa2 = 0.667\n", - "\n", - "fret_parameter = FretParameter(tau0=tau0,\n", - " forster_radius=forster_radius,\n", - " kappa2=kappa2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Donor" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "donor_chains = [' ']*len(donor_labeling_positions)\n", - "\n", - "donor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=1.0,\n", - ")\n", - "\n", - "donor_sticking = Sticking(structure, donor_quenching,\n", - " sticky_mode='surface',\n", - " slow_radius=8.5,\n", - " slow_fact=0.1) # Stas-paper Dye-MD (roughly 10%)\n", - "\n", - "donor_dyes = dict(\n", - " [\n", - " (pos,\n", - " Dye(donor_sticking,\n", - " attachment_residue=pos,\n", - " attachment_chain=chain,\n", - " attachment_atom='CB',\n", - " critical_distance=r_qd_quench, # 3.0 Ang von AV + 6.0 Ang only C-beta quench (so far best 5.0 + 3.0)\n", - " diffusion_coefficient=diffusion_coefficient_donor, # Stas-paper (Dye-MD 30 A2/ns)\n", - " av_radius=3.0,\n", - " av_width=2.5,\n", - " av_length=21.5, # 20 + 5 = 3.5 + 21.5\n", - " tau0=4.2)\n", - " )\n", - " for pos, chain in zip(donor_labeling_positions, donor_chains)\n", - " ]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Acceptor" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "#acceptor_labeling_positions = [18, 254, 577 , 344, 481, 496, 525, 540, 577]\n", - "\n", - "acceptor_chains = [' ']*len(donor_labeling_positions)\n", - "acceptor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=0.8)\n", - "\n", - "acceptor_sticking = Sticking(structure, acceptor_quenching,\n", - " sticky_mode='surface',\n", - " slow_radius=8.5,\n", - " slow_fact=0.1) # Stas-paper Dye-MD (roughly 10%)\n", - "acceptor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=0.8)\n", - "acceptor_dyes = dict(\n", - " [\n", - " (pos,\n", - " Dye(donor_sticking,\n", - " attachment_residue=pos,\n", - " attachment_chain=chain,\n", - " attachment_atom='CB',\n", - " critical_distance=0.0, # The acceptor dye does not have to be quenched setting this to zero speeds up calulation\n", - " diffusion_coefficient=diffusion_coefficient_acceptor,\n", - " av_radius=3.5,\n", - " av_width=2.5,\n", - " tau0=1.0)\n", - " )\n", - " for pos, chain in zip(acceptor_labeling_positions, acceptor_chains)\n", - " ]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Simulation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Donor-decay" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now the simulation parameters are set." - ] - }, - { - "cell_type": "code", - "execution_count": 8, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "simulation_parameter = DiffusionSimulationParameter(t_max=30000,\n", - " t_step=0.016)\n", - "decay_parameter = DecaySimulationParameter(decay_mode='photon', #curve or photon\n", - " n_photons=20.0e6,\n", - " n_curves=250000,\n", - " tac_range=(0, 16.666624 + 0.004069),\n", - " dt_tac=0.004069)" - ] - }, - { - "cell_type": "code", - "execution_count": 9, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "289\t0.945020413509\n", - "401\t0.868100716598\n", - "393\t0.937943723771\n", - "10\t0.979737843729\n", - "301\t0.934255643574\n", - "13\t0.860857583413\n", - "176\t0.816218850376\n", - "305\t0.90661802463\n", - "339\t0.946292211666\n", - "397\t0.916740913639\n", - "382\t0.841078936846\n" - ] - } - ], - "source": [ - "quantum_yields, donor_decays = simulate_decays(donor_dyes, decay_parameter, simulation_parameter, donor_quenching, directory=directory)\n", - "with open(os.path.join(directory, file_prefix+'d0_qy.txt'), 'w') as fp:\n", - " fp.write('Donor position\\tQY\\n')\n", - " for i, dk in enumerate(donor_decays):\n", - " fp.write(\"%s\\t%.3f\\n\" % (dk, quantum_yields[i]))" - ] - }, - { - "cell_type": "code", - "execution_count": 10, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\nrkJggg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import pylab as p\n", - "for k in donor_decays:\n", - " p.semilogy(donor_decays[k][0], donor_decays[k][1], label='%s' % k)\n", - "p.legend()\n", - "p.show()" - ] - }, - { - "cell_type": "code", - "execution_count": 11, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "def vm_rt_to_vv_vh(t, vm, rs, g_factor=1.0, l1=0.0, l2=0.0):\n", - " \"\"\"Get the VV, VH decay from an VM decay given an anisotropy spectrum\n", - "\n", - " :param t: time-axis\n", - " :param vm: magic angle decay\n", - " :param rt: anisotropy spectrum\n", - " :param g_factor: g-factor\n", - " :param l1:\n", - " :param l2:\n", - " :return: vv, vm\n", - " \"\"\"\n", - " rt = np.zeros_like(vm)\n", - " for i in range(0, len(rs), 2):\n", - " b = rs[i]\n", - " rho = rs[i+1]\n", - " rt += b * np.exp(-t/rho)\n", - " vv = vm * (1 + 2.0 * rt)\n", - " vh = vm * (1. - g_factor * rt)\n", - " vv_j = vv * (1. - l1) + vh * l1\n", - " vh_j = vv * l2 + vh * (1. - l2)\n", - " return vv_j, vh_j\n", - "\n", - "for dk in donor_decays:\n", - " t, vm = donor_decays[dk], donor_decays[dk]\n", - " vv, vh = vm_rt_to_vv_vh(t, vm, rs)\n", - " z = np.ones_like(vm)\n", - " np.savetxt(os.path.join(directory, file_prefix+'D0_%s_vv_vh.txt' % dk), np.vstack([vv,vh, z, z]).T, fmt=\"%i\", delimiter=\"\\t\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## FRET-decay" - ] - }, - { - "cell_type": "code", - "execution_count": 12, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Simulating: 176D-401A\n", - "[ 19264. 19479. 19265. ..., 177. 210. 205.]\n", - "Simulating: 301D-393A\n", - "[ 19439. 19358. 19469. ..., 252. 286. 284.]\n", - "Simulating: 301D-339A\n", - "[ 19439. 19358. 19469. ..., 252. 286. 284.]\n", - "Simulating: 13D-401A\n", - "[ 19527. 19107. 19538. ..., 222. 217. 220.]\n", - "Simulating: 176D-339A\n", - "[ 19264. 19479. 19265. ..., 177. 210. 205.]\n", - "Simulating: 305D-401A\n", - "[ 19611. 19191. 19138. ..., 263. 258. 268.]\n", - "Simulating: 10D-339A\n", - "[ 19245. 19438. 19111. ..., 320. 339. 358.]\n", - "Simulating: 289D-339A\n", - "[ 19500. 19631. 19300. ..., 311. 344. 309.]\n", - "Simulating: 301D-382A\n", - "[ 19439. 19358. 19469. ..., 252. 286. 284.]\n", - "Simulating: 13D-397A\n", - "[ 19527. 19107. 19538. ..., 222. 217. 220.]\n", - "Simulating: 401D-176A\n", - "[ 19358. 19169. 19345. ..., 240. 245. 218.]\n", - "Simulating: 393D-301A\n", - "[ 19410. 19205. 19547. ..., 287. 305. 306.]\n", - "Simulating: 339D-301A\n", - "[ 19429. 19281. 19379. ..., 317. 295. 324.]\n", - "Simulating: 401D-13A\n", - "[ 19358. 19169. 19345. ..., 240. 245. 218.]\n", - "Simulating: 339D-176A\n", - "[ 19429. 19281. 19379. ..., 317. 295. 324.]\n", - "Simulating: 401D-305A\n", - "[ 19358. 19169. 19345. ..., 240. 245. 218.]\n", - "Simulating: 339D-10A\n", - "[ 19429. 19281. 19379. ..., 317. 295. 324.]\n", - "Simulating: 339D-289A\n", - "[ 19429. 19281. 19379. ..., 317. 295. 324.]\n", - "Simulating: 382D-301A\n", - "[ 19273. 19542. 19468. ..., 220. 215. 253.]\n", - "Simulating: 397D-13A\n", - "[ 19522. 19486. 19406. ..., 280. 278. 283.]\n" - ] - } - ], - "source": [ - "dye_combinations = [\n", - " [176, 401], [301, 393], [301, 339], [13, 401], [176, 339], [305, 401], [10, 339], [289, 339], [301, 382], [13, 397],\n", - " [401, 176], [393, 301], [339, 301], [401, 13], [339, 176], [401, 305], [339, 10], [339, 289], [382, 301], [397, 13]\n", - "]\n", - "fret_decays, distance_distributions, transfer_eff = simulate_fret_decays(donor_dyes, acceptor_dyes, \n", - " decay_parameter, \n", - " simulation_parameter, \n", - " donor_quenching, acceptor_quenching, fret_parameter, \n", - " dye_combinations=dye_combinations,\n", - " donor_decays=donor_decays,\n", - " directory=directory)" - ] - }, - { - "cell_type": "code", - "execution_count": 13, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "\n", - "\n", - "def scale_acceptor(donor, acceptor, transfer_efficency):\n", - " s_d = sum(donor)\n", - " s_a = sum(acceptor)\n", - " scaling_factor = 1. / ((s_a / transfer_efficency - s_a) / s_d)\n", - " scaled_acceptor = acceptor * scaling_factor\n", - " return donor, scaled_acceptor\n", - "\n", - "def da_a0_to_ad(t, da, ac_s):\n", - " \"\"\"Convolves the donor decay in presence of FRET directly with the acceptor only decay to give the\n", - " FRET-sensitized decay ad\n", - " \"\"\"\n", - " a0 = np.zeros_like(da)\n", - " for i in range(len(ac_s) / 2):\n", - " a = ac_s[i]\n", - " tau = ac_s[i + 1]\n", - " a0 += a * np.exp(-t / tau)\n", - " ad = np.convolve(da, a0, mode='full')[:len(da)]\n", - " ds = da.sum()\n", - " return ad\n", - "\n", - "for i, dk in enumerate(dye_combinations):\n", - " d, a = dk\n", - " t, fd0 = donor_decays[d]\n", - " t, fda = fret_decays[i]\n", - " fad = da_a0_to_ad(t, fda, acs)\n", - " tr = transfer_eff[i]\n", - " fda, fad = scale_acceptor(fda, fad, tr)\n", - " fda_vv, fda_vh = vm_rt_to_vv_vh(t, fda, rs)\n", - " fad_vv, fad_vh = vm_rt_to_vv_vh(t, fad, rs)\n", - " np.savetxt(os.path.join(directory, file_prefix+'FRET_%sD-%sA_vv_vh.txt' % (dk[0], dk[1])), \n", - " np.vstack([fda_vv,fda_vh, fad_vv, fad_vh]).T,\n", - " fmt=\"%i\", delimiter=\"\\t\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": 14, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "with open(os.path.join(directory, file_prefix+'tr.txt'), 'w') as fp:\n", - " fp.write('Dye-pair\\ttransfer\\n')\n", - " for i, dk in enumerate(dye_combinations):\n", - " fp.write('%sD-%sA\\t%.3f\\n' % (dk[0], dk[1], transfer_eff[i]))\n" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "data": { - "image/png": "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\n6BOIiEhJ0f287nz2x2cFtrHkHlVoWq1pcYVUZAkJCSQkJOS4lpzsWmVMV3i6okVVIBTYecr1ncDZ\n2S9Ya690t/MRI0bQsmXLwkcnIiKSbuJNExl3w7gC22RMRXx/+/d0+djZUdGsRrNij62w8vpDOjEx\nkejoaI/0r4qQIiJSIoWGhBIaEupS2zJhZTK/L8lrGjy95XIPkArUOOV6DWBHUTuPi4sjJiYm19CL\niIhIcbj5XOcsi6ZVs6YkMqYsSoeW9klMrkpISCAmJoa4uDiP9enRpMFaexJYAnTOuJa+WLIzML+o\n/Y8YMYIpU6ZoDYOIiHjFxbUvxg6yVItwjuiuW6Fu5khDn+g+uSpJ9mrmP4WOY2NjmTJlCiNGjPBY\nn25PTxhjIoBGZO16aGiMuRDYa63dDAwHxhpjlpC15bIcMNYjEYuIiPhQXosjXXkvGBRmTcNFwGzA\npn8NS78+Duhtrf3cGFMVGIwzLbEM6GKt3V3UYDN2T2jHhIiI+EL2SgN5Vx3wHxk7KXy6e8Ja+wun\nmdaw1r4DvFPYoPKj3RMiIuJLBlPgQsj8TtL0hYw/sD25e0JnT4iIiLgox0hDHglCsE9PKGkQERFx\nkcFkJgb+Pj1RHAIqadCWSxER8ZVHL3mUL275Is/piafaPZX5/aBOg5jZa6Y3Q8tTcWy5NIFQpMIY\n0xJYsmTJEq1pEBERn5q3aR7tP2rPY60fY1gXZy/AX//+xdlvn02vZr0Yf+N4H0eYU7Y1DdHW2sSi\n9BVQIw0iIiK+VpK3XCppEBERcUPGCP3pFkUGo4A6e0J1GkRExNcuqHEBkaUiufPCOzOv+eMIg1/U\nafAl1WkQERFfq1imIgcHHvR1GKelOg0iIiJ+qKRMTyhpEBEREZcoaRARERGXBNSaBi2EFBERf1Sv\nYj061evE0+2f9nUomYpjIaSKO4mIiAQxFXcSERERr1PSICIiIi5R0iAiIiIuUdIgIiIiLtHuCRER\nkSCk3RPaPSEiIuIW7Z4QERERr1PSICIiIi5R0iAiIiIuUdIgIiIiLlHSICIiIi5R0iAiIiIuUZ0G\nERGRIKQ6DarTICIi4hbVaRARERGvU9IgIiIiLlHSICIiIi5R0iAiIiIuUdIgIiIiLlHSICIiIi5R\n0iAiIiIuUdIgIiIiLlHSICIiIi5RGWkREZEgpDLSKiMtIiLiFpWRFhEREa9T0iAiIiIuUdIgIiIi\n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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\nRYOIiIhkuQEUlBUKl1PGbwAAAABJRU5ErkJggg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\nkVz+Aa08s3pzXK8eAAAAAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\nrcHM6FiRcgAAAABJRU5ErkJggg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAg0AAAFnCAYAAAAln3o1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzs3Xd8VFX6x/HPSehBKdIUC4KC2EBYBBRs/OxuwIIasbIo\nigVjx8ZiVxRWVlEQFdYSxRWk6IKiIE1AQKT3jvQSCKFmzu+Pm5lkkkkyM5me79sXL+beOffeZ0Cd\nJ+c85xxjrUVERESkJEnRDkBERETig5IGERER8YuSBhEREfGLkgYRERHxi5IGERER8YuSBhEREfGL\nkgYRERHxi5IGERER8YuSBhEREfGLkgYRERHxi5IGERER8Uu5aD3YGLMW2ANYYJe1tkO0YhEREZGS\nRS1pAFxAW2vtgSjGICIiIn6K5vCEifLzRUREJADR/NK2wGRjzExjzG1RjENERET8EHDSYIxpb4wZ\nbYzZZIxxGWNSfbR50BizxhhzwBgzwxjTysetLrTWtgQ6As8aY84OIn4RERGJkGB6GlKAeUAPnN4C\nL8aYW4B3gN7AecCfwHhjTK387ay1m3N/3wL8ALQIIhYRERGJEGNtoe99/y82xgV0staOznduBjDT\nWtsz99gAG4AB1tq3cs9VAZKstVnGmKrAJKC7tXZOEc85DrgSWAscDDpgERGRsqcS0AAYb63dWZob\nhXT2hDGmPNASeM19zlprjTETgLb5mtYFRhpjLJAMDC4qYch1JfBFKGMVEREpY7oAX5bmBqGeclkL\nJwnYWuD8VqCJ+8BauwZoHsB91wJ8/vnnNG3atJQhRl96ejr9+/ePdhgho88TuxLps4A+TyxLpM8C\nifV5lixZwu233w6536WlEc11GgJxEKBp06a0aBH/pQ/VqlVLiM/hps8TuxLps4A+TyxLpM8Cifd5\ncpV6eD/UScMOIAdn+CG/usCW0t48PT2datWqkZaWRlpaWmlvJyIikrAyMjLIyMggMzMzZPcMadJg\nrT1ijJkDdABGg6cQsgMwoLT379+/fyJmfiIiIiHn/gF77ty5tGzZMiT3DDhpMMakAKfhrOgI0NAY\n0wxn/4gNQD9gaG7yMAtIB6oAQ0MSsYiIiERFMD0NfwMm4qzRYHHWZAAYBnS11g7PXZPhJZxhiXnA\nldba7aUNNlGGJ+I5dl/0eWJXIn0W0OeJZYn0WSAxPk84hidKtU5DpBhjWgBz5syZo+EJERGRAOQb\nnmhprZ1bmntpwygRERHxi5IGERER8Uu8rNMAJE5Ng4iISLippkE1DSIiIgFRTYOIiIhEnJIGERER\n8YtqGkRERBKQahpU0yAiIhIQ1TSIiIhIxClpEBEREb8oaRARERG/qBBSREQkAakQUoWQIiIiAVEh\npIiIiESckgYRERHxi5IGERER8YuSBhEREfGLZk+IiIgkIM2e0OwJERGRgGj2hIiIiESckgYRERHx\ni5IGERER8YuSBhEREfGLkgYRERHxi5IGERER8YvWaRAREUlAWqdB6zSIiIgEROs0iIiISMQpaRAR\nERG/KGkQERERvyhpEBEREb8oaRARERG/KGkQERERvyhpEBEREb8oaRARERG/KGkQERERv8TVMtIt\nW6bTpk01HnoojS5dtIy0iIhIUcr8MtIwB3CWkf7iC7j6aqhRI6qhiYiIxLQyu4z0iy/mve7SBWrW\nBGNg0iSIg9xHREQkrsVV0tCxo5McjBzpff7SSyEpyUkgvvkmOrGJiIgkurhKGtxDKZ06OclDTg48\n+qh3m5tvdpKHK66Aw4fVAyEiIhIqcZU0rNy10us4KQn693cSg02bYMKEvPd++gkqVnTa3HADbN8e\n4WBFREQSTFwlDWOWjSnyvRNOgA4dnARi8GDv90aOhDp1nB6IatVg8eIwByoiIpKA4ipp+GLBF/gz\n2+Pee53kwVqYNQsqVcp7b+9eOOssJ4EwBp54IowBi4iIJJC4ShoAflnzS0DtW7WCAwecBOLLLwu/\n/847TvJwzjkwblyIghQREUlAcZc03Pzfm4O+Ni0trwdizx4oXz7vvYULnXUfjIH27QvP0BARESnr\n4ippuLzR5ew6sItVu1aV+l7VquXNrti6FR54IO+9qVOd4kljoFEjGDMG5s8v9SNFRETiWlSTBmNM\nZWPMWmPMW/60v/WsWwE47d+nhTSOOnVg4EAngVi+3OlxcFu9GlJToVkzJ4no2dPppRARESlrot3T\n8Bzwm7+Nmx/f3PN66Y6l4YiH00+HH35wEoiVK51VKE86Ke/9AQOcpavdhZRjxsDRo2EJRUREJKZE\nLWkwxpwGNAH+F8h107pOA6DdJ+3CEJW3Ro2gTx9Yv95JIgYMKNwmNdWpjTAG1qxxzmlBKRERSUTR\n7Gl4G+gFmEAuantiWwB2HtjJrE2zwhBW0R5+GI4ccZKCxYuhQgXv9xs2dJIH95LWkyZFNDwREZGw\nCjhpMMa0N8aMNsZsMsa4jDGpPto8aIxZY4w5YIyZYYxpVeD9VGCZtda9xKPfiYMxhr6X9wWg9ZDW\ngYZfauVyNxNv2hQOHXISiF27fLe99NK8YYypU51z6oUQEZF4FUxPQwowD+gBFPoKNMbcArwD9AbO\nA/4ExhtjauVr1ga41RizGqfHoZsx5nl/A3jigrwVmf456Z+Bf4IQq1EjbyqntbBoUeE27dvn9ULc\ncQdMnAgHD4LLFfl4RUREghFw0mCtHWetfdFaOwrfPQTpwCBr7X+stUuB+4FsoGu+ezxrrT3FWtsQ\neAL4yFr7SiBxrO25FoA+v/bhqCu2KhHPPDNvKucPPzjrQ+T3+edw2WVQuTIkJ8OQIeqBEBGR2Gf8\nWZa5yIuNcQGdrLWjc4/L4yQIN7rP5Z4fClSz1l7v4x53AWdZa58q5jktgDkXXXQR1apV85z/YcUP\n5JyVA+eA7R3737o5OTBqFNx4Y9FtPvwQ7rvP6ZUQEREJREZGBhkZGV7nMjMzmTx5MkBLa+3c0tw/\n1EnD8cAmoK21dma+dm8CF1lr2wb5nBbAnDlz5tCiRQvP+d0HdlPzrZoA3HHuHfzn+v8E/VkiLTsb\nHnoIhg+H/fuLbjdqlLMRV0pK5GITEZHEMXfuXFq2bAkhSBqivU5DqdSoXIOf7/wZgM/mf8bO7J1R\njsh/VarAJ59AVhbs2OHszNmgQeF2HTtC1apOz8MDDzirWGZnRzxcERGRkCcNO4AcoG6B83WBLaW9\neXp6OqmpqV5dL5edehk1KtUAoFbfWmQdzirtYyLuuOOcnTnXrHFqGw4ehKFDC7f78EOoWNHpdWjY\nEL76SrUQIiLiW0ZGBqmpqaSnp4fsniEdnsg9NwOYaa3tmXtsgPXAAGtt3yCf43N4wqtNn7wigHio\nbwjEJ5/Ao4/Cvn1Ft9m3L6+wUkRExC2qwxPGmBRjTDNjjHtN54a5x+7FlvsB9xpj7jTGnAF8CFQB\nhpYm0JLMvne25/WIJSPC+aiI69oV9u51ehX27nUKJQs65hhnDQn3uhAiIiKhFnBPgzHmYmAihddo\nGGat7ZrbpgfwFM6wxDzgYWvtbIJUcPZEWloaaQXnMQIPjH2AD+d8CMDup3dTvVL1YB8Z8w4ehGnT\nnN03X3ml6AWmAC65xNkjo2rViIUnIiJR5p5JETOzJyLFn+EJt5TXUsg+4lQKbkzfSP1j60cgwug7\nfBhWrICnnnLWhihK69bw5Zdw6qnqkRARKQs0e6IYWb3yCiHPG3ReFCOJrAoV4Kyz4PvvnWGMOXPg\n11+dIsv8Zs50NuJKSoI33nD2x8jJiUrIIiISZxIuaTDGeAoht2dv58kfnyQeelNCrUULuOgiZzqn\nywUTJsBdd3m36dXL2R/DXQvxj3/AwoUwfbqz3beWuBYRkfzianiipJqG/MatHMfVX1ztOU60GRXB\nOnzY+X3UKLj5Zv/aly8f3phERCT0VNPgR01Dfu9Mf4cnfnI2txp83WD+0eIfJJmE61wptfXr4f33\n4a23im7TrZuzHXjz5k5bERGJD6pp8NPjFzzOdY2vA+C+sffRdVTXEq4om04+Gd5806lt+OknqF27\ncJshQ5xhi4EDnaGM53P3JHW5NIwhIlJWJHTSADAmbQy1qji7cg/7cxjP/fxclCOKXUlJ8H//B9u2\nOcWULpdT2zBkSOG2r77qJA/Jyc6vKVMiH6+IiERWXA1PBFLTkF+OK4dyL5fzHP/R/Q+a12tezBXi\ny/LlcMcdMGtW8e2GDYNq1aB9e6hZMzKxiYiIN9U0BFjTkJ+1lsqvVuZQziEAht80nM5ndQ5hlGXL\nihXw0UcwdiwsWVJ0u4cegp49nWmeWhdCRCTyVNMQBGMMmc9k8o/z/gHAzf+9mfdnqaIvWKef7hRO\nLl7sDGXMmuUMbxT03ntO26QkJ2moXBlWrYp8vCIiUnplJmkAqFiuIkNS8wboH/rfQyzdsTSKESWO\nVq2cQkprne2+1693Fpwq6OBBOO20vD0yli6FI0e0W6eISDwoU0mD26bHNnleN32/KR/P/TiK0SSe\nlBQ46SQ4dMhJBqyFHj18t23a1Eku3D0Rb74Z2VhFRMR/cVXTEGwhpC+Hjh6i0quVvM4deO4AlcpV\nKuIKKa29e2HNGpg719m5syTTpjkrW+7dC3XqhD8+EZFEokLIUhRC+uKyLuq9XY/t2dsBaHJcE5Y+\npOGKSNmzBxYtgkcfha1bYcOGkq9ZuNDZY0NERPyjQsgQSTJJbH58s+d42c5l3PyNH2srS0hUrw4X\nXgi//+7UQLhczu6bxTn7bGcY4+67nRkccZDziogkjDKdNAAkJyWT82IOreu3BuCbxd/wwi8vRDmq\nsskYWL06r5jyhhtg3DjfbYcNg8aN82ohfvnFKagUEZHwKfNJAzg9DjO6zfAcvzLlFZ79+dkoRiQp\nKfDtt3DllTBvXt5QRlE6dHAKKo1x1oQ4fFjLW4uIhJqShnwOPX+Ir2/6GoDXp77OoNmD2H94f5Sj\nkmbNnBUmzzwzbzbGFVcU3X71aqhY0Vne2hhYsMDpuTh6NHIxi4gkorgqhAzl7IniXPn5lfy46kfP\n8c6ndlKzstZDjmU//ADXXltyu4YNnVqIbdugbl2tUikiiUuzJ0I8e6Io1lpqvlWTPQf3eM5te2Ib\ntVN8bP8oMembb2DMGPjss6LbNGjgDH0cc4zv1SxFRBKBZk+EmTGG3U/v5rd//OY5V+ftOqzYuSKK\nUUkgOneG//zHGcqYOhVuv71wm7VrnRkc7mGM5593FqQSERHflDQUo82JbVjwwALPceP3GtPxq45R\njEiCceGFTo+DtfDaa0UvLPXqq1CpUt4S18ZonwwRkfyUNJTg7DpnM/KWkZ7j0ctGM37l+ChGJKXR\nqxd8/LGTQBw54ry+/vqi27v3yejbF2bMgH37IheriEisUU1DIHH08a6ay3kxhySjvCtRHDoEp5zi\nrE5Zkp49oXdvZ3jjwAGoUiX88YmIBEM1DVEyr/s8r+Pkl5KjFImEQ8WKsGWL0wvhcjkLSxW1QuW7\n70LNmk4BZUqKU1S5Z4/vtiIiiUJJQwCa1WtGVq8sr3Omj2HWpllRikjCxRhnYSn3CpW7dzv1EBdf\nDO3bF26/bh3UqOFcN2CA02uxZEnk4xYRCae4Gp6I1DoN/nhtyms898tznuMrGl3B+NtV61BWzJ/v\nLDpVkhNPhBEj4OBB38mGiEi4aJ2GKNc0FLT/8H6qvl7V69wf3f+geb3mUYpIIs1aZ6Gob7+FBx8s\nuf0118A//wnnnAMrVzobcImIhJNqGmJESoUU/nrsL69z5w06j59X/xyliCTSjHFWluzRw6mDOHoU\nduwouv0PP8D550Plyk7iMGSIaiFEJH4oaSil4485Htvbu7fm/z77P75e+HWUIpJoMcZZKOq44yA7\nG555BjIynF6Ixo19X3PvvXm1EO5f3brB9u3a9ltEYo+ShhCxvS2bH9/sOb7121sxfQzZR7KjGJVE\nS+XK8PrrcOutzhbfy5Y5ScDEiXDJJfDyy0Vf+/HHUKeOMzNj4ECnHkJEJBYoaQihelXrceh573WI\nU15L4ahL2yuK45JLnMTh+eedXojffoOPPiq6/YMPOgmIMfDGG/C//0UsVBGRQpQ0hFiF5AqsesR7\n7eHyL5fntw2/FXGFlFW33gpt2jjDEZs3w6hRTlJRlF69nEJKY5yEY9s2Z8dOfxajEhEJBSUNYdCw\nRkOm3DPF69wFn1yA6WPYe2hvlKKSWFavHqSmOr0QW7dCly6wf3/R7W+7zSnAbNzYudYYGDYMxo5V\nEiEi4aOkIUzandyOfb0Kb1RQ7Y1qtBnSRkMWUqQ6deDzz52lqbOynF06ofhhDIC774a//91JImbO\ndKZ0ioiEkpKGMKpaoSr7n93PvS3u9To/c9NMvlr4FQePqsJNipeS4uzSaa0zjGGt82vp0uLXeGjT\nBk4/PW9GxnffOdM7ixv+EBEpiRZ3ipDsI9mkvJZS6PyjrR+l/1X9oxCRJIIFC5xaiORkePZZ/665\n4AKnF6NXL2fFyqKmg4pIYgjl4k5xlTTE0jLSwbDWkvRS4c6dG5rewLc3fxuFiCQRdewIo0cHds2B\nA1CpUnjiEZHo0DLScdzTkN+opaPo9HUnr3NPtH2Cvlf0jVJEksjGjnVqHfzVpQs8+ST89BM88UT4\n4hKRyNAy0nGu4xkdmdVtFu1Obuc59/Zvb2P6GN6Z/k4UI5NEdN118OOPsHatf+2/+AKaN3cSB2Oc\nmRpuu3aFJUQRiRNKGqKkVf1WTLlnClse3+J1/omfnmDtnrXRCUoS1uWXwymnOLMxJkyAVaucgsqc\nHJg+He67r+hrMzLyCiqPOw4GD86b0SEiZYuShiirW7Uurhdd3HTmTZ5zjQY0otGARnwx/4soRiaJ\nKCUFOnSAhg2d46QkaNsWBg2CdevgqadKvkf37s423+5EYtUqLXUtUlaopiGGDJs3jLtH3e117ukL\nn+apC5+iZuWa0QlKyhxrnTUeAp1VMWmSk0Ds3ev0SBw86GzIJSLRFcqahnKhCUlC4a7md2Gx3DPq\nHs+5N6e9yZvT3iy0k6ZIuBjjrPGQ/+cJl8vZufPii2FuEf/L8bUGxPr1sHo13HQTXH99WMIVkQjS\n8ESMubv53XQ+s3Oh89oxU6IpKQmqVoU5c6BfP+fcK6+UfN0rr8CXXzo7fb79trNSpYYyROKXkoYY\nNLzzcI6+cJT/dPqP1/mU11J4bcprUYpKxJGe7vRCPPec8/uwYf5d9+STzkqVlSs7xZWdOsEjj4Q3\nVhEJLdU0xDhfdQ4AM7vN5Ow6Z1OlfJXIByXiQ6NGzlBEoJ580lkWe+RIZ2VLEQktrdNQhtzV/C5s\nb1toxcjWQ1r7XJZaJFrc0zithaNH4b33oGdP57127Yq+rm9fGDMGypXLm5GxZYuzSqWIxJaoJA3G\nmGrGmN+NMXONMfONMd2iEUc8uaHpDbx/zfuFzps+hupvVI9CRCJFS06GBx+Ef/3LSSLGjIEXX/R/\n2+7jj3f2x7j8cujaFTZtcnb+XLo0vHGLSPGi1dOwF2hvrW0BtAaeNcbUiFIscaNHqx5sTN9Y6Hzm\noUyGzB3C5n2boxCVSMmqV4c+fZxtvzMznUTC5YJataBmMbOJJ0yATz91Nta64w5o2tRZFtsYJylx\nuSL3GUQkSkmDdbhrqCvn/m6iEUu8qX9sfW4/9/ZC5+8dcy8n9DuB5TuX88IvLxAPtSpSNh17rPO7\nMbBtG+zcCRUq+H+9ex+NgQOdHo3rrnMSiWXLQh+riHiLWk1D7hDFPGA90Ndaq1Xt/TToukHMvnc2\n07tOL/Rek/ea8MqUV7hj5B3kuHKiEJ2I/0zujwpr18Ly5U4S0aYNzJgBp57q3z2+/95JJM44Az74\nwNkfwxh4913YvNmprxCR0Ah49oQxpj3wJNASOB7oZK0dXaDNg8ATQD3gT+Bha+3vRdyvNjASuN5a\nu72INmV29kRJso9kF1kQueTBJZxR64wIRyQSGllZTm9Cu3bO8tfNmwd/ryNHYNEiaNYsdPGJxIto\nz55IAeYBPYBCGYcx5hbgHaA3cB5O0jDeGFPL181yE4U/gfZBxFLmVSlfBdvbsvqR1dzQ9Aav95q+\n35Rp66dFKTKR0qla1dkL44ILnC/7zMy8jbXatg3sXuXLO0mHMfDxx6GPVaSsKNU6DcYYFwV6Gowx\nM4CZ1tqeuccG2AAMsNa+lXuuDpBtrc0yxlQDpgK3WmsXFfEc9TT46eEfHua939/zOjes0zBSm6RS\nvZJmWUhi2LTJKZJ0uZxehPLlnVkWgfrpJ2f3z3nzoHPhhVhFEkIoexpCmjQYY8oD2cCNBRKJoUA1\na+31ucetgMHut4H3rLVDinlOC2DORRddRLVq1bzeS0tLIy0tLejPkGh2HdjFcW8d5/O9/3b+L9Ur\nVadDww4RjkokMubOhZYt4eWXnZ08u3Tx/9qTTnJmatSqpWEMiV8ZGRlkZGR4ncvMzGTy5MkQg0nD\n8cAmoK21dma+dm8CF1lrA+xU9FyvnoYATFk3hRbHt6Dq61V9vp/VK4vMQ5mccMwJEY5MJLKysuCP\nP+CiiwK77t1389aayMpyaiqM5ndJnIp2TYPEuPantCelQgq/3PmLz/ervl6V+v3qRzgqkcirWhXa\nt3c2zdqwAX74wb/revaEhx5y1pU45hjo1ctZodJaOHw4vDGLxLJQJw07gBygboHzdYEtpb15eno6\nqamphbpexLdLT72UUbeO4uHzH/b5vuljeHfGu5qaKQkvLc1ZIOrqq2H7dueL/+efoXv34q/bnjuf\n6803nRUqk5KgYkVo3Rr27Qt/3CKlkZGRQWpqKunp6SG7Z6QKIdfjFEL2DfI5Gp4oJWstY5ePJfWr\n1ELv9b+yP4+2eZTF2xdTr2o9alYuZok+kQS0ezfUq+fUQfi7VPUFF8CoUc66EBs3OkMaF17ozPgQ\niSWhHJ4oF+gFxpgU4DTyVnBsaIxpBuyy1m4A+gFDjTFzgFlAOlAFGFqaQKV0jDH8vcnffb6XPj6d\nBVsX8Mm8T2hQvQFreq6JcHQi0VWjBhw65Lw+dAgqVSr5munToXZt73OjR8OQIc5mXVdc4fRkDB7s\nDI2ceGLo4xaJtGAWd7oYmEjhNRqGWWu75rbpATyFMywxD2dxp9lBB1lg9oRmTARv36F9bMnawqhl\no3jypyd9ttn2xDZqp9T2+Z5IWTB9Ohw8CJdd5kzprFzZKYwMtp7h9NOhQQOnpqJcOWfYo3Jlp+ZC\nJFzcMyliZvZEpGh4IjzuGXUPQ+cN9flewxoNWfLgEiokB7ApgEiCy8pyCiMBUlOdnoVA3Hefs/FW\n+9yl7GbPdno2LrggtHGK5KfZExISn3b8tMj3Vu9ezaxNsyIYjUjsq1oV5s+HX3916hmyswPbrnvw\n4LyEAeBvf3PqIJYtcxaaioOf4aSMU9JQxs29by79r+zPuC7jCr3X/tP2XDbsMoYvGs6E1RNwWe1D\nLHLOOXnrPlSuDE2aOJtitWsX/D3POMOpgXjhBWdWxuWXww03OFM9RWJJXA1PqKYhvLIOZzFyyUju\n/O7OIttMvWcqF558YQSjEokPEyc6NRCLFzs1ERdcAGeeWfr7vvmmMyNj505npsbpp5f+nlI2qKZB\nNQ0RMXjOYLqPLXoC+/5n95N9JJtaVXzuQSYiuUaNgk6dnC275851pmb+73+lu2dWlrNWRLmA575J\nWRXVKZeS+O5reR+1q9TmhuE3+HzfvRX3jid3cFwV3/tciAh07Fi4TiEnB956C559Nrh75p9x8dRT\nThIyf75zvHIl1Kzp/BIJB9U0iE/XN72ec+ueW2ybWn1r8crkVyIUkUhiSE52ahV27HBWpSyoShX/\n7/XWW7BggZOITJ7sDF20ahW6WEUKiqvhCdU0RJa1luU7l1OrSi1qVq5J4/cas3LXykLtJtwxgfGr\nxnNm7TO5u/ndkQ9UJM7t3g2TJjm7a558spNYtG4Nv/8e3P3GjYOPP3YKK885J6ShShxRTYNqGqJq\nwdYFnPth8b0P6x9dz4nHnojRloAipeJyOT0I5ctDZiZUrx7cffr2hb17nZ6ITz+FU08NbZwS+7RO\ng0TFOXXPYVrXaXRs0rHINif/62Q6ftWR20fcHsHIRBJPUpKTMABUq+bURmRmwmOPwY8/+n+fJ5+E\nl1921pZo2BCuv95ZnfKqq5wVKo1xfmVlheVjSIJRT4MEbEvWFu4bcx/JScl8t/S7IttNvGsilzS4\nJHKBiZQh7v91Wwvnnw9z5pT+ns89B6+oTCnhqKdBoqpe1XqMThvNyFtGcvSFo0W2u3TYpRw6eiiC\nkYmUHe4egqQkOLf4UUO/vfoqpKc7icimTc4iUy+84KwPAU5Px+mnO7M0pGyKq54GFULGJtOn5PqF\nDekbqH9Mfae96h1EQmrWLLj0Uhg71tll85dfnKWpV6+G884LzTNycvJ6NF54AV56KTT3lfBRIaSG\nJ2LSy7++zI7sHQyYNaDEtg+1eoh/X/PvCEQlIi4XvPYaPPQQrF3rFERefLFTK3HkSGD36twZvvnG\neX3iiU5h5ujRKqyMB6EcnlDSICFhrSXppSTOrXsu87fOL7btsRWPpVrFaizssZBjKx4boQhFJL8D\nBwJbE6I4DzwAAwc6rzdvdnYC1bbfsUM1DRJzjDEMv2k4P9/5Mzkv5tDmxDZFtt17aC8b9m7gg98/\n4I2pbwCQfSRbG2KJRFDlyk7tgsvlbLi1YkXw9/rgA9iyxSmkPOEEaNs2dHFKbFHSICHT+azO1KpS\niySTxPSu04vdehvgmZ+fodfPvcg+kk3Kayn0mqAt/UQizRhnManTTivdfY4/3hkKAVi40NkG/NAh\nmDoVvvrK6YGQ+KekQcLCGMPdze8m85nMEtu697L475L/hjssESlGZqYz5XLMGKe34LPP4Ikn8t4P\nZL+M7t2hUiVo3x7S0pweiG+/dXYBdVu3DtasCV38En5xVdOg2RPxafv+7dR5u45fbY++cJTkpOQw\nRyQiwWrf3uk9KI0HH3RmYcyY4Rxb6xRpPvMM9OvnJBtSepo9oULIuJR5MJPqb1bnmQuf4Y1pb5TY\nfsIdE6hY+kelAAAgAElEQVRSvgptT9LAqEgsyspydtfs2tV5fcopsGGDUx8RjJNPhvXr845feQXu\nuMPZArxuXafmIjnZGUqRwGn2hMSd1btX06B6A3JcOSQnJZNkkmj1UStm/zW7yGtuOesWupzThb83\n+XsEIxURf+3e7azfUKsWLF8OTZqE/hlNm8KSJfD3vztTPitWDP0zEp1mT0jcaVijIUkmifLJ5Uky\nzr92v9/7OzedeVOR13y96GtSv0plfeb6ItuISPTUqOEkDACNGzuFjzk58OefkJERmmcsWeL8PmaM\nM+PDGEhNhTvvdLYYD7Z3Q4KjpEGiqnrFkrfuO+Vfp/DDih846ip6yWoRib4KFfKWtb71Vtixw+kZ\n+OYbmDABhg8v3f3dHeNjxjhFmm+8AT/95Jy78UaYNq1095eSKWmQqOp7RV/evepdsnplFbvQ07Vf\nXkv5l8vTYlCLEhePEpHYcNxxcPAg3HQTdOjgrCr50UfebT75pHTPuOoqaNMGRoyAdu3giy9Kdz8p\nnpIGiarqlarzSOtHSKmQwkOtHiqx/R9b/qDZh83IceVEIDoRCbVu3Zweg7vuco7btoWNG2HnTue4\nRQtnVsUFF/h/z5kz817ffruzXsQffzhDF0eOwJ49oYu/rFPSIDHj1Q6vcuSFI3x141clti33cjkO\nHj1I5sFMWgxqoboHkTjz+ONw9tnQoAHUr5+3pHW5ctC6tTOt85//DO7ezz3nJB/Jyc6QSY0azvld\nu5yZGBK8uJo9oXUayo7zBp3HvC3zSmzX+LjGLN+5nKoVqrKv174IRCYi4WCtUw8xbJhT5Oi2b59T\nVNm9e2ie060bPP106VfAjAdap0FTLsuMjXs3MnndZG468yYqvuLfHKt+V/Tj5rNuZsG2BVx12lVh\njlBEImnQILj/fujf39nnYurU0BU+3nabs6jU/v3OctiVK4fmvrFC6zRImWP6BLaqi+1t2bh3I1mH\nszij1hlhikpEoi0cCz65N/Jy3zv/M1ascIZUypcP/XPDRes0SJnz2fWfBdR+wuoJnNT/JJq+3zRM\nEYlILJg6Fb7+GkaOhHHjQnNP9yZeSUnOr5NOghdfdAo2Gzd2aibKKvU0SNx4+deX+f2v3xmzfEyJ\nbZNNMjnWmWGx/cnt1KpSK9zhiUgMuf56+O678D5j/nxnW/APPoB586BZs/A+L1jqaZAy6YWLX2Dk\nLSP5+qavcb3o4oG/PVBkW3fCAFC7b20WblsYiRBFJEZ8/rnzK5ybX517rpMwAEyaFL7nxBIlDRJX\nkpOSufmsmzHGMPDagax/1L+plud8cA6mj2HovKGecxv3bmRr1tYwRSoi0ZSSAl26OEMK8+bBscfC\n7NmweXNeG/cXfij06eOsCWGMM3303/92FrZKNEoaJK6dVO0kz+tvOn9TYvt7Rt1D9zHdOXDkACf1\nP4l679QLZ3giEmXHHecMG2RmQsuWUC/ff/LduzvJBcDSpXDNNcE/Z/duZ00IgAMH4JFHnBkZiUZJ\ngySM1CapfrUbPHcwVV6r4jn+dvG3DJo9KFxhiUiMefNNp97BGCdZmDvX2aHz66+dgse5pRr1z7Nj\nR2juE0tUCClxb/Sy0VRIrsCVja4k6aUkmtVtRmqTVF6e/HJA97G9Y/+/BRGJjL174a234MILS9cD\nEQtfsaEshCwXmpBEoid/D8Orl73KzWfdzGk1T+POZndy+r9P9/s+czfPZer6qdzd/O5iN88SkcR3\n7LHwyive5/budYYhTjklOjHFgrjqadAy0hKoxv9uzIpdKwK+7rtbvqPT153IeTGHJKNRPJGybMsW\nOHQoL1nYvdv51ahRyddG8ytWy0hreEICtHbPWn5e/TPdxnQL6LpLGlzCpLWT2PvMXo6peEyYohOR\neLZyJZxeTGdm9epOchFtWqdBxE8Nqjfg7uZ3A9DqhFZM7zodcLbkvv3c24u8bme2s0/vsW9omEJE\nfDvtNBg71tmGO7/OnZ3f4+Bn8oCppkESXnJSMgC3n3s7bU9q6yl4POo6yufzP/d5zYJtCzyv/9j8\nB+WTy3N2nbMB+GvfX5xwzAlhjlpE4sG11zq/r18PJ5/s7E1x2mnw6KNwww3RjS0clDRImeBrZkS5\npHIcev4QXy38iru+u6vIa1sMdobEXC+6+Gz+Z9z13V2s7bmWU6qX4WooEfFy0knePQv/+lf0Ygkn\nDU9ImVYhuQJ3NrvTr7ZJLyV5koslO5Zw8OhB/jHqH2zbvy2cIYqIxAwlDSLA6x1e57rG1/nd/uov\nrqbjVx35ZN4nPPD9A1qOWkTKBA1PiADPtHsGAJd1kfxSsl/X/LHZqX4asWQEI5aM0OJQIpLw1NMg\nkk8gazJsz97udTx/63xmbZrFUddRFm1bFOrQRESiTj0NIgVsfWIrdd+uC0Da2WlkLMzw67pmHzbz\nOt7z9B6qVaoW8vhERKJFPQ0iBdRJqeN5/e+r/+31XqczOvl9n+U7lwPOkEeOKyc0wYmIRFFUkgZj\nzInGmInGmEXGmHnGmJuiEYdIUVY/sppZ3WZxXJXjWP3IagCuOu0qRt4ykpOrnezXPc4fcj5D5g4h\n+aVkzhp4Fj+s+AGARdsW8eeWP8MWu4hIuERlGWljTD2gjrV2vjGmLjAHON1ae6CI9lpGWqJq3Z51\n1E6pTZXyzpbapo8J6j62t/Vcq8JJEYmEuF9G2lq7xVo7P/f1VmAHUDMasYj445Tqp3gSBoDDzx8O\n6j57D+0NVUgiIhEX9ZoGY0xLIMlauynasYj4q3xyeSbfPdlzfMtZt/h1XbU38goj3T0OE9dMpPuY\n7szaNIvfNvwW2kBFREIo4KTBGNPeGDPaGLPJGOMyxqT6aPOgMWaNMeaAMWaGMaZVEfeqCQwD7g08\ndJHoan9Ke+5sdifvX/M+lctXDuoe2/Zvo9PXnRg8dzCth7Tmgk8u4KmfngpxpCIioRFMT0MKMA/o\nARQalDXG3AK8A/QGzgP+BMYbY2oVaFcBGAm8Zq2dGUQcIlE3rNMwerTqQTmTN3u53xX9/L6+7tt1\nCw1Z9J3e1/P6ywVfsnHvxtIHKiISAgEnDdbacdbaF621owBf1WDpwCBr7X+stUuB+4FsoGuBdsOA\nn621XwYag0is6XhGRwB+vP1HHm3zaMju22VEF/6e8feQ3U9EpDRCuriTMaY80BJ4zX3OWmuNMROA\ntvnaXQh0BuYbY67H6bG4w1pb7DJ66enpVKvmvVhOWloaaWlpofsQIkG4rvF1XrMhHmr1EFXKV+Gt\n6W8Fdb9Hxz3Kh7M/BGD3gd0hiVFEEl9GRgYZGd4L0mVmZobs/qWacmmMcQGdrLWjc4+PBzYBbfMP\nORhj3gQusta29X2nEp+jKZcSl0YsGcGNw28s9X1cL7owJrhpniJStsX9lEuRsuKGpjfgetFFr3a9\nSnWfD2d/SK8JvVi1a1WIIhMRCVyo957YAeQAdQucrwtsKe3N3cMTGpKQeGKM4bUOr3HbObdxzgfn\nBHWPAbMGsHTHUqZumMqUe6Ywc+NMUiqkcHads0McrYgkCvdQRcwOT+SemwHMtNb2zD02wHpggLW2\nr+87lfgcDU9IQti2fxuLty/GZV38ueVP3p35Lusy1/l9/Rm1zmD+/fOp8EoFQKtKikjJQjk8EXBP\ngzEmBTiNvJkTDY0xzYBd1toNQD9gqDFmDjALZzZFFWBoaQIVSQR1Uup4NsS67NTLSG+bTpVXq3Dg\nqM8V1AtZumMpLQe3LLHdjI0zyD6SzWWnXlaqeEVE8gu4p8EYczEwkcJrNAyz1nbNbdMDeApnWGIe\n8LC1dnbQQeb2NFx00UUanpCEs+/QPo5949igru1/ZX++X/E9P93xk9d57W8hIvmHJyZPngwh6GmI\nyoZVgdLwhCS6ghtgXdnoSsavGu/39QOvGciPq39k5C0j+e/i/9L5m86AkgYR0ewJkYST2sR7Nfb3\nr3k/oOt7/NCD75Z+xw1f3+BJGPLbmrWVq7+4mqzDWaWKU0TKtlDPnhCRIDxy/iOMXuapJ6ZhjYZB\n3Wfk0pFex/9d/F82ZG4g+0g241aOY9LaSVzX+LpSxSoiZVdc9TSkp6eTmppaaLUrkXjXoWEHr6GE\nUC3k1Pmbzjz242Oe+/kzHLlp7yYGzR7E/K3zQxKDiERHRkYGqamppKenh+yecdXT0L9/f9U0SJlx\nT/N7OOo6ymfzPyv1vdzJgi28x1whrT5qxeaszU571USIxC33pIF8NQ2lFldJg0hZ8knHTwDYsHcD\nk9ZOouXxLZmzeU5Q9+o/oz/gX0+DO2EQESkoroYnRMqik449CYDp/5ge9D12HtgJQKevO3HZMGft\nhnpv12PwnMHFXrd532bGr/R/FoeIJLa46mnQMtKS6ObfP5+K5Sp6nXv/mvfpck4XKiRX4I0Ob/DM\nz8+U6hkT105k6vqpbN2/le5ju5PjyuGYiscwae0khqQO8Wr7f5/9H4u3L+aT1E+457x7SvVcEYms\nmFtGOlK0ToNIHpd1kfxScljuvePJHdTqW8tzXK1iNTIPOf/DUX2DSHzSOg0iZViSSaL3xb0Zf/t4\n1vRcE9J7f7/ie69jbcctIvnF1fCEiDj+eck/Pa+TTBIu6wrJfZfuWBqS+4hIYlJPg0icM4SuN+D1\nqa97He85uMfzOh6GMkUkvOIqadDiTiKFjbp1FHc1u4tdT+3ynHuw1YMhf07SS0mYPoZlO5YBkOPK\n4Yv5XyiZEIlR4VjcSYWQIglkxsYZtP24Lf2u6MdjPz4Wtucse2gZ09ZPo+voroxNG8t5x59H/X71\nWf7Qck4/7nSvtgu2LqBRzUZUKV8lbPGISNFUCCkiPrWu35rhNw3n4dYPh/U5o5aO4pUprwCw/8h+\npqybAhTe+wLg3A/P5Z5Rmq4pkgiUNIgkEGMMnc/qTLmkclx92tVhfc7q3asBuOW/t3h2z3x6wtM+\n2/+55c+wxSIikaOkQSRBjbhlhOd1qKdmFiy+7Damm+f1om2L+GPzH17vWyzDFw2n6ftN2bZ/GweO\nHAhpPCISGUoaRBJUpXKVPK8bVG8Q0ns/8dMTRb539gdn02JwC9K+TeNwzmHP+cd/fJylO5ZS9+26\ntPu0HQNmDlARpUiciaukQbMnRII36LpBntcXnXJR2J/31cKv+OQPZ9Mta61X78TczXPpOa4nC7Yt\nCHscImWVtsbW1tgiQbuv5X10H9sdgF/v/pVf1/5KpXKVaPNxm7A9s6RhCPU0iIRPOLbGjqueBhEJ\nzBsd3qD9ye19vndxg4sLTY8MNfe0T4v1uSR1cctUr9i5gm6ju4VstUsRKT0lDSIJ7Ol2TzP5nslF\nvl+jUg1evexVNj++OaxxrNy1kg2ZGwqd33doH9lHsj2zL/J7ZNwjfPzHx16rUopIdMXV8ISIhJYx\nhmfbPxuRZ1kKD0W0+7Rd3vsFdtFMMs7PNBrCEIkd6mkQKUOqV6rOCxe94PO959s/H+FoiucunNTw\nhEjsUNIgUobsfno3L136ks/3Xr7sZWxv6/n1cerHEY2t77S+/LbhN8+xu97BVw+FiESHhidExKdI\nDws8NeEp57m9Ldv2b2Ps8rFRiUNEihZXPQ1ap0EkctzDAp3P7EzlcpUBIrLp1P1j76fu23ULxSEi\ngdEul9rlUiRiBs8ZTPex3fm046dcdMpFjFwykpvOvIkG7zaIaBybHtvECcecENFniiQS7XIpImHn\n/gnfYGhYoyGPX/A4p1Q/hUY1GkU0jhxXTkDtG/+7MaaP4abhN4UpIpGyS0mDiPhUq0otr9/dfvvH\nb8zrPs/nNc3rNQ95HDnWSRr+NeNfmD7G82tL1haf7VfsWgHAt0u+DXksImWdkgYR8enGpjcyrss4\nrjn9Gq/ztVNq06xeM5/XTLhjQsjjuG/MfQC89Kv3rI+F2xbS77d+tBzckhuH30iP73sUurbcS+X4\nde2vIY9JpKzS7AkR8ckYw5WnXelX21WPrGJH9g6Oq3JcyOP4afVPnngKevzHxwFnAyyAgdcO9Ho/\nx+bwwewPuLjBxSGPS6QsUtIgIqXWsEZDGtZoGLb7z/5rNrsO7PI656uIe/nO5YXOafaFSOhoeEJE\nYl6rj1oVOudr0aezBp5V6Jw7abDWkrEgQ0mESCmop0FEgtKgegMa1WhUZEFizco1C/UOhNKMjTMK\nnTvqOlronMVireWjuR/RfWx3Ducc5q7md4UtLpFEpp4GEQnKmp5rmHDnBBb2WOh1/trTrwVg51M7\ni7z2nDrnsPqR1aV6fu9Jvf1q57Iu+s/oT/ex3QHIPJRZqueKlGXqaRCRkPru1u84nHMYgFndZnH+\nkPN9tju1xqmRiWfpd3y39LuIPEsk0cVVT4OWkRaJfeWSynmWm65aoarPNu56hKEdh0YqLC9T1k3h\n6Z+eZveB3Z5zOa4cBs0eRNbhLD6e+3GhQsvsI9l88scnkQ5VJGjhWEY6rnoa+vfvr2WkReLIqTVO\n5fSap7Muc52n9wHyZj60ObFNVOK6aOhFgLMQ1IhbRgDOYlD3f38/fX7tw+aszbQ+sTVn1znbc82L\nE1/knd/eoe2JbWlau2lU4hYJRFpaGmlpafmXkS61uOppEJH4UqlcJZY/vJx7mt/j8/1oz2QYuXQk\nr095HYB9h/YBsDlrMwDnfHCOV8/C3kN7AbySH5GyRkmDiITdgKsHMOMfM1jTcw2QNzwRjaSh57ie\nXsfP/vIsLuvirelvFWo7YskI9h/ez5C5QzA4i0tZLL9v+p3pG6ZHJF6RWKKkQUTCrkJyBVqf2JoG\n1RvQun5r+l3RD3AWhWp8XGP6X9k/qvGt3r3a58JQ5ZLK8cbUN7h3zL3M3zYfcIZWzh9yPhd+cmGk\nwxSJuriqaRCR+DejW976CpXLV2bZQ8sAeLTNo/yx+Q9aDM6rW7K9Ldv2b6Pu23XDGtO2/dt8nt95\nYKdnwyz3mhNr9qwJaywisUw9DSISM3ztLxEJo5aO8nl+2vppHMk5AuQVb36z+JtC7XJcOfy17y+f\nS1uLJBIlDSIS0yLxReyrngGgSa0mvP3b20BeQvPVwq8KtbttxG3U71ef92a9F74gRWKAkgYRkSIs\n3bHU87qo5bIBhi8aDsDPa34u9n4bMjfw69pfmb91fmgCFIkw1TSISMxwz1DI79iKx3od1z+mPpv2\nbYpUSB7uKZfF8bWJVn4n/+tkz+ttT2yjdkrtUsclEknqaRCRmOGrpqFy+cpkP5sNOLMwNj62MdJh\nFWnu5rnszM7bY+NIzhEWbVvks22OK8fr+LeNv4U1NpFwiFrSYIwZYYzZZYwZHq0YRCQ+JCclRzsE\nn1oObkmDdxt4jv+38n+c/cHZZB/JLtT29amvex13/Kojy3YsC3eIIiEVzZ6GfwF3RPH5IhInkozz\nv6pYnJ2QdTjL57mjrqNeyYOvrbz3HNwT8POyj2Rz1HXUs4JlojiSc4Ql25f4/POU2BG1pMFaOxnQ\nvx0i4lGrSi2f55ON09NQUs1ArMg+ks1Nw28i5bUUADIPZvL9iu8LtQumByXltRTKv1yeY984ls37\nNpc61lixdf9Wzhx4JtPWT4t2KFIMFUKKSMw44ZgT2Ji+keqVqnvt8RCt9RuCdfDoQUYty1v7oage\nBXcPSrC27d/G8cccX6p7iAQi4H9jjTHtjTGjjTGbjDEuY0yqjzYPGmPWGGMOGGNmGGNahSZcEUl0\n9Y+tT0qFFGpUrlHoPffwhLvnIVY1fT9vF8xLh13Ka1Ne89nuwR8exPQxLNy2EHA2wzJ9DL0n9g7q\nuZ2+6sT4leODujbaYnHoSQoLJs1NAeYBPaBwX6Ex5hbgHaA3cB7wJzDeGOO731FExE/u4YlFPRYx\n4uYRjLrV90qOBT3b7tlwhlWsSWsnMXjuYJ/vuesc3EWSa/esBeClyS8F9axRy0Zx96i7g7o2VsRb\nr1JZE/DwhLV2HDAOwPj+200HBllr/5Pb5n7gWqArUHDZNZP7S0TEb01qNaFJrSYAXHzKxfy67tci\n2/776n97loKOVRv3bmRH9o6Ad/30VeNR3CJUB44cYO+hvdStGt69PIIRL/UqZV1IaxqMMeWBloCn\nL85aa40xE4C2Bdr+BJwLpBhj1gOdrbUzi7t/eno61apV8zqXlpZGWlpaiD6BiMSyYLqwrbW0PKFl\nGKIJncnrJlO7b20WPrDQc27u5rm0OL5FMVcVf7+LTrmo0PnLP7ucaRumYXvH7he0rwW+xH8ZGRlk\nZGR4ncvMzAzZ/UNdCFkLSAa2Fji/FWiS/4S19vJAb96/f39atAjuPyIRiX++fhotqTvbZV2FvkAP\nPX+IRdsWee2oGQvcO2oCrM9cX2LSUNQX7Kpdq3wmDdM2aGZCovP1g/TcuXNp2TI0ibNWhBSRhOYr\n0aiQXIHK5StHIZriTd8w3fN68rrJAMz5aw7b9m9j8fbFrNuzrtA1P636qdDwS6DDHLFAhZDxIdRJ\nww4gByg4YFYXKHqgzU/p6emkpqYW6noRkbIr/0/bF5x0QaH3L2/odGqeU+ccAJ5v/3xkAgvCA98/\n4Hndf0Z/AP720d9oM6QNZw08y2v1SYBVu1dxxedXFJqdEc/1ASqEDJ2MjAxSU1NJT08P2T1DOjxh\nrT1ijJkDdABGg6dYsgMwoLT31/CEiBQl+9lsuo3pxvQN01n58Eoa1Wzk9f78B+J3Z8k1e9b4PO9e\ncXLD3g1e5+OypyGOE51Y5R6qiOrwhDEmxRjTzBjTPPdUw9zjk3KP+wH3GmPuNMacAXwIVAGGhiRi\nEZEy4vvlhVeRzM+9ONTyncu9FsPatn8bGQsyOHDkAPsP72dH9g62ZhUsNYtNKoSMbcH0NPwNmIiz\nRoPFWZMBYBjQ1Vo7PHdNhpdwhiXmAVdaa7eXNlj37AnNmBApm24757ZC5649/Vomrp1IuaRydDi1\nA18u+NLnwlD+aFC9gWethGZ1m/Hn1j9LE26pXZdxXbHvD5ozCIAp66dw93d3e85PXjeZFya+wO3n\n3s7czXNZvH1xOMOUGOWeSRHK2RMmHopPjDEtgDlz5szR8IRIGXXw6EHKJ5UvtF+DtZYDRw9QpXwV\nrLVkH8kmpUJKifdbumOp18qNAEseXEKD6g3IceUweM5gHvvxsZB+hlCrVrEamYecL4TaVWqzPdv5\n2eySBpcwae0kGtVoxKrdqwpdF4tTLtfsXkPDAQ2ZcMcEOjTsEO1wEkq+4YmW1tq5pbmX9p4QkbhQ\nqVwln+eNMVQpX8Xz2p+EoSjlk8p7nlPafSEioXxyeZ/n3bMpyiXF3//iVQgZ22L/vwoRkQjJ/4UV\nD0nDjuwdntf5t5R21zcs27ms2OsnrplI2rdpXlM9P577Mc/9/Fyx1/WZ1IcPZ3/oOd6atZXXprxW\nqmmTKoSMD7H/X0U+mnIpIuGUvwgvmG2rAc6rd16owgnIgaMHPK8P5Rzy65rL/nMZXy38igs/udBz\n7ve/fmf8quI3vfpx9Y+efTPAmSr63C/PeSUxwVIhZOjE/JTLcNOUSxEJtbua3UX2kWy+WfyNV++C\nvz0NtrfF9Mn7oruu8XX8seWPkMcZiENH/UsafPGnt8Ba6/Xnk3/mhsSOmJhyKSKSSGzuP+A9PBHs\n9tuxUEdwxFW6Dbr8WZrbV1JVmnqEeCjKFyUNIiIe+bvGg61pKJ/kuzgxklbvXl3s+5/9+RnjVo7z\nOnc45zBfLviSQzmHmP3XbPYc3MPIJSN9Xp8/aXBZF9+v8F5P4umfnqbdJ+1YvXs16zPXM2H1BD6f\n/zlHXUf9iv+fk/7JH5uj21sjvkU/JQ6A1mkQkVAragz9qtOuCup+wdZCRNKd391Z6Nxb097ihYkv\neI5bDm7J6t2rOfrC0UKfKX/SMGLJCM9595/lW9PfAqDRgEbUrFyTXQd2AbD7wG4ebv2wz5jcvT0W\nS59f+3BytZM57/jo1IckinCs0xBXPQ39+/dn9OjRShhEJGQs1tM1nr97vf6x9Ytcz+CfF/8TgP91\n+V+h92JheCIYO7N3eh2vz1wP+B7qcFmXJ0HIP2vDF3fCALD30N4S4/D8XaggstTS0tIYPXo0/fv3\nD9k94yppEBEJldJ8KRU3dh+vSUNB7pqOgjtogpNouXsaQv3l7qu+RGKHkgYRKZPyrwsQ6BoBxRXt\nxcP6Dv5wD0n4mhmRf3gi/5d7adZacP+Zun9PlD/HRKO/FRGRXIH+1Oyrfbx2q/9r5r+8jt07aE5d\nP5VP//iUjXs38vPqn7lk6CXM3zqf935/j61ZW1mxc4XnmgNHDuCPH1b8wJy/5vh8z514vP/7+/xv\nxf94YOwDnl07F29fTI/ve7D7wO6AP5+ERlwlDVrcSURCJdAv9xE3j+Dz6z/nkfMfKbZd57M6lyas\nmNPp6050Hd2Vjl915M+tf/Lrul897+06sItXprziOe73Wz+/7nntl9fyt4/+5nWuYC/FrE2zuObL\na/hwzoeepGF95no+mP0B+4/sD/bjlCnhWNwprpIGFUKKSDj4KoQs6Pqm19Pl3C68e/W7xXbD10mp\n47OA8pc7f/HZvkr5Kp69M2JZ5sHMQolWwSmU/q5EWRxfQz/upEFrOQRGhZAiInGquIQkHr4Mc2xO\noc9Q2kWkfPGVkHnqHdDMimhT0iAiZV6gBXyh/tJy/yQdy466jpbY01AaxSVOBf98NLMiepQ0iIjk\n8jcZCGaWQHH3jocdHnNcPnoafEzHLC0NT8Q2JQ0iIkEK5Cfe4trGQ0/D5qzNhXa/bPdpO6/jD2Z/\n4LV5V0HjV41n6LyhnmOXddHvt34cOnqo2MTJkzTkG57YfWA3Fw+9mDW715B1OIsHv3+Q+Vvn+/15\nvln0Dct3Lve7fX7fLf2OPpP6APDRnI/Yvn97UPeJR3G1ComWkRaRUDm1xqlccNIFPHPhMxxxHWFn\n9k5qp9Qu1K7PJX1KVaj47c3f8um8T4t8/+ubvsZlXXT8qmPQz4iUH1b8UKrrp6yfwpT1UzzH41aO\n491TqucAAA+zSURBVPEfH8dguPr0qwHfvS6+hiceHf8ok9dNpuGAhux4cgcDZw/k8kaXc27dc/2K\n5eb/3kzVClXZ12tfwJ9j+obpjFw6kl7te3Hf2PsYtWwUY28bG/B9wi0cy0jHVdKgrbFFJFQqJFdg\nWtdpnuPJ90z22e7Fi18sdC6QbvIbmt7ADU1vYPI67/sXtUR1WeKuiThwNG99B3+HJ/Yfzpt26e7F\nCbTHpqQlsItScKgp2PuEm7bGFhGJU6r4Lyz/TpkFZ0jkV6inocCfpfs4kjUP+Z8VDzUpoaKkQUQk\nQKreDw130pDjyvGcK7anId+Xc/6/g/zJRyQYY7yXIS9DBZpKGkREJCrcm2K5rMu/Qsh8i3Dl721w\nJxCR+onfYLDWFts7kqiUNIiIBCiYnyzVO1GYry97f4cnot3TAGUrWXBT0iAiEiTVKZSOry97f4cn\n8otKTQO20M6cZUFczZ4QEYkF7imY5ZPL+31NheQK4Qonbl3+2eUAvDrlVSaunQg4G2QVdGL/E72O\njTEMXzTcc1z19aqA76TisfGPkXU4i8F/H+wzhtl/zeZvJ/yt0PlRS0fx7C/PMq/7PK+/5/vH3u95\n9lkDz/I8t/2n7amTUoelO5Yyq9ssUiqkFP3B41hc9TRol0sRiQWPtnmU965+j4tPuRiAJy94ssRr\nWp3QyvP6vhb3FXr/6Quf9jp+9bJXaXl8aKbJxYPpG6b73baoHh5fwxMb9m5gXea6Iu918OhBn+d3\nH9zN4u2LC50fNGcQuw/uJsfmsGbPGs/5ZTuWsWrXKhZvX0yOzSl0XTRol0vtcikiMaBiuYo8eP6D\nnrHtty5/q8Rr3G0rlavEoL8PKvR+k+OaeB0/2/5ZKparGIJoyw5fwwTW2mKHkdxDJEXdq6halPz3\ntNZ6tYuV4QrtcikikqCK291RvBX1Re6rp8Fiiy1Cdc/g8HUd+Fe3YvFOTBK5QFJJg4hIBBX1JeTz\np+QE/vIJh6ISr3D0NBR6Rgz2NISDkgYRkQgqKhFQguC/QGoaSuxpSCp9T0PBdon8d6mkQUQkRiXy\nT6ylUVQSENGaBuOdJKinQUREIkbDE6UXjpoGfxRMTBL5701Jg4hIDEjkL5pQK7IuJIQ1DcU9x2db\n9TSIiEikFNW1Lv4LpremyJqGAP7sCz4jkRNAJQ0iIjEgkb9oQi2gKZe2+OGJImsaShjWKPQMykZP\ng5aRFhEJE/dy08E6/pjjfZ6vk1KHbfu3lere8azaG9V8nh+9fDQvT36ZzVmbC71n+hguPOlCpm2Y\n5nU+2SRz2oDTuLLRlQycPbDQdV8u+JJnJjxDn0v60HV0V8/5PQf3eF5bLBv2bmDD3g2e40QVVz0N\nWkZaROLFlHumsLhH4WWIi+L+6bTv5X0Zf/t4AIZ1GkblcpUB+Pbmbz1tZ3Wb5fMezes1L3RuZreZ\nvHzpy1QuV9lr/4skk8QH137AyodX+h1jrHv6wqd9JgxuBRMGgJqVa7Jt/zY+nfepz2uW7VjGhr0b\nOOo66nccsdLToGWktYy0iMSJdie345Tqp/jd3v3TaZ2UOlzR6AoAqleqzjWnXwPA+fXP97Stf2x9\nn/c4u87ZACzqschz7vz65/P8Rc+T/Vw271zxjud8zos53P+3+2lUs5HfMYbaZadeVuR7k+6axNWn\nXR3Q/S5pcElA7Xu27kmNyjWw2CJrG9z7SJx47Ik+34fYSRIK0jLSIiIJyrMuQBEV+/nP+9MmHhT3\nZWuMKXZmQyif77KuIqde5rhK3nxKhZAiIiJRZIhA0pD75W5tyT0NAd03RnseQkFJg4hIDPAsW1yg\nYt/XeX9WKYwHxf1EHkxPQ7Bf1qXuabDqaRARkQgqaXjCH/E2POFriqRbMD0NgX5Zu//Mi6tpKC7G\nop6rngYREQmJor5QAvnCi7fkIBjGmIB7Tvz5gs/P/WdebE+DH8MT6mkQEZGIKmqDpEB6IOJteKI4\nQfU0BPkTvrW2yGcFVQipngYREYmEspQchHr2RMA9DflnT5SiEFI9DSIiElFFFUIGoqSEI9Z+Ai7u\nSz7JJIW/poF8NQ2lKIQsdN8Y+3MOJSUNIiIxoCwWQhYnmOGJYHoa3H/uIZ1yqZ6G0DPGXGeMWWqM\nWWaM+Ue04hARiWWh6IFwi7VhjViYcumOoVSFkKppCC9jTDLwDnAJ0BJ42hhTIxqxREOi7Z2hzxO7\nEumzQGJ/nlAmB0UJ65fZgtDezuT+E4hgZk+4rynU07DA/3uqpiH8zgcWWmu3WGuzgO+BK6IUS8Ql\n8v/4EkEifZ5E+iyQ2J8nFMMTURVE0hDqQshg1mnwDE8U7GnI/TyaPeEtWknDCcCmfMebAN87sIiI\nlGGJ/AVUnEjUNOS/RrMn/BNw0mCMaW+MGW2M2WSMcRljUn20edAYs8YYc8AYM8MY0yo04YqIJKaS\nhifitgeiGNGuabC5/0AxNQ3qafASTE9DCjAP6AGF/8aNMbfg1Cv0Bs4D/gTGG2Nq5Wv2F5B/n9H6\nuedERMqkuB+eCEKxwxMRmj0Rip6GQvdN4J6GcoFeYK0dB4wDML5T4nRgkLX2P7lt7geuBboCb+W2\nmQWcZYw5HtgHXAW8VMxjKwEsWbIk0HBjUmZmJnPnzo12GCGjzxO7EumzQIx/ntwfe4qN7y/ISc7x\ntMn/eTYu2wh/werFq5l7MO8ee9bsgb/gz3l/ej/Dx49ZO47ZAX/Boj8X+Yxnw9INvuMMxY9sBwO/\nT9bRLNjm+72lC5ayc9XOgO758Q8fB9R+ZcWV9DvQD/6CGX/N8H4z9/N899d3ANw58E7I9n2frH1Z\nzjdZrt9m/UZ2vSIaR0G+785Kpb2XKU03ijHGBXSy1o7OPS6P88d6o/tc7vmhQDVr7fX5zl2H0yNh\ngDettR8X85zbgC+CDlRERES6WGu/LM0NAu5pKEEtIBnYWuD8VqBJ/hPW2rHAWD/vOx7oAqzFyf9E\nRETEP5WABjjfpaUS6qQhLKy1O4FSZUciIiJl2PRQ3CTUUy53ADlA3QLn6wJbQvwsERERiaCQJg3W\n2iPAHKCD+1xusWQHQpTliIiISHQEPDxhjEkBTgPPvKCGxphmwC5r7QagHzDUGDMHZ5ZEOlAFGBqS\niEVERP6/vTsPmaoK4zj+/Zm2E/3RImFUtkelZRQtantUZtQfbVCEtFpaUZhSQSVRWaiVWdACabSv\nCBWtiNkqVpa2GEppVtBOGm0+/fGct6ZJ3/fOneE9c6fnAwPO9TLv73Bnzjxz7j3nhiwanj0haTjw\nCv9do+E+MxuV9hkNjMNPS7wLjDGzec3HDSGEEEIuDZ+eMLPZZtbHzNape4yq2We6mW1rZhuY2f7N\nFAydsrqkpAmS3pL0k6SvJT0paafcuVpB0vi0Oujk3FnKkrSVpJmSvpG0StJ7kvbOnasMSX0kTZS0\nJLXlU0lX5s5VVMFVZ6+VtCK17wVJO+TI2pPu2iKpr6QbJS2Q9HPa5760fk1bKnJsava9M+0ztjcz\nNqLge21XSU9L+iEdpzclDVjT6+XUU1skbSRpmqRl6XOzUNK5jf6dbLfGLqLg6pJVMRS4DdgPOBzo\nBzwvaYOsqZqUirhz8GNTSZI2BeYCvwJHAbsClwLf58zVhPHAufiqrbvgo37jJF2YNVVxPa06ezlw\nIf6+2xdYifcL6/ZmyIK6a8uGwGDgGrx/OwGfmv50bwZsULfHpoukE/C+7ou17dMmenqvbQ/MARYB\nw4A9gIm059T/no7NFPzGkKfh/cIUYFpaM6m4rrt8teMDeAO4pea5gOXAuNzZWtC2zYDVwEG5szTR\nho2Bj4FD8VNWk3NnKtmOG4DZuXO0sD2zgLvqtj0GzMidrURbVgMj67atAC6peb4J8AtwUu68jbZl\nDfvsg89AG5A7b9n24LcF+BwvvpcCY3NnLdse4EH81Hv2fC1oy/vAFXXb5gHXNvLabTvSkFaXHAK8\n1LXNvJUvAvvnytVCm+LV4He5gzThdmCWmb2cO0iTjgPmSXoknTqaL+ms3KGa8BpwmKQdAdKFygcC\nz2RN1QKStgP68+9+4SfgTTqrX/ghd5Ay0my5GcAkM6v0uv+pLccCiyU9l/qGNyQdnztbSa8BIyVt\nBSDpEGBHGlzwqW2LBrpfXbJ/78dpnfRmnAq8amaLcucpQ9Ip+NDqhNxZWmAgcD4+anIkcAdwq6TT\ns6Yq7wbgYeAjSb/h06CnmtlDeWO1RH/8S7UT+4X18GP3gJn9nDtPSeOB38xsWu4gLbAFPpp6OV5w\nHwE8CTwhaWjOYCWNAT4Elqd+4RngAjOb28iLVGJFyA40HdgN//VXOekioKnA4eZrc1RdH+AtM7sq\nPX9P0u7AecDMfLFKOxk/b3kKfi52MHCLpBVmVsX2dDxJfYFH8YJodOY4pUgaAozFr8/oBF0/qp8y\ns1vTvxdIOgDvG+bkiVXaWPw6kxH46aNhwPTULxQeLW7noqEjV5eUNA04BhhqZl/mzlPSEGBzYH4a\nNQEfFRqWLrZbL51Kqoov8Qq81ofAiRmytMIk4HozezQ9XyhpW3xUqOpFw1f4tU1b8u/Rhi2Bd7Ik\nalJNwbA1cGiFRxkOwvuFZf90C6wDTJZ0sZkNzJasnG+AP1hz31CpH3yS1geuw28w+Wza/IGkvYDL\ngMJFQ9uenrAOXF0yFQzHA4eY2ee58zThRfwq4sHAoPSYB9wPDKpYwQA+c2Lnum07A59lyNIKG+IF\nd63VtPHnvSgzW4oXDrX9wib4L6jK9Qs1BcNA4DAzq+qMHfBrGfbknz5hEH7R6iR8VlKlpO+gt/lv\n37AT1esb+qVHfb/wJw32C+080gAdtLqkpOnAqcBIYKWkrhGUH82sHafvrJWZrcSHvf8maSXwbUUv\nfpoCzJU0AXgE/wI6Czg7a6ryZgFXSloOLAT2xj87d2dNVZB6XnV2Kt6+T/E7307EZ1W13VTF7tqC\nj3A9jhffI4B+Nf3Cd+146q/Asfm+bv/fga/MbHHvJi2mQHtuAh6SNAefIXY0fqyG58jbnZ7aImk2\ncLOkMXjRczBwBnBxQ38o99SQAlNHRuMdwy/A68A+uTOVbMdqvKqrf5yRO1uL2vcyFZ1ymfIfAywA\nVuFftKNyZ2qiLRvhBfdSfA2DxfhaAH1zZyuYf/haPi/31uxzNf4rdhV+9fcOuXM32hZgmzX8X9fz\nYbmzlz02dfsvoY2nXBZ8r50JfJI+S/OBEblzl2kLfmHnPcCy1JZFwEWN/p2Gl5EOIYQQwv9T5c9x\nhhBCCKF3RNEQQgghhEKiaAghhBBCIVE0hBBCCKGQKBpCCCGEUEgUDSGEEEIoJIqGEEIIIRQSRUMI\nIYQQComiIYQQQgiFRNEQQgghhEKiaAghhBBCIVE0hBBCCKGQvwBwX0v6yDPdggAAAABJRU5ErkJg\ngg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAg0AAAFnCAYAAAAln3o1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzs3XmczdUfx/HXmcUY29h3siRRZEtJaaFINW3IaFeplGXa\nVb+kTRRTivaVmkpalCLaVLIvIbKHsYuxDGY7vz++ZjPbnbn3zl3m/Xw8PNz7ved77ucW7mfO8jnG\nWouIiIhIYUJ8HYCIiIgEBiUNIiIi4hIlDSIiIuISJQ0iIiLiEiUNIiIi4hIlDSIiIuISJQ0iIiLi\nEiUNIiIi4hIlDSIiIuISJQ0iIiLiEiUNIiIi4pIwX72xMWYTsB+wwH/W2q6+ikVEREQK57OkAUgH\nOllrj/gwBhEREXGRL6cnjI/fX0RERIrAl1/aFphtjJlnjOnnwzhERETEBUVOGowx5xljphpjEowx\n6caY6Dza3GOM2WiMOWKMmWuMOTOPrjpba9sDVwKPGmNOL0b8IiIiUkKKM9JQHlgKDMQZLcjBGHMd\nMAYYDrQFlgEzjDHVs7ez1m4//vsO4DugXTFiERERkRJirM31ve/6zcakA1dZa6dmuzYXmGetHXL8\nuQG2AOOstaOPXysHhFhrDxljKgC/AHdaaxfl8z7VgO7AJuBosQMWEREpfcoCjYAZ1tq97nTk0d0T\nxphwoD3wXMY1a601xswCOmVrWgv40hhjgVDgzfwShuO6Ax95MlYREZFS5nrgY3c68PSWy+o4ScDO\nE67vBJpnPLHWbgTaFKHfTQCTJk2iRYsWboboe7GxscTFxfk6DI/R5/FfwfRZQJ/HnwXTZ4Hg+jyr\nVq3ihhtugOPfpe7wZZ2GojgK0KJFC9q1C/ylD1FRUUHxOTLo8/ivYPosoM/jz4Lps0DwfZ7j3J7e\n93TSsAdIw5l+yK4WsMPdzmNjY4mKiiImJoaYmBh3uxMREQla8fHxxMfHk5iY6LE+PZo0WGtTjDGL\ngK7AVMhcCNkVGOdu/3FxccGY+YmIiHhcxg/Yixcvpn379h7ps8hJgzGmPHAyTkVHgCbGmDNwzo/Y\nAowF3j+ePMwHYoFywPseiVhERER8ojgjDR2An3FqNFicmgwAHwD9rbWfHa/J8BTOtMRSoLu1dre7\nwQbL9EQgx54XfR7/FUyfBfR5/FkwfRYIjs/jjekJt+o0lBRjTDtg0aJFizQ9ISIiUgTZpifaW2sX\nu9OXDowSERERlyhpEBEREZcESp0GIHjWNIiIiHib1jRoTYOIiEiRaE2DiIiIlDglDSIiIuISrWkQ\nEREJQlrToDUNIiIiRaI1DSIiIlLilDSIiIiIS5Q0iIiIiEu0EFJERCQIaSGkFkKKiIgUiRZCioiI\nSIlT0iAiIiIuUdIgIiIiLlHSICIiIi7R7gkREZEgpN0T2j0hIiJSJNo9ISIiIiVOSYOIiIi4REmD\niIiIuERJg4iIiLhESYOIiIi4REmDiIiIuER1GkRERIKQ6jSoToOIiEiRqE6DiIiIlDglDSIiIuIS\nJQ0iIiLiEiUNIiIi4hIlDSIiIuISJQ0iIiLiEiUNIiIi4hIlDSIiIuISJQ0iIiLikoAqI92pUyw1\na0bx6KMx3H23ykiLiIjkp9SXkYZFQFYZ6dq14eOP4cILfRaaiIiIXyu1ZaQ//hgaNsx6vmMHXHQR\nGANlysBtt8GKFb6LT0REJJgFVNLQvDn8+y9YCz/+CGPGZL2WkgLvvgutWjlJhDHwzTeQlOS0FxER\nEfcEVNLw9+6/Mx9fdBHcd5+TECQnQ2xs7vbR0VC+PISEwHXXwcaNJRisiIhIkAmopOGluS/leT08\nHMaOzUogVq1ypiqy++wzaNLEGYGoVw8+/RSOHSuBoEVERIJEQCUNi7YtorCFm+HhcOqp8PbbThJh\nLaxfD5demtVm2zbo2xfKls2ayvj2WyeJ0FSGiIhI3gIqaQCYtWFWke9p0gS++85JCI4cgS5dcre5\n4goniQgJgfffh507IS3N/XhFRESCRUAlDRXKVOCSSZeQbtOL3UfZsvDrr04CkZICW7bkbnPrrc52\nzrAwZxTimWfcCFpERCRIBFTScPWpVwPQ6Z1OHukvLAzq18+axjh8GEaOzN3uf//LmsZo0gSWLdM0\nhoiIlD4BlTQMPnswAPMT5rMnaY/H+y9XDh55JCuJ2LXL2XWR3caN0KaNM41hDHz+OWzf7vFQRERE\n/I5PkwZjTKQxZpMxZrQr7UNMCLe3vR2Aiz64qNBFke6qUQM++cRJIFJTYciQ3G1694a6dbNGIoYN\ng717vRqWiIiIT/h6pOEx4M+i3PBW9FuEh4SzfNdyRv0xykth5RYaCi+95CQQaWnOuohx43K3e/55\nqF49K4l45RXY4/lBERERkRLns6TBGHMy0Bz4vqj3LhqwCIBhPw5j28FtHo6scCEhzg6MQYOypjJS\nU+GNN3K3HTzYGbHISCI++QSOHtWaCBERCTy+HGl4ERgGmKLe2KpWKyLDIgGoN7aeh8MqntBQGDDA\nSQaSkuDNN/NuFxMDkZFO4hERAZs2QXrxN4OIiIiUmCInDcaY84wxU40xCcaYdGNMdB5t7jHGbDTG\nHDHGzDXGnHnC69HAP9badRmXihrHnoeyxvx7fdbLrW2YnhYZCXfckTUKYS089ljudsnJ0Lixk3CE\nhcFNN8GSJRqFEBER/1SckYbywFJgIJDr680Ycx0wBhgOtAWWATOMMdWzNTsb6GuM2YAz4nC7Mebx\nogRRLrwch4YdAmDKqinc8tUtRf8kJeiZZ7LWQ2Q/aCtDWhpMnAjt2jmjEO3bwwcfOFMZIiIi/qDI\nSYO1drq19glr7dfkPUIQC7xhrf3QWrsauAtIAvpn6+NRa+1J1tomwAPAW9baIpdQKl+mPN/GfAvA\nxL8msmr3qqJ2UeJCQrIO2spYC7F1a+52ixfDLbc4oxbGQMWK8PXXJR6uiIhIpjBPdmaMCQfaA89l\nXLPWWmPMLMDtikyxsbFERUXluBYTE8PiAYtp92Y7Wk5oyYFHDlAxoqK7b1ViQkOdA7QypiSshZYt\nYfXqnO0OHYKrrsp6fs89znkaPXs6SYWIiEh8fDzx8fE5riUmJnqsf+NOrQNjTDpwlbV26vHndYAE\noJO1dl62dqOALtbaYiUOxph2wKJFixbRrl27PNs8/evTPPHLEwDse3gflctWLs5b+Z1ff3XOy8h+\n4FZerrnGqWZ5yiklE5eIiASGxYsX0759e4D21trF7vTl6zoNHvN4l8dpWqUpAFVGVeFQ8iEfR+QZ\n558PPXo4OywSEmDGjLzbffEFNG/ujDpUqACLFjkVLUVERDzF00nDHiANqHXC9VrADnc7j42NJTo6\nOtfQC4AxhrWD1maOMFQcWZGVu1a6+5Z+wxin8uQll+TclREf76x7yO7wYejQAWrVyqoPMWaMM8Uh\nIiKlQ3x8PNHR0cTGxnqsT49OTxy/NheYZ60dcvy5ATYD46y1LxTzfQqdnsiw89BOao+pnfk8+fFk\nwkPDi/O2AWfDBpg1C+68s+B20dHw6KNw1lklE5eIiPiOT6cnjDHljTFnGGPaHL/U5PjzBsefjwXu\nMMbcZIw5FXgdKAe8706grqpVoRZHH8vap1jmmTJBNeJQkCZNsgpMWQvr1jnHfJ9o6lQ4+2xnBKJH\nDxgxwrmu6QwRESlIkUcajDHnAz+Tu0bDB9ba/sfbDAQewpmWWAoMstYuLHaQx0caunTpQlRUFDEx\nMcTExBR4T2p6KuFPZ40wrBu0jqZVmxY3hICXkgL//OOMLiQlFdz26afh9tuhdu2C24mIiP/K2EmR\nmJjI7NmzwQMjDW5NT5SUokxP5Lp3RNZ+xIPDDlKhTAUPRxeYkpKcnRYJCQW369bNqVTZty+El45Z\nHhGRoKLdE0Vw5LEjmY8rjqzIxn0bfRiN/yhXzikqlTGVceQIfJ/H0WGzZjlJQ5kyznTG6NHw4osl\nH6+IiPhe0CcNZcPKYodnjaY0GdeER3981IcR+aeyZZ31DRlVKgcPhg8/zN3u4YfhwQezdmW89JJT\nAltERIJfQE1PFGVNw4n+O/If1UZXy3w+/frpdD+5u4cjDU7JyU7hqAYN4LbbCm67cKFT5bJNm4Lb\niYiId2lNQzHWNGRnrSXkqazBlUlXT+L61td7IMLSIzUVtmxxdmAMHVp4+9GjncO3LrrI+7GJiEhu\nWtNQTMYYkh9P5tKTnZrMN3x5Q46FklK4sDDnOO8hQ5ypjPR0p5hURETe7R96CLp2daYyzjlHh26J\niASyUpU0AISHhvPd9d/x2mWvZV4zIwxHU3UGdXEY4yyqPHo0a1HlsmV5t/3zT+fQrYz1EEuXwsaN\nsGJFycYsIiLFE1DTE+6sacjLJys+IWZKVj9r7l1Ds2rN3O5XckpKcg7Uyu/cDHDOyzh0yNnRUa9e\nycUmIhKstKbBzTUNebln2j1MWDgh8/kn137Cdadf59H3EMdffzkjDBERzuFaBbnmGnjySWd04o47\ndPy3iEhxaU2DB42/bDz7H96f+bzvlL4MnDaQY6nHfBhVcGrdGlq1copKWQsHDjjTGq1b5277xRfO\n9TvvhJAQJ2l47DE4pv8tIiI+U+qTBoCoslGkPZFG+zrtAXht4WuUfbYsgTAKE8gqVnRGHZYtc5KI\ntDTYvRsmTMi7/XPPOfUkMtZEfPedTu4UESlJShqOCzEhzL9jPvUqZk2ohzwVwpLtS3wYVekSEgLV\nq8Pddzu7Mlatgnnz4Mor825/2WVO4mEMDBzotJs3r2RjFhEpTQJqTYOnF0Lm5+Cxg1R6vlLm8/s7\n3c+Ll6h2sq/99RfccgsscSGP690b3n/f2dkhIlIaaSGkFxZC5uevnX9xxutnZD4/q95ZTOkzhXqV\ntLTf19atc2pFTJ4MruSO0dFOu759vR+biIi/0ULIEtC6VmvscMsd7e4AYF7CPOrH1efaz671cWRy\n8slOqeq+fZ2FkRlFppYvz7v91KlO0pCxFsIY59CtjPtERMQ1ShoK8eYVb7J56ObM51+s+oIbvrhB\niyT9RJkyzu/GwOmnZxWYWrjQOVjr7rvzvu/BB501FKGhzr3nneec9CkiIvlT0uCCBlENSHsi6yjH\nj5Z/RMhTIew/ur+Au8SX2rd3zr2YMMEZTfjtN2c6o2fPvNv//ruz/sEYJ9HYn+1/7b59JROziIi/\nU9LgohATQvoTOceyq4yqwtWfXs3WA1t9FJW4whg491zo1QumTYO1a52dGbNm5d3+9dehSpWsqYyq\nVWHbtpKNWUTEHwVU0hAbG0t0dDTx8fE+ef+MA6/uan9X5rWvVn9Fg7gGTFw20ScxSdGdfDKceqpz\nkFbGdMbVVxd8T716Tk0JY5xdGSIi/i4+Pp7o6GhiY2M91qd2TxSTtZaKIytyOOVw1rXh/v/fUgqW\nmAiff+7suGjf3jkG3BUpKbBzp87NEBH/o90TfsAYw9pBa+nXql/WtRGGzu92Jt1qSX6gioqC226D\nGjVg82ZnFOKff+CRRwo+LyM8HOrXh7Zt4cYbnePCRUSCjZIGN9SpWIePrvmIlQNXZl6bs2UOoU+F\nMm7eOB9GJp50yikwciSsXg27djnrIc4+O++2S5fCpEnOqZ3GwCefOEmHiEgwUNLgAS1rtOS9K98j\nKiIq89qQ6UMwIwzzE+b7MDLxtBo1nPUQf/7pjEK8/LJzvVOnvNvHxDjtMxZVxsfD/PnOEeAiIoFG\nSYOH3NLmFvY/sp/uTbvnuH7W22fx88affRSVeNvgwU7yMGdOVoGpjEQiL/36wVlnQYMGThIxejTs\n3esc1iUi4u+UNHjY9Bumk/RoEt2adMu8dtGHF2FGGPYk7fFhZOJtGQWmBg92EoiXXoKVK50pjfw8\n/LBzSFdYmHP/kCFOPYn//oM9+uMiIn5GSYMXRIZHMvPGmbx9xds5rtd4oQbVRlcjJS3FR5FJSclI\nAFq2dKY0Dh+GhAT4+mtnjUR+xo2DPn2gWjXnvmHDSi5mEZHCBNSWy5I65dKT1v23jmavNMtxLTwk\nnIT7EqherjrGGB9FJr528KCz3sHVwlHNmztTG889p62dIlI4nXLpR3UaiiI5LZkZ62YQ/Ul0jutD\nzhpCXPc4JQ7Cb79Bly7w3nvOL+fvd/66dnV2aRw8CM2aQWqqU/q6evWSiVdEAocn6zQoaShBx1KP\nUW9sPfYe2Zt5zWDY8cAODicfpnGVxj6MTvxJerpzmJYrypWDpCTncVwcXHMNNGzovdhEJLCouFOA\nigiLYM9De3Kcmmmx1HqxFk3GNfFhZOJvQkKySlxbC8uWOWdmvPRS7rYZCQNAbCycdBLMnAn//guH\nDpVczCIS/JQ0+ECDqAaM7zmednVyjpo8/tPjbNi3wUdRiT9r3do5M2PIEDh2zBmJ6Ncv//aXXAKN\nGkHFik5J7IEDnSkMERF3aHrCx+797l7GLxif49rlp1zOx9d8TMWIij6KSgLJb7/BunWwaRM89ZTr\n9+3cCTVrwqJFTkISFVX4PSISeDQ9EURe7vEyn1z7CSdFnZR57ds131Lp+UqYEYYVu1b4MDoJBOed\nB7feCiNGOFMZK1fCQw85ax0KUquWszW0QweoXNkpeS0iUhAlDT4WGhLKdadfx6ahmzg0LPcEdKvX\nWvG/n/5HIIwIiX9o2RJGjXJqQ1gLP/8M993njCh06JD/fTExWeWuT9y98e+/OddOiEjppKTBj5Qv\nU56jjx3Ndf2Z356hx0c9OJqa+zWRwlxwAYwZA+3awYIFsGGDc7DWuefmf8/55zu1IK6/3lkX0agR\nXHVVSUUsIv5KSYOfiQiLIPGRRH6/9fcc139Y/wORz0bSZ3IfEg4k+Cg6CQaNG8MZZzhrIb791jkK\n/J13crfbtg0+/jhrB8bMmc4oxBVXOGsgnnlGpa5FShsthPRj+4/u5/fNvzN0+lDW71uf47X4a+M5\ntfqptKndxkfRSbBZuhRq14YlS+Cyy5ypDVds3QpPP+0swqxZE9avh6ZNvRuriLiu1BZ3CsQy0p5y\nLPUYZZ8tm+v6gjsW0KFuARPVIm6wFpKToWzuP3oFevZZZ0tohQqqUiniKyojXcpGGk508NhBmoxr\nkuu0zKZVmvLDjT/QpIoKRIl3HD3qFJx68UVnWiMxEf7807V7+/Z1dmbExcHQod6NU0RyK7UjDaU9\naQCw1hLyVN5LUcqHl2frfVupXLZyCUclpVFyMnz+ubNY0lXvvgtVq0KZMs4URqNGzmMR8R7VaSjF\njDEceOQA43qM49uYb3O8djjlMFVGVWHisomkpqv8n3hXmTLOFMSGDc5hWUeOwOWXO6/lNyXRv7+z\nC6NnT+fUzogI2L4dfv8dfv3VaZOSAnv35n2/iPiWRhoCXLpN59RXT2Xtf2tzvXZKtVNYfc9qnaIp\nPrF2LdStC5995iQLrhg5EoYNcx4HwD9NIgFBIw2SKcSEEN08Os/X1uxdw4z1M0o4IhFHs2ZQvrxT\nrXL+fPjjj8LvyUgYAHr3hmrVoFUr+N//nF0ZIuJbGmkIAqnpqfx35D9qvVgrz9dbVG/Blc2vZOjZ\nQ6lVIe82IiVl3Tpo0MA5QOuVV3ImCq5Ytco5Z6NHD6+EJxJ0tBBS8rTz0E6SUpKIXxHPYz89lmeb\ntrXbsvhOt/7MiHjcm286Za7ffNP1ex5+GOrUcdZCfPGF92ITCXRKGsQlo/8YzcOzHs51vW7Fuqy5\ndw3ly5T3QVQi+du61RmBiIpypjW+/tr1e3/9Fb780ikyZYyzOLN+fe/FKhIotKZBXPJQ54f44YYf\nqFexXo7r2w5uo8LICjSIa0DCgQS2HdzmowhFcqpf39mGWaUKfPUVLFvmTGUcPFj4veefDy+9BJUq\nOedlNGgAmzc71S1Xr/Z66CKlgpKGIHdx04v5d+i/eb629cBW6sfVp97YehxOPlzCkYkUrnVr54u/\nQgXnpM3Vq6FJE0hw8fiVk06C776DFi2c0YcePZwFmYez/XH/6CNn26iIFC7MF29qjIkCZgGhx2MY\nZ6192xexlAahIaHY4VnTUGZE7i2YFUZWYHLvyfRq2askQxNxWcOGzu8ZuygOHoTvv4d9+5yKlUOG\nFN7HjBnOrxPVrw9btnguVpFg5auRhgPAedbadsBZwKPGmCo+iqXU2fPgHp7o8kSu670n98aMMPy8\n8WeSUpIIhPUuUnpVqOBsyxwwAAYPduo6LFzoVKk85xznGHBXbd3qlMY+0bFjzk4NEXH4fCGkMaYq\nsBDoYK39L582WgjpBU3HNWXDvvzHZW9tcyvt6rTjpjNuolJEpRKMTMRz0tJgzhy48ELncXEof5ZA\nFhQLIY0xUcaYpcBm4IX8Egbxnnm3z2PF3StYOXBlnq+/t/Q9Bn0/iKjno5i3dR67D+8u4QhF3Bca\nCued55Sm3rbNKVM9Z07R+khIgPffh8mTvRKiSMAoctJgjDnPGDPVGJNgjEk3xuQqR2iMuccYs9EY\nc8QYM9cYc+aJbay1idbaNkBj4HpjTI3ifQQprurlqnNazdNoWaMlq+8peHn52e+cTc0Xa5ZQZCKe\nFxXl1HUIC4NOnWDHDucI7+nTC7+3fn1nC2ifPnDKKc62zo8+crZ1nmj/fhg7VqMTEpyKM9JQHlgK\nDARy/bUwxlwHjAGGA22BZcAMY0yeR9hYa3cfb3NeMWIRD2levTk77t/Bsxc9W2C7FbtWlFBEIt5V\nqxY8+ih07+4spvz5Z+eL/siRnG1OtHYtDB8ON9zgbA2NiHB2ZhgDo0c71+6/X9s8JTi5tabBGJMO\nXGWtnZrt2lxgnrV2yPHnBtiCs0Ni9PFrNYEka+2h4zspfgf6WmvzHCfXmoaSt+3gNuqNrZfv66fX\nPJ0nujxB61qtaV69eQlGJlIyZs+Gli2d8zPKlSteH59+6kyFPP54/id/inib31SEPDFpMMaEA0nA\ntSckEu8DUdbaq48/PxPIKBhrgFcL2nKZkTR06dKFqKioHK/FxMQQExNT7M8g+Xtl3iskpSTxyI+P\nFNgu8ZFELZSUoPbMM87hWQMHFr+PuXPhrLOcxz/84IxqdO/umfhEMsTHxxMfH5/jWmJiIrNnzwY/\nTBrqAAlAJ2vtvGztRgFdrLWdivk+GmnwsVW7V9FyQst8X194x0La123Pzxt/5oJGF+g4bglKe/bA\nzp3Qpg1cfjl88IGzVsKd/sDpIzTUmeIQ8bSg2D0hgaVFjRakPZFG3Yp183y9w1sdMCMMF314Eff/\ncD9Ldywt4QhFvK96dTjtNGcHxpdfOiWrt293Ck6NHVv0aYzq1Z1f4eEQEgLvvOPUhhDxV55OGvYA\nacCJy4dqATvc7Tw2Npbo6OhcQy9SMkJMCAn3JdChbocC28XNjaPtG21LKCoR36pd2yltHRvrHPud\n3dGjRZuCuP12KFvWGXEYM8a5dviwc4iXSFHFx8cTHR1NbGysx/r0aNJgrU0BFgFdM64dXwjZFSji\nzujc4uLimDp1qtYw+NjobqMBeP2y1wtsN32dC3vZRIJInTrOWoWMXxERzmLIevmvKc7XAw/AsGFO\n5csqVbKmMqwtfpEqKV1iYmKYOnUqcXFxHuuzOHUayhtjzjDGtDl+qcnx5w2OPx8L3GGMuckYcyrw\nOlAOeN8jEYvPXdj4Quxwy50d7mTbfdtYO2gtj3TOvVjy0o8uZffh3SSlJPkgShH/EBUFK1c6p3Ym\nJcHMma7f+/zzzu+HDkGNGs4IREiIU2vizjshOdk7MYvkp8gLIY0x5wM/k7tGwwfW2v7H2wwEHsKZ\nllgKDLLWLix2kCfsntCOCf+0ePti2r/ZPt/Xf7v1N85teG4JRiTi35KSYNcu+OYb5/yM4rr5Zqdi\nZVoavPyyc17Gzz/D8uWeilQCUcZOCr/ZPVFStHsicBw8dpBKzxe8/XLz0M00iGpQYBuR0mb7drjn\nHmeBZfPmTo2IL790r88PPnCmN665xjMxSmDS7gnxWxUjKmKHW+xwy6SrJ+XZpuFLDfnmn294a9Fb\nJRydiP+qUwe++MJZs7B6NVx3nXP98ceL3+fNN8O11zrTGkuXOudvPP00/PijylxL8WikQbxq9Z7V\ntBjfIt/XB7QbwOiLR1MpohIWS4hRHiuSlzfegLvuyvrC79bNvf5694a4uOIt0pTA4jcVIUuK1jQE\nthG/jGDmhpkMPHMg139xfYFt7XD///Mo4i+yF4OqVs0ZSSiq2Fhnq+eECfDCCxAZ6bn4xLe0pkEj\nDQFv7d61nPLqKfm+fnvb23krWtMWIq5ISHB2Uxjj7K5Yvx7uvht++skz/QfA14O4QGsaJGA1q9aM\nX27+Jd/X317yNvfNuI8tiVu47OPL+GLVFyUXnEiAqVfPWQtRu7ZThvqUU5y6EMOGZbWp5MaxMMY4\n6ywSE92PVYKDRhrEJ46mHmX34d00fKlhoW1Prnoy826fR9XIqiUQmUhwWLIEzjjD+eJPTXUOzIqN\ndRZWXn110fubNg169oQ1a6ByZahZ0/Mxi3eU2pEGlZEOHmXDylK7Qm0AapSrwa1tbs237br/1jH2\nz7Gkpqfy7/5/WbRtEcdSVaBfpCBt22ZNXYSHw3nnwcKFcNVVMGMGPPFE0fq77DKnr+bNoVYt57Ex\ncPLJTsnr9eu98zmk+LxRRlojDeJTKWkphIaEZu6aMCNcO+bvgU4P8MIlL3gzNJGg9/jj8OyzcOGF\nWesg3D1ps107uO8+aNECjhyBzp3dj1PcU2pHGiT4hIeG59hm+Vmvz1y6b8XuFfy08SfmJ8z3Vmgi\nQe+pp5wv9uwLJ0OO/3Vsn39x1wItXgw33ODcf+65ThIydar7sYp/UNIgfqX3ab2xwy1vXVHwDorp\n66bT9cOunPX2Wfyy6RfAGbUIhJEzEX8REuKcqpldWpqza2LhQujVy7nWooV7dSGuvBJeey1rSmPl\nyuL3Jb6lpEH80u3tbscOt9ze9vZC2174wYUAlHmmDPf/cL+3QxMpNSZPdhKIv/92DtpatAjGj4e6\ndZ0iU2vXut7XwIFZj08/HapXd/peutRJJOLjnWqVyvv9W0CtaVBxp9Lpq9VfsWHfBn7b/Btfrf4q\nzzbrB69NE3ZwAAAgAElEQVSn6bimRIZFkvRYEqnpqaSmp1I2rGye7UXEc8480xmZ8IRPP3VKaH/9\nNURHe6bP0krFnbQQstQr7CTNE6U9kabS1CIl5NAhZ/3C9QUXfnVZp07wzjvOjo0Q/TUuNi2ElFKr\nXR0naezfpr9L7Tu/25l1/63zZkgiclyFCtCvn/M4Ls6Zevj22+L39+efzmmfAwY4/Q4alFUqe/du\n2L/f/ZilaMJ8HYBIUR0cdpDIsEgiwiJ4beFrBbadu3UuzV5pRsd6HZmfMJ/t92/PrA8hIt6RfQD7\njDOyHv/wg1Noqk8fp4Klq5Um33kn6/GGDc7aip07neeDBjkjG2ed5X7cUjhNT0jASk1PZeehndSP\nq0/ZsLIcTT3q0n06FEukZP31l5M87NrlnJGRwd2aENk98AB07eqMdqxbB7fc4rm+A52mJ0SAsJAw\n6lWqx8I7FrLm3jWsumeVS/eZEYZdh3exJ2kPCQcSvByliLRu7Yw+ZE8YAFJS4NVXnceXXuqctPn3\n38V7jxdfdPo47zy49dasSpjGwPLlThtr4aWX4MCB4n+W0i6gRhq0e0IK8/Lcl0lKSeLRnx51+Z7s\nIw/WWownf/wRkQIdO+Z84T/8MIQdnzD/4ANndOKxx5wjvz2hWjX45hs45xyn+NSYMcF/foZ2T2h6\nQlx0/4z7GTt3rEttJ109iRu+vAGAzg0683v/370ZmogUwd69sG2bc2BW9tM7PeG336B+fWjUyLP9\n+htPTk8oaZCgZK0lOS2ZKaumcP0XRdv/pTUPIv4pYxCwdWunqmRammf6nTXL2Y3Rty98/LFTyKpf\nP4iMdEphBzqtaRAphDGGiLAI+rXqx5z+c4p076DvBmFGGN5Y+Aap6amM+n2UTtUU8QMffwxz5sCy\nZc4ujCFDcreJiCh6v926QUyMk5Rcfz28/z5ccomzPiIuztnamZLiHO41Y4bbHyOgaaRBSo1DyYc4\n6aWTqBRRiU37NxXp3tcue427OtzlncBEpFjuvx/GjoXff3dO03ztNbjgAueY7iuu8N77Zv/atBaS\nkqB8ee+9n7s00iBSDBXKVGDvQ3vZOGQjRx47wrvR77p0tgXAvd/dy4KEBSSnJfPoj49yJOWIl6MV\nkcKkpjq/h4Y6v999t3O41uWXw549kJ6e1bZbN+jZ0zPva4yz1mLJEhg50tnmmZ7uTGsEwM/hblHS\nIKVS2bCy3Nr2VsZdOs6l9mk2jY5vd2TI90MY+ftI3l78NtZadh/ezb3f3UtqeqqXIxaRE/Xo4fze\nuHHu16pVc77cZ86EypWdAlHTpnnuS712bWjXztnhAU7icskl8NlnzhRKQpDu5lbSIKVaZHgkdrhl\nS+wWqpStUmj71xe9DsDg6YMJeSqEJ395kvELxrNsxzJvhyoiJ7j0UicJqFUr/zbdusG+fdCwYda1\n1FRYvNg5ZGvvXudsi6JKzefnhMWLnamS+vWL3mcgCKikITY2lujoaOLj430digSZ+pXqc/MZNwOu\nn2sBMGHhBAASjyXyw/ofvBKbiHhWaCi0bQvt20PVqjDu+IDjJ59ktUlJKV7fo0dnPZ47t/gxekJ8\nfDzR0dHExsZ6rE8thBQ5Li09jQPHDlAlsgrXfHoNX67+ssh9LLhjAWVCy9C6VmsvRCgi3ta2rXPQ\nlrXQvz+8955zVPeppzo7LE491fW+Jk3y3Imf7lCdBhEvS0tPY9aGWfT4qEex7rfDLRv2bWDrga10\nOamLh6MTEW85cgSOHoUq+cxWvvEG3OXiRqqwsOKPWHiSdk+IeFloSCjdT+7Ovof3FbuPZq804/z3\nz8eMUFlqkUARGZl/wgBw553wyivO4wcfzPnagAE5n+e37iGQKWkQKUDlspX5o/8f7H94P6n/SyXt\nCddK0F0y8RLSbdZ+r183/cqo30dhrWXJ9iVc+MGFpKV7qJydiJSoe+5xjuYePdo5MwOc8yxeey1n\nBcnJk30TnzeF+ToAEX93ToNzcjwf3HEwG/dv5Js13+R7z8wNM3M8v+CDCwBoWaMlExZO4JdNv/DP\n3n9oXLkxkeGRHo9ZRLzHmKzDrjKmH+68E0JCnCqSv/8OEydCr16+i9FbtKZBpJi2H9xO3bF13eqj\nW5NuzLxxZuENRcQvbd4Mt90GU6c6Uxtpac4oRF33/mnwKK1pEPEDdSrW4crmVxIZVvyRglkbZnkw\nIhEpaQ0bOgWkIo//MxAa6l8Jg6cpaRBxw1d9vyLpsSSqRlalVnmnwkzvlr2L1MeavWtYkLCAlDQ/\nWGYtIlIArWkQ8YC9D+0lKSWJ6z6/jpd7vMzkv11fAdX81axydCn/SyEsRH8tRcQ/6V8nEQ8pF16O\nb2KcxZFvXfEWS7YvyawY6aonf3mSsJAwOtbrSM9mHjpdR0TEQwJqIWSXLl2IiooiJiaGmJgYX4cl\nUqDDyYepMLJCse/v1bIX36/9nlOqncLc2+dSJrSMB6MTkWAXHx9PfHw8iYmJzJ49G1QRUsS//bPn\nH2qWr0mVSKdaTN/P+/Lpyk+L1deSO5ewbMcyBnw7gGn9pnHxxIs5/OhhyoWX82TIIhJktHtCJEA0\nr948M2EA+KTXJwW0LljbN9ry/B/Pk5yWzMUTLwZg1+FdbscoIuIqJQ0iJWzlwJX8dNNPLBqwiAaV\nGhTp3tV7Vud4/uOGHz0ZmohIgZQ0iJSwljVacmHjC2lXpx1rBq1xq6/bv7k987G1ls2Jm90NT0Qk\nX0oaRHyobFhZlt651K0++n/dH2stHyz7gJNeOomN+zZ6KDoRkZyUNIj42Bm1z+D2trfz4VUfMvaS\nsUW+/72l7zHxr4ks37kcgI37N/LekvfIWOSceDTRo/GKSOmlOg0ifuCt6LcyHw89eygfLvuQFbtW\n8OKfL7p0/81f3cwtbW4BoOuHXQEnGdmTtIfuk7rz6y2/0uWkLh6PW0RKF400iPgZYww3t7mZUReP\nYvv9213eUvn+0vdzPE9KSWJ+wnwAzn//fE+HKSKlkEYaRPxUiAmhdoXa7HlwD+WeK8dpNU5j5e6V\nLt9/3nvn5Xh+KPkQZcPKqky1iBSbRhpE/FzZsLIAWCw9Tu5R7H4qjqxIs1eaZT7ftH8T+47sy3ye\nlp5W/CBFpFTwSdJgjKlvjPnZGLPSGLPUGNPLF3GIBAJjDGMuGcOX133J99d/z9bYrfxy8y8ADOo4\nqEh9bdq/idMnnM6wWcNo/HJjqo6uyoM/PMiyHcsIezqMXzb94vkPICJBw1fjlKnAEGvtX8aYWsAi\nY8w0a+0RH8Uj4tfu63Rf5uN6leqRcDABgMplKxe5r5W7V+aY5njxzxczF1z+vvl3Lmh0gXvBikjQ\n8slIg7V2h7X2r+OPdwJ7gKq+iEUkEJ1Z90zG9RjHsHOH0btlb4/1u2n/JiYum8im/Zs81qeIBA+f\nH1hljGkPvGetbV1AGx1YJZKPY6nHSDyWSLXIamxO3EyTcU3c7rNsWFn+ufcf0m06v/37GzeecaMH\nIhURX/DpgVXGmPOMMVONMQnGmHRjTHQebe4xxmw0xhwxxsw1xpyZT19VgQ+AO4oeuogARIRFULN8\nTUJDQmlcpTEPnfOQ230eTT3KSS+dROOXG3PTVzeRlJLkgUhFJNAVZ3qiPLAUGAjkGqYwxlwHjAGG\nA22BZcAMY0z1E9qVAb4EnrPWzitGHCKSh1EXj+LP2/7kx5uyDrP687Y/3eqz/HPl2XdkHylpKfy9\n+2+stZkVKDOs3buWo6lH3XofEfFvRU4arLXTrbVPWGu/BkweTWKBN6y1H1prVwN3AUlA/xPafQD8\naK39uKgxiEjBzq5/Nhc1vijzecd6Hd3us+roqjz5y5OcNuE0xs0bR+vXW/PagtdYtXsVAKe8egr9\nvz7xr7mIBBOP7p4wxoQD7YHnMq5Za60xZhbQKVu7zkBv4C9jzNU4IxY3WmsLrFwTGxtLVFRUjmsx\nMTHExMR47kOIBJEeJ/egV4tehJiQzOJQk66eROyMWHYn7QbgyuZX8vU/X7vU36crPwVg6IyhAAz8\nbmCO1zMqUIqIb8THxxMfH5/jWmKi586fcWshpDEmHbjKWjv1+PM6QALQKfuUgzFmFNDFWtsp754K\nfR8thBRx056kPYz+YzQju47klq9vYdJfkwDo16ofHy/33IDfhY0u5Kebf/JYfyLiHp8uhBSRwFS9\nXHVGXzya0JBQ3ol+J3PNQ7mwckSERnjsfX7e9LPH+hIR/+LppGEPkAbUOuF6LWCHu53HxsYSHR2d\na+hFRIqmTGgZLmh0AQ93fpiR3UYyufdkj/YfHR+duVDycPJhzAjDn1vcW4wpIkUTHx9PdHQ0sbGx\nHuvTo9MTx6/NBeZZa4ccf26AzcA4a+0LxXwfTU+IeNnWA1tpENfAY/1d2fxKerXsxY1fZtV4sMNz\n/ntz7WfXcm6Dc4nt5Ll/1EQkJ1/XaShvjDnDGNPm+KUmx59n/GszFrjDGHOTMeZU4HWgHPC+O4GK\niHfVr1SfnQ/s5K+7/vJIf1//83WOhCEvX6z6gvt+uK/ANiLiP4qze6ID8DPOjgeLU5MBnC2U/a21\nnx2vyfAUzrTEUqC7tXa3u8Fm7J7QjgkR76hZviY1y9f0yXv/d+Q/yoeXJyLMc+srREqzjJ0Untw9\nUZw6Db9aa0OstaEn/Oqfrc0Ea20ja22ktbaTtXahJ4KNi4tj6tSpShhEvGzMJc7PAjNvnJl57YFO\nDwAwoN2AYp93cSj5EEkpSfx35D9OHndyjteqja7GVZ9eVeD9g74bxP9++l+x3luktImJiWHq1KnE\nxcV5rE9fnXIpIn4s9uxY+rftT+WylTk47CARoREs3LaQF/98kcjwSGfx5N9FXzxZcWTFPK8v3Ob8\nXDF93fQC7391watO++0LmdJnCuXCyxU5BhEpPm25FJFcjDGZx25XKFOB8NBwnDXNYK2lamRV/h36\nL3P6z/HI+01bM61I7aevm67dGCI+EFAjDVrTIOI77eq048bWN/LIuY8A0DCqIQ2jGnqk7yd/fbLI\n92QkMSKSN2+safD50diu0JZLEf+1bMcypv4zlSd+ecIj/f330H/sOryLCmUqkJKeQqPKjQCoMqoK\n+4/uz2z3400/5jhfQ0Ty5sktlwE10iAi/ueM2mew98jezOenVDuFJlWaFLo+IT9VR1fN8fyLPl9w\ndYurcyQMACbP8/JExJuUNIiI246lHgPgvrPvY0x3Z+eFGeGZL/WPln/ks22gIpJTQC2EVBlpEf9U\nKaISAGfWO9PjfU9ZNYVz3zs313WLZfnO5Uz5ewrJacl0fKsj/+z5B2stqempHo9DJND4XRnpkqI1\nDSL+b+7WuZxV76zMBYoZIw1DzxrK8l3L+XHjj15779cve527pt0FwMAOA5mwcEKuktUipZVOuRQR\nv3N2/bNz7GjocXIPAO4/537SbXqu9veceY/H3jv7eocJCyd4rF8RyUlJg4h4RYUyFTIfn5g0XN/q\neupVrOex93rkx0c81peI5E9Jg4h4xehuo7npjJuoU6FOrqShQ90OWLw7ffDCHy+Qmp7KGwvfYOeh\nnV59L5HSIqDWNHTp0kXFnUQC0LnvnssfW/4AoEGlBvw79F+2H9pOi/EtOHDsQInGsuLuFZxW87Sc\n13at4FjqMdrXbV+isYh4U/biTrNnzwYPrGkIqKRBCyFFAlPndzszZ4tTcvqG1jcw8eqJACzfuZzW\nr7cu8XgW3rGQ+364j/NPOp+nLnwqc9GmFk9KMNJCSBEJKBnTE1P6TGFCz6yFiqEhoT6Jp8NbHZj9\n72yenv20231tTtzM9V9cr22eUiooaRARr+vcoDMAV596NRUjsk66bFG9BU9f+DSNKzf2VWi5jJs3\njrcWveVy++G/DOfj5R+zZu8aL0Yl4h+UNIiI1z3f7Xm2xG7JdciUMYbHuzzOG5e/4aPIckpOS2bI\n9CEM+HYAAC/OeZHuk7r7OCoR/6GkQUS8LiwkjPqV6uf7+sVNL6Zns54AjOo2KsdrX173ZY7nGUd2\nN6nSxMNRQr2xWdtAX1vwGg/OfJAf1v/g8fcRCVQBlTSojLRI8Ovftj81ytXIfH7VqVdlPj6r3lmM\n7jYagFvOuMUj7/fpik8zH+9J2pP5eOB3A126f2/S3sIbifiAN8pIB9SBVXFxcdo9IRLkQkwIiwYs\nouFLDTOvLbhjARGhEbSq1YoVu1YATq2HubfN5ex3znbr/fpO6Vvsew8lH+KbNd8A5DqFU8TXMsoT\nZNs94baAGmkQkeAVERoBgLWWBlENcrzWoW4HWtVqBcDpNU9n94O7ubTZpZQvU77E4nvut+eo/WJt\nEg4kkG7TGfDNAFbuWpn5+k1f3lRisYj4ipIGEfELEy6bwLMXPUvVyKqFtq1erjoA4SHheb5+f6f7\nPRrbgWMHeOynx9h5eCfDfxnOviP7eGvxW8TOyBr2Xb9vPWaE4bd/f6PSyEo899tzHo1BxB8oaRAR\nv1C7Qm0ePe/RHDsssq9nyEvz6s29HRYAUc9HZT5evH0xk/6aBDi7LU702crPOJh8kMd+eqxEYhMp\nSUoaRMQvJT6SyGe9Piu0Xcr/UjIfP9/1ecCZ4vCWJTuWMHTGUACOph516Z7JKyez/r/1XotJpKQo\naRARv1QpohLhoXlPP2QXFuKs565XsR5dTuqS47XIsEgGdxzslfgAVu5emeta9qO5B38/mHSbTp/P\n+9D53c652n664tMcuzdE/J2SBhEJCsaYzCSjfJnyjOsxjrm3z+XlS1/ObHNKtVO8Hkf2Ez1fmf8K\nG/dtBGDf0X252vad0tet3RsiJS2gtlzGxsbqlEsRyVPDqIa0r9Oe8T3Hc2ubW4kMj8zx+gWNLuCr\n676i8qjKPopQpGRlP+XSU3TKpYgEvB/W/0C7Ou0yd1WcaMa6GXSo24Fq5apR9pmyHEs7BkC/Vv34\nePnHXo3t+lbX89HyjwBnzcWzvz2LMYZrW1zLe0vfA3S6pniXJ0+5VNIgIqVK+NPhpKanMv366XRr\n0o2wp30/4KqkQbxJR2OLiBRTi+otAOh+cnefHc19ojlb5mBGGJWkFr+npEFESpWfbv6J+bfP93UY\nOWTsoBg6Yygtxrcg4UACZoRxa5vmO4vfofHL/nPkuAQHJQ0iUqpUL1edM+udmev6LW1uyfE8o6x1\nSZr01yRW71lN/TjnRNCv//k6z3az/53NRR9cVGBfD858kE37N3k6RCnllDSIiABvXP5GjufNqjWj\nZvmaJfLe4+aPy/P64eTDrNq9ihfnvEj88nhmbZgFOPUfft70c4F9Zq+sKeIpvl8BJCLiB8qElsl1\nbeaNM3nsp8f4ds23PogInvjlCZ745Ykc12bdOItlO5cBcCz1GFP/mUrv03rnujfE6GdC8Tz9qRIR\nyaZW+VqZj1vXas03Md/4MJrcuk3slvn4iZ+foM/nfVi7d22udkoaxBv0p0pEJJty4eVcatehbgcv\nR1K47Ye2A5CSnpLrNYOmJ8TzlDSIiGTTpEoTAOpWrJt5rUa5Grna1alQp8Riyk9GsjD1n6mEjAgh\n9KlQIp6JYPz88XmONGzavwkzwvDYjzqBU4onoIo7denSRWWkRcSjzAjnJ3I73PL92u85q/5ZzNs6\nj7Pqn0XVyKoA1HihBnuS9rBh8Aa2H9rO/qP76VS/Ew3iGnA45bAvwwecUQVLzn/L61WsR8LBBP4e\n+DcJBxPo1qQb7y55l9um3gaooFRpkL2M9OzZs8EDxZ0CaiFkXFycKkKKiNdc2uzSHL9nePPyN3lp\n3ks0rtKYxlWyah/4S3GoExMGyNo90XJCS6fNcOvy1IsEh4wfsLNVhHSbpidEpFSrUrZKoW2ubnE1\nv97ya67rnRvkPu7aX2w9sDXXtbxGlkOfCiU6PprLP76c0Kf8IwkS/6WkQURKtXWD17F56OZi3Tu5\n92Q+vibngVcfXfORJ8LyuLcWvcWHf32Y63q6TeebNd8wbe20HMd6u2LammkFVq201vLGwjdITksu\ncrzin5Q0iEipVjWyKg2iGhTr3vJlytOsWrMc1/q16pd5voU/GfDtAKavm+7RPi+Pv5y2b7TN9/Wf\nNv7EXdPuYvz88R59X/EdJQ0iIm6IDIvMde3Zi57Ns22vlr28HY7LZv872yP9HEw+mO9IQsYR5P6w\nWFQ8Q0mDiIgbTqt5Gp/2+rTQdn/0/yPPNQW+8sAPD7Dt4LZc1/cf3Z/r2sFjBzmUfIiUtNz1IAD2\nHdnn8fjEPylpEBFxU5/T+uR4nn2HBUC1yGqc0+CcPHc5+MqCbQuoN7ZerutVRlXhy1Vf5rhW6flK\nVBxZkQs+uCDPvgr7XP6ULIl7lDSIiHhYm9ptMh/vf3g/m4ZuAgLny/PDvz7kr51/5bo+Z8sc/jvy\nX547M/KSvSrltDXTWPffOo/FKL6hpEFExAtqla/FmXXPJKpsFBXKVADgkqaX+Dgq13y1+ivOeP0M\n5m6dm+u1k8edTIO4oi0ctVj6fdGPr1Z/5akQxUeUNIiIeMGOB3Yw/475Oa7llTT0Pb1vrmubhmxi\n+vWe3elQHD+s/4HJKyfnuLbvqLN+YeehnZnXklKSWLN3TY52/+7/l8RjiYAzwqKzMIKDzypCGmO+\nAC4AZllr+xTSXEQk4FUvVz3Xtby+TENDQjMrOvrS8F+G5/vaFfFXZD7uM7kPi7YvylGautHLjXLd\nEyjTM5I/X440vATc6MP3FxEpUZUiKmU+blqlKZBzEWGPk3sAEGr8vzLjgm0LMh8v2r6owLYWizG5\nz8fILjU9lSMpRzwWn3iHz5IGa+1s4JCv3l9ExJcuanwRkPXTd/s67TMrMoaYkKAazs+YnihopOHa\nz66l3HM6G8PfaU2DiIgPjO85nh3378j86Tv+2vjML9X8pic61utYojF6UmHTLVP/mVpCkYg7ipw0\nGGPOM8ZMNcYkGGPSjTHRebS5xxiz0RhzxBgz1xhzpmfCFREJDuGh4dSqUCvz5MnI8MjMkYZQE0qZ\n0DK57mlUuVFJhlhkHd/qyI1f3ph53HiGp2Y/leP47oXbFnL+++ezYd8Gyj9XnlavtcrV18tzX2bY\nrGFeiXPyysnc+KVmx4ujOAshywNLgXeAL0580RhzHTAGGADMB2KBGcaYU6y1e9yIVUTEby24Y0Gx\nKiPGdY+jY92O1K9UPytpCAnlvIbnZbYJDwknJT2FsJDC/8nuWK8j8xPmF9rOGxZsW5BjrcOJMkZS\nhv04jNn/zmbMnDEkpSSxYteKXG2HzhgKwMhuIz0eZ5/PnbX3E6+e6PG+g12RRxqstdOttU9Ya7+G\nPCfdYoE3rLUfWmtXA3cBSUD/PNqafPoQEQkoHep24OKmFxf5vsplK3P3mXcD5BhpyD6c37aOcyhU\nQUlDxiLLs+udXeQYSsLeI3szRxoy1mvsPLwzV7vktGT+2PxH5vOdh3ayYd8GjqYeZe3etS4XljrR\nzkM7tdDSAzy65dIYEw60B57LuGattcaYWUCnE9rOBFoD5Y0xm4He1tp5BfUfGxtLVFRUjmsxMTHE\nxMR46BOIiHjflc2vzPN69pGG7KJPiWZ+wvx8d1Vc1uwypq2d5tkgveDEhZBTVk3J1abJy01IOJiQ\n+bz2mNoAXHrypXy/7nunn+FF37pZe0xtLmp8ET/e9GOR7w0k8fHxxMfH57iWmJjosf49XaehOhAK\nnJg+7gSaZ79grS1ySh4XF0e7du2KH52IiI8dfexoviMG2Ucasnv0vEe5/5z7uWfaPbnu2fXALqqX\nq07IU8Gxrj17wpBdRsLgjp82/uR2H/4urx+kFy9eTPv27T3Sv8+KO4mIlEYRYRH5vpbfSIMxhrJh\nZfO8p0b5Gp4LzsssltV7VrNx/0a3+klNT+XnjT9nTndc0OiCXAtHtx/czs7DOzm1+qn8ueXPYr9X\nWnoa36/7nsiwSLo26epW3MHA00nDHiANqHXC9VrADnc7z5ie0JSEiASjQR0H8efWPwkxeY8auFIl\n8qpTr2Lc/HGeDs0jrLW0GN/C7X7GzBnDIz8+kvn80XMf5dmuz+Zo02J8CxKPJXLPmfcwfsH4Yr/X\nq/NfzVyUuTV2K/Uq5T4Z1F9lTFX47fSEtTbFGLMI6ApMBTDOn/KugNt/ijU9ISLBLKZVDDGt3PuB\nqEPdDh6KxvM8dTT4toPbcjzfcmBLrjYZ5164O6qx/dD2zMfH0o651VdJy/gB26fTE8aY8sDJZO16\naGKMOQP4z1q7BRgLvH88ecjYclkOeN8jEYuISL489cXsDXkdt10c/yb+m+P57qTdbE7cDEDDqIbs\nOJQ1sP3v/pxtk1KS8uxzb9JeDiYfpGb5mpm1M06U3whQaVKckYYOwM+APf5rzPHrHwD9rbWfGWOq\nA0/hTEssBbpba3e7G6ymJ0SkNDuxtHSb2m1ytcmrKJS/yGu3RHF8/c/XOZ5PXzedk146CYBPrv2E\nvlOyTg5duXtljrbnvHNOnn1Wf8E5TKx9nfYsHLAwzzaBVtrbL6YnrLW/Ukh9B2vtBGBCcYPKj6Yn\nRKQ0y1jTMPe2ubSp3SbXgkkg3wWTpcWJScKJlu1cVuDrJx6+lT1R8IeTR4vCL6YnRETEt8qFlytw\nF4Z4TvZEQdMTOrBKRERKqdMnnM6ChAV0fCvnQWBp6Wlc9vFlPDzzYd5a/Fbm9UCbnvCGgBpp0JoG\nESlNfrn5F2ZumJn5vKAvrWn9pnlsoWEg23V4l8ttV+5eSce3c58cuv3Qdr5b+x3frf0ux/VAm57w\nizUNvqQ1DSJSmpzf6HzOb3R+rut57ZDo2awnPZv1dKnfU6qdwpq9a9yOzx95YjTgxHLXGQJtesIb\naxoC67+AiEgplvGTbn5fauIZ/rxt1deUNIiIBAjNqRfOE6MBExbkvfnv878/p+dHPVmyfQkAm/Zv\n4uGZD3PJxEtIPJrIyl0rGfHLCI6mHnU7Bn8VUElDbGws0dHRuU7wEhEpDQa0H0BURBRNqzZ1qX2o\nCdR+Dr8AAA/ESURBVOXeM+/NdX1k15E0rdKUhzs/7PJ7P9DpAZfb+pInRglG/TEqz+uDvh/E9+u+\np92bzjR5i/EtGD1nNDM3zORQ8iFW7FrBk78+SXJastsxeEJ8fDzR0dHExsZ6rM+AShri4uKYOnWq\nFkGKSKnUtk5b9j+ynwplKhTY7pVLXwHgvSvf45WerzCo46Acr1/T4hrWDV7H892ep3LZyoW+771n\n3ssLl7zgcpyf9foMgDGXjCmkpedlHPpVErKPKISYkMyExV9GhGJiYpg6dSpxcXEe6zOgkgYRESlc\nxpeWKz91u7I+oqi7Bnz55ZmWnlbi7wnHk4bj/y0DbZdFUShpEBEJMp7+0irql3/Gl6cvdhuU5EhD\ndqEhoX430uANAbXlUkREXJfx5V3QaIIroxFFTUIyvrh98RP3u0vfLZH32XloZ47nXT/smlknY+7W\nuVgs3Zp0K5FYSlJAjTRoIaSISOF6t+xNp/qduKL5FUDOxCD+2rz//cx++FXGmogMGT85d2/aHYDn\nLnou1/0d6zlFkgZ1HFQqfuK++aubczzPXlir28RuXDzx4pIOKRdvLIQMqJEGFXcSESlcjfI1mHPb\nnDxf63t63zyvT+kzhabjmtKvVT/u7XgvQ6cPJc3mXB8w/YbpmY97NutJmzeyEo15t8/LfDzpr0lA\n4BVDKoqDyQd9HUKhVNxJREQ8qriFogpKCDKmJ4I5aSitBbaC9/+oiIgUqrhrGgpar1AadhGU1qqR\nShpERKTA9Qd5vVZQ+4wvVI00BJ/g/T8qIiJAIbsnMnZYnPCTc2GjBAW9nrl7IogXQs5LmFd4oyAU\nUEmDdk+IiBRf5wadXW47pc8UGlVuBOSdIDSt0pTODTrzfNfnubH1jTley16n4cnzn6RW+VrFD1qK\nTbsntHtCRKTIMkYRxl06zuV7optHUy2yGue+d26er0eERfB7/9/zfC37QsjhFwxn+AXDufXrW3l/\n6fsFxzncsmT7ksyzHcQ92j0hIiLFltd0QUE1FYpbb8Gd4k6+qugorlHSICIiBfLE2ROuJh5KGvyb\nkgYRkSDnykLIgl7zxNkTrm5RLK1bGQOFkgYRkVKi2CMGxTx7ojhbLkvrVsZAoaRBREQ8yp01DRpp\n8G9KGkREglxBCxqrRlYFICzE2UxXIbxC5mvhIeEAlAsvV6z3y2ukobCpjoz3DAZT/p7i6xA8LqC2\nXMbGxhIVFZW5jURERNzz262/sXj7YhpENeDNy9/kutOvy3zt7Ppn8+qlr3Jbu9uK1GdBxZ2MMXlO\nQSy7axkA7eq0Y3zP8dQoV4M+n/fJ1e6mM27iw2UfFikeX+k1uRd2uO9GTuLj44mPjycxMdFjfQZU\n0qA6DSIintW4SmMaV2kMwB3t78jxmjGGezreU+Q+Czp7Ir+Rhta1WmfeM/DMgc7Fz53fapSrwe6k\n3QCMvWRswCQNvqY6DSIi4vcKnJ7QOoeApqRBRCTIlfSOBG8ejR3MJ2cGAiUNIiKlREl94Ra0pqE4\nCUz2e4L5EKxAoKRBREQ8Kq/iTm71p+kJv6GkQUQkyJX0l647dRoKo+kJ31LSICIS5IpbDrrY7+fC\nIVhF6k9VIv2GkgYRkVKipNc05DU94W4CoDUNvqWkQUREPMrTuye0psF/KGkQERGPqlK2CgAVymSV\npK5RrgYATao0KXa/URFRWtPgYwGVNMTGxhIdHU18fLyvQxERkXzcfebdfHLtJ5zb8NzMa09d+BSf\n9/6c+XfMZ8QFI1hz7xq+jfmW9YPX8/313xfYX8aUxvK7l+e4vuCOBZmPHzvvsQL7GHHBCNYPXl/U\njwLAxKsn5vta48qNi9VnSYiPjyc6OprY2FiP9WkCYYGJMaYdsGjRokUqIy0iUkS3T72dd5a8w4q7\nV3BazdN8HY7LzAhnVCEqIorEY4nY4ZaDxw5S6flKANjhluavNmfN3jUkP55MmWfK5NlPRGgERx8/\nmqPPotgSu4UGcQ1yXe/coDO/9/89s0873Obq35dnT2TIVka6vbV2sTt9BdRIg4iIlD4FrWko6JwL\nV+53RX6LL0vjWgslDSIiQS4QRpQLkqMi5AnJQUHbO70t0P+7FoeSBhER8WtujzS4u80zn7410iAi\nIuLH8htRKGikwVtf7hppEBGRoJM5hB+E2xVd+WzeKiilkQYREQlagVpNsaA1DS7d7+5CyPymJzTS\nICIiEjhc+eL21pe7RhpERCToBPqXm7vxe2vLZUa57NJESYOISCkRqGsaChop8GVCpKShBBljLjfG\nrDbG/GOMuc1XcYiIiH9zZculN+WXbKWlp3n9vf2NT5IGY0woMAa4AGgPPGyMqeKLWHwh2M7O0Ofx\nX8H0WUCfx5/56rN4baRheeFNNNJQcjoCK6y1O6y1h4BpwCU+iqXEBdM/FKDP48+C6bOAPk9xlcRP\n4978LD7ZpZAtadCahiy+ShrqAgnZnicA9XwUi4hIqRCoWy4L4sttj2lW0xOFMsacZ4yZaoxJMMak\nG2Oi82hzjzFmozHmiDFmrjHmTM+EKyIipY2vd3/kt6ZBIw2uKQ8sBQZC7v+TxpjrcNYrDAfaAsuA\nGcaY6tmabQPqZ3te7/g1ERHxMF9/6XqTdk+UrLCi3mCtnQ5MBzB5p1+xwBvW2g+Pt7kLuAzoD4w+\n3mY+cJox/2/v/mOtrus4jj9f/EiEZrpZkLNFhKKtgsTVLIEU+2WEUluZLteYZZGQroawbCtYS6kB\nGlFb2VDL/FGZ4eyX2RhBaniMW5dbYVJCCBugEPdKKPfdH5/PhcPxcu73fM+X+znf4/uxne2eL1/O\neX32Pedz3ufz/X4+R68F/gu8H1hU52lHAHR1dTUatyXt3buXSqWpnzRvKd6e1tVObQFvT167/7kb\ntkPnxk66T+k+Ls9xXNoSv0r2Du2FQ1CpVDjw4oHD2yuVCge3HYT94e96Xz0PZ8v69fTAkX07nujo\n9//17Os56nn7y9AKr9eqz84RzT6WmjkfJKkXuNTMfhHvDwd6gI/0bYvbVwGvMrNZVdtmEEYkBNxk\nZrfWeZ7LgR/lDuqcc865K8zszmYeoOGRhgGcCgwFdtZs3wlMqN5gZg8AD2R83F8DVwD/ItR/zjnn\nnMtmBDCW8FnalKKLhuPCzHYDTVVHzjnn3MvY+iIepOgpl7uAQ8Domu2jgR0FP5dzzjnnBlGhRYOZ\nvQA8Dkzv2xYvlpxOQVWOc84559Jo+PSEpFHAeDi8Ssg4SROBPWa2FVgKrJL0OGGWxHXASGBVIYmd\nc845l0TDsyckTQN+z0vXaLjNzGbHfeYA8wmnJf4MzDWzDc3Hdc4551wqDZ+eMLM1ZjbEzIbW3GZX\n7bPSzMaa2Ylmdl4zBUO7rC4paaGkxyTtk7RT0n2SzkydqwiSFsTVQZemzpKXpNMk3SFpl6QeSRsl\nnZM6Vx6ShkhaLOmp2JYnJd2QOldWGVedXSRpe2zfbyWNT5F1IPXaImmYpJskdUjaH/e5La5f05Ky\nHJuqfb8b95k3mBkbkfG1drak+yU9F4/To5JO7+/xUhqoLZJGSVohaWt833RKurrR50n209hZZFxd\nsiymAN8C3gFcBAwHfiPpxKSpmhSLuE8Tjk0pSToZWAf8D3gfcDbwBeDZlLmasAC4mrBq61mEUb/5\nkq5Jmiq7gVadvR64hvC6ezvQTegXXjGYITOq15aRwCTgq4T+bRZhavr9gxmwQXWPTR9Jswh93X+O\ntU+LGOi19kZgLbAJmAq8BVhMa079H+jYLCP8MOTlhH5hGbAirpmUnZm17A14BLi56r6AbcD81NkK\naNupQC9wfuosTbThlcDfgQsJp6yWps6Usx03AmtS5yiwPauB79Vs+wlwe+psOdrSC8ys2bYduK7q\n/knA88BHU+dttC397HMuYQba6anz5m0P4WcBniYU31uAeamz5m0P8GPCqffk+Qpoy1+AL9Vs2wAs\nauSxW3akIa4uORn4Xd82C618CDgvVa4CnUyoBvekDtKEbwOrzezh1EGa9CFgg6R74qmjiqSrUodq\nwnpguqQzAOKFyu8CHkyaqgCS3gCM4eh+YR/wKO3VLzyXOkgecbbc7cASMyv1uv+xLR8ENkv6Vewb\nHpF0SepsOa0HZko6DUDSBcAZNLjgU8sWDdRfXXLM4McpTnwxLgf+YGabUufJQ9JlhKHVhamzFGAc\n8FnCqMl7ge8At0j6RNJU+d0I3A38TdJBwjTo5WZ2V9pYhRhD+FBtx37hBMKxu9PM9qfOk9MC4KCZ\nrUgdpACvIYymXk8ouN8D3Af8TNKUlMFymgt0Adtiv/Ag8DkzW9fIg5RiRcg2tBJ4E+HbX+nEi4CW\nAxdZWJuj7IYAj5nZl+P9jZLeDHwGuCNdrNw+RjhveRnhXOwk4GZJ282sjO1pe5KGAfcSCqI5iePk\nImkyMI9wfUY76PtS/XMzuyX+3SHpnYS+YW2aWLnNI1xnMoNw+mgqsDL2C5lHi1u5aGjL1SUlrQAu\nBqaY2TOp8+Q0GXg1UImjJhBGhabGi+1OiKeSyuIZQgVerQv4cIIsRVgCfN3M7o33OyWNJYwKlb1o\n2EG4tmk0R482jAaeSJKoSVUFw+uAC0s8ynA+oV/YeqRbYCiwVNK1ZjYuWbJ8dgEv0n/fUKovfJJG\nAF8j/MDkL+Pmv0p6G/BFIHPR0LKnJ6wNV5eMBcMlwAVm9nTqPE14iHAV8SRgYrxtAH4ITCxZwQBh\n5sSEmm0TgH8nyFKEkYSCu1ovLfx+z8rMthAKh+p+4STCN6jS9QtVBcM4YLqZlXXGDoRrGd7KkT5h\nIuGi1SWEWUmlEj+D/sRL+4YzKV/fMDzeavuFQzTYL7TySAO00eqSklYCHwdmAt2S+kZQ9ppZK07f\nOSYz6yYMex8mqRvYXdKLn5YB6yQtBO4hfABdBXwqaar8VgM3SNoGdALnEN4730+aKiMNvOrsckL7\nniT88u1iwqyqlpuqWK8thBGunxKK7xnA8Kp+YU8rnvrLcGyerdn/BWCHmW0e3KTZZGjPN4C7JK0l\nzBD7AOFYTUuRt56B2iJpDfBNSXMJRc+7gSuBaxt6otRTQzJMHZlD6BieB/4InJs6U8529BKqutrb\nlamzFdS+hynplMuY/2KgA+ghfNDOTp2pibaMIhTcWwhrGGwmrAUwLHW2jPmnHeP98oOqfb5C+Bbb\nQ7j6e3zq3I22BXh9P//Wd39q6ux5j03N/k/RwlMuM77WPgn8I76XKsCM1LnztIVwYeetwNbYlk3A\n5xt9noaXkXbOOefcy1Ppz3E655xzbnB40eCcc865TLxocM4551wmXjQ455xzLhMvGpxzzjmXiRcN\nzjnnnMvEiwbnnHPOZeJFg3POOecy8aLBOeecc5l40eCcc865TLxocM4551wmXjQ455xzLpP/Aw6v\ncd6ltYmJAAAAAElFTkSuQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\nQmCC\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\nOKQ7UIMcsgAAAABJRU5ErkJggg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\nIOF6sJKieC0AAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\nrfJnYeJFUgAAAABJRU5ErkJggg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAg0AAAFnCAYAAAAln3o1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzs3Xd4VVXWx/HvTgUSCL1J72JBQAQU0EEUFc1gN+hrQ4VB\nHYxdVBBQUJgBLKOIDRklgqgINhRQEUZQQECRIlW6QCD0JCT7/eOk3TRuktvz+zyPD/ees8++686g\nWdllbWOtRURERORUwvwdgIiIiAQHJQ0iIiLiFiUNIiIi4hYlDSIiIuIWJQ0iIiLiFiUNIiIi4hYl\nDSIiIuIWJQ0iIiLiFiUNIiIi4hYlDSIiIuIWJQ0iIiLilgh/fbAxZgtwELBAsrX2Yn/FIiIiIqfm\nt6QByAS6WmuP+zEGERERcZM/pyeMnz9fRERESsCfP7QtsMAYs8QY08+PcYiIiIgbSpw0GGO6G2Nm\nGWN2GGMyjTHxhbS51xiz2Rhz3Biz2BjTqZCuLrDWdgT+DgwxxpxZivhFRETER0oz0hADrAAG4YwW\nuDDG3Aj8GxgGtAdWAnOMMTXztrPW7sr6czfwBdChFLGIiIiIjxhrC/zcd/9hYzKBvtbaWXmuLQaW\nWGsHZ703wDbgJWvtmKxrlYAwa+0RY0ws8B0wwFq7rIjPqQH0BrYAJ0odsIiISPlTAWgCzLHW7i9L\nRx7dPWGMiQQ6AqOyr1lrrTFmLtA1T9M6wCfGGAuEA5OKShiy9Abe92SsIiIi5czNwNSydODpLZc1\ncZKAPfmu7wFaZ7+x1m4GzilBv1sA3nvvPU4//fQyhuh/iYmJjB8/3t9heIy+T+AKpe8C+j6BLJS+\nC4TW91mzZg233HILZP0sLQt/1mkoiRMAp59+Oh06BP/Sh7i4uJD4Htn0fQJXKH0X0PcJZKH0XSD0\nvk+WMk/vezpp2Adk4Ew/5FUH2F3WzhMTE4mLiyMhIYGEhISydiciIhKykpKSSEpKIiUlxWN9ejRp\nsNamG2OWARcDsyBnIeTFwEtl7X/8+PGhmPmJiIh4XPYv2MuXL6djx44e6bPESYMxJgZogVPREaCZ\nMaYdzvkR24BxwOSs5OEnIBGoBEz2SMQiIiLiF6UZaTgX+BanRoPFqckA8C5wp7V2elZNhhE40xIr\ngN7W2r1lDTZUpieCOfbC6PsErlD6LqDvE8hC6btAaHwfb0xPlKlOg68YYzoAy5YtW6bpCRERkRLI\nMz3R0Vq7vCx96cAoERERcYuSBhEREXFLsNRpAEJnTYOIiIi3aU2D1jSIiIiUiNY0iIiIiM8paRAR\nERG3aE2DiIhICNKaBq1pEBERKRGtaRARERGfU9IgIiIiblHSICIiIm7RQkgREZEQpIWQWggpIiJS\nIloIKSIiIj6npEFERETcoqRBRERE3KKkQURERNyi3RMiIiIhSLsntHtCRESkRLR7QkRERHxOSYOI\niIi4RUmDiIiIuEVJg4iIiLhFSYOIiIi4RUmDiIiIuEV1GkREREKQ6jSoToOIiEiJqE6DiIiI+JyS\nBhEREXGLkgYRERFxi5IGERERcYuSBhEREXGLkgYRERFxi5IGERERcYuSBhEREXGLkgYRERFxS1CV\nke7YMZG2beN4+OEE7rhDZaRFRESKUu7LSMMyILeM9JNPwhNPQEyM30ITEREJaOW2jHSHe//t8v65\n5yA2Foxx/jl0yE+BiYiIlANBlTQsT5/Kku0/YS0sXFjwflyckzx06gTbtkF6uu9jFBERCVVBlTQA\ndH6zMwAXXADWws6d8L//ubZZuhQaNYKoKCeJePddWL9eSYSIiEhZBFXScM3p1wBw2rjTOJ5+HIB6\n9aBrVyeBOHIEJk+G665zfe7226F169wkYtIkp72IiIi4L6gWQv689Gc6fdYp57odVnTsaWnwzTew\ndy/ccUfRfS9aBGeeCVWqeDBgERGRAFFuF0KGmTD+evivnPcRIyI4mXmy0LZRUdCnjzPKYC1kZsK3\n3xZsd8EFuWshHnvMS4GLiIiEgKBKGgBqxdTiwGMHAMiwGUSOjMSd0RJj4KKLchOI+fOhb1/XNmPG\n5O7EaNfOmcbQOggRERFH0CUNAFUrVGXdfety3oeNCCP1ZKrbzxsDf/sbfPKJk0QcPQqvvOLaZtUq\nGDAgdx3Ev/7lrJkQEREpr4IyaQBoVaMVqU/lJgoVnqvA0bSjpeqrUiW4914ngbAW1q2DRx5xbfPI\nI1C5spNAtG4Nu3eXJXoREZHg49ekwRhT0RizxRgzpjTPR4VHsS1xW8772NGxLNm+pMxxtWrlTFVY\nC6mpTuXJvNavd3ZtZE9l3HsvrFmjqQwREQlt/h5peBL4sSwdNKjSgIyhGTnvu7zVhaRfk8oaV46o\nKHj2WSeBOHgQXn0VzjvPtc2rr0Lbtk7bvn3h++899vEiIiIBw29JgzGmBdAa+LKsfYWZMOwwS+O4\nxgD0+7gfiV8lurVAsiTi4uAf/4AlS5wk4sQJ+Oor1zaffuosuMwehTAGlpdpg4uIiEhg8OdIw7+A\nJwDjqQ43/nMjAzoOAGDCkgmEjQgj5YTnTvfKLzoaevd2EohDh2DtWmeBZX4dO+YmEE8+CYcPey0k\nERERrylx0mCM6W6MmWWM2WGMyTTGxBfS5l5jzGZjzHFjzGJjTKd89+OBddbaDdmXShe+q/CwcCZe\nOZGvb/k651rVF6qyYvcKT3RfrMqVnQWS8+fnLqhcsQJOP9213ahRTiGp7CTitdcgOdnr4YmIiJRZ\naUYaYoAVwCCgwPi/MeZG4N/AMKA9sBKYY4ypmadZF+AmY8wmnBGHu4wxT5UilkJd0vwSjj95POd9\n+9fb0/2d7kUWgvKWdu3g99+dBGLDhoJ1IQAGDYIaNZwE4qOPVN5aREQCV4mTBmvtV9baodbaTyl8\nhCAReN1aO8VauxYYCBwD7szTxxBrbWNrbTPgYeANa+2zpfsKhasQUcGlzPTCPxcSNTKKw6n+mRto\n3typC5GZ6SyofOCBgm2uuw7CwnJHIT7+GDIyCrYTERHxhzKdPWGMyQT6WmtnZb2PxEkQrs2+lnV9\nMhBnrb26kD5uA86w1j5azOd0AJb16NGDuLg4l3sJCQkkJCQUGWNGZgaf//E5f//g7znXpl4zlYSz\nin7Glw4fhrffdo76njGj+LYTJ8JVV0H9+r6JTUREgktSUhJJSa47CFNSUliwYAF44OwJTycN9YAd\nQFdr7ZI87V4Aelhru5byczoAy5YtW0aHDh1KFeuP237k/LfPz3nfs2lP5twyh4iwiFL15y3WwsaN\nziFaqUUUuUxIgAkTnISjYUNnq6eIiEhhyu2BVWXRtWFXl+mK+ZvnEzkykobjG5KRGThzAMZAixbO\nds5t22DcuIJtkpKgTh2nXXS0s1YixXubRERERADPJw37gAygTr7rdYAyF15OTEwkPj6+wNBLSWQO\nzWTz4M0577cf2k7EyAjW719f1vA8rkEDSEzM3Y2xYwdEFDIw8umnULWqk3D06OGUvJ471/fxiohI\n4EhKSiI+Pp7ExESP9enR6Ymsa4uBJdbawVnvDfAn8JK1dmwpP6fM0xOFuWvWXbz1y1s57088eYLo\niGiP9e9tu3bB7NnOwVpFmToVOneGZs18F5eIiAQOv05PGGNijDHtjDHnZF1qlvW+Ydb7ccDdxphb\njTFtgIlAJWByWQL1hjfj32TlwJU57ys8V4EKz1YgPSM4DpGoVw/uuSf3uO+hQwu26dfP2bmRvSPj\nueecNROHDsGxY76PWUREgleJRxqMMRcC31KwRsO71to7s9oMAh7FmZZYAdxvrV1a6iDz7Z441Y6J\nkpq5diaTlk3iyw25Fa0X3L6A7o27e+wzfMVaJzk4dgwuvRQWLSq+fUqKc8pnYdMeIiISvLJ3UgTM\n7glf8db0RH5vLX+Lu2bf5XJt4R0LuaDRBV77TF/Ys8fZrvnMM6duO3euUwo7rNwskRURCW3aPeEl\n/Tv0J2NoBuEmPOdat3e6YYZ77HgMv6hTB4YNy11Q+euvTl2IwvTqBeHhzmhF27awerVvYxURkcCl\npCGfMBPGyaEn+fJm18M3zXDD5+s/91NUnnXmmXDBBU4CsWcPfPtt4e3WrHHaZq+HuPFGOH688LYi\nIhL6gmp6wltrGoqSkZnBnI1z6DO1T86153o+x5DuQ7z+2f7w559Owag5c2DLFnj55eLbHz7srIWo\nUMEn4YmISAloTYOX1zQUJfVkKhWec/3JWC+2Hl//39ecWftMn8fjK6mp8N//OqMRTxVznFj9+s7x\n3y+9BE2a+Cw8ERFxg9Y0+Fh0RDR2mOWR8x/JubbryC7Oeu0sZq6dSerJIuo9B7noaLjrLnjyydz1\nELGxzqmcee3c6dSLaNrUmcZo107TGCIioUhJQwmMuWQMmUMzXa5dPe1qaoypwa7Du/wUlW8dPgz7\n9jkJREoK3HxzwTarVjnbOI1x/gwLg2uugeRk38crIiKeE1TTE75e01CUrQe3YrE0fbGpy/X5t86n\nba221InNX0U7tGUXl1q6FK644tTJwTvvwBlnQKdOvolPRKQ80poGP61pKE7Ll1uyIXmDy7VZN83i\nylZX4lTQLr/uvNNJEIrzwAPOoVyrVjnTGiIi4lla0xBAfvvHb+x9ZC+zE2bnXIv/IJ6wEWEEQ0Lm\nTW+/nbsW4uhRuOWWgm0mTHCmL845x5nOmDQJfvnF97GKiMipKWkoo+iIaGpWqsmVra50OXobIGxE\nGGa44Xi6VgVWquTsxLDWWTg5alTh7QYMgA4dnATiwQfhww+dI8JFRMT/lDR4WPrT6bzzd9cx+Uqj\nKlFrbK2gOQjL2+rVgyeeyF0LkZwM/fsXbDd+PNxwAzRq5CQRL77oHLRVzgdwRET8JqjWNATKQkh3\nnMw8SeMJjdl5eKfL9YEdBzK612iqVqjqp8gCW0aGM7pwqv97o6Kc3RvR0U5CsXcv1KzpvBYRES2E\nDMiFkKey8/BOTht3WoHr6+9bT8saLf0QUfA4cQLOP98Zidi69dTtw8Ph4EGnloSIiDi0EDKI1K9c\nHzvMsj1xO1HhUTnXW73SivikeA6nHvZjdIGtQgVYvtwpaW0tpKc752EMHVp4+4wMqFzZGW1o3RpW\nrPBpuCIiIU9Jg4+cVuU0Up9KZeaNM3OuzV4/myrPV+Hp+U9zNO2oH6MLDhER0KYNDB/uJBGLFzvJ\nQWHWr4f27XMP23r4YVi3zrfxioiEGk1P+Ji1lolLJzLoi0GF3v+83+dc0fIKH0cVGg4ehGrVTt3u\noYecbZ61azvJhIhIKPPk9ISSBj9asHUBM9fOZPzi8S7Xx/Qaw+3n3E6tmFp+iiw0fPEF9OlTfJtr\nroGGDZ1Klpde6pu4RER8qdwmDcG0e6Ikft7xM+e9eV6B61P6TuH/2v2fHyIKLe+846yH+Oc/nZM7\ni3P66c6Jnjfd5IxGiIgEK+2eCLGRhrwyMjOYuHQi9315X4F7FSIqsP/R/VSKrOSHyEJLSgqsXu0c\n59206anbv/iic0bGjBkwdqwSCREJPto9EYLCw8K597x7Of7kcSb0nuBy78TJE8SMiiEtI81P0YWO\nuDhnG2eTJrklrjMz4dprnZoP+Q0e7LQfN84pSrV1q3Mwl4hIeaSkIcBUiKjA4C6D2f/ofm444waX\ne9HPRnP+W+ez6cAmP0UXmoxxRhJOnHDOyJg3r/DDs/76y0k2OnXK3ZWxZo2zAFNEpDxQ0hCgqles\nzrTrpvHxDR+7XP9x+480f6k5ZrjhZOZJP0UXuipVgp49nRoPx47Bvn3Ft2/b1tmxYQzceKNzbf9+\nZw2FiEioUdIQ4K4+/WpOPn2SrQ8ULIkYOTISM9zw7eZvybSZfogutFWsCDVqOFMYO3bArl3OVAVA\ny0KKeU6f7iQPNWs6Za43aUBIREKMkoYgEB4WTqO4RthhlsX9Fxe433NKT8JHhPP73t85knbEDxGG\nvvr1oW5dWLTISSLWr3emK4rTvHnuNIYxMG2ak3yIiAQrJQ1BpnODzmQOzWTsJWML3Dvj1TOoPLoy\nwbAjJhTUqpW7mNJa+PXX4tvfdBM0aJCbRIwc6YxeiIgEi6DachmqdRpK68TJE6zas4rOb3YucO/P\nB/6kRqUa2qbpB5mZ8NNP0LkzdOsG//vfqZ/p3x+GDHGqVJ48CVV1CKqIlJHqNIRwnYay2Ht0LzfM\nuIHvtnxX4N6T3Z9kxN9GEGY0qOQvu3bBoEHOuRmvvAJH3JhBmjYNbrjh1O1ERE6l3FaEVNJQvCNp\nR6g8unKh957u8TTPXPSMkocAMX8+XHzxqdtFRzvrKE6cgAsu8H5cIhJ6VNxJChUbFcuae9fw9S1f\nc18n18qSIxeMJHxEOJe9dxnpGdoP6G89e8LmzZCW5mzvHD268HapqXDuuc40hzFw9dXw9ddw4YVO\nWexVq3wbt4iUbxppCGGPffMYY/43ptB7Z9Q6g7m3zqVubF0fRyVF+e03OOss+OADWLIExo8/9TMA\nL78MfftCTIzz3p2TPkWk/ND0hJTIgeMHqD6meqH3Hj3/US5scqGO4w4Q+/Y5dR6ypaQ4oxH/+Ad8\n9JF7ffz1l7OzQ0QEND0hJVStYjXsMMuH139It0bdXO6N+d8Y+kztgxlu+Oh3N38qidfkTRjAOSuj\nVi14/nnn/d13O3/Wq1d0H7VrO1MZr78O33/vjFqIiHiCkoZy5Lq21/HDHT/Qp2Wfwu9/eB1fb/za\nx1GJO1q0cGpBTJqUW6HyVNsyBw6Eiy6CLl1ci0yNG+ecsSEiUlJKGsqhz/p9RvrT6Zx8uuDZFb3f\n640Zbpj22zSdqhnAjIEDB3ILSyUnw3vvQXw8nH128c8+9BDExsI558Avv8CyZapUKSLuUdJQTkWE\nRRAeFs64S8dx/3n3F7h/00c3Ef1sNL/s+oXth7b7IUIpiWrV4Oab4dNPYeVKOHzYud6qFXz1lVPS\nOr+VK6FDB2d3RoMGsGVL7nMiIoVR0lDOJXZN5KXLX8IOs+x+aDetarRyud9hUgcajm/IjN9nsDF5\now7GChKxsc4IxLp10Ls3/P473F8wN3TRtClUqZI7jXHffTqtU0RcBdXuCZWR9o3k48nUGFOj0HtN\nqzZl4z83YozxcVTiKRkZ8PHHMGWKk1x88EHx7WfPdhZetmsHb7wBf/ubU91SRAKbykhry6XPZGRm\nMGnZJAZ9MajINvNunUfPpj19GJV4g7XO+RivvHLqBCKvZ5+Frl2d48IrVPBefCJSNtpyKV4XHhbO\nPzr9Azus6KTy4ikXs+nAJh9GJd5gjFOiOinJGYX4xz/gjjtg+XJnaqMoTz3llMKuWNE5W2PDBti/\nH5Yu9V3sIuJbShrklDKHZnJsyDEm/31ygXvNX2qOGW5I/CqRJ+c9qTUPQS4sDF59Fd5+G9q3dxZR\nduni3Ovfv+jnXnsNWrZ06kx06uSUus7M+qtgrVMz4sQJ78cvIt6lpEFOyRhDxciK3HbObaQ8nlJo\nmwlLJjBq4Shmrp3J/mP7tV0zhEyaBA8/DG++6f6R3b17Q3i4M4px001OzYjeveHQIec8DREJTkoa\npESqRFcpdsri2unXUnNsTaKfjWZj8kYdjhUCzjoLxo51Xn/4Idx+uzN6cOgQ/Oc/p35++nTnzwUL\nnAqXFSo4W0MzMrwWsoh4iZIGKZWjQ46S9lQaR544wsuXv1xomxYvt+CBrx7wcWTiTb16wTvvOK8r\nV3bWMljrnNSZng5r17rXT9++zlqI//7XWVCZkeH0IyKBTbsnxCOOpx/nug+v44s/vij0/rn1z2XJ\nXUsIM8pTQ93mzRAV5SQETzxRsmejouDPP6FOHe/EJlIeafeEBJyKkRX5vN/nHHzsIDsf3MmUvlNc\n7i/duZTwEeF0eqMTbyx7gy//+JIDxw/4KVrxpqZN4bTTICHBWVi5fr2TCHz44amfTUuDunXhmWfg\n73+HTXk252zf7vQjIv6jkQbxmv6f9uftFW8X2+anu36iTc02VI6u7KOoxN+OHHHOurj+eucgrk8+\nKdnzBw44RakiIrwTn0io0UiDBIW3/v4W4y4dV2yb8948j/rj6vsoIgkEsbHQujWsWuVUpsxWpYp7\nz1erBpGRzmFb//kP7NvnnThFpCC/JA3GmDhjzM/GmOXGmFXGmLv8EYd4X2LXROwwy56H9/DiZS8S\nbsILtDmSdgQz3HDupHP9EKH428GDzkLIlBSnxoO7OnRwzseoVQs6d3YKS61Y4f5iTBEpOb9MTxjn\n4IJoa+0JY0xFYDXOsEmhk9yanggtZnjR51YMu3AYqSdTGXbRMCpEqDZxeZOW5iQQaWnOP5s2OcWl\nBg1y6kSkuVn+47XXnOJSNWvCVVc5OzVEyitPTk/4fU2DMaY6sBQ411qbXEQbJQ0hZNWeVVSrUI3V\ne1dz+fuXF9nujnPu4JUrXmHVnlV0adDFhxFKILHWKRKV7bbbnMO2SqJ1a5g7FxYvhuuu82x8IoEu\nJNY0ZE1RrAD+BMYWlTBI6Dm7ztk0jGvIZS0uY/6t84ts986Kd4gZFUPXt7qy+8huH0YogST/gaqT\nJzv/nDgBDz0En3126j7WrYOGDZ3Fl/fc4/zzzTfeiFYktJU4aTDGdDfGzDLG7DDGZBpj4gtpc68x\nZrMx5rgxZrExpsBMpbU2xVp7DtAUuNkYU6t0X0GC2d+a/o3vbvuOFtVb0K1RN3o07lFou3r/rocZ\nbth8YLOPI5RAY4wz2hAdDf/6F/Tpk1sP4v77T/38G284/1x6qdPXJ5/Aeec5J3wuWeLd2EWCXYmn\nJ4wxlwHnA8uAj4GrrbWz8ty/EXgXuAf4CUgErgdaWWsLXedsjPkPMM9a+3ER9zU9UY588NsHvLvy\nXb7a8FWh9/953j+ZcNkETP5fQaXcOnHCGTm46qrcaykp7p+VkdfUqU5C0q0b1K7tuRhF/CVg1jQY\nYzKBvvmShsXAEmvt4Kz3BtgGvGStHZN1rTZwzFp7xBgTBywEbrLWri7ic5Q0lFMvLHyBx+c9XuT9\nmTfOpFujbtSoVMOHUUkwOXQIjh93dmmMG+ccwFUSe/Y4h2/V0F8xCVIBmzQYYyKBY8C1+RKJyUCc\ntfbqrPedgOx/dQ3wirX2zWI+pwOwrEePHsTFxbncS0hIICEhodTfQQJfrym9mLd5Ht0bdeeHP38o\ntM3TPZ5m4LkDqV9ZNR+kaJmZTgIAztTGww+XvI8LL4Q774Rbb/VsbCKekJSURFJSksu1lJQUFixY\nAAGYNNQDdgBdrbVL8rR7Aehhre1ays/RSINgrSVsRPHLcJ7u8TSPnP8I0RHRRIVH+SgyCSa7djlT\nF23aOMd079njnJdx0UUwbBgMH+5+P7VqOUnIf//rjGL88otXQxcplZDYPSFSUsYYjj95nMyhmbwV\n/1ahbUYuGEmV56vQeEJjrLVsTN7o4ygl0NWr5yQM4KxdaNTIGT2w1jnz4vBh9/uJiHAWU956q1NY\nyhi49lqdkSGhy9NJwz4gA8h/Rl0doMx75hITE4mPjy8w9CLlR4WIChhjuLP9nTSs0pCIsMIPINh9\nZDdhI8Jo8XILFv650MdRSjCLjYWhQ+GGG2DaNPjpJxg50v3nP/4YGjeGc891kogXX3Su//abdmeI\nbyUlJREfH09iYqLH+vTVQsg/cRZCji3l52h6QooVOTKSk5kni7y/auAqftz+I21rtaVbo24+jExC\nRVqaMzKRrVIlOHas5P306gVff12w/oSIt3hyeqLE58QZY2KAFjgLGAGaGWPaAcnW2m3AOGCyMWYZ\nuVsuKwGTyxKoSHHSn05n9V+reW/Vezy/6PkC98+eeHbO622J22hQpYEvw5MQEBXlTGEcO+YUi2rf\nHrZtg927nToP7po71zky/JproGNHGDLEezGLeFpp6jRcCHwL5H/wXWvtnVltBgGP4kxLrADut9Yu\nLXWQ+XZPaMeEFCc9I52oZ0+9CPLQ44eoHF2ZA8cPULVCVdV9kFJLTc0dhSjpX6MaNZzjvhs0gJkz\nnWRExBOyd1IEzO4JX9H0hJTU8fTj3DrzVmb8PsOt9i9f/jL3nXefl6OS8mDlSqcmxIUXwj//CS+/\nXLLnn3oKXnrJqS/x4IPw44/Qvz/07ataEVI6AVOnwVeUNEhZFHeqZmHein+LO9vf6aVopLyxFl54\nIbfUdVlkZDhTGyIloS2XIiWQ/GgyBx87iB1m+aLfF7Sq0arY9v1n9ef9Ve+TnpHuowgllBkDjz3m\nlLSuWBHWr3dqOmRklLyv8HA4cgR27nQWZq5ZAyeLXv8r4nFBNdKgNQ3iKe6MPrSt1ZZO9Tsxue9k\n7wck5VL2f349MXrwwQdw443O6wMHnBoSlSuXvV8JXlrToOkJ8ZC0jDR2HNrBgRMHuPz9y/nr6F+n\nfGZ2wmzOqHUGTas19UGEUp6MGwdjx8LChXDmmc4BXE2bOpUqy2LpUmeB5plneiZOCU5a0yDiYdZa\nrp1+LZ+s/eSUbTcP3kyTqk28H5SUe/PnO9MPCQmQnFz6fv76C2rWVG2I8kprGkQ8zBjD1Gun0u+s\nfrSo3oKzap9VZNumLzZl8JeDfRidlFc9e8Kll8LGjbBli3PtlltK3k/t2s4UyEUXwVlZf7WTk+Ho\nUU9FKuVFUI00aE2D+EpGZgYRI4uvffbh9R9yafNLycjMINNm6nhu8brs3RPLlsGOHfD88zBoECxf\nDhMmuN9PzZqwb5/z+s03nX579XJqRUTpnLeQoTUNmp4QHzqZeZJaY2tx8MRBxl4ylke+eaTY9pe3\nuJwvN3xJ5tBMFYoSn+vWDRYtcqpTNm8OpTmip0kTeOUV6NPHeZ+c7NSd+NvfPBqq+Jhfy0iLlBcR\nYRHse2QfGTaDqPAoftn9C1N/nVpk+y83fAnAJf+9hE9v+pToiGjSM9KpGFnRVyFLObZwISxYAN27\nO2sXSpM0bNkCV14J1au7rqE4eNBZW6HiUqI1DSLFCA8LJyrcGa+d0HsCiV1OfVrcvM3ziB0dS+TI\nSCqNqsT5b53P3E1zvR2qCD165C52XLLESRyszT0zw135F11WrepMaTz4IAwYAJMnO+WuIyK0LqK8\n0fSESCkYmQrCAAAgAElEQVRk2kzCR4S73b5l9Zasv389czfN5ZM1n/CfPv/xYnQip3b4MMyYAXd6\noPjpjz9Cly5l70e8o9xuudRCSAkk+4/t51DqIZq91KzEz865ZQ6XNr/UC1GJlMyll8I335S9n4YN\n4fHHnZM727SBuLiy9yllo4WQGmmQAPTuincZvXA06/avo0p0FQ6lHnLrue9v/54ejXuw6cAmYqNi\nqR1T28uRihSUmuqsWahb17P9jhsHV18Ndeo45bPzO3rU2akRGenZz5WCyu1Ig5IGCWRbD26lesXq\nVHm+itvPNK/WnI0HNlK9YnX2P7rfi9GJFO+jj5w/r7su99qTT0JmJoweXba+zzwT+vWDyy5zXkdG\nOmsvLrsMvnTWD7Npk7N7QwdyeZ6SBpEAZ63l641f88naT3h92etuPdO/fX+e7/U8NSvV9HJ0IkU7\ncgTWroUqVaBVvrPdvv3WKTjlSdY6Z2VUrw6jRnnmNFBxpYqQIgHOGEPvFr2ZeOVErmp1lVvPvPXL\nWzw450FW7F7B2EVjvRyhSOFiY+HccwsmDODUa/jqK2dr5qefeubz2rSB555zXr/3HqTrcNmAppEG\nES/LtJlk2kxav9KaTQc2uf3czgd3Eh0RTerJVOpVrufFCEVKJz7eOVnz0UedH/YzZkCnTlCpUtn6\n3bjRKVAFuSeBSumV2+kJ7Z6QYLfr8C7qVa7Hi4tf5IE5D7j93KBzB3HL2bfQtWFXL0Yn4hnp6c4U\nx9lnl72vESNg6FBn2iQy0qkNoXUP7tHuCY00SIg4cPwA1cdUL/Fzl7W4jC9v/tILEYl4h6cqqo8d\nC49kVXLft0/VKUtCaxpEgly1itXIHJpZ4ue+2vAVZrjBDDc88nXxZ2GIBIK1a+Gnn5xdGOeck3v9\nwQdL1s8jef6616wJtWo5lSmNgYcegtmzPRKunIKSBhE/McbQpmYbAJIfTT5F64L+9eO/+Hz956zd\nt5a2/2nL8fTjng5RpMxat3bWORgDS5fCkCFw223wr3/B7t3O4kdwFl+WxL59cMcdzutx45z1FcY4\nx38bo7UQ3qLpCRE/Sj2ZSobNoFJkJd5a/ha1Y2pz9bSrybAZvHrFqwz6YlCJ+tv4z400qdqEMKPf\nByQ4WOsc9W2tc0JnfDzMmuWZvgcOhIkT4fPP4Yor3Htm2zbniPBQOqhW0xMiISI6IppKkc5S8/4d\n+nNV66tIfzqdd/7+Dnd3vLvE/TV/qTlPzX/K02GKeI0xzihDrVrO+6uvzr03fnzZ+p440fmzTx9n\nIeV990FMDGzeDPPnwwcfOK+zbdkCjRo50x5SOCUNIgHGGMPt59xORFgEWwZv4cpWVwKwZfAWt56f\n+utUokZG8eg3j3oxShHPatIEtm51pi6yPZBvg9HBg876hdKoXBn+8x/ntM+zzoKLL4aEBGjWDKZM\ncZKXrVudtitXlu4zygMlDSIBrHHVxsxOmI0dZmlctTG9mvUC4Nvbvi3yma0pW0nPTGfs/8bmLJrs\n+W5PMjIzfBW2SKk0auT88F65Ev7807m2Z4/zg95a5xCsMWNcn9m/H0aOLNnn5D/OOztRuegi58/U\nVPjuu5JGXz4EVdKQmJhIfHw8SUlJ/g5FxC+yD7VqVq0ZX/T7wu3nvt3yLREjI3jlp1fYenAr2w9t\nd7k/a92sEhWeEvGms892Ts0EqF3b9cCrsDB49VVn98Xu3U756aeectZCeMrEiU71yy/c/1csICUl\nJREfH09iYqLH+tRCSJEgsvfoXl79+VWGXjgUY5xRBIAO9TqwfFfJ1jfN/b+59Pu4H5v+uYnY0bE6\nNEuCXqVKcDxrE1G3brBwYdn6GzLE6bNePbj9dnjjDWjXDjp3du4Hy2JJTy6EjPBMSCLiC7ViajHs\nomEFrn/e73N+2PoDN8y4we2+ev3XmeoY8NkAAJKPJ7Nu3zpa12ztmWBFfGzbNmfqoVEj5/3s2WUb\ngRg1Kvd1//6u94yBlBRnncW6dc7ujNWroWXL0n9eMAiq6QkRcfX+Ne/zRb8vqBtbl+vPuD7n+uDO\ng93v49f3c14P+24YJzNPejRGEV+pUSM3YQC46irXhZWeZK1zEmijRnDJJU7p7FatYMcOSEvzzmcG\nAiUNIkGs31n9uLzl5Tnv41s7v1add9p5AAzoOKBE/U1bPY3HvnkMgEbjGzFl5RQPRSriH5MnOwsb\nt26FDz+EW291rr/0Epw44fnPa9AAoqOd00B37/Z8//6m6QmREHJmrTOZtW4WvZv35sgTR4iJiqFT\n/U7cNfsut/v4eO3H/JH8B9sObeO2mbdxSbNLdMqmBLWoKGdEoFEjuPZauPJKuOYaCA93dkm0bOns\nnDh82FkHEReXWzeitC7PyuWDYNlgiWghpEgIOZl5kpW7V9KxfkeX6++teo//bfsfv/31Gz/8+UOJ\n+72nwz083u1xmlZr6qlQRQJKRobzAz4i61fpNWvg++/ho49g0aLcBZYlFQg/YlURUkQKFREWUSBh\nALjl7Ft4tc+r9G3TN+da3di6bvc7afkkmr3UjA3JG4ptV2NMDf79v3+7H7BIgAgPz00YAE4/3SlD\n/c03sHOn/+IKNEoaRMqRxC6JLL9nOasGrmJin4klfr7lyy35dc+vmOGGySsm89yC50jPSM+5n3w8\nmSHzh3gyZBG/q1rVGTHIO2owfrwzGlHeaE2DSDlijKF9vfYAnFXnLJ7r+RxPzn+yRH2cPfFsAO74\n1DlisHn15lza/FKqV6wOQDBMeYqUVs2azlRGdonr776DJ56AH38s2Pbrr30amk9opEGkHLvvvPsY\n2HEgG+7fwOEnDnN5i8tP/VA+v+75lRpjatD0RWe9Q3pmOolfea4CnUgg2b4ddu3KfX/hhfDxx9Cl\nC3Tv7lxbssQZlbjkEv/E6E1BtRCyR48exMXFkZCQQEJCgr/DEgk5n679lL7T+p66oRvssMD/b4uI\nJw0e7Gzl3LvXGZHwt6SkJJKSkkhJSWHBggVQ3hZCjh8/nlmzZilhEPESk1UX98nuT3Ly6ZOsu29d\nqftaunMpB08czFn/IBLqXnjBqc8QCAkDQEJCArNmzWJ8Wc8YzyOokgYR8a7ezXtzT4d7ePj8hwkP\nC6dVjVal7qvTG52o9kI1IHf9g0goq1ABevf2dxTepaRBRHJER0Tz+lWvU7VC1ULvL7lrSc7r8xue\nX6K+zXDDwM8Gknw8ucC9H7f9SOrJ1JIFKyI+p6RBRNxih1kaVGkAwNVtrmbG9TMIN+El6uP1Za9T\nY0wNao2thRluuGnGTXy/5XvOf/t8aoyp4Y2wRcSDlDSIiNsybSbgrH2oV7ker/V5Ledej8Y93O5n\n37F9gHPWxUXvXgTA0fSjDPu24AmeIhI4lDSISLHqxdYjsYuzhbJiREUATq95OgB3dbiLH/v/yIfX\nf8iM62eU+bNGLBhR5j5ExHtU3ElEirXzodwaujUq1WDZPcs4u45T4MkYQ5cGXXLuT+k7hVtn3prz\nfsb1M9h+aDsPzHnA7c87bdxp7Dy8k1UDV1ExsiL1YusRExUDwPZD26lVqRbREdFl/VoiUgoaaRCR\nEulQrwMRYYX/vvF/7f7PpT7DtW2vZXCXwSVaNLnzsJOknD3xbFq+3JLY0bGkZaQB0HB8Q+6efXcZ\noheRslDSICIe991t37H23rU575+58BlaVG/BxU0vLlV/0c9GM3/zfAAW/rnQIzGKSMkpaRARj7uw\nyYW0rtk65/0lzS/hj/v/oE5sHQDGXTquxH1ePMVJOLYc3IIZbvjtr98AmPbbNPYf25/T7ve9v+eM\nTIiIZ/klaTDGNDDGfGuMWW2MWWGMuc4fcYiIb716xat80e8LErsm0qJ6i1L1YXGmP8567Sz+OvoX\nN310E13e6sLoH0aTaTM549UzdPaFiJf4a6ThJDDYWnsG0BuYYIyp6KdYRMRH4irEcXlL51CsP+7/\ng8yhmWXqr86/nJGLDckbGDJ/CCczTwLw086fOJJ2hAmLJ3DNtGv478r/li1wEQH8tHvCWrsb2J31\neo8xZh9QHdjhj3hExD+MMQzsOJCk35JISU0pc3/Rzzq7KpbuXErl0ZVzrn+y9hMiwiLo0bgHtWNq\nExkeWebPEimP/L6mwRjTEQiz1iphECmHXrvyNQ4+fpAmVZsQExnD4v6LvfI5/T7uR4PxDRj0+SCv\n9C9SHpQ4aTDGdDfGzDLG7DDGZBpj4gtpc68xZrMx5rgxZrExplMRfVUH3gW0h0qknFt/33qSH0v2\n+iLGuZvnsmL3ikLvbT+0nY6TOpJyouyjHiKhqDQjDTHACmAQYPPfNMbcCPwbGAa0B1YCc4wxNfO1\niwI+AUZZa5fk70dEypfI8EiiwqNIzSj+4Kq8patLY8vBLbR/vT3r9uUe+22GG+6ZfQ+TV0xm+a7l\nLNi6oEyfIRKqSpw0WGu/stYOtdZ+CphCmiQCr1trp1hr1wIDgWPAnfnavQvMs9ZOLWkMIhK6sndV\nVKtQLefa7ITZXN7CWUB5xzl3MP266WX+nL+O/uXy/o3lb7B2n1NbwpjC/tMmIsbaAoMF7j9sTCbQ\n11o7K+t9JE6CcG32tazrk4E4a+3VWe8vAL4HVuEkHhb4P2vt6iI+pwOwrEePHsTFxbncS0hIICEh\nodTfQUQC01VJV/HZ+s/46+G/qBVTq8B9M7xsP9h7NO7BrJtmEVchrkBfn/f7nCtaXlGm/kX8ISkp\niaSkJJdrKSkpLFiwAKCjtXZ5Wfr39O6JmkA4sCff9T1ATqUXa+2i0nz2+PHj6dChQ5kCFJHgMLDj\nQD5b/xlxFeIKvZ9wZgJJvyUVes8dC7YuoOoLVVl4R8EKk6bQQVTHit0riE+KZ+19a6kUWanUny/i\nDYX9Ir18+XI6duzokf79vntCRKQwfVr1wQ6zRIVHFXp/6rVTscMsR544AkDTqk15rudzJf6cbu90\nK3DNGMPi7YtJPp5c4N7LS15m26FtbDm4pcSfJRLsPD3SsA/IAOrku16HrLoMZZGYmEhcXJymJEQk\nR0xUDBlDMwgzYXzxxxce6fO9Ve/x/q/v06ZmG86uczZ3nnMnvVv05om5T/D2ircBCDfhHvksEW/J\nnqpISfHcbiCPrmnIurYYWGKtHZz13gB/Ai9Za8eW8nM6AMuWLVum6QkRKdboH0YzZP4Qj/ZZq1It\nNg3e5FIw6o/7/8hZtLl+/3p6vNODNfeuoVrFakV1I+IXeaYnyrymoTR1GmKMMe2MMedkXWqW9b5h\n1vtxwN3GmFuNMW2AiUAlYHJZAhURcccT3Z/ADrMuR3SX1d5je10SBoCWL7fMOSjrvVXvsefoHn7e\n+bPHPlMkEJVmTcO5wC/AMpxdD/8GlgPDAay104GHgRFZ7c4Geltr95Y12MTEROLj4wusDBURKczd\nHbxbNy7hI2eaNCLMmenNPvtCJBAkJSURHx9PYqLnDnAr0/SEr2h6QkRKK3s7ZWxULEfSjni8fzvM\nMuqHUTw5/0k+velTIsMiGf79cBbf5VoO+1j6Me22EL/w6/SEiEgw+uP+PxjTa0yh997t+26p+03P\nSOfH7T8CcCj1EFdMvYIlO1yL3K7+azUxo2L4bst3pf4ckUCgpEFEyoW6sXV56PyHmHPLnAL3yjLi\n2vu93ny2/jMAl8OwXlj4Qs7r9fvXA7B4u3cO4xLxlaBKGrSmQURK6p2/v8Pb8c42yTATxqXNL6Vj\nPddCN21rtc15XaNijRL1/+2Wb3NeH047nPP68XmPcyTtCJ3f7Mznf3wOFL/mYebamZw4eaJEny1S\nHK1p0JoGEfGAXYd3UX9c/Zz3dpilw+sd+GX3L6Q/nc7uI7tpOL5hMT2UzbbEbRxPP85n6z8jsWsi\n21K20WhCI+5qfxdvxL/htc+V8smTaxo8XdxJRCTg1atcr8C1727/jj1H9hARFuH1BYt5E5LErok5\nIxBv/vKmkgYJaEE1PSEi4i1VoqvQskZLIHcLpS+Y4YZF2xblvD+SdoTpq6cz4vsRnDPxnGKeFPG9\noBppUBlpEfG0wopAVYmuwnVtr2PG7zMAeObCZ3jm+2cAiA6PJjUj1aMxvLE8d3QhfxEpkdIKuDLS\nvqI1DSLiaQ3HN2T7oe1FVo7cf2w/NcfWZNKVk9h5eCfPfP8M06+bTp9WfYgZFeOzOAuLL9Nmciz9\nGLFRsUU+dyTtSLH3pfxQnQYRkTJaPWg1ux8q+hy9GpVqYIdZ7u54N4M6DeL6ttdzZasrCTO+/c/m\nl398SerJVJ6Y+wTH048DMPTboVQeXZlMm1noMz9u+5HKoyuzdOdSX4Yq5YCSBhEpl6pEV6FObP4D\neQtXK6YW06+fTsXIigWShtMqn+aN8HJcMfUKPl7zMc8vep7JKyYD8NwPzhHg+47t46PfP+KHrT+4\nPLNyz0oAft3zq1djk/JHSYOISAnkTxqe7fksfz7wZ877dfet8/hnZtgMgAJ1HA6lHuK6D6+jx+Qe\nLtcNTulsS+BPP0twCaqkQcWdRMTfwk04AI3iGtG1QVeuanUVDeNyt1A2jmvs8c98+xenOFVaRprL\n9cKmH1btWcW01dMAp9JlekY6Sb8mnbLqpRluGDLPs0eKi3+puJMWQopIADDDDR3qdWDZPctyru05\nsofjJ4/ToEoDIkdGeu2zR1w0gqHfDS1wvX3d9iy6cxGVRuXWmDin7jn0O7Mfj859lMX9F9O5Qeci\n+zXDDeEmnJNDdVJnqNFCSBERP7vjnDtc3teJrUOTqk1yRiK8pbCEAeCX3b9w+6e3u1xbsXsFOw7v\nAOBo+tFT9p09DSJSFCUNIiIlZIdZ7jvvvkLvGWO45vRrXK5ViKjgi7CYvnp6gWsvLnkRgL9/8Pec\na19v/JoNyRt8EpOElqAq7iQiEgymXjOVAycOUO/fBctV+8uRtCO8uPhFPln7Cd9v/Z4wE0bG0KJH\nFrYe3Erjqp5fnyHBTSMNIiIeFh0RTd3YutzV/i4gdzcDQFx0HBc0vMAvcT0w5wG+3/o9QJE1HgA+\nW/8ZTV5sojoPUkBQJQ3aPSEiwWTilRM5NuSYy7V9j+6j82nOgsSrWl3F6ItH81qf1/wRHi8teanQ\n62v2rgFgy8EtPoxGPM0buyeCanpi/Pjx2j0hIkEjPCycimEVXa5FhEVw3mnnAfDS5S/RpGoTft7x\ns0ubw08cpuaYmh4/4yK/wV8NZu2+tYy+eHTOtR+2/oAxWXUegmB3nRQt+5ymPLsnyiyoRhpERIJZ\nyuPOwUE3nnkjex/ZS5OqTQDodFon9j6yl+nXTSc2KpaYyBhOPHWCvY/s9XpMry19jQGfDch532Ny\nD5fplPx+2PoDT89/2utxSWBS0iAi4mVn1D4DcEpXZ6tZqaZLm5qVanL9Gddz+InDOb/p52/jLZsP\nbnZ5//A3DwPOFkwz3PDKT6+w96iTwFw4+UKe/eHZAn0cSTvC0bRTb+uU4KakQUTEy+bcMoef7vrJ\n32EU6acdhcc2a90sAO7/8n5q/6s2q/asyilNPW/TPJfFlFVGVznlbpFMm8m8TfM8FLX4g5IGEREv\nq16xOp1O6+S1/lcMWOGVfpN+c1103m5iu5zXvf7biyHzhjD116mAc87F4bTDxfb3+tLX6fXfXkXu\nylj056ICh29JYAmqhZAiIuXVxU0vJiYqJue3/4oRFTl+0jkqu1JkpeIe9ZoXFr0AQNcGXXOurd23\nljY12xTaPrs6ZcqJlELvd3unG+AUz5LApJEGEZEgMPfWucy8cSYAdWPrsvSe3N/W804T5N0J4Ss3\nfXRTzutbP7kVgCfmPsFzC54rtH32mg0JPkGVNKhOg4iUZ9k/bCtGVKRtrbZUjHC2c+Y9Avvxbo/7\nPK68ayJiomIAeH7R8zz17VN0e7ubz+MRhzfqNARV0jB+/HhmzZpFQkKCv0MREfGbM2ufCThbN8Gp\npxAbFVugXVR4lE/jAogMcz3hc9G2RTmvy1L3Yci8ITR7sVmpny+PEhISmDVrFuPHj/dYn0GVNIiI\nlHcLbl/A+9e8D+SWp7ZY1t23jl8G/OLS9vATxS9M9IbCph4+WfOJy/uLp1zMaz+/hhluOJR66JR9\nLvpzEaMXji6wNVR8TwshRUSCSPfG3XNeZycNmTaT+pXrU79yfZe2/hhp+Hrj15jhronDNdOdUz8v\naXZJzrV7v7gXgB2HdlClVhWK89GajzwcpZSWRhpERIJU3di6AESHR/s5Evd8s+mbnNdhxvnxU9zB\nWRJ4NNIgIhKkhl44lI71O9KyRkuX6ysGrPDLKENJZFjnWO6+0/oy55Y5XDv9Wpf7V7x/BfGt45m0\nbBLn1j/XHyFKIZQ0iIgEqeiIaK45/ZoC19vVbVdI68C0IXkDr/38Git2uxao+nLDl3y54UsAIsNz\nF1fO2TCHQ6mHuP6M630apzg0PSEiEsLm3TqPV6949ZTt+rTs44NoCvfpuk+Lvb8xeWPO68vev4wb\nZtzA27+8zbaUbaX6vEybydRfp+oUz1JQ0iAiEsCev/h5ejTuUernezbtyT86/SPnfURYRIFtkQCn\n1zw953WFiAql/rzS+CP5D5f3Ww9udXm///j+As/0n9Wfc14/p1SfN+23adz88c1aYFkKShpERALY\nY90e4/vbvy9zPzUr1SQmMob0p9NJezqNbo1ciy51bZhbCvqmM2/y6+LKJi82catd8vHkUvV/8MRB\nwDmZU0pGaxpERMqB7YnbXd5nb9fMds3p13Do8UOEmTAqRFQg6dfgq7zb+pXWPHbBY9zZ/k5/hxKy\ngmqkQWWkRURKJzoimuiI3NGD7CJMeZOHytGViYmKITws3KU0dSD7v0/+jwGzBwCwfv967v/yfiYt\nm5SzXsFay6Rlk0jLSMt5Jvu75U+cQo03ykgH1UjD+PHj6dChg7/DEBEJetk/MCf3ncyUlVMK3A+W\nRYLvrXoPgJE9RwJwLP0YAz4bQJOqTbi0+aV8t+U7Bnw2gCNpR3iw64NA7nfLrhURqhISEkhISGD5\n8uV07NjRI32G9v9iIiJSqPZ12wOQcGYCc2+dW+D+BY0uOGUfz/7tWY/HVVp1/lXH5f2JkycA6Dml\nJwAPff0Qvab0AnILSt0681ZunHGjD6MMfkoaRETKoTGXjOH3Qb+71EDIa3bCbBb3X8yOB3cwpNsQ\nl3vr71vP61e+znmnneeLUEvllo9vYeXulS7X5m2exxvL3uBY+rGca9NXT2fzAZ1p4a6gmp4QERHP\niAyP5PRapxd5PzYqls4NOgMQVyHO5V7LGi1pWaMl32z8prBHA8LhtMOFbsm857N7CkxLnPvGuex/\ntOC2TilIIw0iIlIqMVExJX4mc6j/z5rIf95F8vFkzHBD2/+0JXZULPM3zyd2VKzLiES2u2fdzV2z\n7vJVqAFHSYOIiLhtzb1rcl53bdCVR85/hEfOf8Tt5ws7OjtQrNm3hqPpR/nnl//kaPpRth/azuHU\nwy5Jxpu/vMlbv7zl8lx2G2utW0d9BzMlDSIiUqy8Oyna1GyT89oYw5hLxjDmkjEl6i8uOu7Ujfxo\n9d7VgDMiUeX5Kjy34DkAMjIzCm1f5fkqPPrNo7y29DXino8L6cRBSYOIiJTZDWfcUODajgd3+CES\nzzlw/AAAM9fNZN2+dfx19K+ce8fSj7Fk+5Kc96/89EpOWerDqYd9G6gPKWkQEZEyu/msm3NeX9DQ\n2a5Zv3J9oPCEIhhc8LbzPZbvWk6b/7Sh/rj6Ofeqv1CdLm91Yc+RPQCkZqQyf/N8ILCnYMpKSYOI\niJRZfOv4nNcL71yIHZZVkXGYZdp101zaulttMrGL5yoZlkZxcaZmpAKwYOuCAvcybSa//fWb1+Ly\nJ78lDcaYj40xycaY6f6KQURETi37lM2+bfoW265yVGUubnrxKfsb2HGgW5/brk47t9r50w0zCo6i\nPLvgWc567ayc6Y1Q4s86DROAt4Db/BiDiIicQteGXXNGDopz6An3FgC+cMkLjPnfqRdPtqrRyq3+\nAs2SHc5ah2Ppx6hWsZqfo/Esv400WGsXADqXVESkHOjVrFeBa7FRscU+EyyHZuW3YvcKIHjjL47W\nNIiIiNfNTpjN3kf25rw/8NgBdj640+3nVwxY4Y2wvCp/EalQUOKkwRjT3RgzyxizwxiTaYyJL6TN\nvcaYzcaY48aYxcaYTp4JV0REglGFiArUrFQz533VClWpHF252Gfy1odoVzfw1zfkFywnhZZEaUYa\nYoAVwCAoOPZijLkR+DcwDGgPrATmGGNq5m8rIiJSlKKG9yf0nuDjSEpH0xOAtfYra+1Qa+2nQGGb\nUROB1621U6y1a4GBwDHgzkLamiL6EBGRcqpTfWdwuqjf1Ad3GezLcEpt1Z5V/g7B4zy6e8IYEwl0\nBEZlX7PWWmPMXKBrvrbfAGcDMcaYP4HrrbVLKEZiYiJxca7lRxMSEkhISPDQNxAREX/r0bgHP+/8\nmUZxjfwdSpk8Nf8pl/oVvpCUlERSUpLLtZSUFI/17+ktlzWBcGBPvut7gNZ5L1hrLylp5+PHj6dD\nhw6lj05ERAJefOt4Rv5tJBUjK7rV/u34t7lzljOY/UDnB5iwJDCmL/wxPVHYL9LLly+nY8eOHulf\nuydERCSgGIzbCQNAmMn9UVYpspI3QpIsnh5p2AdkAHXyXa8D7C5r59nTE5qSEBEJPU2qNmHLwS0u\nJ2nm1bZWW3o26enjqIJX9lRFwE5PWGvTjTHLgIuBWQDGObnjYuClsvav6QkRkdB13mnnsXnw5iLv\nrx60utDrgXpAlL+3XGb/gu3J6YkSJw3GmBigBbm7HpoZY9oBydbabcA4YHJW8vATzm6KSsBkj0Qs\nIiJShEBKIDJshr9D8LjSjDScC3yLU6PB4tRkAHgXuNNaOz2rJsMInGmJFUBva+3ewjorCU1PiIiE\nrtL8Zl4npg5n1j4z533XBl2LbHtJs0v4ZtM3pYqtNNbuW+uzzyqMN6YnjL+HT9xhjOkALFu2bJmm\nJ15iqZwAAAzLSURBVEREQogZnjsycH3b65l+vevBx8fTj5NhMwqcU5GWkcbJzJNEhEUQFR7F0bSj\nAMRExeT0+d1t33HRuxflPJP+dDqRIyOLjOWVy1/hvi/vK+tXcuHOQV/elmd6oqO1dnlZ+vLnKZci\nIiI5CtuiWNQuiqjwKKLCo3Lex0TFFGhTo1INl/d5d1kUprA+xJW2XIqISLlgVIC4zIJqpEFrGkRE\nQsu066ax6/AuVuxZwdAeQz3S5wu9XuCMWmcUWCNhjOGyFpfx1YavAHj1ilcZ9MUgj3xmIAr4LZfe\npi2XIiKh5YYzbvB4n49e8CgAv+75tcC9zqd1zkkaBpw7wCVpKMtIxINdHmTc4nGlft4bvLHlUtMT\nIiJSbuQdffDkdEUonmhZGCUNIiJSLuWv6RBINR4CVVAlDYmJicTHxxc4wUtERCS/ZtWa5bzOPjEz\n4ayi18PlHYXoUK9kU+GBWL4gKSmJ+Ph4EhMTPdan1jSIiEhIiomKKVAnIf+5Ft0bdeeHP38o8OyS\nu5YUW9MhGGhNg4iIiAdl2syc13mnJ0q63kFrGkREREJcUedDlCWBCGVKGkREpNzKyCwiaciTKJyq\nkiQE5poGbwiqNQ0q7iQiIp5UrWK1nNdXtroy53XekYaZN81kzd41ZNpMHp/3eIE+Pr3pU86qfRZf\nbPiCDckbvBtwCai4kxZCioiIB2WPIhx47ABVK1QtcL9xXGOubHVlTkJRWNIQ3zoegD/u/8PlAC5/\n00JIERERHyovCxzdpaRBRETKrey1CFrs6B4lDSIiUm5ljySoGqR7lDSIiEi5V9RIg0YgXAXVQkjt\nnhARkbIaduEwKkdVBmBUz1GkZaQRExXj1rNvXvUmd8++2621Dm/Hv12mOMvKG7snTDDsLTXGdACW\nLVu2TLsnRETEa7J3P9hhFjPc0DiuMVse2FJku+y22ao+X5WU1JQC1/0pz+6Jjtba5WXpS9MTIiIi\neeSdktDuCVdKGkRERDwk1JMMJQ0iIiJ5aCdF0ZQ0iIiIiFuUNIiIiIhblDSIiIjkUb1i9ZzXhZ1H\nkVf+Og7BsCOxLFSnQUREJMvHN3xMu7rtAEi6NonujboX237NvWsKvZ50bZLHYysp1WlQnQYREQkA\nees55FV5dGWOpB0JmBoNoDoNIiIi4gdKGkRERDwkGEbvy0JJg4iIiLhFSYOIiIi4RUmDiIiIuEVJ\ng4iIiIfo7AkRERERlDSIiIh4jHZPiIiIiKAy0iIiIiW24f4N7Du2r8D1QFrToDLSKiMtIiIBrOJz\nFTlx8oTKSIuIiEj5pqRBRERE3KKkQURExEOCYcq/LJQ0iIiIiFuUNIiIiHhIIO2e8AYlDSIiIuIW\nJQ0iIiIeojUNIiIiIihpEBERETf5LWkwxlxpjFlrjFlnjOnvrzhERETEPX5JGowx4cC/gYuAjsBj\nxphq/ojFH5KSkvwdgkfp+wSuUPouoO8TyELpu0Dpv492T3jHecBv1trd1tojwOfApX6Kxef0L1dg\nC6XvE0rfBfR9AlkofRcIve/jKf5KGuoDO/K83wGc5qdYREREPEK7J/IxxnQ3xswyxuwwxmQaY+IL\naXOvMWazMea4MWaxMaaTZ8IVERERfynNSEMMsAIYBAUnb4wxN+KsVxgGtAdWAnOMMTXzNNsJNMjz\n/rSsayIiIkEr1Nc0RJT0AWvtV8BXAMYYU0iTROB1a+2UrDYDgT7AncCYrDY/AWcYY+oBh4HLgBHF\nfGwFgDVr1pQ03ICUkpLC8uVlOtI8oOj7BK5Q+i6g7xPIQum7QOm/j91pwRJQ/1vk+dlZoax9mbLM\nvxhjMoG+1tpZWe8jgWPAtdnXsq5PBuKstVfnuXYlzoiEAV6w1r5VzOf0A94vdaAiIiJys7V2alk6\nKPFIwynUBMKBPfmu7wFa571grf0M+MzNfucANwNbgBNlC1FERKRcqQA0wflZWiaeThq8wlq7H/6/\nvfuPvaqu4zj+fCFkQnP+YcGcLSP81UpIXM0USLFaRjj7o6wt55hlkZCuhrBsK1nLqAEaUVs/5o9W\nppU5NmtlNkaQGlJSYIWTJYS0Ef6Y4NLk3R+fzzevV/h+zz337Pu55+vrsd3te8/37N7XZ+fez33f\nzzmfz6Wv6sjMzOwVbFMTD9L0lMt9wAvA5K7tk4G9DT+XmZmZjaJGi4aIeB54EJg7tC1fLDmXhqoc\nMzMzK6Pn0xOSJgHTSBcwAkyVNB3YHxG7gJXATZIeJM2SuBqYCNzUSGIzMzMroufZE5LmAL/l5Ws0\n3BwRC/I+C4ElpNMSfwIWRcTm/uOamZlZKT2fnoiI9RExLiKO6rot6NhnbUScFBHHRMTZ/RQMY2V1\nSUnLJD0g6WlJ/5J0p6RTSudqgqSleXXQlaWz1CXpBEm3Ston6aCkhySdWTpXHZLGSVou6dHclkck\nXVs6V1UVV529TtKe3L5fS5pWIutIhmuLpPGSvippq6Rn8j435/VrBlKVY9Ox77fzPotHM2MvKr7W\nTpd0l6Qn83G6X9KJh3u8kkZqi6RJktZI2pXfN9skXdHr8xT7aewqKq4u2RazgG8A7wAuACYAv5J0\nTNFUfcpF3CdIx6aVJB0HbAT+A7wXOB34LPBEyVx9WApcQVq19TTSqN8SSVcWTVXdSKvOXgNcSXrd\nvR04QOoXXjWaISsari0TgRnAl0j928Wkqel3jWbAHg17bIZIupjU1/3zSPsMiJFea28CNgDbgdnA\nW4HlDObU/5GOzSrSD0N+lNQvrALW5DWTqouIgb0B9wE3dNwXsBtYUjpbA207HjgEnFs6Sx9teA3w\nN+B80imrlaUz1WzH9cD60jkabM864Dtd234C3FI6W422HALmd23bA1zdcf9Y4FngQ6Xz9tqWw+xz\nFmkG2oml89ZtD+lnAR4jFd87gcWls9ZtD/Aj0qn34vkaaMufgc93bdsMXNfLYw/sSENeXXIm8Juh\nbZFaeQ9wdqlcDTqOVA3uLx2kD98E1kXEvaWD9OkDwGZJt+dTR1skXV46VB82AXMlnQyQL1Q+B7i7\naKoGSHojMIWX9gtPA/cztvqFJ0sHqSPPlrsFWBERrV73P7fl/cAOSb/MfcN9ki4qna2mTcB8SScA\nSDoPOJkeF3wa2KKB4VeXnDL6cZqTX4yrgd9FxPbSeeqQdAlpaHVZ6SwNmAp8ijRq8h7gW8CNkj5W\nNFV91wM/Bv4q6TnSNOjVEXFb2ViNmEL6UB2L/cLRpGP3w4h4pnSempYCz0XEmtJBGvA60mjqNaSC\n+93AncDPJM0qGaymRcDDwO7cL9wNfDoiNvbyIK1YEXIMWgu8mfTtr3XyRUCrgQsirc3RduOAByLi\nC/n+Q5LeAnwSuLVcrNo+TDpveQnpXOwM4AZJeyKije0Z8ySNB+4gFUQLC8epRdJMYDHp+oyxYOhL\n9c8j4sb891ZJ7yT1DRvKxKptMek6k3mk00ezgbW5X6g8WjzIRcOYXF1S0hrgQmBWRDxeOk9NM4HX\nAlvyqAmkUaHZ+WK7o/OppLZ4nFSBd3oY+GCBLE1YAXwlIu7I97dJOok0KtT2omEv6dqmybx0tGEy\n8MciifrUUTC8Hji/xaMM55L6hV0vdgscBayUdFVETC2WrJ59wH85fN/Qqi98kl4NfJn0A5O/yJv/\nIultwOeAykXDwJ6eiDG4umQuGC4CzouIx0rn6cM9pKuIZwDT820z8ANgessKBkgzJ07t2nYq8I8C\nWZowkVRwdzrEAL/fq4qInaTCobNfOJb0Dap1/UJHwTAVmBsRbZ2xA+lahjN4sU+YTrpodQVpVlKr\n5M+gP/DyvuEU2tc3TMi37n7hBXrsFwZ5pAHG0OqSktYCHwHmAwckDY2gPBURgzh954gi4gBp2Pv/\nJB0A/t3Si59WARslLQNuJ30AXQ58vGiq+tYB10raDWwDziS9d75bNFVFGnnV2dWk9j1C+uXb5aRZ\nVQM3VXG4tpBGuH5KKr7nARM6+oX9g3jqr8KxeaJr/+eBvRGxY3STVlOhPV8DbpO0gTRD7H2kYzWn\nRN7hjNQWSeuBr0taRCp63gVcClzV0xOVnhpSYerIQlLH8Czwe+Cs0plqtuMQqarrvl1aOltD7buX\nlk65zPkvBLYCB0kftAtKZ+qjLZNIBfdO0hoGO0hrAYwvna1i/jlHeL98v2OfL5K+xR4kXf09rXTu\nXtsCvOEw/xu6P7t09rrHpmv/RxngKZcVX2uXAX/P76UtwLzSueu0hXRh5/eAXbkt24HP9Po8PS8j\nbWZmZq9MrT/HaWZmZqPDRYOZmZlV4qLBzMzMKnHRYGZmZpW4aDAzM7NKXDSYmZlZJS4azMzMrBIX\nDWZmZlaJiwYzMzOrxEWDmZmZVeKiwczMzCpx0WBmZmaV/A9ZGxk8JdSEGAAAAABJRU5ErkJggg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAg0AAAFnCAYAAAAln3o1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzs3Xd0lcXWx/HvpJEEMJQgVVSq2CgBBRXUq1ewIYqKARV7\nLze+ioqFC6LYKHbFCpYoCiqiiA0BpXilqQhSlSIgNbSEtHn/mBRC2klyen6ftVieM2ee5+xngWQz\nZY+x1iIiIiJSnohAByAiIiKhQUmDiIiIeERJg4iIiHhESYOIiIh4REmDiIiIeERJg4iIiHhESYOI\niIh4REmDiIiIeERJg4iIiHhESYOIiIh4REmDiIiIeCQqUF9sjPkT2AlYYLu19oxAxSIiIiLlC1jS\nAOQC3ay16QGMQURERDwUyOkJE+DvFxERkQoI5A9tC8w0xswzxvQPYBwiIiLigQonDcaY7saYycaY\nDcaYXGNM7xL63GqMWWOMSTfGzDXGdCnhVidba5OAC4DBxphjKxG/iIiI+EllRhpqAouAW3CjBUUY\nY/oBI4EhQEdgMTDNGJN4YD9r7ca8/24CvgA6VSIWERER8RNjbbGf+55fbEwu0MdaO/mAtrnAPGvt\nnXnvDbAOeNZa+2ReWzwQYa3dY4ypBXwP3GitnV/K99QHegJ/AhmVDlhERKT6iQWOAKZZa7dV5UZe\n3T1hjIkGkoDH8tustdYY8w3Q7YCuDYGPjTEWiATGlpYw5OkJvOvNWEVERKqZAcB7VbmBt7dcJuKS\ngM0HtW8G2ua/sdauATpU4L5/Arzzzju0a9euiiEGXkpKCqNHjw50GF6j5wle4fQsoOcJZuH0LBBe\nz7N06VIuv/xyyPtZWhWBrNNQERkA7dq1o1On0F/6kJCQEBbPkU/PE7zC6VlAzxPMwulZIPyeJ0+V\np/e9nTRsBXJw0w8HaghsqurNU1JSSEhIIDk5meTk5KreTkREJGylpqaSmppKWlqa1+7p1aTBWptl\njJkPnAFMhoKFkGcAz1b1/qNHjw7HzE9ERMTr8v+BvWDBApKSkrxyzwonDcaYmkArXEVHgBbGmPa4\n8yPWAaOAt/KSh5+AFCAeeMsrEYuIiEhAVGakoTMwHVejweJqMgCMA66x1k7Iq8kwDDctsQjoaa3d\nUtVgw2V6IpRjL4meJ3iF07OAnieYhdOzQHg8jy+mJ6pUp8FfjDGdgPnz58/X9ISIiEgFHDA9kWSt\nXVCVe+nAKBEREfGIkgYRERHxSKjUaQDCZ02DiIiIr2lNg9Y0iIiIVIjWNIiIiIjfKWkQERERj2hN\ng4iISBjSmgataRAREakQrWkQERERv1PSICIiIh5R0iAiIiIe0UJIERGRMKSFkFoIKSIiUiFaCCki\nIiJ+p6RBREREPKKkQURERDyipEFEREQ8ot0TIiIiYUi7J7R7QkREpEK0e0JERET8TkmDiIiIeERJ\ng4iIiHhESYOIiIh4REmDiIiIeERJg4iIiHhEdRpERETCkOo0qE6DiIhIhahOg4iIiPidkgYRERHx\niJIGERER8YiSBhEREfGIkgYRERHxiJIGERER8YiSBhEREfGIkgYRERHxiJIGERER8UhIlZFOSvoP\niYl1uPPOZB54IBljAh2RiIhIcKr2ZaQ5Lwmm/FzkszPPhLfegqZNAxKaiIhIUKu+ZaSbzKfOOSOL\nNH3zDTRrBsa4X2+/DcuWBSg+ERGRMBZaSQOw84S76fpaN3Jz4Y03in9+5ZXQrp1LIBo3hgkTICvL\n/3GKiIiEm5BKGu495V4A5q6fyylvnsxVV1mshdxclxg891zR/ps2Qb9+EBPjkojTToM1ayAnx/+x\ni4iIhLqQShouPeZSlt3q5h5mr5tNxLAIcnJzMAaiouC228BayM6GL76AK64oev2MGdCihetrDAwc\nCKtWBeBBREREQlBIJQ0AbRPbsm3QtoL3UY9E8dfOv4r0iYyEs8+G8eNdArFuHXz5JVx3XdF7jR8P\nrVq5BCIxEZ59FjZv9sdTiIiIhJ6QSxoA6sXVI+uhwoUKRzxzBLPXzS6xb2SkWyjZsye8+qobidiz\nBzp1Ktpv2za4805o1MglEZddBldfDbt2+fJJREREQkdIJg0AURFR5DycQ6fG7qf/yW+cTJ3H6/DT\nhp/KvbZmTZg/3yUQ1sL27fDAA0X7fPCB28qZkOCSiIsvhl9/1XoIERGpvkI2aQCIMBHMv2E+f9z2\nBwBp+9M48bUTWbplaYXuU7cuDB/uEoj0dLce4uqri/aZOBGOP75wPYQxsHWrW4QpIiJSHYR00pCv\nTf02pD+QXvD+6BePZuqKqeTaiv9Ej4116yHeeMMlETt3wuTJbgfGwRo0cNMfxsAtt8DPP7s1FCIi\nIuEooEmDMSbOGPOnMebJqt4rNiqW9AfSGXTSIADOee8cIodF8svmX6p034QEOP982L/fJRH79sHg\nwW7h5IFeegm6dIHoaJdEvPCCWw/hxeqdIiIiARXokYYHgDneullsVCxP/PsJZlw1o6Ct/cvtMUMN\nGdkZXvmOuDh49FHYssVNTezfD2PHFu93220u4ahTp3A645tvvBKCiIhIQAQsaTDGtALaAlO9fe8e\nh/fADrHc1fWugra4R+NYm7bWq99jjJu2uP76wkWV69fDBReU3P/f/y5MIObPh+XLvRqOiIiITwVy\npOFp4H7AZ2dVjuw5kr2D9xa8P3zM4XR8pSOb9mzy1VfStCl88glkZsKSJTBvXsn9OneGtm0Lk4gf\nf3TrIbSwUkREglWFkwZjTHdjzGRjzAZjTK4xpncJfW41xqwxxqQbY+YaY7oc9Hlv4A9r7cr8psqF\nX7746Hj2P7i/4P2iTYtoPLIxCzZW6aCvckVHw9FHwwknFI5C7NoFH31Ucv9TTnHXREa6glPTpsFf\nf5XcV0REJBAqM9JQE1gE3AIUO1fbGNMPGAkMAToCi4FpxpgDlw52BS4zxqzGjThcZ4x5sBKxeCQm\nMgY7xLL01sKtmEljkzBDDZv3+K8EZO3a0LevSyD273dTGSNHFu+3ahX06gVHHFE4EvH887B6tUsm\nREREAsFYW+znvucXG5ML9LHWTj6gbS4wz1p7Z957A6wDnrXWFtslYYwZCBxjrR1Uxvd0AubPnz+f\nTgeXcqyEm6fczMvzXy54/0X/Lzi79dlVvm9VLVoEU6e63Rllee45OO44N4oRF+ef2EREJDQtWLCA\npKQkgCRrbZWG2b2aNBhjooF9QN+DEom3gARr7YUl3MPjpKFHjx4kJCQU+Sw5OZnk5OQKx/7IjEd4\n+PuHi7T9cPUPnNz85Arfyxesha++gkGD4Jdydo3ef78bmejRwz+xiYhIcEpNTSU1NbVIW1paGjNn\nzoQgTBoaAxuAbtbaeQf0ewLoYa3tVsnv8epIQz5rLU/Nfop7v7m3SPvy25bTun5rr32PtyxfDu3a\nlb9YslEj+O03qF/fP3GJiEjw8uZIQ6DrNASUMYZBJw/in7v/odkhzQra2zzfhhs/u5GqJFS+0KaN\nO/vCWpc4lLZlc9MmV3wqfz3EypXu9M7MTP/GKyIi4cXbScNWIAdoeFB7Q6DK+xxTUlLo3bt3saGX\nqmpQswHrUtbx5YAvC9rGLhhLxLAIPvq9lO0OAWYMtG5duDPDWliwoOTRhdat3ehDjRrw8MOwYwdk\neKfWlYiIBKnU1FR69+5NSkqK1+7pr4WQa3ELIZ+q5Pf4ZHqiJNm52Zzw6gks3LSwSPuqO1bRom4L\nn363N2Vnw+WXu0QhNRWyskru16QJzJ0Lhx7q+oqISHgJ6PSEMaamMaa9MaZDXlOLvPeH5b0fBVxv\njLnSGHMU8DIQD7xVlUD9JSoiigU3LuDPO//k1i63FrS3fLYlNR+ryartqwIYneeiouD992HcODct\nkZNTcrnrv/+G5s3dQV350xmjR8PevcX7iohI9VbhkQZjzKnAdIrXaBhnrb0mr88twCDctMQi4HZr\n7c+VDvKg3ROV3TFRGb/98xsdX+lIdm7h8ZXx0fHMv2E+RyUe5ZcYvG3rVli61FWrvOeesvs++yxc\ncYU7Q0NEREJH/k6KoNk94S/+nJ4ozQs/vcBtU28r0nZdx+t47pzniI2KDUhM3pKd7apPvv02DB1a\ndt/33nOVK884A+rW9U98IiJSeUFTp8FfgiFpyNf2+bYs31Z020L2Q9lERkQGKCLvshZ274b+/eGL\nL9z7skycCHv2uCSiaVP/xCgiIp7TlssA+v2W31mfsr5IW9QjUSQ+mcjSLUtLuSp0GAOHHAJTprht\nndZCerorNDVwYPH+ffu69mbN3LUvvwx//ukSDxERCS8hNdIQiDUNZbHWEjGseN41dcBUerXqFYCI\n/GPSJLdQ8sory+43YoRbD9GwoVuYKSIi/qM1DUEwPXEway3zN86ny6tdin228MaFdGjUoYSrwoe1\n8O238M038MQTZfeNi4Prr4cxY9zoRXy8f2IUEanOtKYhSK3esZqWz7Ys1p77cC6uXEX4y82Fn392\n0xkPPVR+/4QEV8EyNrTXkoqIBC2taQhSLeq2wA6xJB9bdOokYlgEHy75kL2Z4V/8ICLCnb754IMu\ngcjOdkeAlyYtzY1A5NeIeO892LjRf/GKiIjnQmqkIdjWNJQlPSudG6bcwDu/vFOk/fw25zM5eXIp\nV4W/HTtg+nR44w34/PPS+9WtCzfeCGvWwCOPuFLYIiLiOa1pCPLpiYPl2lze/+19BkwaUOyzz/t/\nzjmtzwlAVMFl82Y4/XRXbKo899wDw4dDTIzv4xIRCReanggRESaC/sf1xw6xrLx9JTcl3VTw2bnv\nnYsZarjti9uC7jRNf2rYEH7/3S2o/OUXtzPj0UdL7vvUU+58DGOgVi13CNeaNYXXioiIbylp8JOW\n9Vry0nkvYYdYhp8+vKD9hf+9QMSwCAZ/OziA0QWH446DCy+EwYPdsd/p6e6grdWri5/euXevG6Vo\n0cKto2jfHs480y3CFBER31DSEAAP9HiAB7o/UKRtxA8jMEMNvd7pxZa9WwIUWfBo3drtqIiKgiOP\ndOdl5Oa6JGLQoJKv+fZb6NLFjUQ0bQrffQeHHw6LF/s3dhGRcBVSaxpCaSGkJ3bv383QGUMZOWdk\nsc++H/g9PQ7vUW22alaGte68jFWrYNiwsvueeCIcdhiMH+92a4iIhDsthAyxhZCe2rZvGx/+/iE3\nf35zsc+23rOV+vH1S7hKDrZsGdxxB3z9dfl9b7zRTYdcdRXUrOnz0EREAkbFncLY8m3Laft822Lt\nn/f/nLNbna2RBw/t3OnWRYwYAZ98UnbfAQPgX/9yyUOvXq7g1K5d7rNDDvF9rCIivqSkIcxt27eN\nC96/gB/X/Vjss48u+YhVO1Zxz0n3KIGooK1b4X//g3MqsNN19Wq3pkJEJFRpy2WYqx9fnx+u+YGf\nr/+Zx894nJjIwsIEF394Mfd+cy+j5owKYIShKTERzj7brYXYvh1OO63ws9LKWLdo4RZW9u8P//wD\n+/fDb7/5JVwRkaCjkYYQsTZtLYePObxY+5xr53BU4lHUia0TgKjCy6ZN0LixZ33vvNMdC96uHdSp\no1M8RSR4VdvpiXDbPVFRv2z+has/vZoFG4v/nr907ktccvQlWjTpBXv2uO2ds2fD1Knw7ruwbVvZ\n16SmwqWXQkaGTu8UkeCg3RPVeKThQDm5OXR/sztz1s8p9lnfdn0Zf+F44qP1k8ubFi1yUxubNnnW\n//zzYfJkWLLETYV07+7b+ERESqM1DdVcZEQks6+dTe7DucVO1Jy4dCI1H6vJp8s+DVB04alDB3f6\nprWFv26/vfT+n33m1kIceyz06OFGK0IgPxcRKZOShhBmjOG9vu9hh1imD5xe5LM+H/TBDDWYoYb/\nbfhfgCIMb88+W5hA7NtXdgnryy935a6NceWu337bf3GKiHiLkoYwcdoRp2GHWJbftrzYZye8dgJ3\nf3U37/36Hpk5mQGILvzFxUFSUmESkZNTet9vv4Urr3QJRP6vN990p3fm14cQEQlGShrCTOv6rcl4\nIKPYyMPIOSMZMGkANYbXYNu+beTa3ABFWD1ERLjEITfXJRFzii8/KeKaa9y5GgkJhYnE7Nn+iVVE\nxFNKGsJQjaganHbEaey6bxdb79la7PPEpxKJHBbJxt0bq/Wx3L6WPx0B0LVr4ShEejo8/TRcfXXZ\n1598srt+4EC3RuKFF8AtgBYRCQztnqgGrLUs2bKE4146rsTP68TWYfug7aowGSB797ppiSVLICWl\n/OJR//d/0LGj26GhMtciUh7VaaimdRq84dfNv3L8y8eX+vn0gdM57YjT/BeQlGjgQHciZ0V89x2c\nfrpv4hGR0KM6DRpp8JpNezbReGTJ5Q/PbnU2w04fRucmnf0clRzsscfcls033nCLJT2VkwNbtsCh\nhxZOkYhI9aQ6DVJljWo1YtugbbSt35YIU/SPwdSVU+nyapcSK0+Kfw0eDKec4pKGpUvdwsp33oHW\nrcu+LjISGjVy6yoeegimT4c1a/wTs4iEL400SIEnfniC+769r8TPko9NZtjpw2hUqxG1Ymr5OTIp\nSXa2O/47MdEduJWQ4Nl1S5dCy5YusYjQPxtEwp5GGsQn7j3lXrYP2s7FR19c7LPU31Jp/VxrWj3b\nSjsugkRUFBx9tJuCOOQQl0TMnu3WNlxwQenXtWvnakJERrodGtdd5xZffvSRqlaKSNk00iAl2rxn\nM9//+T2XTbysxM8zH8wkOjLaz1FJRVjrEomoKLdD4//+D8aOLf+6t9+Gzp3dFEhkpO/jFBHf0kiD\n+FzDWg3pd2w/9g3eR/OE5sU+jxkew3WTr+OPrX8EIDrxhDEQHe3+W6sWvPIK3HyzG1lo27b06664\nwo1GREW55GH8eJg4Ea66Cj7VkSYi1ZpGGsQj2/Zt44hnjmBP5p4SP78p6SaeOfsZYiJj/ByZVNaG\nDe5ArfR02L/f8+vefRdatHAJRUSE1kWIBDuNNIjf1Y+vz+77d2OHWLYN2lbs85fnv0yN4TV4Y+Eb\nrN6xOgARSkU1bQo7dkBGRmG1ykWL3DkaZU1jDBgA3bq5UYzISDeSsWWL/+IWkcBR0iAVVi+uHukP\npHNdx+s4pfkpRT67dvK1tHy2Ja2fa82U5VPYtGdTgKKUymjf3p3Yef31sHu3K3f93XflX5dfDyL/\n1yuvuBEMEQkvmp4Qr1i1fRWtnmtV4mdr/7OWBjUbEBsV6+eoxFv++gt+/x3GjYMvv4S0tIpdn5EB\nNWr4JjYRKZvKSKuMdFCasGQCc9bNYcy8MSV+/sI5L3BLl1v8HJX4yvbt8Npr0KSJWzzpiddfdyd6\nbt0K9eu7UYn9+92iS+3UEPEulZHWSENI2Je1j4s+uIhpq6aV/PngfYA7jfPgapQSupKSYIEHfx2d\ncAL89JN7fdFFMGkSnHeemwpp2xY2b3YFq5REiHiHFkJKUIuPjufLy79k+W3LS/78sXjiH4un1zu9\n6PByB9bsUH3jcPDFFy4B2LMHhgxxbSVNY+QnDOD6A0yZAkcd5UYeGjWCG25wCUhuru/jFhHPaaRB\nfO71Ba9jjOHaydeW2ue5s5/j6g5XUzOmph8jE3/IzoZHH4VVq1zhqIo6/XQ3/ZGc7Mpli0jFVNs1\nDUoaQtuO9B3Ue7JemX0mXzaZc1qfw8Y9G2l2SDM/RSb+kpvrkojoaHcQ1+zZ0L07zJrl2fVZWW79\nw86d7qwNY1y1y6goLbQUKY2mJyQk1Y2rS9p9acy4agZNazctsU/v93sT9UgUh40+jJl/zfRzhOJr\nERHu3Atj3LZOgGnTXL2IU0+Fvn3Lvj6/wmXduu5eTz7pql3GxlasQJWIVI5GGiRgNu3ZxJJ/lnDm\n22eW2mfa5dM4q+VZfoxK/MlalwQcaONGN3KwejV07Vqx+734oitadc45MGaMWydx3nnei1ckFHlz\npCHKOyGJVFyjWo1oVKsRdoglMyeTGsOLjy/3fKcnkSaSG5JuYEyvMRiMDsoKIwcnDACNG7v/JibC\nsGHurIxGjTwrV31LCTt6ly9320Nbt4Z6Zc+OiUg5ND0hQSEmMob0B9LZee9OWtUrWiQqx+bw0s8v\nUWN4DWKGx2CGGpWqrgaMgYcecklEfj2H/JLXf/wBtWt7dp82bdyIRf368N//urbFi2HlSle1cutW\nnz2CSNhR0iBBIzYqloTYBH69+VfqxtYts2/LZ1syfvF4Vm5f6afoJNBiYgoXO7ZpA7t2uQRi5043\nFfHBB+XfY+hQl4B06OBGHuLjoUEDeOkl38YuEi60pkGClrWWXJvLwk0L6fJqlzL7nnTYSfx4zY9+\nikyC1d69LjG49VaYN8+Vvx40yLNrW7SA995ziyynToU77ih5+kQk1IT8lktjTALwDRCJW1fxrLX2\ntTL6K2mo5vZk7mH1jtW0f7l9qX3evvBtujbrWmx6Q6q3lSvd7owTTqjc9cOHwwMPeDcmEX8Kh6TB\nADWstRnGmDhgCe5hdpTSX0mDAJCZk8l3a77jls9vYc3O0itJRkVEkfVQlh8jk2B3/fVuy+bgwfDq\nq+7grQOrU3rqm2/cqZ5Nm0LNmrBtmzt/QyRYhXydButk5L2Ny/uvBgKlXDGRMfRq1YvVd65m8U2L\nAbjnpHuK9cvOzcYMNTz+w+PsydxDZk4m89bP83e4EkRefdVtyWzWzE1hzJ4Nmza5Q7cq4swz4fjj\n3cLK2FiXPIwY4ZuYRYJNwNY05E1RzABaAfdYa0tdiqSRBinPi/97kVu/uLXUzxNqJJC2P419g/cR\nFx1Xaj8RgCeegCVLKl72uls3mDPHVa788ks44wyI0x83CbCAjjQYY7obYyYbYzYYY3KNMb1L6HOr\nMWaNMSbdGDPXGFNsFZu1Ns1a2wE4EhhgjGlQuUcQgVu63MLimxbT56g+JX6ett+dnBT/WDwpX6aw\nYtsKf4YnIebee2H8eJg7F378EU4+2bPr5sxx/42OhvPPh7vvhn/+gQ0bICfHHeC1dq3v4hbxtcpM\nT9QEFgG3AMWGKYwx/YCRwBCgI7AYmGaMSSzpZtbaLXl9ulciFpECxzc8nkmXTirSdlfXu4r1GzNv\nDG2eb4MZarjkw0v8FZ6EoBNPhJNOgh9+cGdmfPCBSyAWL4Y+JeenRbz4IjRs6KZEoqKgTh04/HAl\nDhK6qjQ9YYzJBfpYaycf0DYXmGetvTPvvQHW4XZIPJnXdiiwz1q7J2+a4gfgMmvtklK+R9MT4rHJ\nf0ymXWI7tqdv58RmJ2KGlr1cJjE+kc13b+azPz6jzwd9SLsvjUNqHOKnaCWU/fwzdCl7N3CZWreG\na66BpUvd1MaNN2qbp3hf0JaRNsZEA0nAY/lt1lprjPkG6HZA18OBsS6fwADPlJYwHCglJYWEhIQi\nbcnJySQnJ3shegkXvdsWnTFLPjaZvVl7OeWwUxj0TfFN+1v3bSVyWCTtEtsBMHf9XJ13IR7p3Bn+\n/hu+/Rb+9S/4+mu46iq3lqFhQ1f3oSwrVsD997vX48e7hOHGG30etoSx1NRUUlNTi7SlpaV57f5e\nHWkwxjQGNgDdrLXzDuj3BNDDWtut5DuV+z0aaRCv2LxnM41GNiq338IbF9KhUQc/RCTh5p9/XIGo\n6GiYPx9++80lEhXVoAEsWODWQjRt6qY6br7Z3VekIoJ2pEEk2DWs1ZCch3N4bt5zfLT0I35Y+0OJ\n/Tq+0hGAE5qewE8bfmL6wOmcdsRpfoxUQtWhhxa+TkpyvwYMgD174Omn3fqGm28u/z5btsBhhxVt\ny8iA9u2hZ0/vxiziKW+PNEQD+4C+B61zeAtIsNZeWMnv6QTM79GjBwkJCZqSEK/akb6Dek+Wf/zh\n0/9+msPrHE7nJp05os4Rvg9MwlZamisMNXasK3ldGddcA2+8AS+8AD16wLHHurM4Zs5077U2QvKn\nKtLS0pg5cyYEuiJkBRZCrsUthHyqkt+j6QnxuYzsDG774jZeX/h6uX3tkOA/s0VCS24ufPaZZ7sy\nyvP00+6E0B9+AP2VKYGu01DTGNPeGJM/4dsi733+QNoo4HpjzJXGmKOAl4F44K2qBCria7FRsbzW\n+zW23rOVh3o8VGZfM9Rghhr2Z+/3U3QS7iIi4IIL3JqInTvdds/Kuvtud+x3UpJLRB55BDZv9l6s\nUn1VeKTBGHMqMJ3iNRrGWWuvyetzCzAIaIir6XC7tfbnSgep6QkJgHnr5zF0xlCmrpxaZr/89Q6b\n9myiRmQN6saVfay3iCesdad2rl4Ny5dDZCR07+4WSFbFpElw2mlusaaEt6CbnvAXTU9IIM1eN5uT\n3/CwJCCozoP41NatsG6dO7q7e3e4+mq44gp3FHhF9OwJN93kilfFxUHt2r6JVwIv5A+sEgklJx12\nEm9f+Daf9PuEudfOLbd/wuMJpGelM2DSAH5c+6MfIpTqJDEROnaEWbPgscdcgai5c2HIkIrdZ9o0\nuPBCV0/ikEPcSIYxrn3DBvj4Y9/EL6FNIw0iFfT6gte59JhLOeRxz0YT3rnwHfof159cm0tkRKSP\no5Pqav9+ePNNGDfOJRHeMHq0qzOxdKk7g0NCkzdHGkIqadCaBgkm+SdrpnRNYfTc0R5do10X4m9v\nvAHHHQfHHAPTp7upDU/qRBxs0SJXIwLgl1/c8eC//ebuvXEjNCq/Zpr4mdY0aKRBgoi1ll37d1G7\nRm2+XvU1vd7tVe41Jx12Eue3OZ8+R/WheUJz4qPj/RCpSFEvvlj5+hAHOvVUmDEDpkyBs892izcj\nNZgWdKrtSIOSBglmE3+fSLNDmtH19a4e9W9auynrUtaRnZtNZk4mNWNq+jhCkUITJsAXX7jtmYsX\nu3UM995buXvFxbktnuASBwkuShpEQkD+6Zqzrp5F9zfLP/l98CmDGT13NLvu30VUhCq8i//t2QM7\ndriphpiYqt/vP/9xJbTr13cLLuM1sBYQ1TZp0JoGCSX5SYMdYsnIziDu0TiPrnv53Je5IekGjOoA\nSwDl5LiCU+vWwTvvuKJTzzxT+fs1aQLnnut2ecTGunM0mjb1XrxSnNY0aKRBQkjqr6nMXjeb5855\nDoARs0YWPV38AAAgAElEQVQw+LvBHl+/d/Be4qPjyczJxFpLjagavgpVxCNZWW4Eok8fuOQSN4pQ\nVe3awe+/V/0+UrpqO9KgpEFCXYeXO7B48+IibfecdA9PzS75WJY6sXXIzs0mLiqOf+75xx8hinhs\n3jzomreEZ80aOPLIyt2nbVtXF2LuXDjjDLc+om1bl6SsWAFHHeVGPaRyVNxJJER9dOlHBa/fufAd\n7BDLk/9+stT+OzN2sidzD1v2bWH4zOG88vMrfL78czKyM5i6ouzy1iK+duKJ7myL7Gw44gj4738L\nP7vpJs/v88cfcPTR7uTOww93SYIxblTjmGOgc+fCvkuWFC66FP/TSIOIn3296mv25+znvDbnFbT1\neLMHs9bOqvC9Vt+xmiPrVvKfdyJelpPjfqgb4+o3LF3qkoG6dd0Cy6r44gt4+WWYPBkuvRQ++MC1\n5+a679MSoNJV2+kJLYSUcJVrc7HWEvVI5XZNfNH/C85ufbaXoxLxni1bXEJx+unu/U03uSSgKnJz\n3dHfGzfC2LFw3nmaxjiQFkJqpEGqgQ9++4DMnEyu/OTKCl3XvXl3pg+crlLVEjI2b65aJcnISDe6\nkW/sWLj++qrHFW60pkEkjPU7th9XtL+Ctf9Zy1//+Yttg7Z5dN2stbO4ccqNfLrsU8BNg5ihhqaj\ntK9NgtOBdRteftnVcjjQUUeVff2BCQPADTcUTlVcfjns3OmdOKWQkgaRIHVYwmE0T2hOvbh6bB+0\nndS+qQB8eMmH/H5LyXvUXl/4On0+6IMZajjrnbMA+Hv336RnpZOTm1PiNSKBUrs2rF/vphluvNFN\nM/z1V+FWznPPrfy9333XraXITyLyf912W+lVK9esgYsucrs2pGRKGkRCQN24ulx27GXYIZaLj76Y\ndg3aVej6+Mfi6T+pv4+iE6m8pk0LFzEaA82bw1tvuVGCg3+4jxtX9e974QW37sEYl6jkJxPbtsGw\nYW7r5+LFrpiVFKekQSRETbp0EmN6juGTfp941H/Ckgl0fa0rmTmZRdr/2vmXL8ITqbSoKEhIgLPc\nYBnr17t//V95pUsk5s3zzveMHVv4OjHRJSsAZ55ZfKpEnJBaCKndEyIlyy9Z7anGtRqzcc9GXjr3\nJW7+/GY+vexTerft7aPoRLzvjz/g7bfd6MO6dfDmm67Ow6xZ8NVX8MgjVf+O8eNh5UpXf+Knn1xd\nilCi3RPaPSFSov98+R8mLJnAGxe8wdnvVnzr5ZieY7iz653sydzDpKWTqBtbl/Pbnu+DSEW8x9rC\nqQ1rYc4cOOkk9/7BB+HRR2HMGHdwVlWMGwcDB7rXd9zhkpRJk9z7f/5xp3xu2eIqYgZjvYhqW6dB\nSYNI+SYsmcDhCYd7fER3aeyQ4P+7QaQ0ixdDhw7uB/zw4fDKK969/wcfwMKF8PjjhW1vvgnJyVAj\nyI6J0ZZLESnVpcdcyonNTqRRrUYF7ysj5pEYXvzfi94MTcRv2rd3ow/NmrlzLACmT4err3av77ij\navfv169owgDu3rGxsGCB24kRjjTSIBKmcm0uABEmAmstOzJ28Pfuv/l61deM+GEEW/Zt8eg+g04a\nxIgzRxBhItifvZ+dGTtpWEurxCR05Oa6kYeOHd25FT/9BD16QGqqK0kdHV3Yd/16l2h4Q7D8eNX0\nhIh4xWsLXuP6zypeQu/K9lcyro8X9r+JBIH774fZs+Hbb93OjU8/dcd/V9Ull8CECVW/T1VpekJE\nvOK6Ttcx99q5zLtuHqcefqrH141fPJ7HZj3Gtn2uWmV6Vjpr09b6KkwRnxoxAmbMcAkDwAUXwJQp\nbhRi0SK3dgFcMaqK+PBD78YZDDTSICIAZOVkETM8psLX9TmqD/uz9zN15VT6tutb5PhvkXCRnu6S\niiuuKDxh0xPB8CO22o40pKSk0Lt3b1JTUwMdikjYiY4snNjt3rw7kcazg68+WfYJU1dOBWDi0ons\n3r/bJ/GJBFJcnFv78P777n3HjrB8ednXBPrwrNTUVHr37k1KSorX7qmRBhEpYIYaerftzaeXfcqu\n/btIeDyB4w49jl//+bVC96kZXZM1d66hQc0G/LP3H37++2fOaX2Oj6IW8a/1613Fytq13UhCbq47\ncfPAGg0vveSO/w4G3hxpiPJOSCISDrbcs4XaMW7i9pAahxTUaug7oS+Tlk4iKiKK7Nzscu+zN2sv\nhz59KBcffTEf/e6mK5bduoz46HgOSzjMdw8g4gcH7q4wxiUMADNnwt690KtXYOLyB400iIhHsnOz\niYqI4suVX1aq6mQ+FY0S8a9qu6ZBRAInKsINTPZqVbV/Ro1fPJ6pK6Z6IyQR8TMlDSJSYctvW873\nA78HYMktSyp07cBPBnLOe+cQMTSCU986lZzcHB9EKCK+oKRBRCqsdf3WnHrEqdghlqMbHM38G+Zz\nxfFXVOgeFsvMv2YyfvF41qatZfa62bw6/1XqPlHXR1GLSFVpIaSIVFmnxp0weUvH5147l9PHnU56\ndrpH114z+Zpibfuy9hEfHV/wPtfm8v5v73PZsZcRYfRvHZFA0f99IuIVWTlZACTGJ5J2X1qV7lXz\nsZqYoYY3F77J+l3r+ej3jxgwaUDBTgwRCQyNNIiIV9x2wm18vuJzmh7SlOjIaHbdt4u+E/ry9eqv\nK33Pg0ch/tn7T1XDFJEq0EiDiHjFSYedRNp9acRGxQJQu0ZtvrriK3bfv5uOjToy+bLJVf6OfVn7\n+HDJhwVnXuR7e/HbzP97fpXvLyJlC6k6DT169CAhIYHk5GSSk5MDHZaIVMDG3RtpMqoJI84YwVer\nvmL6n9OrdL/Xe7/O4k2LGdNrDBHD3L9/VANCpFBqaiqpqamkpaUxc+ZM0NHYIhKKrLXc98193Nn1\nTprUbkKN4TXIzMms1L3Oa3MeU5ZPcfcdYrl4wsXk2lwm9ZvkzZBFQpbKSItISDPG8MS/nyh4v+u+\nXezP2c8D3z7A8/97vkL3yk8YAGavm83EpRMByMnNISM7g5oxNb0TtIgoaRCRwKsRVYMaUTV47pzn\n+HfLfxMVEUVURBQ93+lZofuc/MbJBa8bjWzE1n1bi0xZrEtbx2njTmPedfNIjE/0Wvwi1YWSBhEJ\nKr3b9i543bVZV+aun1up+2zdtxVw2zfPbnU2V3e4mg9//5DVO1bz7epv6XdsP6/EK1KdKGkQkaA1\n59o5rNi2gjbPt6n0PfZl7WPi0okF0xYAu/bvYtu+bdSPr++NMEWqDW25FJGglhCbALiqkwAP93i4\nyve8YcoNJD6ViBlqGDBpAB8u+VA1IEQ8oJEGEQlqDeIbMPiUwdzS5RaaHtKUzJxMdmfuZuhpQznk\n8UOqfP/3fn2P9359j+7NuzOm1xiWb1vOZcde5oXIRcKPRhpEJKgZY3j0jEdpekhTAGIiYxjVcxS1\na9T26ves3rGapLFJJE9MJisni7um3UVahiuHvS9rHyu2rfDq94mEIiUNIiLAht0bCl6/vvB1Rs8d\nzei5owG47KPLqrSuQiRcKGkQkZD1x21/MOqsUQBcfvzlXrvvzZ/fDLgqlg9Pf5jPln/mtXuLhLKA\nrGkwxjQD3gYOBbKA4dZaHV8nIhXSpn4b2nRrQ0q3FAD2ZO6hZ8ueDJ0xlLqxdVm6dWmV7j92wdhi\nbcu3LSctI41Za2dxU+ebihzhLRLuAlJG2hjTCDjUWvuLMaYhMB9oba1NL6W/ykiLSIU9/9PzRJgI\ndqTv4MHpD1b5futT1tNsdLMibdsHbefXf36lbf229HynJ99c+Y0KR0lQCfky0tbaTcCmvNebjTFb\ngXrAhjIvFBGpgNtOuK3gtTeShoMTBoB6T9YD4IVzXmDx5sV8vvxzBnYYWOXvEglGAV/TYIxJAiKs\ntUoYRMRnPu73sU/vf+sXtwIwa+0sn36PSCBVOGkwxnQ3xkw2xmwwxuQaY3qX0OdWY8waY0y6MWau\nMaZLKfeqB4wDrq946CIinutzVB+GnDoEgCvbXwnA33f9zZieY7z6Pa8vfL3g9RcrvqDfRypXLeGj\nMiMNNYFFwC1AsQURxph+wEhgCNARWAxMM8YkHtQvBvgYeMxaO68ScYiIVMh/T/svdojlmV7P8OI5\nL9K4dmPu7HonnZt09sn3nfveuUxYMoHS1o7ty9rH8z89X+rnIsGmwkmDtfZLa+3D1tpPAVNClxTg\nFWvteGvtMuAmYB9wzUH9xgHfWmvfq2gMIiJVUSe2Djd3ubng/YyrZrDs1mXsHbyXu7vdXeX7j1s0\njll/FU5TLNy0sMjnf+78E2stw2cO5/apt7NgY5XWpon4jVcXQhpjooEk4LH8NmutNcZ8A3Q7oN/J\nwCXAL8aYC3EjFldYa5eUdf+UlBQSEhKKtCUnJ5OcnOy9hxCRaic+Op62iW0BeOqsp2hZr2VBrYYh\npw5h6IyhFbrfVZ9eVeR90tgkVt6+kt2Zu9mRvoN/jf8Xb13wFrv27wJg5faVrNm5hq9WfcVzZz9H\njagaVX8oqZZSU1NJTU0t0paWlua1+1dpy6UxJhfoY62dnPe+MW4HRLcDpxyMMU8APay13Uq+U7nf\noy2XIuI31lrSs9OZ+ddMerbsiTEGM7SkgdXKO7/N+STGJ/LmojeLtE+6dBIXtrvQq98l1VvIb7kU\nEQlmxhjio+Pp1aqXz76jtCqTF024iC33bKlQrYfs3GyiIvTXufiet7dcbgVygIYHtTckry5DVaSk\npNC7d+9iQy8iIuFk9JzRXPXJVWX2sdayPX07K7evJPqRaL5b851/gpOQkZqaSu/evUlJSfHaPb2a\nNFhrs3DVHc/IbzPGmLz3s6t6/9GjRzN58mStYRCRgFlx+wo2/t9Gn37HYz88xrjF44q1r0tbV/B6\n1JxR1H+yPos2LQIosvBSBNyav8mTJzN69Giv3bPC41nGmJpAKwp3TrQwxrQHtltr1wGjgLeMMfOB\nn3C7KeKBt7wSsYhIAKy6YxXz1s+jVb1WAMy9di6REZG0qNuC+k/WB2Dtf9bSfExzr31nVk4W0ZHR\n7MzYyYw/Z9Dngz4A2CGW6X9OB2B/9n4Acm2u175XpDSVmQTrDEzH7XiwuJoM4LZQXmOtnZBXk2EY\nblpiEdDTWrulqsHm757QjgkR8bcWdVvQom6LgvcnNjuxWJ/DEg7jmyu+4cy3z/TKd8YMj2Ha5dPo\n+U7PIu3WWj5f8Tng1l9A+UnD5j2baT6mOb/d/But67f2SnwS3PJ3Unhz90Rl6jTMsNZGWGsjD/p1\nzQF9XrTWHmGtjbPWdrPW/uyNYDU9ISLBLn9BYucmnb2ykPLghAFgxfYVxdpybS7d3+xOncfr8MQP\nTxT7fM76OWTmZPLxMt+W05bg4YvpiYCfPSEiEup+vv5n5l47F4DoyGgAujfvztQBU33yfW2fb1vw\nOn+EYfqf0/lh7Q+k7U/jvm/vo/PYolUuDZ6NSIiURUmDiEgVJTVJKpiuaFvf/UDv265vsX7ZD2V7\n/btzcnMAN5JwoPkb5wPw9OynWZu2tmAaY+ZfMzFDDRt3+3Yxp4SnkEoatOVSRIJd/fj62CGWk5uf\nDMDFR19c8FlkRKTXv+/g6pMHyrW53PP1PSRPTCbCuL/up650ox8lTXFIePHFlssqVYT0F1WEFJFQ\nlWtziRzmkgU7xBZUlryy/ZXUja3LM/OeCUhcT5z5BNZa7j3l3oB8v/iPKkKKiISICBPB33f9jc07\nFPi8NucxZfkUxvUZR+qvbtQ0NiqWjOwMv8Z17zcuWagTW4dlW5dxVYeraJ7QnLpxdf0ah4QWJQ0i\nIj7WuHbjgtcf9/uYrJwswP3ABhjdczQZ2RmkTPPeMLKnbvr8JgDGzBvDCU1PYN5184r1ycnNIeqR\nKD5L/ozz2pzn7xAliGhNg4iIH0VFRBEXHQdAr1a9mHTpJG5IuoH/dP0PM66awYlNC+s/DD5lMADH\nHXqcX2JbvGkxWTlZTPx9Ir9v+b2gPX8UJFBTKVI5WtOgNQ0iEuYun3Q57/76LituX0Greq1YtnUZ\nDWs2pN6T9fweix3ifj7s3r+bQx4/hDNbnMnXV3xdvJ+17MvaR82Ymv4OUTzgzTUNITXSICIS7rJy\n3dRFTGQMAEclHhWwdQYjZo0AIMe6bZ2Gko8Hf+F/L1BrRC32Zu71W2wSGEoaRESCSJcmXQBIqJFQ\npH37oO3svn8382+YX+J1/27xb6/HMvi7wWTlZJGd6+pL5Nd6yPft6m/57I/P+Gb1NwDsztzt9Rgk\nuChpEBEJInd1u4v1KetJiC2aNNSNq0utmFp0alzyFG37hu19Ek9mTmZB0nCwM98+k97v9y6oP/HU\nj08RClPeUnkhlTRoIaSIhLsIE0HTQ5qW2eeTfp8AcPsJtxe03dn1Tro16+b1eDJzMmk8snGRtsdm\nPVZQbwJg0tJJAIyaO4qIYRGYoYa7pt3l9VikYrQQUgshRUSKyP/hbYfYIoWkfKFny558efmXRRKG\nsuQvpJTA0kJIEREB4KTDTuLoBkcDFJSKzte5SeeSLqm0aaum8fFSz0/JvHzS5azftR5w2zYzsjNK\nnerIl5Obw/7s/VWKU3xHSYOISAj78ZofWXLLkmLtF7W7iIHtBxa8z3jAOxUnL5pwkcd93/31XYZ+\nPxSAuEfjiHs0jm6vlz2FcvGHFxP7aGyRtu3p23n/t/crHqx4nZIGEZEwZK3l1i63svqO1az9z1pq\nRNVg+6DtPln3UJbXFr5WMNoA8PPfP7Nt3zb2ZO4pEutfO/8C4JNlbr3Gmh1rqPVYLTbt2cS1k68l\neWJyuaMU4ntKGkREwtC/W/wbYwxH1j2SwxIOA9wOjNnXzuan636iXpwrFnXsocf6PJbDRh9W5H3i\nU4nUHlG7YKfFu7++yxHPHMHybcsL+nyy7BP2Zu1lxp8z2LZvG+AO/5LACqmkQbsnREQ8c1Pnm0r9\nrEvTLmy+ezMZD2TQul5rP0ZV1A9rfwBg4caFAIycPbLgs8ycTAD2Ze1jb5YrGlVe0rBh1wbiHo0r\nGLWo7rR7QrsnRETK9MvmX8jOzS61nsPBxs4fy41TbiSpcRLzN5ZcOMpXXjjnBc5vcz7np57P4s2L\ny+2/5/49BaWqJ/4+kXNan0NcdBw7M3byw9of2J6+nYGfDOSlc18qM2mqbnQ0toiIlOj4hsdXqP8N\nSTdw6uGnEmEiaPN8Gx9FVbJbv7iVu7+6m/TsdI/6T/5jMhv3bOSidhdx8YcXc3e3u3nqrKeo+4Qr\nsz2uzzhA0xi+pKRBRKSaa5vYlo27Nwbkuz1NGAD6T+oPwMfL3LbP7enbi3y+dMtSgIK1EsNmDGPM\n3DFsv7doP0/k2ly2p28nMT6xwteGs5Ba0yAiIr7RuHZjPu7neQ2GQMpfC7Fz/04WbCwcbf/+r+8B\nsLikYcj3Q9iRsaPY9Su2reDPnX+W+R2PznyUBk81ICsnyztBhwklDSIiAkCfo/rw7kXvArDhrg0F\n5aqh9BMuA2nS0kkkjU0q1l7eWr02z7fhyGeOLLPP9D+nA2ib50GUNIiISIH+x/XHDrE0qd2EC466\noKA9d0guI88ayQPdHyhoe++i9+jevDvXd7qeCRdPCES4ReQnNgevaUj5MqXSB2kdfLJndac1DSIi\n4pG7urlDqB6d9SgAnRp3YubVMws7fBSIqArNWT8HKJyeyDdm3hge7PEg9ePre3yvg+8hTkiNNKhO\ng4hI4OX/iz4qIjj/3ZkyrXhdgvwRgyX/FC+5XZL8kYlQKEtQGl/UaQjO3/FSjB49WnUaRET8aOXt\nK9mWvq1IW79j+/H+b+8TGeG7EzWr6qIPip6RkZ/ofLDkA4+uD4eRhuTkZJKTkw+s01BlITXSICIi\n/tWyXktOaHpCkbb8xYEHjzT8dvNvNIhvUO49z29zvvcCLEX+tsx89Z6sR9NRTXlk5iMFbcu2LsMM\nNazYtgKA/hP70+kV9w/TgpGGMEgevElJg4iIVEiz2s0AiIuKK9J+zKHHcNoRpwGw4vYVrLlzDStu\nX1Hs+ggTQc+WPX0e58H+3v13kfff//k9AD+u+xGA1N9SWbhpYZE+oTw94QtKGkREpEJGnDmC7678\nrsSFha/3fp1ZV8+iVb1WHFHnCFrVa1Xw2bTLpwHQqFYjPrzkQ7/FW1F7M/cWjDBopKEoJQ0iIlIh\nsVGxnH7k6SV+VrtGbU5pfkqJn53V8iw+vexTRvUcRe0atX0Zokdu/vxmAK7+9Gq+XPllQfs9X99T\nUEAqf6Rh9Y7VdHqlE3sz9/o/0CCipEFERPymd9vexEfHBzqMYnqn9i54/dLPLxW8nrt+LjP+nEHL\nZ1uycNNCFm5ayN7Mvdz91d0FJ3FWJyG1e0JERELPxEsnsj97f6DDKFNWbsnlos9656wi7yNNJK8u\neJWRc0bSuUlnrLVcduxl1aYIlJIGERHxqYvaXVTm5wk1Ekjbn1ak7cakG3ll/iu+DKtSjDGsS1sH\nwPCZw1myZQlx0XH0OaoPWTlZbE/fTsNaDQMcpe9oekJERALq5OYnA/DI6Y/w2vmvAXBz55uL9Wtd\nr7Vf4yrJR79/xKi5owBYssUVirrwgwsBuGnKTTQa2ShgsfmDkgYREQmY+nH1SenqKhY2iG/ANR2v\nYdd9u2jfqH2xvkfWLfuQKX9YtWNVie0LNi7gjUVvAJR4iFa4CKnpiZSUFBISEgqqXImISOj67srv\naJvYlsa1GpPaN5VLjr4EY0zBzoroiOiCtQat67Xm3YveZdScUYz4YUTAYv529bcltr+16K2C1wce\n1x1IqamppKamkpaWVn5nD4VU0qAy0iIi4ePAbZuXHXtZmX3PbX0uifGJJMYn+jqsMu3O3F1i+8En\na1prA744UmWkRUSk2jiw3sNRiUcBwVuh8YX/vVDkfbgWhQqpkQYREak+JidPZvOezezN2stxhx5X\nYp83L3iTuKg4LpvoRioa1WrEpj2b/BlmiVZsW0HbxLaBDsPrlDSIiEhQqhVTi1r1ahVpO/hf8Fd1\nuIqM7IyC90mNk/h8xed+ia8sx710HJkPhV/xJ01PiIhISIuNii14HRMZE8BICpVWLCrUKWkQEZGQ\n88jpj/Dz9T8Xaz+05qEFr78cUHiexPt93/dLXAdam7bW79/pa0oaREQkZBzT4BjA7aZIalJ8R0DH\nRh0LPu/ZqvD47X7H9ivSr/9x/X0YpXP4mMN9/h3+pqRBRERCxtmtz2bDXRvo2LhjiZ9fcswlQPm7\nF4JlGiPUKGkQEZGQ0qR2k2Jt+XUeDEVrI1xy9CUl3qNebL2C1zd0usGL0YU3JQ0iIhLyUvumYocU\nFlTKr+cw4ZIJ2CHutR1imTpgKgC1a9TGDrHYIZaXznup5JtKMQFLGowxk4wx240xEwIVg4iIhJf4\n6HgALj764hI/b1vf1U7415H/KmiLMPr3s6cCWadhDPA6MDCAMYiISBiJiYwpGFkoyZF1jyzzcylb\nwNIra+1MYE+gvl9EREQqRmMyIiIiHtp89+aC1/lTIdVJhZMGY0x3Y8xkY8wGY0yuMaZ3CX1uNcas\nMcakG2PmGmO6eCdcERER36sfV7/E9gOLRwXr4Vm+VJmRhprAIuAWKL4R1hjTDxgJDAE6AouBacaY\nwJ5nKiIiUo6PLvmIUWeNYtUdq4CiJaqlEkmDtfZLa+3D1tpPgZIOC08BXrHWjrfWLgNuAvYB15TQ\n15RyDxEREb/re3RfUrqlkBCbABQdWTiYxXJem/MK3pe2YyOceHX3hDEmGkgCHstvs9ZaY8w3QLeD\n+n4NHA/UNMasBS6x1s4r6/4pKSkkJCQUaUtOTiY5OdlLTyAiItXViU1PLNZ2ydGXMHLOyCJtkSaS\nHJvDgOMG0KZ+G6YsnwLAWS3O4qPfP/JLrKVJTU0lNTW1SFtaWprX7m+qMidjjMkF+lhrJ+e9bwxs\nALodmAAYY54Aelhru5V8p3K/pxMwf/78+XTq1KnS8YqIiJQkMyeTCBNBVEThv6UzsjOIiYwhclhk\nQZsdYsnMySQrJ4u46DhWbV9Fm+fbMOC4Abx94dtkZGdw9ItH8+fOPwv6B9qCBQtISkoCSLLWLqjK\nvQJZp0FERCQolHQWRWnrGWIiY4r1jzARGGOIi44rKGV9cEnrcODtLZdbgRyg4UHtDYFNVb15SkoK\nvXv3Ljb0IiIi4iuXH385UHLlyPxzMK44/oqCtvtOuQ+goKR1oKSmptK7d29SUlK8dk+vTk/ktc0F\n5llr78x7b4C1wLPW2qcq+T2anhARkYAxQw2RJpLsh7M97h8VEUXWQ1k+jqx8AZ2eMMbUBFpRuOuh\nhTGmPbDdWrsOGAW8ZYyZD/yE200RD7xVlUBFREQCqaIjB+E4PVGZNQ2dgem4Gg0WV5MBYBxwjbV2\nQl5NhmG4aYlFQE9r7ZaqBpu/e0I7JkRExN/ypylCRf5OiqDZPeEvmp4QEZFAysjOIDoimsiIyPI7\n46YnYiJj2P/gfh9HVj7tnhAREfGjylSGDMfpCR1YJSIi4gOB3j3hCyE10qA1DSIiEipK2qLpT1rT\noDUNIiISAsxQQ83omuwZvCfQoXh1TYOmJ0RERHwgHKcnlDSIiIj4QDguhNSaBhERES/r0KgDKV29\nV765MrSmQWsaREREKkRrGkRERMTvlDSIiIiIR5Q0iIiIiEe0EFJERCQMaSGkFkKKiIhUiBZCioiI\niN8paRARERGPKGkQERERjyhpEBEREY9o94SIiEgY0u4J7Z4QERGpEO2eEBEREb9T0iAiIiIeUdIg\nIiIiHlHSICIiIh5R0iAiIiIeUdIgIiIiHlGdBhERkTCkOg2q0yAiIlIhqtMgIiIifqekQURERDyi\npEFEREQ8oqRBREREPKKkQURERDyipEFEREQ8oqRBREREPKKkQURERDyipEFEREQ8ojLSIiIiYUhl\npFVGWkREpEJURlpERET8TkmDiIiIeERJg4iIiHhESYOIiIh4REmDiIiIeERJg4iIiHhESYOIiIh4\nRJtRXukAAAjcSURBVEmDiIiIeERJg4iIiHgkYEmDMeY8Y8wyY8wfxphrAxWHiIiIeCYgSYMxJhIY\nCZwGJAH3GmPqBiKWQEhNTQ10CF6l5wle4fQsoOcJZuH0LBB+z+MtgRppOAH4zVq7yVq7B/gcOCtA\nsfhduP1h1PMEr3B6FtDzBLNwehYIv+fxlkAlDU2ADQe83wA0DVAsIiIi4oEKJw3GmO7GmMnGmA3G\nmFxjTO8S+txqjFljjEk3xsw1xnTxTrgiIiISKJUZaagJLAJuAYqdq22M6YdbrzAE6AgsBqYZYxIP\n6PY30OyA903z2kRERCRIRVX0Amvtl8CXAMYYU0KXFOAVa+34vD43AecC1wBP5vX5CTjGGNMY2A30\nAoaV8bWxAEuXLq1ouEEpLS2NBQuqdKR5UNHzBK9wehbQ8wSzcHoWCK/nOeBnZ2xV72WsLTZY4PnF\nxuQCfay1k/PeRwP7gL75bXntbwEJ1toLD2g7DzciYYAnrLWvl/E9/YF3Kx2oiIiIDLDWvleVG1R4\npKEciUAksPmg9s1A2wMbrLVTgCke3ncaMAD4E8ioWogiIiLVSixwBO5naZV4O2nwCWvtNqBK2ZGI\niEg1NtsbN/H2lsutQA7Q8KD2hsAmL3+XiIiI+JFXkwZrbRYwHzgjvy1vseQZeCnLERERkcCo8PSE\nMaYm0Aq3gBGghTGmPbDdWrsOGAW8ZYyZj9slkQLEA295JWIREREJiArvnjDGnApMp3iNhnHW2mvy\n+twCDMJNSywCbrfW/lz1cEVERCRQKjw9Ya2dYa2NsNZGHvTrmgP6vGitPcJaG2et7VaVhCFcqksa\nY+43xvxkjNlljNlsjPnYGNMm0HF5gzHmvrzqoKMCHUtlGWOaGGPeNsZsNcbsM8YsNsZ0CnRclWGM\niTDGPGKMWZ33LCuNMQ8GOi5PeVh1dpgx5u+85/vaGNMqELGWp6xnMcZEGWOeMMb8YozZk9dnXF79\nmqDkye/NAX1fzutzhz9jrAgP/6y1M8Z8aozZmff7NM8Y06yk+wVSec9ijKlpjHneGLMu7/+bJcaY\nGyv6PQE7GtsTHlaXDBXdgeeAE4EzgWjgK2NMXECjqqK8JO4G3O9NSDLG1AF+BPYDPYF2wP8BOwIZ\nVxXcB9yIq9p6FG7Ub5Ax5raARuW58qrO3gvchvtzdwKwF/f3Qow/g/RQWc8SD3QAhuL+frsQtzX9\nU38GWEFl/t7kM8ZciPu7bkNpfYJEeX/WWgKzgN+BHsBxwCME59b/8n5vRuMOhuyP+3thNPB8Xs0k\nz1lrg/YXMBd45oD3BlgPDAp0bF54tkQgFzgl0LFU4RlqAX8A/8JNWY0KdEyVfI7HgRmBjsOLz/MZ\n8OpBbR8B4wMdWyWeJRfofVDb30DKAe8PAdKBSwMdb0WfpYQ+nXE70Jr9f3v3FiJ1GcZx/PuUYhRE\nN+USRLVkQkRrbTcdXDMryDaFbrKLJMKgDDcvgpIKoohii9rE7Ka6qChTOoBgXZgQpp2WjSw12mhJ\nJb0oO9AaWPl08byb46brf/4z7Dv/6feBAWccdn8vs/PO839Pkztv2fYQXwuwiyi+R4C+3FnLtgd4\nnZh6z56vCW35Enhg3GODwCP1/OyWHWlIp0t2A++PPebRyo3AZblyNdFpRDW4P3eQBjwHrHf3TbmD\nNOhGYNDM1qapoyEzW5I7VAO2AvPMbAZAWqh8BbAha6omMLNzgQ6O7Bd+Az6hvfqFX3IHKSPtlnsZ\n6Hf3Sp/7n9pyAzBsZu+lvuFjM1uYO1tJW4EFZnYmgJnNBWZQ54FPLVs0MPHpkh2TH6d50h/jAPCh\nu+/InacMM1tEDK2uyJ2lCTqBu4hRk+uA54GVZnZr1lTlPQG8AXxtZgeJbdAD7r4mb6ym6CA+VNux\nX5hGvHavufvvufOUdD9w0N1X5Q7SBGcQo6n3EQX3tcDbwFtmNjtnsJKWATuBPalf2ADc7e5b6vkh\nlTgRsg2tBi4grv4qJy0CGgCu8Tibo+pOAD5194fS/S/M7ELgTuCVfLFKu5mYt1xEzMXOAp41sx/c\nvYrtaXtmNgVYRxRESzPHKcXMuoE+Yn1GOxi7qH7H3Vemf28zs8uJvmFznlil9RHrTHqJ6aMeYHXq\nFwqPFrdy0dCWp0ua2SpgPjDb3ffmzlNSN3A6MJRGTSBGhXrSYrtpaSqpKvYSFXitncBNGbI0Qz/w\nuLuvS/e3m9k5xKhQ1YuGfcTapukcOdowHfg8S6IG1RQMZwFXV3iU4UqiX9h9uFvgROBpM1vu7p3Z\nkpXzI/AXR+8bKnXBZ2YnAY8RXzD5bnr4KzO7GLgXKFw0tOz0hLfh6ZKpYFgIzHX3XbnzNGAjsYp4\nFtCVboPAq0BXxQoGiJ0TM8c9NhP4PkOWZjiZKLhrHaKF3+9FufsIUTjU9gunEldQlesXagqGTmCe\nu1d1xw7EWoaLONwndBGLVvuJXUmVkj6DPuO/fcP5VK9vmJpu4/uFv6mzX2jlkQZoo9MlzWw1cAuw\nABg1s7ERlF/dvRW37xyTu48Sw97/MrNR4KeKLn56BthiZiuAtcQH0BLgjqypylsPPGhme4DtwCXE\ne+eFrKkKsuOfOjtAtO9b4ptvHyV2VbXcVsWJ2kKMcL1JFN+9wNSafmF/K079FXhtfh73/D+Bfe4+\nPLlJiynQnieBNWa2mdghdj3xWs3JkXcix2uLmX0APGVmy4ii5ypgMbC8rl+Ue2tIga0jS4mO4Q/g\nI+DS3JlKtuMQUdWNvy3Ona1J7dtERbdcpvzzgW3AAeKD9vbcmRpoyylEwT1CnGEwTJwFMCV3toL5\n5xzj/fJSzXMeJq5iDxCrv8/LnbvetgBnH+X/xu735M5e9rUZ9/zvaOEtlwX/1m4DvknvpSGgN3fu\nMm0hFna+COxObdkB3FPv76n7GGkRERH5f6r8HKeIiIhMDhUNIiIiUoiKBhERESlERYOIiIgUoqJB\nREREClHRICIiIoWoaBAREZFCVDSIiIhIISoaREREpBAVDSIiIlKIigYREREpREWDiIiIFPIPGxP1\n2UQJhCIAAAAASUVORK5CYII=\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAg0AAAFnCAYAAAAln3o1AAAABHNCSVQICAgIfAhkiAAAAAlwSFlz\nAAAPYQAAD2EBqD+naQAAIABJREFUeJzs3XmczWX/x/HXNZth7GQnsmuxpUikFJXSpkW0qUQqTVGp\ncA/tkva0WlqmW931S5JkSakQQoXse2RnGMbMXL8/rlnNdmbmzDlzzryfj4dH53y/17nO53vXPfNx\nLZ/LWGsRERERyUuIvwMQERGRwKCkQURERDyipEFEREQ8oqRBREREPKKkQURERDyipEFEREQ8oqRB\nREREPKKkQURERDyipEFEREQ8oqRBREREPKKkQURERDwS5q8vNsZsAg4AFthnre3qr1hEREQkb35L\nGoBkoIO1Nt6PMYiIiIiH/Dk9Yfz8/SIiIpIP/vylbYEfjTELjTE3+zEOERER8UC+kwZjTCdjzFRj\nzHZjTLIxpmc2bQYZYzYaY+KNMQuMMe2y6aqjtbYtcBXwuDHmjALELyIiIj5SkJGGKGAZcC9utCAT\nY8yNwFhgJNAaWA58Z4ypmrGdtfaflH/uBKYDbQoQi4iIiPiIsTbL733PP2xMMnC1tXZqhmsLgIXW\n2sEp7w2wFXjVWvtCyrUyQIi1Ns4YUxb4AbjHWrskh++pAnQHNgHHChywiIhIyRMJ1Ae+s9buLUxH\nXt09YYwJB9oCz6Res9ZaY8wsoEOGptWBL40xFggF3skpYUjRHfjYm7GKiIiUMH2ATwrTgbe3XFbF\nJQG7Trq+C2ia+sZauxFolY9+NwF89NFHNG/evJAh+l90dDTjxo3zdxheo+cpvoLpWUDPU5wF07NA\ncD3PqlWr6Nu3L6T8Li0Mf9ZpyI9jAM2bN6dNm8Bf+lChQoWgeI5Uep7iK5ieBfQ8xVkwPQsE3/Ok\nKPT0vreThj1AEm76IaPqwM7Cdh4dHU2FChXo3bs3vXv3Lmx3IiIiQSs2NpbY2FgOHjzotT69mjRY\na08YY5YAXYGpkLYQsivwamH7HzduXDBmfiIiIl6X+hfspUuX0rZtW6/0me+kwRgTBTTCVXQEOM0Y\n0xJ3fsRW4CVgYkrysAiIBsoAE70SsYiIiPhFQUYazgbm4mo0WFxNBoBJQD9r7ZSUmgyjcNMSy4Du\n1trdhQ02WKYnAjn27Oh5iq9gehbQ8xRnwfQsEBzPUxTTE4Wq0+Arxpg2wJIlS5ZoekJERCQfMkxP\ntLXWLi1MXzowSkRERDyipEFEREQ8Eih1GoDgWdMgIiJS1LSmQWsaRERE8kVrGkRERMTnlDSIiIiI\nR7SmQUREJAhpTYPWNIiIiOSL1jSIiIiIzylpEBEREY8oaRARERGPaCGkiIhIENJCSC2EFBERyRct\nhBQRERGfU9IgIiIiHlHSICIiIh5R0iAiIiIe0e4JERGRIKTdE9o9ISIiki/aPSEiIiI+p6RBRERE\nPKKkQURERDyipEFEREQ8oqRBREREPKKkQURERDyiOg0iIiJBSHUaVKdBREQkX1SnQURERHxOSYOI\niIh4REmDiIiIeERJg4iIiHhESYOIiIh4REmDiIiIeERJg4iIiHhESYOIiIh4REmDiIiIeCSgyki3\nbRtN3boVuP/+3gwdqjLSIiIiOSnxZaSJnAXHuqZd/+ILuOYa/8UlIiJS3JXcMtK3XgyhCWlvr70W\njIEHHoANG/wYl4iISAkQWEkDwPBSbNsG7dunX3rtNWjY0CUQF14IXhyJERERkRSBlzQAL/81lFnz\njmAtLF4MERHp9374ASpWdAlEixYwe7bfwhQREQkqAZU0LLx7IV0bdOXFX1+k7LNlAWjbFo4fB2th\n6UkzNatWwcUXQ9OmMGAAfPaZH4IWEREJEgGVNISFhDHr1ll0qtcJABNjOJZ4LO1+69YueTh6FBYt\nSv/cmjXw9ttwww1uBMIY+Ppr11ZEREQ8E1BJQ6o5t81Je1366dLEn4jPdL90aWjXziUFO3fCvfdm\n7aNnTwgJgYsugj//hGPHsrYRERGRdAGZNISFhPF/N/5f2vsyz5Rhz9E92batXh3eeMMlEMnJcOBA\n5vtz58KZZ7pEwxjo2xe2by/K6EVERAJTQCYNAFc1uwo7Mn1+4ZQxpzB349xcP2MMVKjgEojUJGLo\n0MxtPv4Y6tRxbfv1c21EREQkgJOGVCeGn6BH4x4AXDT5Iq7/7HqPP2sMvPCCSyDi4rIWipowAUJD\n0xOI//s/OHHCm9GLiIgEDr8mDcaY0saYTcaYFwraR1hIGNNunsbMvjMB+Hzl55gYQ0JSQh6fzCwq\nylWYTB2BmDMn8/0JE1xSERHhkojRoyEhf18hIiIS0Pw90vAE8Ks3Orqk4SUcfCy9qlOpp0qxK25X\ngfpKLRKVOo2xcmXWNiNGQKlS6bsxJk+GTZsKGLyIiEgA8FvSYIxpBDQFvvVWn+VLlSd5RPoihBpj\na/C/lf8rdL/Nm6cnEAcPwqefZm1z223QoIFLID74QKMQIiISfPw50vAiMAww3uzUGIMdaRnUbhAA\nvT7rhYkxJCUneaX/8uXhxhtdAhEfD48/nrXNnXe6UYj27d20xqRJWXdtiIiIBJp8Jw3GmE7GmKnG\nmO3GmGRjTM9s2gwyxmw0xsQbYxYYY9qddL8n8Le1dl3qpYKFn7PXL3+dr276Ku192Ogwar9U26vf\nERkJTz+dPgpx7BjExqbfX7jQLaC8/XaoVCl9KmP/fq+GISIi4hMFGWmIApYB9wJZaioaY24ExgIj\ngdbAcuA7Y0zVDM3aAzcZYzbgRhzuMsY8WYBYctWzaU+SRqSPMOw4vIOmrzdl68Gt3v4qwI0u3HQT\nJCa60tYffJB9u8qV0xOI8eO1rVNERAJDvpMGa+0Ma+0Ia+1XZD9CEA28ba2dbK1dDQwAjgL9MvTx\nuLX2VGvtacAQ4F1r7VMFe4TchZgQ7EibVgxqzd411Hu5Hm8seqMovg5w2zQjIuCOO9wIxOHDrpT1\nU9k84cCB6e2vuMJNY+zYUWShiYiIFJixhTiAwRiTDFxtrZ2a8j4clyBcl3ot5fpEoIK19pps+rgN\nON1a+0gu39MGWNK5c2cqVKiQ6V7v3r3p3bu3R/HO2TiHrpO7Zrq2Z+geqpSp4tHnvSUuzq17mDIl\n93bnnAOff55ebEpERCQ3sbGxxGacJwcOHjzIjz/+CNDWWrs02w96yNtJQ01gO9DBWrswQ7vngc7W\n2g4F/J42wJIlS5bQpk2bAsebavnO5bR6u1Xa+80PbqZWuVqEhYQVuu/8OnAA5s93518MG5Z7208+\ncYduhYb6JjYREQl8S5cupW3btuCFpMHfdRr8omWNlpm2Zp768qmEjw5n/pb5Po+lYkU3LfHYY7Bh\ng5ua+Pvv7NvefDOEhblRh48/1imdIiLiW95OGvYASUD1k65XB3YWtvPo6Gh69uyZZeilIIwxJI9I\n5p6296Rd6zShE1fGXklhRl8Ko0EDqFkTmjRJP6FzzRoYPjxr27593SmdxrjzMw4f9n28IiJSfMXG\nxtKzZ0+io6O91qdXpydSri0AFlprB6e8N8AW4FVr7ZgCfo9XpydOlpCUQOcJnVm4PW1GhfZ12vPj\n7T8SHhru9e8rqMREePNNd2rnmjU5t1u8GNxIlIiIlHR+nZ4wxkQZY1oaY1IXBZyW8r5uyvuXgLuN\nMbcaY5oB44EywMTCBFqUIkIjWHDXAp66MH17w4JtC4h4KoJ3l7zrx8gyCwuDBx5w0xfJyTBvHrRq\nlbXd2Wenb+l84gm3ZkIHbYmISGHle6TBGHMBMJesNRomWWv7pbS5F3gENy2xDLjfWru4wEGetHsi\nPzsm8ivZJnPe++dlGnUAd5qmPxZK5seWLXDqqbm3ufVWeOstKFPGNzGJiIh/pO6kKDa7J3ylqKcn\nsvP9+u/p9lG3TNeubX4tH13zEaXDS/skhsJISIBbbsl9W2fZsnD//RAdDaec4rvYRETEd7w5PaGk\nIReJyYkYDGGjM48wfNf3OzrV6xQQyQNAUhIsWODWOjz4YM7tZs92pbDPPBPq1s25nYiIBA5tufSR\nsJAwQkNCOfL4kUzXu3/UnTLPlOGfw//4KbL8CQ2Fjh1h8GC3K+Po0ezbde0KPXpAvXpuPURYGLgR\nLRERkQAbafDFmobc7D26l6pjqma6dnats1l01yJMgJZsPHo0fcvmhx/m3nbWLJdYiIhI8ac1DT6e\nnsiOtZYPfv+Au76+K8u9Y08co1RYKT9E5T3x8dCnj9txsXt39m1atIAKFdyCyrPOUolrEZHiTNMT\nfmSM4c42d3L8yeNc3ezqTPcin45kyMwhbD+03U/RFV7p0vDFF/Dvv24qY+7crG1WroRff3XbPVML\nTN16q6tmmZSUtb2IiAQHJQ0FFBEawZc3fokdaenfpn/a9bG/jqXOuDqs2r3Kj9F5T5cuLnmw1h20\ntX49lC+ftd2HH0Lt2ullrq+80p2nISIiwSOgpif8vaYhN3EJcVR+vjInkjNXUTo87DBlI8r6Kaqi\nc+QI7N8PL74Ir7ySe9tRo7IvhS0iIkVHaxqKwZqGvPy69VfO++C8TNduOP0GxnUfR61ytfwUlW98\n8407fCsvTz7p1kJccYWbDhERkaKjOg0BYMWuFbQc3zLL9WBYLJkXa+G662D7dli0KPe2p54Kc+bA\naaf5JjYRkZJGCyEDwFnVzyJxeCIz+86kaZWmadcjn47ExBgW7yhwVe1izxi3mHLhQpdAHD/uCkdl\nZ/NmaNgw/awMY2DtWt/GKyIinlHSUIRCQ0K5pOElrL5vNUv7Z07u2r3bDhNjWL9vvZ+i852ICLjo\novQFlRs3wmWXuRLW2WnSJD2B6NfPJR0iIuJ/ATU9UZwXQnrij11/MHP9TIZ8PyTTdYPhzOpnMqPP\nDGqWq+mn6Pxn+3Z49ll35Hduatd2IxZNm+beTkREtBAyoNY05GbhtoW0f799tvc2Dt5I/Yr1fRtQ\nMbNzJ9T0IHf64gu3i+PGGyE8vOjjEhEJRFrTEODOrXMuJ4af4O42d2e51+CVBpgYQ7JN9kNkxUON\nGm4aIznZlbm+/vrs2117rTvJMyIC2rVzRacWB+9SERERv1PS4CdhIWG8c+U72JGWtfdnXfkXOiqU\niNER7Di8ww/RFQ/GuC2Z//2vK2udlOSqTvbrl7Xt4sVw+ukueTDGrYuYNMn3MYuIBDMlDcVAo8qN\nsCMth4cdznT9RPIJar9Umx6f9AiYEzWLgjHulM6QEDdt8f77biRi2DB49FG45JKsn1m7Fm6/Pf20\nTmPgpZd8HrqISFBR0lCMlI0oix1pmXf7vEzXp6+dTq2XavHE7CdY+s9SjidqOwHAM8/Ac8/BzJlu\nBOK22+D337O2Sz0P4+GHM2/t3LjRt/GKiAS6gFoIGei7J/IrpwJRADP6zKB7o+4+jihwHD/uDtu6\n7DLP2v/wA1xwQZGGJCLiU9o9ESS7J/Lrrd/e4t7p92a5vmfoHqqUqeKHiALL8uXuVM6BA129iDlz\ncm57yinw5pvQq5fv4hMRKUraPVHCDGw3EDvS8t9e/810veqYqpgYg4kxJCXrTOqctGwJAwa4dRCz\nZ8M//7j1DuDWSmS0e7fbrZFxGmPYMLeT47fffB66iEixoqQhgNxw+g3YkZY/B2Y9czpsdBidJnTi\n8PHD7D6y2w/RBY4aNWDCBJdEzJ8PiYnQvLnbvpmd556D0FA45xydkSEiJZuShgB0erXTmXrTVHo0\n7pHp+vwt8yn/XHmqvViNBdsWsGr3Kj9FGFhCQ12Nh8mT3VqItWvdGofsbNyYeRRi9Wo3cgFw7Jir\nKyEiEqyUNASoK5teybSbpxH/RDxd6nfJcr/D+x1o8WYLdsXt8n1wASwiAho1cosiUwtMvf9+zu2b\nN4datWDQIFdTIioKNmyAffvcCIaISDBR0hDgIsMimXvbXOxIS5XSWRdF1hhbAxNjuPzjy0t0lcmC\nSj0068QJlwR88omrF3GyN99Mf92wIVSp4kpbjxkD64P/TDIRKSGUNASRfx7+h4OPHWTCVROy3Pt2\n3beEjgrlso893IMomYSFuWmM3r1d3YdDh9wZGY88Ak8+mfPnHnnEjVwYA506wcsvu8O5REQCUUBt\nuSxpdRoKylrLvvh9TPlrSrZbNc+odgZ/DPzDD5EFr23b3HbNyZMhIcElEgcO5Nx+8WJ44AHo3FlJ\nhIgUDdVpKKF1Ggpr9obZXPzhxVmutzilBROumkC7Wu0wxvghsuCWnAyNG7s1Dp6YOBFatXJbREVE\nvEV1GiRfup7WleQRyYztNjbT9ZW7V3Lue+cSMiqEoTOH+im64BUS4tYzWOvWREyenHv72293SYMx\n7tjvRx+FmBifhCoi4hElDSWEMYaHOjyUViSqe8PMJahf/PVFTIyh9dutMTGGHzb94J9Ag1RYmKsD\nYa37c+gQdOmSc/vrroMXXoD//AfOPReWLYNbb4U1a3wVsYhIVkoaSqAbTr+BGX1nsPb+tVzb/NpM\n95btXAbAhZMuxMQY/tiltQ9FoVw5dzbGd9+597lt61y0CFq3hg8/hKZN3UjEjBkQHe1GMpKS0g/l\nEhEpSlrTIMSfiKfMM2VyvD+qyyiGXzDchxGVLFu3Qt266e8nTHDTGffck79+AuD/yiLiB1rTIF5V\nOrw0ySOSOf0UV2nyZCN+GIGJMXyx6gs/RBf8MiYMAHfcAf37uyRg/36XRGzaBNdck3s/xsBNN7m1\nEx9/nH49Lg727vV62CJSAmmkQbKYtmYav279lWfmP5PtfR3L7T/79rly1W3awK58FvsMgP+ri0gR\n0EiDFKkrmlzB012fxo607HtkX5b7l358KSbGMOibQaQmnSpX7RuVK7uy1Tt3wu+/w4svukWTY8dC\nhQq5f9YY6NvXbenUGRkiUhAaaZA8HUs8xpNznmTsr2OzvV+1TFX2HN3D3/f9TZMqTXwcnWR04ABU\nqlSwzwbAjwIRKQCNNIhPRYZF8mK3F0kakcRL3V7Kcn/P0T0A9JrSi71HNXnuTxUrpm/rtBbuu8/z\nz6aWup46VSMRIpK9gBppUBnp4uFY4jF+2PRDrudYaNSh+IiPh1Wr3LbNFSvcmoj27T377AsvuF0c\n4eHuFE8RCRwqI63piWJn5vqZdP8o50WRhx47RLlS5XwYkXgqv5XDu3VztSJ+/dWNSFSuXDRxiYh3\naXpCio1uDbthR1rin4jP9n7558pjYgzHEo+xdu9aH0cnuYmPd4dr7dgBCxZAixa5t585E6pXh6uv\ndkd/16vnPjd3rutHRIKfkgbxisiwSOxIy5HHj2R7v/TTpWnyehPGLx7P7iO7fRydZCcy0k071Kzp\nSlX/9ZdbBxEX547wBpcY5GTrVujQAS66CEqVcrs5unZ1JbJFJDgpaRCvKhNeBjvSYkdarm9xfZb7\nA78ZSLUXq2FiDJsObPJ9gJKnqCgYPNglEJs3uxLXF16Y9+fatIE5c9zWzwEDYNYsLaoUCTZKGqTI\nTLl+CnuG7qFbw27Z3m/wSgNMjGHepnms27eOxOREH0conujXzyUDGXdlHDwIDz6Y82fefhsuuQSu\nusolIU2bus/FxsKff/oudhHxLi2EFJ84dPwQRxKOMGreKMYvGZ9tmzOqncHn139O06pNfRydFFR8\nvDtQq2NHuO02+OQTzz63dKlLPE47LfcpEBEpPG8uhFTSID43e8NsLv7w4lzb7H90P+UiyhEaEuqj\nqMQbpk+HTz910xMdO3r2mdmzoVUr7cYQKSraPSEBretpXdPWPeSk0vOVCBsdxl///uXDyKSwLr/c\nHZh13nnuuO7XXoOQPH7KdO3qdmMY4/707u2mNpYvd4syA+DvNSIlhpIG8auEJxPYNWQXXRt0zfb+\nGW+dwZlvnalFkwEoJMRVpPzqq/Rrr7wC5fIo2/Hpp24RZatWrm3HjtCrF9x6q7t/4oTb6SEivqfp\nCSlWrLWEjMo5l21QsQEbD2xk6k1TubLplT6MTLxt50544w146qmCfX7tWmjYMP9FqkRKmoCfnjDG\nVDDG/GaMWWqMWWGMucsfcUjxY4zh8+s/Z1z3cXSq1ynL/Y0HNgLQ89OefLTiIzYf2OzrEMVLatSA\n0aPdIVv9+8P69fmbimjc2I1m/PAD7NnjFlYeOFBk4YoIfhppMMYYoJS19pgxpjTwFy4D2p9De400\nlFALti2gw/sdcm0zpdcUrj89a00ICUzx8VCmjHs9ZIg7/js/Lr8cvvnG+3GJBKqAH2mwzrGUt6nH\n4GiQUbJoX6c902+ezupBq+lQJ/vk4YbPb8DEGEbPG83xxOMkJSf5OErxptKlITHRLaQcM8aNPnhS\nXCrV9OnpiyrHjXPXDhxwiypFpHD8thAyZYpiGbAFGGOt3eevWKR4u6zxZTSt2pRf7vyFf4f8yyPn\nPZJtuxE/jCDy6UjCRocx5ucxPo5SvCk0NPOuiwkT4PXXXenq1as97+ehh1zyUKmSW1TZo4cbidi4\n0fsxi5QE+U4ajDGdjDFTjTHbjTHJxpie2bQZZIzZaIyJN8YsMMa0O7mNtfagtbYV0ADoY4w5pWCP\nICXJKVGn8Pwlz2NHWjYN3pRju0dmPUL46HD+3vM3++KVjwa6U0+FQYOgTh1XXfLvv91ZF5s3u5GI\n3buhefO8+5k+Hb791hWVuvJK18+QIW5kQ0TyVpCRhihgGXAvkGVBhDHmRmAsMBJoDSwHvjPGVM2u\nM2vt7pQ2WVe9ieTi1Iqn5no/MTmRZm80o8oLVXh3ybs+ikp8oUkTtyUztZpk1aqwciXMnw8//5ze\nJjfTpkGzZjB2LNx8M9SvD9dc4xKIf/4p0vBFAla+kwZr7Qxr7Qhr7Vdkvw4hGnjbWjvZWrsaGAAc\nBfqlNjDGVDPGlE15XQHoDPxdkAeQki32ulhm9JmRZ7v+0/pjYgwXT76YP3b94YPIxB86dnSFpax1\nowjWulM48/LZZ27U4v/+z538WasWTJwI27bBpk1FHbVI4CjU7gljTDJwtbV2asr7cFyCcF3qtZTr\nE4EK1tprUt63A95JvQ28bq19L5fvaQMs6dy5MxUqVMh0r3fv3vTu3bvAzyDBIyk5iWGzhzH43MHU\nGVcnz/bDzh/GM12f8UFk4k/JybBlC6xb5ypNFsTMme70zm++gTvv1HkZUnzFxsYSGxub6drBgwf5\n8ccfwd9nT2STNNQEtgMdrLULM7R7Huhsrc1971zO36Mtl5IvPT7pQYgJYdqaabm2m3z1ZHYc3sHQ\njkMJMSqQWhJMm+bWRrz5JrxbwFmrTz91Cytbt4aaNb0bn4i3BfyWS5Gi9s3N3/B176+5reVtAPQ+\nI/vRqFv/71Yem/0YoaNC+XD5h+yL30dCUoIvQxUfu+IKtx7inXfg2DG4/npXZOrPP+Huu+GFF8D9\npSxnN93kdmLUqpW+vXPECEhIgC+/1HkZErz8Mj1RgO/JND2hKQkpiP3x+zl/wvms3L0y13bn1T2P\nlbtXsuiuRTSu0thH0Ulxs2GDK1NdEFOnut0Zhw6517t3u2mN8uW9G6NIblKnKort9ETKtQXAQmvt\n4JT3BleL4VVrbYE2z2t6Qrxlz9E9/L3nb86fcL5H7f8Y+AdnVDujiKOS4uqll9xiyHHj4MMPoW1b\naNHCs8+OGeNO/Pwjw7pbjUCIP/h1esIYE2WMaWmMaZVy6bSU93VT3r8E3G2MudUY0wwYD5QBJhYm\nUBFvqFqmKh3rdWToeUMBSB6RzFVNr8qx/ZlvnYmJMZgYw5yNc3wVphQTDz3kEgdroW9fVwvi6FF3\nzsWuXbl/dujQzAkDwO23w4wZULeuO7Vz3boiC12kSOR7pMEYcwEwl6w1GiZZa/ultLkXeASojqvp\ncL+1dnGBg9T0hHhZ6n/3xhiSbTKho0I9+lzrGq35fefvPHjug4y7dFxRhigBYto0mDMnvWR1ft1x\nhzu8a+FCaNMG7r/f7c747DPo3BmqV/duvFJyFLvpCV/R9IT4monJ+yiU+hXrs3Gw6hGLs2WLO6nz\nwgvTF0cW9sdrs2YueThDM2RSCNo9IVLEtkVvy7PNpgOb+GPXH5gYw33T7+Ph7x72QWRSXNWrl36w\n1tq1rqrkf/4DEREF73P1ajjzTK+EJ+IVShpEslG7fG0ODzvMg+c+yLr73cRzhVIVsrQ7a/xZALzx\n2xu8tOAlXl7wMtsPbScQRvCk6DRq5KYVRo6E48fdiMPOnS6ZKIjUkQtj4K67YM8emDfPuzGLeCKg\npie0pkH8ZcpfU7jktEsYv3g8j895PM/2r176Ko/Nfoz3e77PJaddQpUyVXwQpQSC5GSYPRu6dSt8\nXxdd5EYiRoyA116DCy6ALl0K368EB61p0JoGKQbW7VvH6B9HM3n5ZI8/ExYSxonhJ4owKglES5a4\nw7aqV3cjEZGRblGkyXtJTY7eftuNQnzyCRw+DGXLei9eCUxa0yDiR40qN2LS1ZNIHpHs8WcSkxMx\nMYYuE7sUXWAScNq2dcd+R0a6UzZr1HDXf/yx4L/s77nHJQzgkpG773brKwYMgNq1vRK2lGBKGkQK\nyBjDieEneLbrs0y4agJPdHoiz8/M2zyPMT+P4eCxgwD8svUXQmJCiEuIK+pwJYB06uRGCdatg/h4\nty5i3TpX4yE/jh6F995z5a7ffht27HDTGMeOwbffwq+/Fk38ErwCanpCaxqkuDuScIQ5G+fQ89Oe\nebYd0HYAczbNYc3eNbx35Xvc2eZOH0Qogcxad3T3Cy+4EYpNm2DIkML3uXatO8SrdGmvhCnFhNY0\naE2DBIj1+9ZTs1xNrv70ar7f8L1Hn/m538+cV/e8Io5Mgs3rr0NSEgwcCKVKFbyfiAh34Nb69e4E\nz1NO8V6M4l9a0yBSzDWs3JAy4WX4b6//8kHPDzz6TMcPOmJiDMcTjxN/Ip7Ve1YXcZQSDO67DwYP\ndr/0K1d213btctUk8yMh5XDXhg2hWjU3pRET4xZlDhzopkjAldW++27vxS+BRSMNIj5wwcQL+HFz\nHuctZyNuWBxREVFFEJEEow0bYNUqd2w3FG4XRnZGjIBRo9zrAPjVISk00iASYGKvi+WdK97BjrTY\nkZZLG13N93W9AAAgAElEQVTq0efKPqv9cuK5005LTxjAHc2datkyeDhD0dJPP83/uRapCQOkF5ua\nNSt9FEKCX0CNNGghpASLQ8cPsfSfpdSrUI9KkZW4Z9o9fLbysxzbt6zekpW7V3J2rbOpX7E+F9a/\nkEsbXUrdCnVz/IwIuGmHQ4dcPQiAMmXcjozUH/1vv+22YxbG3Xe7fho2hM2b3fdFaYDM77QQUtMT\nEqR2xe3ipy0/cf1n1+frc0PPG0pMlxhKh2vZu3hmxw7YuzfzmRb//OPWMHhT9+7u5M9eveCqq+CZ\nZ7zbv3hO0xMiQaZ62er0atGLVYNW0a2h5/WFx/wyhhZvtuDoiaOs2r2qCCOUYFGrVtZDsGrWhK1b\n3VZOa9P/7N1b8O/57jto0QJWroRnn4WuXaFxY/j3X1i+3PXfowcsWlS45xHfUtIgUow0q9qM7/p+\nx7Ndn/X4M5sObCLqmShavNmiCCOTYFenDgwdmvla5crwQcrmnzffdP985JGC9T9njitQVb06tGrl\nCkxNnw633OLuL1vmTvWU4k1Jg0gx9Nj5j2FHWj6+9mMGnj2Qlfeu9Ohzy3cuB+Dw8cM0erUR6/at\nK8owpQS44w43KjBwoPtF/9xz8Pzzbvoho/zOHM+c6f65Zo37Z+vW0Ly5Ww+xaZMbjZDiR2saRAKE\nifFs/9yF9S8kMTmRn7b8BMCfA//k9GqnF2VoUkJ99ZVbaHnDDe64bmu9XxQqAH5FFXveXNMQUEmD\ndk9ISbb36F7KlSpHqafyX/bvfzf8j3a12lG3Ql2SbTKJyYlEhEYUQZRSkiUnw3XXweWXQ//+0KcP\nbN8OP/xQ8D6/+w46dkzfjWEt/Pe/UK8e/Pmn+x7JnnZPaKRBhJ+3/EypsFKUL1WeTQc28dv233hy\n7pP57ufRjo/y3MXPFUGEIhAX507qPH7cLbJs1Mj7xaYAJk6Eiy+GI0egSRPv9x8MSuxIg5IGkawO\nHz9M+efKF+izsdfFctMZN3k5IpHsGQMXXugSiWXL3Cmc3tahA/zyi/f7DWTacikiacqVKkfCkwkF\n+mzv//Xmrd/e4u89fxP1TBR7ju7xcnQi6bZsgWnT4Oef3cjAL7/A4sXwWc51zfLt11/dTpDnUgbR\nVK3Su5Q0iASB8NBwAGK6xHBlkysBOL/e+R599t7p99LsjWYcPXGUMT+PyXTv162/8tPmn7wbrJRY\ndeu6ipSpOnSAtm1dAailS91UgzcGv7dvh2HDXH2IyEj4/Xd3/d13Yfjwwvdfkml6QiTI7Ivfx9yN\nc6ldvjYDvxnI0xc9TY9PeuT9wRRhIWEsumsR/5n3H6b+PRUAO7L4/5yQ4LFrV+ZTO//8E2bMgCFD\nCt5n7doumUj1+ONuceWQIe67gpnWNIiIx/Yc3cMpY05hwlUT6NWiF+WeLZfvPhKeTCAsJAxTFCvZ\nRHJw4gQkJkLplCrpe/fC6ae7pMKbXn8dRo+G6Gh49FGYPRvOOsv720f9xZtJQ5h3QhKR4qpqmaoc\neuwQ5UrlP1lIFfGU+6vYpsGbOLXiqQBYa0mySYSYEEKMZjrF+8LD3Z9UVarAvHnQrBlMmeLqQ3jD\nffe5fz72mDub49VX3fvjx90ukNQRDwmwkQbVaRApvP9b/X/M2jCL8YvHk2ST8v35CVdN4OpmV9P8\njebsjNtJvQr12Pzg5iKIVCR348ZB06bu7IzPPnOFpsaOLZrvmj8fvv8e/vOfoum/KKhOg6YnRLzq\n3yP/UuelOpxIPlGofjY/uJl6Fep5KSqRgrEWQop40KtMGVixAr7+Gs45B847r2i/zxu05VJEvKJa\nVDXubH0nAE90eqLA/Zz68qkMn6Nl6eJfxqSf0Pnbb25XxhVXePc7jh51haqio12lyjFj3BRGSaGk\nQaSEG9pxKN0admN45+EkjXDTFf3b9Ofo4/mrvPPUT0/R4o0WLN6xGBNjmLl+ZlGEK+KRs892UxZf\nf+2O405Ozrzd01seecSVsq5a1fW/ZAmEhrqk4q+/vP99/qbpCRHJZF/8PsqXKu92S6QcklU2oixx\nCfn761S5iHLMu30eISaEljVa8s2ab2hfpz1VylQpirBF8vTnn3Dmme61te4X/Nlnw5VXui2Z48d7\n9/uuuQa++MK7fRaEpidEpMhULl2ZsBC3serH23/kvSvf4/Cww3Sp3yVf/RxOOEybd9rQ6u1WzFg3\ngytir6DLpC4MmDaALQe3FEHkIrk74ww4eDD92O1Kldw/L7wQbr/dva5Z03vft2+f9/oqLjTSICIe\nOZZ4jLiEODbu38g5753DpY0uJS4hjvlb5heoPxWMkuLgt99cVcqQEFi0CNq1cyWuy+WwQ7lcOTh8\n2PP+i8OvWNVpEBGfiwyLJDIskqplqnJ42GHKRpQFSJvCyK/v13/P2bXOJjQklPKlCnbglkhhtWuX\n/vqcc9w/y5aF/fvhzjuhRg3o3h2uusrde/JJVwCqpFLSICL5lpowFEa3j7plev9d3+9oXrU5dSvU\nLXTfIoVVsSL873/p73/80ZWcvu8+eO012LbNVas87zw3QpGdolh46W9a0yAihRIR6qpF9m/Tn1cu\nfQWAAW0H5Luf7h91p97L9UhMTuTTPz+l15RegKs8OWzWMMb+UkRVe0Q80KkTLFzoEoHFi90hWKGh\n6adp7tjhpjUGD3bvR4927YKNRhpEpFD+efgfEpISqFG2BtZaTqt0Gpc2upTxSwq2FD18dHrd4O2H\ntvP8z8/z2qLXAHj4vIe9ErNIYVSv7v6AW0SZcd3C4MGwbBk8/HD6mRnBJKAWQqqMtEjgOJJwhEdn\nPcobv73BCxe/QM1yNbnly1sK3e+82+fR+dTOXohQJLipjLR2T4gElCMJR3hv6Xs8cO4DGGNISk4i\nbHThBzi180LEc6rTICIBISoiisHtB6cdqR0aEuqVfg8cO8AXq76g15Re3PrlrYyeN5qEpARGzRtF\n/Il4r3yHiGSlNQ0i4lN2pGXcr+N4eObDfHb9Z/T6rFe++6j0fKUs10b8MAJwlSijO0QXOk4RyUoj\nDSLic9Edokkemcx1La7jh9t+YPC5g73W9z9x/+S75LWIeEZJg4j41QX1L+DlS18mblgcpcPccvNm\nVZsVuL8xv4yh3LPl6P5Rd9bvW592ffaG2SQlJxU6XpGSTNMTIlIsREVE8de9f/G/Vf9jyHlDsNay\nfNdyWr/dukD9zVw/k0avNcKOtCzavoiLP7w47Z4WUooUjJIGESk2GlRqwJDzhgBgjKFVjVbEPxFP\n6acLvuG9oGWuRSQrTU+ISLEWGRaJHWl5qP1DXuvzeOJxnpj9BCbGsP3QdhKTE73Wt0gwU9IgIgFh\nbPexJA5PpGfTnoXu666v7+KZ+c8AUGdcnUxVKEUkZ0oaRCRghIaEMvKCkWnvLz7t4lxa5+yjFR9l\nuWZiDJOWTeJIwhHunnq3dmCIZMMvFSGNMXWAD4FqwAngKWvt57m0V0VIEUmzYf8GTqt0GpC+ZsGO\ntCTbZEJHeaeAVOPKjVlz/xqv9CXiT8FQETIRGGytPR3oDrxsjAnCoz1EpCikJgwAy+5ZxtL+7udg\niPHej7S1+9YCcCLpBPM2zct07+ctP2NiDFsPbvXa94kEAr8kDdbandbaFSmvdwF7gMr+iEVEAlvL\nGi1pXTP3bZlDOgwpUN9/7PqDO6feSZdJXej2YTcAbvjsBs6fcD4Aa/amj0QkJSfx4IwH2X1kd4G+\nSyQQ+H1NgzGmLRBird3u71hEJDg0rtw40/vHOz1eoH7unX4vH674EIDvN3xPQlICn638LO1+xrM0\nft/5O68sfIWYeTEF+i6RQJDvpMEY08kYM9UYs90Yk2yMybKU2RgzyBiz0RgTb4xZYIxpl0NflYFJ\nwN35D11EJKv4J+KZdPUkAJ7s9CR2pKVS6axnVXhi/pb5md6/suCVTO8vnHQhU/6awv74/Rjc2ooP\nV3zIloNbCvR9IsVdQUYaooBlwL1AllWUxpgbgbHASKA1sBz4zhhT9aR2EcCXwDPW2oUFiENEJIvI\nsEja12nPy91fZlinYWnX373yXWqWrZmpbeq0RWr56rw8MuuRLNdu/PxGKr9QmbPfPRuAQ8cPcerL\np6qolASlfCcN1toZ1toR1tqvgOz+XxENvG2tnWytXQ0MAI4C/U5qNwmYba39JL8xiIjkxhjD4PaD\nKRNeJu3aXW3uYsfDOzLVeYgMi2TNfWtYNWiVP8IUCTheLSNtjAkH2gLPpF6z1lpjzCygQ4Z2HYHr\ngRXGmGtwIxa3WGv/yq3/6OhoKlSokOla79696d27t/ceQkSC2lc3fZW+TRNL4yqNOXT8UJF8l4kx\nbHhgAw0qNSiS/kVOFhsbS2xsbKZrBw8e9Fr/harTYIxJBq621k5NeV8T2A50yDjlYIx5Huhsre2Q\nfU95fo/qNIiI17y9+G0GfDOA/Y/up2JkRY4nHify6UguPu1iPrv+M/p80Yfpa6d75bs+vvZjdsXt\non/b/kRFRHmlT5H8CIY6DSIifnPP2fdgR1oqRlYEoFRYKbZGb2VGnxlUjKzIDS1u8Np39fmiDw/N\nfIj+0/oD7tyLWRtm8cvWXzh47CCvL3pd6x8kYHj7lMs9QBJQ/aTr1YGdhe08dXpCUxIi4m11ytdJ\ne31bq9u4teWtHE86zsrdKxk2exgz188sVP+f/PEJH1/7MaPmjUo796Jj3Y7sjHM/Gq21GKPkQbwn\ndarCm9MTXh1psNaeAJYAXVOvGff/gq7AL4Xtf9y4cUydOlUJg4gUOWMMkWGRtKnZhrIRZQGoV6Fe\n4fqMMWkJA8DPW3+mVFgpAE4kn0i7Hn8injov1WHJjiVp1z5e8XFagiHiid69ezN16lTGjRvntT4L\nUqchyhjT0hjTKuXSaSnv66a8fwm42xhzqzGmGTAeKANM9ErEIiI+lpScBMCCOxekXVs1aBVxw+J4\n5dJXcvqYR1IXYX6//nsqPufWV2w7tI3th7fzysL0vvt+2ZdeU3oV6rtECqsgIw1nA7/jRhQsribD\nUiAGwFo7BRgCjEppdxbQ3Vpb6Nqq0dHR9OzZM8vKUBGRopRkXdIQGhJK6xquZHVYSBhREVE8cO4D\nxA0r+ImY2w5tA+CK2Cs4ePwgK3at4P5v7wcg2SYDcOdXdwKwN34vAIePH9YpnJKn2NhYevbsSXR0\ntNf69Mspl/ml3RMi4k/jfh3HQzMfIm5YHKEhoUz9eyo3nJ55sWSz15vx996/vfq9N5x+A61rtGbY\nbFekqkmVJrx+2et0+6hb2vu/7v2LsBBvL0+TYKLdEyIiPvRg+wfZ/+h+oiKiiAyLzJIwFJUpf01J\nSxjAjTykJgzgDsya8tcUAuEvfxIclDSIiOTBGJO2PbOwfu73c4E/u27fuizX+nzRhwnLJqS9/+SP\nTzAxhoSkhAJ/j0hOAipp0JoGESmuqkVVS3u9/oH1hJisP14jQiM4r+55Xv/uO6feiYkxfLv2WyYu\nmwjAscRjafeX7VzG6j2rvf69UrxpTYPWNIhIMfXvkX/5afNP9GjSg8iwSHbF7WL+lvn0+szteGhU\nuRGrBq0iLCSMuRvnctHki4okjjY127D0n6UcePQAFSJd2f3U4lE3nXETsdfpL10ljdY0iIgUM9Wi\nqnFdi+uIDIsEoHrZ6lzX4rq0+2UjyqYtWLywwYVFFsfSf9zvhISkBC6adBErdq1Iu/fpn58W2fdK\nyaCkQUSkCNUqVwvA5zscdhzewdxNc/nPD//Jsc1f//7Fou2LfBeUBLyA2qejMtIiEmhe7v4yN3x+\ng8+ThgsnudGML1d/mWObM946AwA70k1TJyYnEmpCVc46SBT7MtJFTWWkRSTQpE5RdKiT9yG/ZcLL\neO179x/bn+31wd8OZn/8fp768am0a6kFpsJHhzN87nDiT8QzYu4IEpMTvRaP+F5RlJEOqJEGEZFA\nE2JC2PDAhkwHYuXkmYueYcwvY9h+eHuRxfPqold5ddGrma71+aIP826fB8BHKz4iMiyS0T+OpnWN\n1lze+HKOnDhC5dKViywmCRwBNdIgIhKIGlRqQHhoeJ7tHjj3AabdPI3Hz3+c+9rd54PInB83/8gX\nq74AYPPBzQyfOxyAqWumEvl0JFVeqML8LfMBV2DqRNKJHPuS4KakQUTEj8ZcMibttTGGVjVa8XTX\np3nlslcID8maaFSPqg7As12f9Woc1025Lsu11JoPAMt3Lgfgnq/vIeKpCK9+twSOgJqe0EJIEQkW\n/w75l/DQcCpGVmRX3C7OrH5mpvshJoTdQ3ez5+ge1u5by2UfX8aNp9/IxKsn8u+Rf/lh0w8+jTf1\n8Kz3fn8v0/X5W+ZTs2xNGlZu6NN4JG9FsRBSxZ1ERIq5FbtW0HJ8S+5uczfvXPkOANZaQkb5brD4\nrtZ30b5Oe+76+i73/SMtf+z6g7PGn5X2XoonFXcSESlBQk0oQKbS1L7eFvne7++lJQwAY38Zm5Yw\npPrvn/9l/OLxACQlJ3Es8RhHTxzVgVpBREmDiEgx1+KUFozqMsrjdQy++Fv/kO+HZHo/a8Msbvrf\nTQz8ZiDWWvp+2ZfST5cm6pkozn3v3CKPR3xDSYOISDFnjGH4BcOpVLpSpuv/DvmXuGFxLLtnWdq1\n2uVqAxTJwVi5ueTDS9JeT14+OVPJ6t92/Mbz85+nygtVOHriqE/jEu9S0iAiEqBOiTqFqIgoWtZo\nSbeG3YD00y2vb3G93+K6/avbs1x7bPZj7Ivfx47DO3wfkHhNQCUNOhpbRCR7z3V9DnA1IQAGnzuY\nI48fydSmaZWmPo/rZCt3rwQgLiEu06jDLV/ewsPfPeyvsIKSjsbW7gkRkRx9u/Zb2tRsQ/Wy1dOu\npR6LDfBBzw/oN7WfP0JLc07tc1h418K0uD659hM6n9qZOuPqpL2vV6Ee1ctWp1HlRv4MNWh4c/dE\nQNVpEBGRnF3W+LIc79UuVzvtLIlqUdX498i/vgork0XbF2XaTXHzFzdnup/xvbZxFj9KGkREgtiM\nPjNITE6kR5MeHEs8xuaDmxlxwQgiQl1Vx4wjEb6Sn/oS7yx5h3um3ZNrAnHo+CEiQiOIDIv0RniS\nCyUNIiJBrHuj7mmvI8Mieeqip3JpXfyM+WVMnm0qPFeBtjXbsrj/Yh9EVLIF1EJIEREpWVILWv3f\n6v9j9Z7VObZb8s8SX4VUoilpEBEpwe4/5/4c7/10x08+jCR7qUnDNf+9huZvNAdg5vqZDJ8znAdn\nPEhCUkJa25+3/OyXGEsSTU+IiJRgr172Kq8tei3L9fE9xtOhTgc/RJSuzxd9sh1d6P5R+pTL2bXO\nTnt9/oTztXiyiAVU0qBTLkVEit7EqyZyW6vb/B0Gn/zxSZZrsX9krtOT8TwOyUynXKpOg4iI1528\ngyLj39YXbFtAh/czjzg81P4h4hLieGfpOz6JLz/sSMtHKz7ili9v0ahDCp1yKSIiXlO3fN20151P\n7ZzpXvs67QGoX7F+2rX6Fesz/orxTL95eqY1ERn78adxC8YBLhkq+0xZP0cTXJQ0iIiUcIv7L2b5\ngOXMu30es26ZleX+gjsXsGLAirT3g84ZhDGGyxpfRs2yNdOu92jcwyfx5sWQPnJy5MQRTIzBxBg2\n7t+Y9nrITHdK5+IdizExhl1xu7L0s2r3qrTPiaOkQUSkhKsWVY2zqp9F51M7Ex4anuX+uXXOpVyp\ncmltM64jGNpxKDP7zmTubXN5qftLWT77zc3fFF3g2TAxJsftl1P/npr2euyvYwH4YtUXQPqZGBmd\nNf4sAH7d9qu3wwxYShpERMQjP93xE0v6Z/6FHBYSxiUNL6FL/S6UDi+d5TOtarTyVXh5evC7B7Nc\nS7bJAFw0+SLe/O1NFm1fRKcJnUi2yWllt7/f8H2mHRslWUDtnhAREf85v975+f5McS/t/PWar9Ne\nD5o+iIsaXMT8LfMzncA5cdlEP0RWPClpEBERr/m2z7fsOLyDyLBIyoSXISo8yt8h5erkaYktB7cA\nsG7fujw/u3jHYqLCo2h+SvO0aweOHeCnzT9xZdMrvRtoMaGkQUREvObSRpdmen/ytv4JV03gjq/u\n8GVIOdp6cGuWa6nJQuu3W+f5+XbvtgMyb1G9a+pd/G/V/0gcnkhoSKiXIi0+tKZBRESKjDGZa0Bk\n3NlwUYOLfB1OJvVeruf1Pncf3Q3AieQTXu+7OFDSICIiPpO6CwPItF0zEGw/tD3PNmEhbgD/eOLx\nog7HLwIqaYiOjqZnz57Exsbm3VhERIqFubfNZWv0VmKvi+WaZtekXX+rx1tprz+//vO010PPG+rT\n+Dw1b/O8tNdL/0kvrDhp2SQWblvIb9t/IzzEbVk9nuT/pCE2NpaePXsSHR3ttT4Dak3DuHHjVEZa\nRCTAdKnfBYCbzrgp0/WMow6nVjw17fWgdoMY88sYn8SWH6nrM6y1tH2nbdr127+6Pe11aoGrjKdv\n+kvqOU0ZykgXWkCNNIiISHAZ0HYAAKEmfdFgVETx3HHR98u+mBjD3V/fnWOb1OJYmp4QERHxsiSb\nBGQ+rbJqmarZtp3RZ4ZPYsrL+7+/n+O91DUN906/11fh+JSSBhER8ZvUioyebE8sE16mqMMptNQ1\nDTPXz8z2PItAp6RBRET8JjVpyDjSkJPisE4gL6kjDQAz1hWPkRFvUtIgIiJ+k3F64pd+v7DmvjWZ\n7mfcVZGxrsOkqyf5JsB8yliXYvSPo/0YSdFQ0iAiIj51VvWz0l6fU+scACqXrkyHuh1oXKVxprbX\ntbiOFqe0ADL/Qu59Rm8fRJp/k5dPTnud8fyKYBFQWy5FRCTwLbhzAccSjwFwb7t7uab5NVSLqpZj\n+9/u/i3LboTw0HD+vu9vmr7etEhjLYzUUzKDiUYaRETEp0qHl6ZS6UqAGz2oVa5Wru3LhJdJa1+5\ndGU61u0IQJMqTRh5wciiDbYQUqdegomSBhERCRh7H9nL/H7z097/p8t/sCNtpkOjcvLm5W8WZWhZ\naKTBi4wxXxhj9hljpvgrBhERKb5ubXmrV/s7+fCsoqakwbteBm7x4/eLiEgxZUfaAu+QWDFgRbbX\nM56w6QtKGrzIWvsjEOev7xcRkeCUU0XJZlWb+TSOpGStaRARESnWaparme0oxQX1L8i2/YC2A9gW\nvY1t0dv46Y6fvBaHFkICxphOxpipxpjtxphkY0zPbNoMMsZsNMbEG2MWGGPaeSdcERGRvNWrUM/j\ntlERUdQuX5va5WtTp3ydIowq8BWkTkMUsAx4H/ji5JvGmBuBsUB/YBEQDXxnjGlird1TiFhFREQ8\n0vnUzrnef/XSV2lQqQGxf8YS0yUm7bon5axLsnz/r2OtnWGtHWGt/QqyXVUSDbxtrZ1srV0NDACO\nAv2yaWty6ENERKTAQkxIWj2H7Nx/7v1c0eQKPr7240xHcee2WHLiVRO9GWJA8mpFSGNMONAWeCb1\nmrXWGmNmAR1Oavs9cBYQZYzZAlxvrV2YW//R0dFUqFAh07XevXvTu3fxLCcqIiK+lfF8itQ1Bb1a\n9OLzlelnWPQ5s0+On68YWTHHe/mZ8vCX2NhYYmNjM107ePCg1/o31uZdECPHDxuTDFxtrZ2a8r4m\nsB3okDEBMMY8D3S21nbIvqc8v6cNsGTJkiW0adOmwPGKiEjwSkhKINSEph2zfe5757Jo+yISnkwg\n2SZTKqwUxxOPExYSlutR3EdPHCXEhFD66dKZrq+9fy2NX3NnY8y+dTZdJ3fNMyZPik4VtaVLl9K2\nbVuAttbapYXpS2dPiIhIUIgIjcj0PnXLY1hIWFphp1JhpfLsp0x4mWyvZ5y6CA8JL2iYAc3bKz72\nAElA9ZOuVwd2Frbz6OhoevbsmWXoRURE5GQPtn8QKJpKkM1Pae71Pr0tNjaWnj17Eh0d7bU+vTrS\nYK09YYxZAnQFUqcsTMr7Vwvb/7hx4zQ9ISIiHul7Vl/6ntXX6/1GhkXmWEAqo8fPf9zr350fqWv+\nMkxPFFq+kwZjTBTQiPRdD6cZY1oC+6y1W4GXgIkpyUPqlssywESvRCwiIuJHhVkLGOgKMtJwNjAX\nsCl/xqZcnwT0s9ZOMcZUBUbhpiWWAd2ttbsLG2zq7gntmBARkaIWYkIoHVaaIyeOAKQdz937TPf7\np0mVJqzZu4ZTypzC7qNZf8V1qFugtf9ek7qTotjsnvAV7Z4QERFfS0hK4J/D/1D/lfpc1ugypveZ\nzrHEY4SHhBMaEsqJpBMkJCUQHhpOqacyL7CMGxaXqf6DP2n3hIiISBGLCI1I25qZmgBEhkWm3Q8P\nDSc8NOsuivCQ8GKTMHib6mWKiIjkIHU03tfHahdXAZU0aMuliIj4Uu3ytbm91e08f/Hzuba7vsX1\naa+Ly/kVRbHlUmsaRERECmndvnVp1SIjwyKJfyLezxGl8+aahuKRDomIiASJYJ7KUNIgIiJSSBlH\n7YvL9ERRCKjdE6rTICIixVGd8nWoXLoy++L38cblb/g7HEB1GrSmQUREJJ+0pkFERER8TkmDiIiI\neERJg4iIiHhECyFFRESCkBZCaiGkiIhIvmghpIiIiPickgYRERHxiJIGERER8YiSBhEREfGIdk+I\niIgEIe2e0O4JERGRfNHuCREREfE5JQ0iIiLiESUNIiIi4hElDSIiIuIRJQ0iIiLiESUNIiIi4hHV\naRAREQlCqtOgOg0iIiL5ojoNIiIi4nNKGkRERMQjShpERETEI0oaRERExCNKGkRERMQjShpERETE\nI0oaRERExCNKGkRERMQjShpERETEIyojLSIiEoRURlplpEVERPJFZaRFRETE55Q0iIiIiEeUNIiI\niIhHlDSIiIiIR5Q0iIiIiEeUNIiIiIhHlDSIiIiIR5Q0iIiIiEeUNIiIiIhH/JY0GGOuMMasNsb8\nbYy5019xiIiIiGf8kjQYY0KBsUAXoC3wqDGmkj9i8YfY2Fh/h+BVep7iK5ieBfQ8xVkwPQsE3/N4\ni7VY02AAAAiWSURBVL9GGs4B/rTW7rTWxgHfAN38FIvPBdt/jHqe4iuYngX0PMVZMD0LBN/zeIu/\nkoZawPYM77cDtf0Ui4iIiHgg30mDMaaTMWaqMWa7MSbZGNMzmzaDjDEbjTHxxpgFxph23glXRERE\n/KUgIw1RwDLgXiDLudrGmBtx6xVGAq2B5cB3xpiqGZrtAOpkeF875ZqIiIgUU2H5/YC1dgYwA8AY\nY7JpEg28ba2dnNJmANAD6Ae8kNJmEXC6MaYmcBi4FBiVy9dGAqxatSq/4RZLBw8eZOnSQh1pXqzo\neYqvYHoW0PMUZ8H0LBBcz5Phd2dkYfsy1mYZLPD8w8YkA1dba6emvA8HjgLXpV5LuT4RqGCtvSbD\ntStwIxIGeN5a+34u33Mz8HGBAxUREZE+1tpPCtNBvkca8lAVCAV2nXR9F9A04wVr7TRgmof9fgf0\nATYBxwoXooiISIkSCdTH/S4tFG8nDUXCWrsXKFR2JCIiUoL94o1OvL3lcg+QBFQ/6Xp1YKeXv0tE\nRER8yKtJg7X2BLAE6Jp6LWWxZFe8lOWIiIiIf+R7esIYEwU0wi1gBDjNGNMS2Get3Qq8BEw0xizB\n7ZKIBsoAE70SsYiIiPhFvndPGGMuAOaStUbDJGttv5Q29wKP4KYllgH3W2sXFz5cERER8Zd8T09Y\na+dZa0OstaEn/emXoc2b1tr61trS1toOhUkYgqW6pDFmmDFmkTHmkDFmlzHmS2NME3/H5Q3GmMdS\nqoO+5O9YCsoYU8sY86ExZo8x5qgxZrkxpo2/4yoIY0yIMWa0MWZDyrOsM8Y86e+4POVh1dlRxpgd\nKc/3vTGmkT9izUtuz2KMCTPGPG+MWWGMiUtpMymlfk2x5Mm/mwxtx6e0ecCXMeaHh/+tNTfGfGWM\nOZDy72mhMaZOdv35U17PYoyJMsa8bozZmvL/m7+MMffk93v8djS2JzysLhkoOgGvAecCFwPhwExj\nTGm/RlVIKUlcf9y/m4BkjKkI/AwcB7oDzYGHgf3+jKsQHgPuwVVtbYYb9XvEGHOfX6PyXF5VZx8F\n7sP9d3cOcAT3cyHCl0F6KLdnKQO0AmJwP9+uwW1N/8qXAeZTrv9uUhljrsH9rNueU5tiIq//1hoC\nPwErgc7AmcBoiufW/7z+3YzDHQx5M+7nwjjg9ZSaSZ6z1hbbP8AC4JUM7w2wDXjE37F54dmqAsnA\n+f6OpRDPUBb4G7gIN2X1kr9jKuBzPAfM83ccXnyer4F3T7r2OTDZ37EV4FmSgZ4nXdsBRGd4Xx6I\nB27wd7z5fZZs2pyN24FWx9/xFvR5cMcCbMEl3xuBB/wda0GfB4jFTb37PT4vPMsfwBMnXVsMjMpP\n38V2pCGlumRbYHbqNeuechbQwV9xeVFFXDa4z9+BFMIbwNfW2jn+DqSQrgQWG2OmpEwdLTXG3OXv\noArhF6CrMaYxQMpC5Y7AdL9G5QXGmAZADTL/XDgELCS4fi4c8HcgBZGyW24y8IK1NqDr/qc8Sw9g\nrTFmRsrPhgXGmKv8HVsB/QL0NMbUAjDGXAg0Jp8Fn4pt0kDu1SVr+D4c70n5j/FlYL61dqW/4ykI\nY8xNuKHVYf6OxQtOAwbiRk26AW8BrxpjbvFrVAX3HPBfYLUxJgG3Dfpla+2n/g3LK2rgfqkG48+F\nUrh/d//f3v2EWFlGcRz/nhpJCtqZq0iGSJBoTF2JjtqfRTIUtKk2IlIgiuZCUCEhCBHGMIthVuWm\niGgwhaA2IcgggoqSpIKKYoq66A9BM4GZx8V5Rm+3Gee57ww+9739PvDC3DuXuefhnffc8z7/7pfu\n/mfpeCraCtx094HSgUyDJ4je1C1Ewf0ysB/4xsyWlgysog3AWeBqygvfAevd/XArf6QWO0J2oEFg\nHnH3VztpEtAe4CWPvTnq7iHgqLtvT49/NLNngbXA5+XCquwNYtzyTWIsdj7wsZldc/c6tqfjmVkX\nMEQUROsKh1OJmS0ENhLzMzrB2E31AXf/JP18yswWE7lhuExYlW0k5pn0EcNHvcBgygvZvcXtXDR0\n5O6SZjYArASWuvv10vFUtBCYBZxIvSYQvUK9abLdI2koqS6uExV4o7PA6wVimQ79wE53H0qPT5vZ\nHKJXqO5Fww1ibtNs/t3bMBs4WSSiKWooGJ4EXqhxL8MSIi9cuZcWeBjYbWab3L27WGTV/ALcYvzc\nUKsbPjObCewgvmDy+/T0T2b2PLAZyC4a2nZ4wjtwd8lUMLwGrHD3n0vHMwU/ELOI5wM96TgOfAH0\n1KxggFg5MbfpubnA5QKxTIdHiYK70W3a+HrP5e6XiMKhMS88TtxB1S4vNBQM3cCL7l7XFTsQcxme\n415O6CEmrfYTq5JqJX0GHeO/ueEZ6pcbZqSjOS/8Q4t5oZ17GqCDdpc0s0HgLeBVYMTMxnpQ/nD3\ndly+MyF3HyG6ve8ysxHg15pOfvoIOGxm24CviQ+gt4F3ikZV3bfAe2Z2FTgNLCCunU+LRpXJJt91\ndg/RvgvEN99+QKyqarulivdrC9HDtY8ovvuAGQ154bd2HPrLODe/N73+b+CGu59/sJHmyWjPLuAr\nMxsmVoi9QpyrZSXivZ/J2mJmh4APzWwDUfQsB1YBm1p6o9JLQzKWjqwjEsNfwBFgUemYKrbjNlHV\nNR+rSsc2Te07SE2XXKb4VwKngFHig3ZN6Zim0JbHiIL7ErGHwXliL4Cu0rFlxr9sgutlb8Nr3ifu\nYkeJ2d9Pl4671bYAT43zu7HHvaVjr3puml5/kTZecpn5v7YaOJeupRNAX+m4q7SFmNj5GXAlteUM\n8G6r79PyNtIiIiLy/1T7MU4RERF5MFQ0iIiISBYVDSIiIpJFRYOIiIhkUdEgIiIiWVQ0iIiISBYV\nDSIiIpJFRYOIiIhkUdEgIiIiWVQ0iIiISBYVDSIiIpJFRYOIiIhkuQOSSAB4bUsNPwAAAABJRU5E\nrkJggg==\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "image/png": "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\n", - "text/plain": [ - "" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "for i, (d, a) in enumerate(dye_combinations):\n", - " t, fd0 = donor_decays[d]\n", - " p.semilogy(t, fd0)\n", - " t, fda = fret_decays[i]\n", - " p.semilogy(t, fda)\n", - " p.show()" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python [default]", - "language": "python", - "name": "python2" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.12" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/notebooks/simulate_decays_for_structure.ipynb b/notebooks/simulate_decays_for_structure.ipynb deleted file mode 100644 index 01cb722..0000000 --- a/notebooks/simulate_decays_for_structure.ipynb +++ /dev/null @@ -1,555 +0,0 @@ -{ - "cells": [ - { - "cell_type": "code", - "execution_count": 1, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "C:\\atlastin\n" - ] - } - ], - "source": [ - "cd C:\\atlastin" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "%matplotlib inline" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "from collections import OrderedDict\n", - "import mfm\n", - "from mfm.fluorescence.fps.dynamic import Sticking, Dye, ProteinQuenching, DiffusionSimulationParameter, \\\n", - " DiffusionSimulation\n", - "from mfm.fluorescence.simulation.dye_diffusion import DyeDecay, DecaySimulationParameter, FRETDecay\n", - "from mfm.fitting.models.tcspc.tcspc import FretParameter\n", - "from mfm.fitting.optimization import solve_nnls\n", - "import numpy as np\n", - "import itertools\n", - "import os\n", - "mfm.verbose = False\n", - "\n", - "\n", - "def simulate_fret_decays(donors, acceptors, decay_parameter, \n", - " simulation_parameter, donor_quenching, acceptor_quenching,\n", - " fret_parameter, save=True, directory=\"./\", \n", - " dye_combinations=None, donor_decays=None):\n", - " donor_keys = donors.keys()\n", - " acceptor_keys = acceptors.keys()\n", - " fret_decays = list()\n", - " \n", - " distances = list()\n", - " eff = list()\n", - " if dye_combinations is None:\n", - " dye_combinations = itertools.product(donor_keys, acceptor_keys)\n", - " \n", - " for donor_key, acceptor_key in dye_combinations:\n", - " print \"Simulating: %sD-%sA\" % (donor_key, acceptor_key)\n", - " fn = directory+file_prefix+\"_FRET-%sD-%sA_\" % (donor_key, acceptor_key)\n", - "\n", - " donor = donors[donor_key]\n", - " acceptor = acceptors[acceptor_key]\n", - "\n", - " donor_diffusion_simulation = DiffusionSimulation(donor,\n", - " donor_quenching,\n", - " simulation_parameter)\n", - " donor_diffusion_simulation.update()\n", - "\n", - " acceptor_diffusion_simulation = DiffusionSimulation(acceptor,\n", - " acceptor_quenching,\n", - " simulation_parameter)\n", - " acceptor_diffusion_simulation.update()\n", - " if save:\n", - " donor_diffusion_simulation.save(filename=fn+\"_D_diff.xyz\", mode='xyz', skip=10)\n", - " acceptor_diffusion_simulation.save(filename=fn+\"_A_diff.xyz\", mode='xyz', skip=10)\n", - "\n", - " fret_sim = FRETDecay(donor_diffusion_simulation, acceptor_diffusion_simulation,\n", - " fret_parameter, decay_parameter)\n", - " fret_sim.update()\n", - " decay = fret_sim.get_histogram()\n", - " decay = np.vstack(decay)\n", - " if save:\n", - " np.savetxt(fn + \"-dRDA.txt\" , fret_sim.dRDA.T)\n", - " #np.savetxt(fn +\"-decay.txt\" , decay.T, fmt=\"%i\", delimiter=\"\\t\")\n", - " fret_decays.append(decay)\n", - " distances.append(np.histogram(fret_sim.dRDA, bins=np.linspace(0, 150, 150), density=True))\n", - " donor_decay = donor_decays[donor_key][1]\n", - " print donor_decay\n", - " #print sum(donor_decay)\n", - " eff.append( 1. - sum(decay[1])/sum(donor_decay))\n", - " return fret_decays, distances, eff\n", - "\n", - "\n", - "def simulate_decays(dyes, decay_parameter, simulation_parameter, quenching_parameter, save_decays=False,\n", - " directory=\"./\"):\n", - " dye_decays = OrderedDict()\n", - " quantum_yields = list()\n", - " for dye_key in dyes:\n", - " \n", - " dye = dyes[dye_key]\n", - " diffusion_simulation = DiffusionSimulation(dye,\n", - " quenching_parameter,\n", - " simulation_parameter)\n", - " try:\n", - " diffusion_simulation.update()\n", - " #diffusion_simulation.save('%sD_diffusion.xyz' % dye_key, mode='xyz', skip=5)\n", - " av = diffusion_simulation.av\n", - " #av.save('%sD' % dye_key)\n", - "\n", - " fd0_sim_curve = DyeDecay(decay_parameter, diffusion_simulation)\n", - " fd0_sim_curve.update()\n", - " decay = fd0_sim_curve.get_histogram()\n", - " qy = fd0_sim_curve.quantum_yield\n", - " print \"%s\\t%s\" % (dye_key, qy)\n", - " filename = \"Donor-%s.txt\" % dye_key\n", - " decay = np.vstack(decay)\n", - " if save_decays:\n", - " np.savetxt(directory+filename, decay.T, fmt=\"%i\", delimiter=\"\\t\")\n", - " except ValueError:\n", - " decay = np.ones(10)\n", - " \n", - " dye_decays[dye_key] = decay\n", - " quantum_yields.append(qy)\n", - " \n", - " return quantum_yields, dye_decays" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Simulation parameters" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "There are two PDBs of hGBP1. Both PDBs are coarse grained models of hGBP1. In the coarse model the sidechains are stripped. Instead of the stripped sidechain are pseudo atom was placed at the center of mass of the side-chain. The program identifies the type of the sidechain by the name of the amino-acid. In one PDB the names of the natural amino-acids were used. In the second PDB the names of the natural quenchers (TYR, TRP, HIS, MET) were replaced by ALA.\n", - "\n", - "Given the PDB-files now a new structure object is generated and the simulation parameters are set." - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Input\n", - "-----\n" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "pdb_file = './crystal/4idn_fixed.pdb' # C2\n", - "#pdb_file = './crystal/3q5d_fixed.pdb' # C1\n", - "#pdb_file = './crystal/3q5e_fixed.pdb' # C3\n", - "file_prefix = 'C2_'\n", - "directory = './tmp/'# This directory is used for saving\n", - "\n", - "diffusion_coefficient_donor = 7.5 # A2/ns\n", - "diffusion_coefficient_acceptor = 4.0 # A2/ns\n", - "r_qd_quench = 3.0 + 5.5 # Distance below the Donor is quenched\n", - "\n", - "rs = [0.2, 0.3, 0.38-0.2, 20] # sum should amplitudes should be 0.38 (0.4) anisotropy spectrum, amplitude, rotational time (interleaved) b1, rho1, b2, rho2, ....\n", - "acs = [1.0, 1.5] # This is the lifetime spectrum of the acceptor (interleaved)\n", - "\n", - "# Residue numbers for the attachment of the dyes\n", - "donor_labeling_positions = list(set([176, 401, 301, 393, 301, 339, 13, 401, 176, 339, 305, 401, 10, 339, 289, 339, 301, 382, 13, 397]))\n", - "acceptor_labeling_positions = list(set([176, 401, 301, 393, 301, 339, 13, 401, 176, 339, 305, 401, 10, 339, 289, 339, 301, 382, 13, 397]))\n", - "\n", - "# These are the FRET-pairs which are going to be simulated (first position D, second A)\n", - "dye_combinations = [\n", - " [176, 401], [301, 393], [301, 339], [13, 401], [176, 339], [305, 401], [10, 339], [289, 339], [301, 382], [13, 397],\n", - " [401, 176], [393, 301], [339, 301], [401, 13], [339, 176], [401, 305], [339, 10], [339, 289], [382, 301], [397, 13]\n", - "]\n", - "\n", - "dye_combinations = [\n", - " [13, 401],\n", - " [401, 13]\n", - "]\n" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "structure = mfm.Structure(pdb_file)\n", - "tau0 = 4.1\n", - "forster_radius = 52.0\n", - "kappa2 = 0.667\n", - "\n", - "fret_parameter = FretParameter(tau0=tau0,\n", - " forster_radius=forster_radius,\n", - " kappa2=kappa2)" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Donor" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "donor_chains = [' ']*len(donor_labeling_positions)\n", - "\n", - "donor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=1.0,\n", - ")\n", - "\n", - "donor_sticking = Sticking(structure, donor_quenching,\n", - " sticky_mode='surface',\n", - " slow_radius=8.5,\n", - " slow_fact=0.1) # Stas-paper Dye-MD (roughly 10%)\n", - "\n", - "donor_dyes = dict(\n", - " [\n", - " (pos,\n", - " Dye(donor_sticking,\n", - " attachment_residue=pos,\n", - " attachment_chain=chain,\n", - " attachment_atom='CB',\n", - " critical_distance=r_qd_quench, # 3.0 Ang von AV + 6.0 Ang only C-beta quench (so far best 5.0 + 3.0)\n", - " diffusion_coefficient=diffusion_coefficient_donor, # Stas-paper (Dye-MD 30 A2/ns)\n", - " av_radius=3.0,\n", - " av_width=2.5,\n", - " av_length=21.5, # 20 + 5 = 3.5 + 21.5\n", - " tau0=4.2)\n", - " )\n", - " for pos, chain in zip(donor_labeling_positions, donor_chains)\n", - " ]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Acceptor" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "#acceptor_labeling_positions = [18, 254, 577 , 344, 481, 496, 525, 540, 577]\n", - "\n", - "acceptor_chains = [' ']*len(donor_labeling_positions)\n", - "acceptor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=0.8)\n", - "\n", - "acceptor_sticking = Sticking(structure, acceptor_quenching,\n", - " sticky_mode='surface',\n", - " slow_radius=8.5,\n", - " slow_fact=0.1) # Stas-paper Dye-MD (roughly 10%)\n", - "acceptor_quenching = ProteinQuenching(structure,\n", - " all_atoms_quench=False,\n", - " quench_scale=0.8)\n", - "acceptor_dyes = dict(\n", - " [\n", - " (pos,\n", - " Dye(donor_sticking,\n", - " attachment_residue=pos,\n", - " attachment_chain=chain,\n", - " attachment_atom='CB',\n", - " critical_distance=0.0, # The acceptor dye does not have to be quenched setting this to zero speeds up calulation\n", - " diffusion_coefficient=diffusion_coefficient_acceptor,\n", - " av_radius=3.5,\n", - " av_width=2.5,\n", - " tau0=1.0)\n", - " )\n", - " for pos, chain in zip(acceptor_labeling_positions, acceptor_chains)\n", - " ]\n", - ")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "# Simulation" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## Donor-decay" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "Now the simulation parameters are set." - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": true - }, - "outputs": [], - "source": [ - "simulation_parameter = DiffusionSimulationParameter(t_max=30000,\n", - " t_step=0.016)\n", - "decay_parameter = DecaySimulationParameter(decay_mode='photon', #curve or photon\n", - " n_photons=20.0e6,\n", - " n_curves=250000,\n", - " tac_range=(0, 16.666624 + 0.004069),\n", - " dt_tac=0.004069)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "289\t0.945020413509\n", - "401\t0.868100716598\n", - "393\t0.937943723771\n", - "10\t0.979737843729\n", - "301\t0.934255643574\n", - "13\t0.860857583413\n", - "176\t0.816218850376\n", - "305\t0.90661802463\n" - ] - } - ], - "source": [ - "quantum_yields, donor_decays = simulate_decays(donor_dyes, decay_parameter, simulation_parameter, donor_quenching, directory=directory)\n", - "with open(os.path.join(directory, file_prefix+'d0_qy.txt'), 'w') as fp:\n", - " fp.write('Donor position\\tQY\\n')\n", - " for i, dk in enumerate(donor_decays):\n", - " fp.write(\"%s\\t%.3f\\n\" % (dk, quantum_yields[i]))" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "import pylab as p\n", - "for k in donor_decays:\n", - " p.semilogy(donor_decays[k][0], donor_decays[k][1], label='%s' % k)\n", - "p.legend()\n", - "p.show()" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "def vm_rt_to_vv_vh(t, vm, rs, g_factor=1.0, l1=0.0, l2=0.0):\n", - " \"\"\"Get the VV, VH decay from an VM decay given an anisotropy spectrum\n", - "\n", - " :param t: time-axis\n", - " :param vm: magic angle decay\n", - " :param rt: anisotropy spectrum\n", - " :param g_factor: g-factor\n", - " :param l1:\n", - " :param l2:\n", - " :return: vv, vm\n", - " \"\"\"\n", - " rt = np.zeros_like(vm)\n", - " for i in range(0, len(rs), 2):\n", - " b = rs[i]\n", - " rho = rs[i+1]\n", - " rt += b * np.exp(-t/rho)\n", - " vv = vm * (1 + 2.0 * rt)\n", - " vh = vm * (1. - g_factor * rt)\n", - " vv_j = vv * (1. - l1) + vh * l1\n", - " vh_j = vv * l2 + vh * (1. - l2)\n", - " return vv_j, vh_j\n", - "\n", - "for dk in donor_decays:\n", - " t, vm = donor_decays[dk], donor_decays[dk]\n", - " vv, vh = vm_rt_to_vv_vh(t, vm, rs)\n", - " z = np.ones_like(vm)\n", - " np.savetxt(os.path.join(directory, file_prefix+'D0_%s_vv_vh.txt' % dk), np.vstack([vv,vh, z, z]).T, fmt=\"%i\", delimiter=\"\\t\")" - ] - }, - { - "cell_type": "markdown", - "metadata": {}, - "source": [ - "## FRET-decay" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "dye_combinations = [\n", - " [176, 401], [301, 393], [301, 339], [13, 401], [176, 339], [305, 401], [10, 339], [289, 339], [301, 382], [13, 397],\n", - " [401, 176], [393, 301], [339, 301], [401, 13], [339, 176], [401, 305], [339, 10], [339, 289], [382, 301], [397, 13]\n", - "]\n", - "fret_decays, distance_distributions, transfer_eff = simulate_fret_decays(donor_dyes, acceptor_dyes, \n", - " decay_parameter, \n", - " simulation_parameter, \n", - " donor_quenching, acceptor_quenching, fret_parameter, \n", - " dye_combinations=dye_combinations,\n", - " donor_decays=donor_decays,\n", - " directory=directory)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "\n", - "\n", - "def scale_acceptor(donor, acceptor, transfer_efficency):\n", - " s_d = sum(donor)\n", - " s_a = sum(acceptor)\n", - " scaling_factor = 1. / ((s_a / transfer_efficency - s_a) / s_d)\n", - " scaled_acceptor = acceptor * scaling_factor\n", - " return donor, scaled_acceptor\n", - "\n", - "def da_a0_to_ad(t, da, ac_s):\n", - " \"\"\"Convolves the donor decay in presence of FRET directly with the acceptor only decay to give the\n", - " FRET-sensitized decay ad\n", - " \"\"\"\n", - " a0 = np.zeros_like(da)\n", - " for i in range(len(ac_s) / 2):\n", - " a = ac_s[i]\n", - " tau = ac_s[i + 1]\n", - " a0 += a * np.exp(-t / tau)\n", - " ad = np.convolve(da, a0, mode='full')[:len(da)]\n", - " ds = da.sum()\n", - " return ad\n", - "\n", - "for i, dk in enumerate(dye_combinations):\n", - " d, a = dk\n", - " t, fd0 = donor_decays[d]\n", - " t, fda = fret_decays[i]\n", - " fad = da_a0_to_ad(t, fda, acs)\n", - " tr = transfer_eff[i]\n", - " fda, fad = scale_acceptor(fda, fad, tr)\n", - " fda_vv, fda_vh = vm_rt_to_vv_vh(t, fda, rs)\n", - " fad_vv, fad_vh = vm_rt_to_vv_vh(t, fad, rs)\n", - " np.savetxt(os.path.join(directory, file_prefix+'FRET_%sD-%sA_vv_vh.txt' % (dk[0], dk[1])), \n", - " np.vstack([fda_vv,fda_vh, fad_vv, fad_vh]).T,\n", - " fmt=\"%i\", delimiter=\"\\t\")\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "with open(os.path.join(directory, file_prefix+'tr.txt'), 'w') as fp:\n", - " fp.write('Dye-pair\\ttransfer\\n')\n", - " for i, dk in enumerate(dye_combinations):\n", - " fp.write('%sD-%sA\\t%.3f\\n' % (dk[0], dk[1], transfer_eff[i]))\n" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [ - "for i, (d, a) in enumerate(dye_combinations):\n", - " t, fd0 = donor_decays[d]\n", - " p.semilogy(t, fd0)\n", - " t, fda = fret_decays[i]\n", - " p.semilogy(t, fda)\n", - " p.show()" - ] - } - ], - "metadata": { - "anaconda-cloud": {}, - "kernelspec": { - "display_name": "Python [default]", - "language": "python", - "name": "python2" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 2 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython2", - "version": "2.7.12" - } - }, - "nbformat": 4, - "nbformat_minor": 0 -} diff --git a/notebooks/top500_quenching.ipynb b/notebooks/top500_quenching.ipynb deleted file mode 100644 index c04455b..0000000 --- a/notebooks/top500_quenching.ipynb +++ /dev/null @@ -1,61 +0,0 @@ -{ - "worksheets": [ - { - "cells": [ - { - "cell_type": "code", - "metadata": {}, - "outputs": [ - { - "output_type": "stream", - "stream": "\\\\psf\\Home\\Documents\\ChiSurf\\devel\n", - "text": [ - "\\\\psf\\Home\\Documents\\ChiSurf\\devel\n" - ] - } - ], - "input": [ - "cd \\\\psf\\Home\\Documents\\ChiSurf\\devel" - ], - "language": "python", - "prompt_number": 3 - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "import mfm\n", - "from mfm.fluorescence.fps.dynamic import Sticking, Dye, ProteinQuenching, DiffusionSimulationParameter, \\\n", - " DiffusionSimulation\n", - "from mfm.fluorescence.simulation.dye_diffusion import DyeDecay, DecaySimulationParameter, FRETDecay\n", - "from mfm.fitting.models.tcspc.tcspc import FretParameter\n", - "from mfm.fitting.optimization import solve_nnls, maxent\n", - "import numpy as np\n", - "import itertools\n", - "import pylab as p\n", - "\n", - "mfm.verbose = False" - ], - "language": "python" - }, - { - "cell_type": "code", - "metadata": {}, - "outputs": [], - "input": [ - "" - ], - "language": "python" - } - ] - } - ], - "cells": [], - "metadata": { - "name": "", - "signature": "sha256:8a5f9637f1dc498b9d75df265ffc19d5ff769fae1fff099ef5b0d1613c8b30c1" - }, - "nbformat": 3, - "nbformat_minor": 0 -} \ No newline at end of file diff --git a/okf/architecture/index.md b/okf/architecture/index.md new file mode 100644 index 0000000..de54311 --- /dev/null +++ b/okf/architecture/index.md @@ -0,0 +1,7 @@ +# Architecture + +* [Package layout](package-layout.md) - Where each kind of code lives in `quest/`, and the rule that decides it: a module's directory says what *kind* of thing it is, its name says *which*. A prefix like `structure_fetch` is a directory that was never created. +* [Simulation pipeline](simulation-pipeline.md) - The three stages every run goes through: accessible volume, Brownian diffusion in that volume, photon/decay generation — and where each stage lives in the code. +* [Project schema](project-schema.md) - The project-JSON contract shared by the CLI, the API, the web UI and the GUI, and the parameter catalog that documents it. +* [Surfaces](surfaces.md) - The four user-facing surfaces (Python API, CLI, web UI, Qt GUI) and the rule that they are thin wrappers over one service layer. +* [Job artefacts](job-artefacts.md) - What a run writes to `jobs//`, and why bulk work turns it off. diff --git a/okf/architecture/job-artefacts.md b/okf/architecture/job-artefacts.md new file mode 100644 index 0000000..ca53bab --- /dev/null +++ b/okf/architecture/job-artefacts.md @@ -0,0 +1,58 @@ +--- +type: Architecture +title: Job artefacts +description: What a run writes to jobs//, and why bulk work turns it off. +resource: quest/core/ +tags: [outputs, mrc, csv, jobs, performance] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: quest-core + resource: ../../quest/core/ + title: quest/core/ + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# A run is a directory + +`simulate_project` mints a UUID per run and writes everything under +`/jobs//`. `project_dir` defaults to the current working +directory, which is why a repo-root `jobs/` folder accumulates during +development (it is git-ignored; the web backend keeps its own under +`QUEST_WEBUI_DATA_DIR`). + +| File | Content | +|---|---| +| `project.json` | The exact project dict that produced the run — the run is reproducible from it | +| `result.json` | Scalars and curves: quantum yields, lifetime, contact fraction, AV/contact volumes, FRET efficiency, `aa_residence` | +| `decay.csv` | Time axis and donor (and FRET) counts | +| `results.csv` | The scalar metrics in tabular form | +| `aa_residence.csv` | Per-residue-type contact and quenching breakdown | +| `av.mrc`, `acv.mrc` | Accessible volume and accessible **contact** volume as density grids | +| `diffusion_coefficients.mrc`, `quenching_rates.mrc` | The per-voxel physics grids, when present | +| `sampled_dye_density.mrc` | Where the trajectory actually went, voxelised | +| `out.xyz`, `out_slow.xyz` | AV / slow-AV point clouds | +| `trajectory.npy` | The raw walk | + +The `.mrc` writer is hand-rolled in `quest/core/simulation.py` (`write_mrc`) — a 1024-byte +MODE 2 header plus float32 data, with the origin in words 50–52 so the grid +lands on the structure in a molecular viewer. + +# `save_outputs=False` is a real optimisation, not a flag + +`simulate_project(..., save_outputs=False)` skips the whole directory *and* the +thinned point clouds. For a residue scan — which reads only the scalar metrics +and `aa_residence` — the artefacts dominate the runtime and nothing ever reads +them. Both `quest scan` and the web `/api/scan` use it. Anything that loops over +sites should too. + +Note that `save_outputs` also drives `save_avs` in the project dict, so the AV +point clouds are not written either. + +# Consequence for the viewer + +Because the full clouds stay on disk, what travels through `result.json` to a 3D +viewer is *thinned* (`trajectory_display_points`, default 2000). A viewer that +needs the full cloud reads the `.xyz`/`.mrc` files from the job directory. diff --git a/okf/architecture/package-layout.md b/okf/architecture/package-layout.md new file mode 100644 index 0000000..2affca5 --- /dev/null +++ b/okf/architecture/package-layout.md @@ -0,0 +1,122 @@ +--- +type: Architecture +title: Package layout +description: Where each kind of code lives in `quest/`, the rule that decides it, and the two naming habits that produced the mess this replaced. +resource: quest/ +tags: [layout, architecture, packaging, naming] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-28T20:00:00Z } +stale_after: 2027-01-28 +sources: + - id: quest + resource: ../../quest + title: quest/ + author: human:tpeulen + last_modified: 2026-07-28 +okf_check_paths: false # cites names that were deliberately never created +--- + +# The rule + +**A module's directory says what kind of thing it is; its name says which +thing.** If you find yourself putting the kind in the *name* — `structure_fetch`, +`structure_info` — the directory is missing. + +```text +quest/ + api.py the facade: verbs, over a client (LAY-04) + cli.py Click commands -> the facade + manifest.json identity, entry points, RPC methods, state schema + + project.py the project schema: template, validate + scan.py simulating a set of labelling sites + runs.py run *artefacts* on disk + tasks.py *running* work: jobs, progress, cancellation + i18n.py locales + + core/ the domain. Qt-free, host-free, no job bookkeeping + simulation.py the pipeline, `simulate_project` + dye_diffusion.py the walk and the quenching model + av.py accessible volumes and the grid kernels + photon.py the photon trace + io.py xyz/MRC writers + fps_json.py the fps.json format + structure/ everything about a structure + fetch.py where one comes from: path, PDB ID, bytes + reader.py -> QuEst's atom array (IMP parses) + model.py the `Structure` object and coarse-graining + metadata.py what is in it: chains, residues, atoms + + rpc/ the service layer + contract.py identity, error codes, the serialization boundary + dispatcher.py the envelope and the in-process client + services.py the method table and its handlers + + gui/ the Qt surface, rendered from the parameter catalog + hosts/ reaching sibling checkouts, neither installed + imp_tricks.py splices `IMP.bff` in from source + chisurf.py splices ChiSurf in from source + settings/ parameter catalog, dye presets, locales +``` + +# What this replaced, and why it was worse + +Until 2026-07-28 the top level was flat and the *names* carried the structure: + +| was | is | +|---|---| +| `quest/structure_fetch.py` | `quest/core/structure/fetch.py` | +| `quest/structure_info.py` | `quest/core/structure/metadata.py` | +| `quest/core/structure.py` | `quest/core/structure/model.py` | +| `quest/core/pdb.py` | `quest/core/structure/reader.py` | +| `quest/imp_tricks.py` | `quest/hosts/imp_tricks.py` | +| `quest/chisurf_host.py` | `quest/hosts/chisurf.py` | +| `quest/backend/` | `quest/rpc/` | + +Two habits produced it, and both are worth naming so they are not repeated. + +**A prefix is a directory that was never created.** `structure_fetch`, +`structure_info`, `core/structure` and `core/pdb` were four aspects of one +subject, split across two packages, with a naming convention that *implied* the +relationship the layout denied. "Where does a structure come from" had no single +answer, and `core/pdb.py` did not even carry the prefix — it read mmCIF too. + +**A suffix that means "the other side of a bridge" hides a pair.** +`imp_tricks.py` and `chisurf_host.py` do the same job — splice a sibling +checkout onto the import path — and looked unrelated. They are `hosts/` now, and +a third bridge has an obvious home. + +`backend/` → `rpc/` is the smaller change and is about matching what already +exists elsewhere: ChiSurf plugins use `rpc/services.py`, QuEst's own ChiSurf +plugin uses `rpc/services.py`, and `manifest.json` calls the entry point +`services`. "Backend" also meant three other things in this project — the *AV* +backend, the *web* backend, the *transport*. + +# The seams this preserves + +Renaming did not move any boundary, and must not: + +- **`core/` has no Qt, no host, and no job bookkeeping.** It takes plain data + and callables — `should_cancel` is a predicate, not a `Job` + ([subsystems/tasks.md](/subsystems/tasks.md)) — so the domain never learns + what is driving it. +- **`hosts/` is optional in every direction.** Each bridge returns empty or + `False` with no checkout, and QuEst runs standalone. +- **`rpc/` is where serialization *stops*.** Handlers return native objects; a + transport converts ([specs/programme-2026-07.md](/specs/programme-2026-07.md), + decision 7). +- **One structure seam.** A caller says *what* to label, never *how to read it* + ([specs/structure-io.md](/specs/structure-io.md)). + +# Where new code goes + +- Something the science does → `core/`, and if it is about structures, + `core/structure/`. +- A new RPC method → `rpc/services.py`, plus `manifest.json`, plus the ChiSurf + plugin's copy of the method table (a test enforces all three). +- A new **parameter** → `settings/parameter_catalog.json`, then regenerate the + docs and the Qt view spec — **and edit the web UI by hand**, which is the one + surface the catalog does not reach. See the trap in + [handover.md](/handover.md). +- Reaching another checkout → `hosts/`. +- Anything Qt → `gui/`, never `core/`. diff --git a/okf/architecture/project-schema.md b/okf/architecture/project-schema.md new file mode 100644 index 0000000..695bbac --- /dev/null +++ b/okf/architecture/project-schema.md @@ -0,0 +1,109 @@ +--- +type: Specification +title: Project schema +description: The project-JSON contract shared by every QuEst surface, and the parameter catalog that documents it. +resource: quest/cli.py +tags: [schema, project, json, parameters] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: quest-cli-py + resource: ../../quest/cli.py + title: quest/cli.py + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# One document, every surface + +A QuEst **project** is a plain JSON object. The CLI, the Python API, the web UI +and the Qt GUI all read and write the same document — there is no second format +and no per-surface variant. `quest template [--with-fret]` emits a valid +starter; `quest validate -p project.json` checks one. Both live in +`quest/cli.py` (`_template_project`, `_validate_project`). + +# The document + +```jsonc +{ + "tau0": 4.2, // unquenched donor lifetime, ns + "n_photons": 500000, // photons to collect (photon mode) + "t_max": 16000.0, // diffusion duration, ns + "t_step": 0.032, // diffusion time step, ns + "dg": 0.5, // AV grid spacing, Angstrom + "critical_distance": 8.5, // fallback dye-centre -> quencher radius, A + "slow_radius": 8.5, // stickiness radius around a residue, A + "av_parameter": {"linker_length": 21.5, "linker_width": 0.5, "radius1": 3.5}, + "amino_acid_interactions": { "TRP": {"kQ": …, "quench_radius": …, + "quench_atoms": [...], "slow_factor": …}, … }, + "pdb": "structure.pdb", // path, or a bare 4-character RCSB PDB ID + "attachment": {"chain": "A", "residue": 1, "atom": "CB"}, + "n_bins": 4096, // TAC histogram bins + "parallel_trajectories": -1, // -1 = all cores + "coarse_grained": false, + "random_seed": null, // set for reproducible runs + "decay_mode": "photon", // or "curve" (+ n_curves / dt_tac / n_tac) + "save_avs": false, + "output_file": "out", + "fret": { + "enabled": true, + "dyes": [ {"name": "donor", "D": 7.5, "attachment": {...}, + "av_parameter": {...}, "slow_radius": …, + "amino_acid_interactions": {...}}, + {"name": "acceptor", "D": 7.5, "attachment": {...}, "av_parameter": {...}} ], + "R0_matrix": [[null, 5.5], [5.5, null]] + } +} +``` + +**Required top-level keys** (enforced by `validate`): `tau0`, `n_photons`, +`t_max`, `t_step`, `dg`, `critical_distance`, `av_parameter`, +`amino_acid_interactions`, plus a structure (`pdb` or an override) and at least +one entry in `fret.dyes` carrying a diffusion coefficient `D`. + +# Units: Ångström and nanoseconds, everywhere + +Every length in a project is in **Ångström** — linker geometry, dye radii, +`critical_distance`, `slow_radius`, the grid spacing `dg`, and the Förster radii +in `fret.R0_matrix`. Every time is in **nanoseconds** (`tau0`, `t_max`, +`t_step`), and diffusion coefficients are Ų/ns. + +`R0_matrix` is the one that has bitten: the transfer rate goes as `(R0/r)^6`, so +a Förster radius entered in nanometres is ten times too small and FRET +disappears without an error. `quest/project.py` exposes the template value as +`DEFAULT_FORSTER_RADIUS = 52.0` with the unit stated, and +`tests/test_fret_units.py` pins it. + +# Two rules that keep it coherent + +- **The donor is `fret.dyes[0]`, always** — even when `fret.enabled` is false. + That is where `D`, and optionally a per-dye `slow_radius`, + `amino_acid_interactions`, `av_parameter`, `random_seed` and `coarse_grained` + live. Top-level values are the fallback; the dye entry wins where both exist + (see `build_donor_from_project`). +- **Dotted paths address everything.** The CLI's `--set a.b.c=value` and + `--grid a.b.c=v1,v2` walk the same dotted path into the document, which is why + nesting stays shallow and predictable. New keys should keep that property. + +# The parameter catalog is the single source of truth for help text + +`quest/settings/parameter_catalog.json` maps each dotted parameter id to its +label, category, type, unit and description. It feeds: + +- the web UI's field labels and help badges, +- `doc/parameters.md`, which is **generated** by `doc/generate_parameter_docs.py` + and must never be hand-edited, and +- the `/api/parameter-catalog` endpoint. + +Changing a parameter's meaning means editing the catalog and regenerating the +doc **in the same change** — see +[workflows/change-tracking.md](/workflows/change-tracking.md). + +# Dye presets + +`quest/settings/dye_repository.json` holds per-dye starting values (`tau0`, `D`, +`av_parameter`, `slow_radius`, and a full `amino_acid_interactions` table) for +Alexa488, Alexa594, Cy3, Cy5 and Atto488. The web UI serves them at `/api/dyes` +and can append user dyes there. They are **starting values to be calibrated**, +not constants — see [references/pet-quenching-theory.md](/references/pet-quenching-theory.md). diff --git a/okf/architecture/simulation-pipeline.md b/okf/architecture/simulation-pipeline.md new file mode 100644 index 0000000..af72e50 --- /dev/null +++ b/okf/architecture/simulation-pipeline.md @@ -0,0 +1,110 @@ +--- +type: Architecture +title: Simulation pipeline +description: The three stages of a QuEst run — accessible volume, Brownian diffusion, photon generation — and where each lives. +resource: quest/core/ +tags: [simulation, accessible-volume, brownian-dynamics, monte-carlo] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-02-06 +sources: + - id: quest-core + resource: ../../quest/core/ + title: quest/core/ + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# The three stages + +Every QuEst run — from the CLI, the API, the web UI or the GUI — is the same +three-stage pipeline, orchestrated by +[`simulate_project`](/subsystems/core-api.md) in `quest/core/simulation.py`. + +## 1. Accessible volume (where the dye can be) + +The dye is a sphere on a flexible linker. Given the attachment atom +(chain/residue/atom) and the linker geometry (`linker_length`, `linker_width`, +`radius1..3`), the set of sterically reachable dye-centre positions is +enumerated on a cubic grid of spacing `dg`. + +Two further grids are derived from it, both in `AV.calc_slow_av`: + +- a **slow-factor grid** — near-surface voxels where the dye diffuses more + slowly because of unspecific stickiness, and +- a **k_quench grid** — the per-voxel PET quenching rate, summed over every + residue whose contact sphere covers that voxel. + +Code: [subsystems/accessible-volume.md](/subsystems/accessible-volume.md) +(`quest/core/av.py`, which now owns both the grid kernels and the IMP.bff +backend that used to live in `lib/imp_av.py`). + +## 2. Brownian diffusion (where the dye goes) + +A single long random walk of `t_max / t_step` steps is run *inside* the AV, with +the local diffusion coefficient taken from the slow-factor grid, so the dye +lingers where it sticks. The walk is a numba kernel (`_simulate_traj_grid` / +`_simulate_traj`) and reflects at the AV boundary. + +The trajectory is the object everything downstream reads: quenching is evaluated +per frame, and the residue-resolved contact statistics are run-length analyses +over the same frames. + +Code: [subsystems/dye-diffusion.md](/subsystems/dye-diffusion.md). + +## 3. Photons and the decay (what the experiment would see) + +Walking the trajectory with an excited-state clock produces the fluorescence +decay. Each frame contributes a de-excitation rate `1/tau0 + k_quench(frame)`; +photons are drawn until `n_photons` are collected (photon mode) or the decay +histogram is integrated directly over many curves (curve mode). + +Code: [subsystems/photon-decay.md](/subsystems/photon-decay.md). + +**Stage 0, implicitly: the structure arrives without water.** `read` strips +every residue named as water after the IMP parse, and `structure_metadata` +filters the PDB text it hands a viewer, so no stage below ever sees an `HOH` — +and no surface can offer one as a labeling site +([subsystems/structure-io.md](/subsystems/structure-io.md)). + +Verified against the tree on 2026-08-10 (paths re-checked by symbol, not +recalled): `calc_slow_av` and the `_simulate_traj` / `_simulate_traj_grid` +kernels are in `quest/core/av.py`, `_photon_rate_walk` in +`quest/core/photon.py`, `get_histogram` in `quest/core/dye_diffusion.py`, and +`simulate_project` in `quest/core/simulation.py` with `save_outputs` and +`render_data` as separate keyword-only parameters. The three-stage structure is +unchanged by the `quest/lib` -> `quest/core` move; only the file names were. + +# What comes out + +A [`DecaySimulationResult`](/subsystems/core-api.md): the decay curve, the donor +quantum yield and mean lifetime, the contact fraction, AV/contact volumes, the +optional FRET channel, the thinned trajectory and point clouds a 3D viewer +needs, and `aa_residence` — the per-residue-type breakdown of contact time and +quenching contribution described in +[subsystems/quenching-model.md](/subsystems/quenching-model.md). + +Two flags control how much of that a caller gets, and they are **separate on +purpose**: + +- `save_outputs` — write the job directory (`result.json`, `.mrc` volumes, + `.xyz` clouds, CSV tables) under `jobs//`. +- `render_data` — build the thinned trajectory, autocorrelation and point + clouds that a plot or a 3D viewer consumes. + +They used to be one flag, which conflated *write files?* with *return something +to draw?*. The Qt form passes `save_outputs=False` so an interactive run does not +litter the working directory, and silently lost its trajectory, AV and +autocorrelation plots along with it. A residue scan wants neither and passes +both `False`: thinning point clouds nobody reads, once per residue, is the +overhead the fast path existed to avoid. + +# Two invariants worth keeping + +- **One trajectory, many read-outs.** The decay, the contact fractions, the + residence statistics and the autocorrelation all derive from the *same* walk. + Anything that re-simulates to answer a second question is a bug waiting to + disagree with itself. +- **The grids carry the physics.** Stickiness and quenching are properties of + *voxels*, not of a per-frame distance loop. A new interaction term belongs in + `calc_slow_av`, next to the others. diff --git a/okf/architecture/surfaces.md b/okf/architecture/surfaces.md new file mode 100644 index 0000000..a8184ad --- /dev/null +++ b/okf/architecture/surfaces.md @@ -0,0 +1,102 @@ +--- +type: Architecture +title: Surfaces +description: The four user-facing surfaces and the rule that each is a thin wrapper over one service layer. +resource: quest/api.py +tags: [api, cli, webui, gui, layering] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-02-06 +sources: + - id: quest-api-py + resource: ../../quest/api.py + title: quest/api.py + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# One service layer, four front ends + +``` + CLI web backend Qt GUI notebooks + (quest/cli.py) (webui/backend) (quest/gui/) (quest.api) + \ | | / + \________________|________________|________________/ + | + quest.api (the verbs) + | + quest.rpc (client + registry) + | + quest/core/ + | + DonorDecay / SimulateDiffusion / AV / photon kernels +``` + +`quest/api.py` is a **verb facade over an RPC client**, not a re-export shim: +`simulate`, `scan`, `template`, `validate`, `describe` and the data verbs all go +through `quest.rpc`, so every surface exercises one registry, one validation +path and one set of error codes ([subsystems/core-api.md](/subsystems/core-api.md)). +It still re-exports the domain names for notebooks. `quest/core/` is where the +logic lives. + +> This page describes the tree as it is. The **target** is the +> core/rpc/api/cli/gui split adopted from the ChiSurf plugin contract — +> [specs/plugin-integration.md](/specs/plugin-integration.md) — with the current +> divergences itemised in [specs/assessment.md](/specs/assessment.md). QuEst is +> also embedded in ChiSurf as its `quenching_estimator` plugin, which today +> reaches only the Qt widget. + +# The layering rule + +A surface parses input, calls the service layer, and formats output. Simulation +logic does not live in a surface. Two consequences that have already been paid +for: + +- **The validation rules live in `quest/project.py`**, and every surface + enforces those. The backend imports `quest.api`, `quest.rpc` and + `quest.runs`; the CLI's `_validate_project` is a thin wrapper that only + translates `ProjectValidationError` into a `ClickException`. (Until + 2026-07-28 the backend borrowed the CLI's own `_validate_project` and + `_template_project` -- the same guarantee, reached the wrong way round.) +- **The Qt widget owns no simulation state.** + `TransientDecayGenerator` is a `QWidget` around a `ProjectFormModel` whose + `model.project` is a plain project dict at all times, so the form edits the + same document the CLI and the API consume. It used to *inherit* `DonorDecay`, + which shared one model at the price of a widget that was also a simulation. + +New behaviour therefore lands in `quest/core/` first, and the surfaces expose +it. A feature that exists only in the web UI is a design error. + +# The surfaces + +| Surface | Entry | Notes | +|---|---|---| +| Python API | `from quest.api import …` | Documented in [subsystems/core-api.md](/subsystems/core-api.md); safe in headless environments | +| CLI | `quest simulate/scan/template/validate/gui` | [subsystems/cli.md](/subsystems/cli.md) | +| Web UI | FastAPI + Next.js (+ Electron shell) | [subsystems/webui.md](/subsystems/webui.md) | +| Qt GUI | `cs.quest`, `quest gui` (`quest.gui:start_gui`) | Needs a Qt binding and a ChiSurf checkout to render the form — [subsystems/gui.md](/subsystems/gui.md) | + +# Qt is optional, and the layout is what keeps it that way + +Qt is imported in nine files and **every one of them is under `quest/gui/`**: +`app.py`, `autoform_panel.py`, `chimol_widget.py`, `dye_widget.py`, +`form_model.py`, `guided_tour.py`, `plots.py`, `quencher_widget.py`, +`theme.py`. Nothing in `quest/core/`, `quest/rpc/`, the CLI or the web backend +touches it. (This concept said "exactly three files" until 2026-08-10 — the +count grew with the viewer, the tour and the plots; the rule it was standing +for did not change, which is why a *rule* is the durable claim and a count is +not.) + +`form_model.py` is on that list only through two function-local +`from qtpy import QtWidgets` calls in its file dialogs, so importing the model +still pulls in no Qt — the subprocess guardrail in `tests/test_form_model.py` +asserts exactly that, and `tests/test_service_layer.py` asserts the same for +`quest.api` / `quest.rpc` / `quest.core`. + +That is a stronger guarantee than the one this concept used to describe -- +`try`/`except qtpy` with dummy widget bases inside `core/av.py` and +`core/dye_diffusion.py`, which no longer import Qt at all. The rule is now +structural: **Qt lives in `quest/gui/` and nowhere else**, which is what lets +the CLI, the API and the web backend run in an interpreter without a binding. + +Verified against the tree on 2026-08-10. diff --git a/okf/handover.md b/okf/handover.md new file mode 100644 index 0000000..aa4b5e9 --- /dev/null +++ b/okf/handover.md @@ -0,0 +1,275 @@ +--- +type: Handover +title: Session handover +description: Where the tree stands, what the 2026-07 programme has closed, what is left, and the traps that cost time — written to be the first thing a fresh session reads after the index. +resource: okf/log.md +tags: [handover, state, open-questions] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-28T18:00:00Z } +stale_after: 2026-10-28 +--- + +# Read this, then [`specs/programme-2026-07.md`](specs/programme-2026-07.md), then [`log.md`](log.md) + +**2026-08-10 — everything below is now committed, and `.gitignore` was hiding +three frontend sources.** The AutoForm migration and the desktop viewer work +described here as "landed" were all uncommitted modifications; they are five +commits now (`74d7421`, `c79ec26`, `c31e3d2`, `7170f58`, `30fae2c`), each +re-verified rather than trusted. **`lib/` in `.gitignore` was unanchored and +also matched `webui/frontend/src/lib/`**, so `autoformPaths.ts`, +`parameterCatalog.ts` and `projectHelpers.ts` had never been committed and the +frontend could not be built from a clean clone — fixed by anchoring `/lib/`. +The library baseline is **706 passed, 1 skipped** — 695 after the sweep, plus +the eleven tests that came with the desktop-run and CI work below. Nothing is +pushed. + +**2026-08-09 — the web UI is AutoForm-only, and the previous headline +baselines changed.** The legacy hand-written React form was deleted from +`webui/frontend/src/components/AppLayout.tsx`; AutoForm (backed by the same +`/api/autoform-spec` JSON the desktop renders through ChiSurf) is unconditional, +with only a JSON overlay toggle remaining. The scan residue picker moved into +`webui/frontend/src/app/scan/page.tsx`. A real **web AutoForm bug** was fixed +en route: the flat `attr` names in the view spec never matched the nested +project schema, so FRET never seeded its acceptor and several fields wrote keys +the backend rejected — see `webui/frontend/src/lib/autoformPaths.ts`. + +Final baselines (measured 2026-08-09): **693 passed, 1 skipped** (library + Qt ++ backend) and **54 passed** (browser e2e, Playwright). Both browser failures +that were open on 2026-08-08 (tour cross-page navigation, FRET simulation 500) +are **closed** — the 500 was the acceptor-seeding bug above. + +**2026-08-06 — the bundle is now OKF v0.2, and every path in it was re-checked +against the tree.** The migration added the frontmatter families, `sources`, +`okf_version: "0.2"`, a vendored validator, and two new concepts +([subsystems/tasks.md](subsystems/tasks.md), +[references/okf-format.md](references/okf-format.md)). + +It also **reopened `known-issues.md`**, which had been empty since 2026-07-28: +the bundle was still describing the pre-refactor tree — `quest/lib/`, +`quest/core.py`, `quest/jobs.py`. Every path has since been corrected against a +`grep` for the symbol, and `overview.md`'s source-layout table was rebuilt. What +was *not* re-read is the prose, so four concepts were marked unverified on +purpose — `subsystems/core-api.md`, `subsystems/structure-io.md`, +`architecture/surfaces.md`, `architecture/simulation-pipeline.md` — because each +describes *where things live* and every one of those places moved. + +> **All four were read against the code on 2026-08-10 and are verified.** Three +> were already correct (every symbol resolved by `hasattr`, including the names +> they claim are *gone*); `architecture/surfaces.md` was the one that had rotted +> — it said Qt was imported in "exactly three files" where there are nine, all +> still under `quest/gui/`, so the rule held and the count did not. The two +> surface concepts, [subsystems/webui.md](subsystems/webui.md) and +> [subsystems/gui.md](subsystems/gui.md), were *not* on that list and were the +> genuinely stale ones; they are corrected too. + +Re-check any time, from this repo alone: + +```bash +python3 okf/references/tools/okf_validate.py okf --version 0.2 \ + --check-paths "quest/,webui/,tests/,doc/" +``` + +**The baseline is 0 warnings without `--check-paths`** (no concept is stale) +**and 20 with it** (re-measured 2026-08-10) -- every one a sentence that names a +path *because it is gone*. More than 20 means something new rotted. The sentence +below about `known-issues.md` having no open entry was true on 2026-07-28 and is +not now. + +**Nothing is pushed.** A thirteen-phase +programme was agreed by interview on 2026-07-28 and **twelve of its thirteen +phases are done** (seventeen commits in `quest`, two in `imp-tricks`, one in +`chisurf`). **Every `LAY-*` row is closed, on both sides.** + +**Phase 12 is closed as "not doing it": imp-tricks stays local.** The owner +ruled publication out on 2026-07-28, reversing the interview decision. Nothing +in the code is waiting on it — the consequence is CI, below. The decisions behind it — and +the three places they *reverse* what this bundle used to assert — are in +[specs/programme-2026-07.md](specs/programme-2026-07.md). Read that before +proposing work in these areas; several "obvious" next steps there have already +been evaluated and rejected with reasons. + +# State + +All in `arm64`. **The base environment is retired** — one interpreter now runs +everything ([workflows/environment.md](workflows/environment.md)). + +| | tests | +|---|---| +| library + Qt GUI + web backend, one command | **706 passed, 1 skipped** | +| notebooks + examples (`-m notebooks`) | **16 passed, 2 skipped** | +| browser e2e (Playwright, both servers up) | **54 passed** | +| ChiSurf `quenching_estimator` | **14 passed** | +| notebooks + examples (`-m notebooks`, cold cache) | **16 passed** | +| imp-tricks `tests/bff` | **201 passed, 24 skipped, 5 failed** — the 5 predate all of this | + +Library row measured 2026-08-10 (re-measured after the desktop-run change), browser row 2026-08-09; the rest last measured +on 2026-07-28 and unchanged since. + +**Numbers moved twice, and both are re-baselined in `tests/baselines/`.** If you +are comparing against anything computed before 2026-07-28, read the phase 3 and +phase 4 entries in [log.md](log.md) first — the grid registration and the +residue identity were both wrong, on both backends. + +# Done: phases 0–7 + +| # | Commit | What | +|---|---|---| +| 0 | `b979744` | Run artefacts opt-in and out of the checkout (39 GB / 2870 dirs deleted); `-m notebooks` fixed; `quest/utils.py` deleted | +| 1 | `d394efc` | One `arm64` environment; base retired; optional-dependency fallbacks tested by simulated absence | +| 2 | `40743de` | Numeric baselines; browser e2e and the ChiSurf plugin verified for the first time in three sessions | +| 3 | `fc80e9c` | **One Ångström↔voxel map.** Two registration defects, both backends | +| 4 | `83bac32` | **Residue identity from IMP** — `(chain, res_id, insertion_code)`. Closes `DUP-06` | +| 5 | `d9ba940` | κ² stated (`fret.kappa2`, default 2/3, no numeric change); `DUP-03` rejected; `OBJ-02` decided | +| 6+7 | `dae3763`, imp-tricks `3dbefc8` | Upstream `r_mp` and `split_av_acv` fixed; `subav` and `dRmp` adopted; `DUP-02` closed | +| 8 | `4539b22` | **`quest.api` is a facade**; serialization moved to the transport; contract, `error_code` taxonomy, `quest.contract.describe`. Closes `LAY-04` | +| 9 | `82b75d4`, `8218c22` | **One mechanism for long-running work**, cooperatively cancelable; `jobs` (running) split from `runs` (artefacts). Closes `LAY-07` | +| 10 | chisurf `669fce499` | **The plugin declares itself**: manifest, `api`/`rpc`/`cli`/`gui`, no `core/`, a dockable widget, and no `quest` import at ChiSurf startup. Closes `LAY-05`'s ChiSurf half | +| 11 | `0dd0ac5` | i18n gets an end condition: frontend keys must resolve, and the 90-string chrome backlog is a ratchet | +| 13 | `a78709a` | `known-issues.md` pruned 358 → 263 lines; every entry closed, two that asserted the opposite of the truth inverted | + +# Left: phases 12 and 13 + +1. ~~**Phase 12 — publish imp-tricks**~~ — **not doing it.** Everything stays + local by owner ruling (2026-07-28). The recipe is written + (`~/dev/imp-tricks/rattler-recipe/recipe.yaml`, `noarch: python`) and the + version is deliberately still `0.1.0`, to be decided at release. If that ever + changes: publish to anaconda.org (`tpeulen`) and PyPI, then pin the version + in `pixi.toml` and `rattler-recipe/recipe.yaml` in place of the current `*`. + + **The two red CI jobs are fixed (2026-08-10), without publishing anything.** + `default` and `desktop` were unsolvable because the `py` feature required + `imp-tricks`, which no channel serves — and, it turned out, also `labellib`, + whose numpy-2 builds are on the **`dev` label** of the `tpeulen` channel + rather than its root. `pixi lock` now solves all four environments. What it + cost is stated rather than hidden: a pixi environment cannot compute an + accessible volume, so **141 tests skip there with that reason and ~550 still + run**. Details in [workflows/environment.md](workflows/environment.md) and + [workflows/testing.md](workflows/testing.md). + + | CI job | environment | state | + |---|---|---| + | `test` | `default` (`py` + web + test) | **solves; ~550 tests, 141 skipped** | + | `gui` | `desktop` (`py` + gui + web + test) | **solves** (the Qt suite skips without ChiSurf, as before) | + | `frontend` | `frontend` (separate solve-group) | green | + | `package` | `build` (`no-default-feature`) | green | + + **Earlier notes said "all four jobs", which is wrong** — `frontend` and + `build` never carry the `py` feature. Corrected 2026-07-28 by reading + `pixi.toml`'s `[environments]` against `.github/workflows/ci.yml`. + + Publishing imp-tricks remains the thing that would make CI cover the + simulation path, and it still needs credentials. + +2. **Phase 13 — the last of the closeout**: rewrite this file once 12 lands. + The prune of [references/known-issues.md](references/known-issues.md) is + done (`a78709a`). + +# A solved trap: the catalog drove a three-place edit + +> **Closed 2026-08-09.** The web form is AutoForm-only now. Previously the Qt form +> was generated from the catalog but the web form was hand-written React, so +> adding a parameter was a three-place edit and the web was the surface that +> fell behind (`fret.kappa2` shipped there on 2026-07-28 with two of three +> surfaces wired). + +**A parameter added to `quest/settings/parameter_catalog.json` now reaches +every surface from one spec.** `quest/gui/quest.view.json` is *generated* from +the catalog; `/api/autoform-spec` serves the same `build_view_spec(locale)`; +the desktop renders it through ChiSurf's AutoForm and the web through +`webui/frontend/src/components/autoform/`. The glue that keeps the web in step +with the project schema is `webui/frontend/src/lib/autoformPaths.ts` (spec +`attr` → nested project path), and `tests/test_autoform_blueprint.py` fails if +the catalog grows a parameter that map does not cover. + +Adding a parameter is now a **one-place** edit (the catalog) with the mapping +table the one follow-up, not three hand-synchronised surfaces. + +# Still open, needing a decision + +- ~~**What to do about the two permanently red CI jobs**~~ — **done + 2026-08-10**, by the first of the three options: `imp-tricks` is a pixi + feature no environment uses, and the tests that need it skip with a stated + reason (141 of them). The accounting it was said to cost is in + [workflows/testing.md](workflows/testing.md). +- **Where ChiSurf's fps.json `payload.py` belongs** (`DUP-07` remainder). The + owner is not convinced `chisurf/core` is right, and **upstream has since ruled + against it**: ChiSurf's own `okf/specs/chimol.md` (2026-08-10, `a2ff49665`) + places the labelling plugin — the `LabelStructure` widget that owns this + payload — **in ChiMOL**, on the grounds that placing a dye on a structure is + structural work done while looking at the structure. It sits in `modelling/` + only until ChiMOL hardens, and **the `fps_json_payload` getter/setter seam is + what the move rides on, so that seam must stay intact.** So the answer is + neither `chisurf/core` nor here; the question is now *when*, not *where*. + Nothing in QuEst depends on it. +- **`asa`/`spherePoints` → `IMP.cgmol.sterics.asa`** (`DUP-05` remainder). Cold + path; deliberately not rushed. +- **The scratch files in the tree**: `out.xyz`, `out_slow.xyz`, `test.pdb`, + `test.cif`, `webui-viewer-testpdb.png`, `tests/sim_test.log`. All gitignored. + `sim_test.log` is cited by a known-issue that has since been corrected. + +# Traps that cost time here + +Ordered by how much. The first four were all learned or corrected on +2026-07-28. + +- **"The tree is clean" is not evidence that the tree is committed.** An + ignored file never appears in `git status`, and `lib/` in `.gitignore` — the + unanchored entry from the standard Python block — matched + `webui/frontend/src/lib/`, so three frontend sources lived only in the + working copy for weeks. Before trusting such a sentence, run + `git status --ignored=matching --untracked-files=all` and read past the + `node_modules`/`.pixi` noise. +- **A view-spec `attr` is not the project path.** The spec names fields by the + flat `ProjectFormModel` attribute (`attachment_chain`, `fret_enabled`, + `fret_R0`), and the project JSON is nested (`attachment.chain`, + `fret.enabled`, `fret.R0_matrix[0][1]`). Reading/writing the flat key silently + produced projects the backend rejected — FRET never seeded its acceptor and + "worked" as a one-dye donor run. The web resolves through + `webui/frontend/src/lib/autoformPaths.ts`; the Qt side has `FIELD_PATHS`. +- **Enabling FRET is not `set fret.enabled = true`.** The acceptor dye and R0 + matrix must be seeded (on the last labelable residue, not a water); a bare + toggle leaves a project that "validates" but cannot transfer. The web routes + the `fret.enabled` field through `setFretEnabled` for this reason. +- **The Next.js dev server takes > 3 s on a cold request**, which was silently + skipping the entire browser suite (the module-scoped `_server_is_up` check). + The timeout is 10 s now; prime the frontend with one request before a run. +- **A styled toggle's real checkbox is hidden** (`.switch input` is + `display:none`), so Playwright's `.click()` on the switch times out + intermittently. Drive the checkbox through its label or `evaluate()`, or use + `.check()` — not a click on the visible `.slider`. +- **Clear *both* numba caches.** `tests/conftest.py` imports ChiSurf, which sets + `NUMBA_CACHE_DIR=~/.chisurf/cache` into `os.environ`, so under pytest numba + reads and writes *there* — not beside the source. The command recorded here + for two days cleared only `quest/**/__pycache__`, and 193 kernels were sitting + in the other directory. Both, every time: + + find quest -name '__pycache__' -type d -exec sh -c 'rm -f "$1"/*.nbi "$1"/*.nbc' _ {} \; + find ~/.chisurf/cache \( -name '*.nbi' -o -name '*.nbc' \) -delete + +- **A reference implementation that copies the code under test is not a + reference.** `tests/test_grid_kernels.py` compared the kernels against a + hand-written version that had copied their `int()`, so it was structurally + unable to see a one-voxel error affecting half the grid. Derive a reference + from the specification. +- **A test that has never been *seen* to fail is not evidence.** Five times now. + The most recent: an upstream test asserted `r_mp == 50.0` and passed only + because the function returned the wrong quantity under that name. +- **Check the bridge was invoked before blaming the other repository.** A probe + written `import quest.hosts.imp_tricks` (the module, without calling + `enable_imp_tricks()`) reported `IMP.bff.av` and `IMP.cgmol` missing, and + "fix the `IMP.cgmol` import" was carried into a work plan as an upstream + defect. There was none. `import quest` alone does not splice; `quest.core`, + `quest.core.av` and `quest.api` do. +- **Do not pass `-p no:pytest-qt`.** It was mandatory while base had no Qt + binding. `arm64` has pytest-qt, and the flag removes the `qtbot` fixture. +- **`Structure(path)` defaults to `make_coarse=True`.** A scratch script + comparing coordinates against a PDB file will look 1.5 Å wrong. +- **uvicorn does not reload.** Restart it before any browser run. Locale files + are `lru_cache`d per process, so editing one has no effect until restart. +- **The frontend needs Node ≥ 20**; `/opt/homebrew/bin/node` is 26, the one on + `PATH` is 18.15 and Next refuses to start. +- **`playwright` must come from pip.** conda-forge's `playwright` is the *Node* + package; installing it leaves `import playwright` failing. +- **Verify that an edit actually applied.** A slice-based deletion here removed + 93 lines of dead kernel *and* the 40-line adapter written minutes earlier; + only the next test run caught it. diff --git a/okf/index.md b/okf/index.md new file mode 100644 index 0000000..8812ee1 --- /dev/null +++ b/okf/index.md @@ -0,0 +1,33 @@ +--- +okf_version: "0.2" +--- + +# QuEst Knowledge Bundle + +An [Open Knowledge Format](https://github.com/GoogleCloudPlatform/knowledge-catalog) +**v0.2** bundle describing the QuEst codebase — the simulation pipeline, its +subsystems, the project-file contract, and the developer workflows. Authored for +agents and humans who need durable context on how this repository is organized. + +This bundle is the project's **persistent memory**: what is learned about the +code, the environment, and the physics is written here rather than left in a +chat log. Start here, not in the source tree. + +The conventions are shared with [FPSIMP](../../fpsimp/okf/index.md), which the +two projects follow so that a reader moving between them finds the same shape — +both are heading for one server. Format, validation and the 2026-08-06 migration +from v0.1: [references/okf-format.md](references/okf-format.md). + +# Concepts + +* [**Session handover**](handover.md) - **Read first.** Where the tree stands, what is uncommitted in both repositories, which decisions are waiting on a human, and the traps that cost time. +* [Overview](overview.md) - What QuEst is, the source layout, and the entry points. +* [Update log](log.md) - The running, dated narrative of what changed and why. + +# Subdirectories + +* [architecture](architecture/index.md) - The three-stage simulation pipeline, the project-JSON contract that every surface shares, and the four user-facing surfaces. +* [subsystems](subsystems/index.md) - The major code areas: core service layer, RPC, tasks, accessible volumes, dye diffusion, the quenching model, photon/decay generation, structure I/O, and the CLI/web/GUI front ends. +* [specs](specs/index.md) - The target architecture — the core/rpc/api/cli/gui split adopted from the ChiSurf plugin contract — and the backlog tracking where today's code diverges from it. +* [workflows](workflows/index.md) - Developer workflows: change tracking (the memory loop), environment, and testing. +* [references](references/index.md) - PET-quenching theory, known issues, the OKF format itself, and pointers to the maintained user documentation. diff --git a/okf/log.md b/okf/log.md new file mode 100644 index 0000000..4d307a9 --- /dev/null +++ b/okf/log.md @@ -0,0 +1,2734 @@ +# Update Log + +## 2026-08-11 + +* **A dependency policy now scopes "prefer depending on `IMP.bff`".** The + owner's rule, set today: *if a simple method is only available inside a complex + package, reimplement the method and A/B it against the reference; do not add + the dependency.* Canonical copy in FPSIMP, + [references/dependency-policy.md](../../fpsimp/okf/references/dependency-policy.md); + [AGENTS.md](../AGENTS.md) records it beside the rule it qualifies. + + It does **not** reopen anything here. The question is asked when a dependency + would be *added*, and QuEst already depends on `IMP.bff` for `compute_av` — + a Dijkstra over a voxel grid, machinery that plainly earns it — so the five + smaller kernels adopted beside it (`density2points`, `random_distances`, + `av_pair_statistics`, `mean_position_distance`, `split_av_acv`) are settled. + The rule binds the next time something new would pull in a new package. It + bites much harder in FPSIMP, which depends on `IMP.bff` for nothing, and where + it has already settled the κ² question against adoption. + + Recorded here too because the two repositories are meant to run the same + rules, and this one reads as a reversal of QuEst's standing instruction if you + meet it without the scoping. + +* **A stale path, noted not fixed.** `quest/hosts/imp_tricks.py` defaults to + `~/dev/imp-tricks/src` and every error message names it, but `IMP.bff` was + handed from imp-tricks to `../imp.bff` on 2026-08-10 and that checkout no + longer contains `IMP/bff/`. The six symbols QuEst imports now resolve only + from an installed or compiled `imp.bff`. Nothing here has broken — the splice + returns `[]` when it finds nothing and the compiled module answers — but the + shim now points at a tree that cannot supply what its name promises. + +* **The sibling link is bidirectional, and both repositories now say + `AGENTS.md`.** FPSIMP kept its agent guidance in `CLAUDE.md` — the same + content under a name only one tool reads — while this repository and + `../imp-tricks` had already moved to the tool-agnostic `AGENTS.md`. FPSIMP + renamed it today, so the family convention is now uniform: a root `AGENTS.md`, + no per-tool instruction file. Two FPSIMP concepts had been citing this + repository's `CLAUDE.md` as a source since our own rename deleted it; they now + cite `AGENTS.md`, and the convention is written down in FPSIMP's + [okf-conventions.md](../../fpsimp/okf/references/okf-conventions.md), which is + the canonical copy of the rule set the two bundles share. + + On this side: [AGENTS.md](../AGENTS.md) now links `../fpsimp/AGENTS.md` and that + conventions concept directly, rather than naming the sibling in prose, and + says which validator copy is canonical. One stale mention in + [specs/programme-2026-07.md](/specs/programme-2026-07.md) named the root + `CLAUDE.md`; it names `AGENTS.md` now, and says the file was called + `CLAUDE.md` when the passage was written — the reversal it records is about + the environments, not the filename, and losing that would make the sentence + read as if a different document had been contradicted. + +## 2026-08-10 + +* **The desktop run is a job, and the window survives it.** `LAY-07` closed on + 2026-07-28 by building `quest/tasks.py`; the desktop went on calling + `simulate_project` on the GUI thread anyway, so the surface that motivated the + mechanism was the one not using it (found by re-reading + [subsystems/gui.md](/subsystems/gui.md) against the code this morning). + + `ProjectFormModel` now has `start_simulation` (registers a job, spawns the + worker, returns the `job_id`), `wait_simulation(timeout)`, `poll_simulation` + and `cancel_simulation`; `run_simulation` is those joined, so the synchronous + contract headless callers depend on is unchanged and there is still only one + code path. **The worker never notifies** — a listener redraws widgets and + that is only safe on the GUI thread — which is why applying the outcome is a + separate call; `test_the_worker_never_notifies` records the thread every + listener fires on. `update_all` pumps the event queue between joins and + ignores re-entrant clicks, which pumping makes possible. + + Two limits are written into the code rather than discovered later. The + trajectory kernels are `njit(nogil=True)` so the GUI thread really does get + the interpreter back during the dominant cost, but the AV grid kernels are + `parallel=True` without `nogil` and still hold it — a smaller freeze, not + none. And cancelling a single simulation cannot interrupt it: `_simulate_traj` + is one `njit` call and a jitted kernel cannot poll a flag, so Cancel discards + the result rather than stopping the work. A scan does stop. + + Also: clicking ▶ on a broken project no longer raises out of the Qt slot; the + failure shows in the status line. `run_simulation()` still raises. + Baseline: **706 passed, 1 skipped** (was 695; 11 new tests). + +* **The two permanently red CI jobs are green, and nothing was published.** + This was the open decision the handover carried; taking it needed a + measurement it did not have. + + **What was actually wrong was two things, not one.** `imp-tricks` was the + known blocker. The second surfaced on the first solve attempt: **`labellib` + is not on conda-forge at all**, and on the owner's channel its `main` label + stops at the 2020 builds — py37-py39, pinning `numpy <2` against this + project's `numpy >=2.0`. The numpy-2 builds live on the channel's **`dev` + label**, for `linux-64`, `osx-arm64` and `win-64` only. So `[feature.py]` + points at `https://conda.anaconda.org/tpeulen/label/dev` and restricts itself + to those three platforms — which is exactly the CI matrix. `imp-tricks` + became a feature **no environment uses**: anything requiring it would take + `pixi lock` down with it. `pixi lock` now solves all four environments. + + **The cost, measured rather than assumed.** Both AV backends dispatch through + `IMP.bff.av`, so "LabelLib is the fallback" never meant QuEst could compute an + accessible volume without imp-tricks — with `IMP_TRICKS_SRC` pointed at + nothing, **98 tests failed and 8 errored**, including the `labellib` + baselines. That correction is now in + [subsystems/accessible-volume.md](/subsystems/accessible-volume.md). + + Turning that into signal took two mechanisms in `tests/conftest.py`, because + the failures arrive two ways: `hookwrapper` hooks rewrite QuEst's own + sentinel message into a skip (most of the suite, no annotations), and + `@pytest.mark.needs_av` marks the tests that *swallow* the error and assert on + a status instead — an envelope's `ok: False`, a CLI exit code, a status line + reading "Failed". **Neither converts anything where imp-tricks is present**, + so a real regression cannot be laundered into a skip. Result without it: + **550 passed, 141 skipped, 0 failed**. Twelve of those skips are over-skip + from marking by module rather than by test, and are recorded as such. + + What CI now covers is the contract, the project schema, the RPC envelopes, + i18n, the view spec and the form model — the layer that changed most this + week. What it does not cover is every number: publishing imp-tricks is still + the only thing that would test the simulation path in CI. + +* **A session's worth of finished work was sitting uncommitted; it is committed + now, in five pieces.** The bundle described the 2026-08-09 AutoForm migration + and the 2026-08-07 desktop viewer work as landed, and the tree held all of it + as modifications. Committed as `74d7421` (gitignore), `c79ec26` (water), + `c31e3d2` (RPC), `7170f58` (web AutoForm), `30fae2c` (click-to-select), each + verified green rather than taken on trust. Re-measured baseline: + **695 passed, 1 skipped** — two more than the 693 the handover recorded, from + tests added after that measurement. + +* **`.gitignore` had been hiding three frontend sources, and the frontend could + not be built from a clean clone.** The standard Python-packaging block + contains an unanchored `lib/`, which also matches + `webui/frontend/src/lib/` — so `autoformPaths.ts` (the fix the 2026-08-09 + entry below is *about*), `parameterCatalog.ts` and `projectHelpers.ts` had + never been committed, in a tree whose history looked clean. The working copy + was the only copy. `/lib/` and `/lib64/` are anchored to the repository root + now; neither directory exists here, so nothing else changed. + + **The general lesson is worth more than the fix: `git status` looks clean + when a file is ignored, so "the tree is clean" is not evidence that the tree + is committed.** `git status --ignored=matching --untracked-files=all` is what + answers the question, and it is cheap to run before trusting a handover + sentence that says everything is committed. + +* **The ZMQ transport did not serialise its results, and had lost an error + code.** `process_message` returned the dispatcher envelope untouched, so a + handler returning a native object (numpy array, `DecaySimulationResult`) + raised inside `json.dumps` and the caller got no reply at all; the transport + is exactly the boundary [the contract](/subsystems/rpc.md) names for + `to_payload`. It converts there now — and only when the envelope *has* a + `result`, since a failure envelope carries none and should not be handed a + null one. `serve_one` also no longer lets an unhandled error kill the poll + loop without replying. + + Separately, both `fail()` call sites had been downgraded from + `invalid_request`/`invalid_payload` to the default `operation_failed`, with + tests written to match. The cause is that `service_error` *validates* codes + against `ERROR_CODES` and neither name was in the table — so the passing test + encoded the workaround. `invalid_request` is in the table now (a malformed + envelope is the caller's fault, not a failed operation, and a host reacts to + it differently), the call sites are restored, and the tests assert the code. + +* **One water filter, not two.** `metadata.py` carried a byte-identical copy of + `reader.strip_water_pdb_text` under a private name; it imports the one + implementation now. Same behaviour, one place to correct it. + +* **The two surface concepts were re-read against the code they describe.** + Step 2 of the loop had been skipped while the surfaces changed underneath + them: [subsystems/webui.md](/subsystems/webui.md) still described a + hand-written React form, a labeling page carrying the FRET panel, a backend + importing the CLI's private helpers, and `data-testid="tour-btn"`; none of + those had been true for a day or more. What is corrected, each verified + against the tree rather than the prose: + + - **The backend route list** was five routes short (`/api/autoform-spec`, + `/api/tour`, `/api/demo-project`, `/api/i18n`, `POST /api/dyes`), and the + paragraph justifying the `quest.cli` private imports describes a coupling + that `LAY-01` removed in phase 8 — `main.py` imports `quest.api`. + - **The sidebar form is generated**, with `lib/autoformPaths.ts` named as + load-bearing and the two fields that bypass `setNested` + (`fret.enabled` → `setFretEnabled`, `fret.R0_matrix.0.1` → + `setForsterRadius`) written down where a reader will meet them. + - **Click-to-select** documented on both surfaces at once, which is the point + of the rule in `AGENTS.md`. + - The **duplicated "Design language" section** (two verbatim copies) is one, + and the browser-suite section carries the AutoForm locators, the 10 s + `_server_is_up` timeout and the hidden-checkbox trap. + + [subsystems/gui.md](/subsystems/gui.md) gains `structure_label` and + `auto_attach_to_structure`, the `ChiMolStructureWidget` embedding, and two + corrections: the file table (nine files, not five), and the retired base + environment, which survived in two sentences — one of them recommending + `-p no:pytest-qt`, which the handover lists as a trap. + + **One finding is a real gap, not a stale sentence.** `gui.md` said the + desktop run was synchronous "— `LAY-07`, still open". `LAY-07` *is* closed: + `quest/tasks.py` owns the one mechanism. But `ProjectFormModel.run_simulation` + still calls `simulate_project` on the GUI thread instead of registering a job, + so the window is unresponsive for the duration of a run and cannot cancel it. + Closing the backlog row gave the desktop a mechanism it does not use. Recorded + in the concept as the current state; not fixed here. + +* **The four concepts the handover had marked unverified since 2026-08-06 are + verified.** They were flagged because the refactor moved everything they + describe and only their *paths* had been corrected, never their prose. Read + against the code: + + - [subsystems/core-api.md](/subsystems/core-api.md) — **clean.** Every symbol + it names resolves (checked with `hasattr` per module, not by eye), and + `DecaySimulationResult`'s dataclass fields match the documented list in + both directions: nothing documented is absent, nothing present is + undocumented. + - [subsystems/structure-io.md](/subsystems/structure-io.md) — **clean**, and + the removal claims hold too: every name it says is *gone* was checked to be + actually absent, since a removal claim rots the same way a presence claim + does. Its water paragraph described one filter where there are three + (`_strip_waters` on the array, `strip_water_pdb_text` on text, + `water_stripped_pdb_path` for a viewer that wants a file); now tabulated. + - [architecture/simulation-pipeline.md](/architecture/simulation-pipeline.md) + — **clean**; every kernel resolves in the module claimed. Gained the + implicit stage 0: the structure arrives water-free. + - [architecture/surfaces.md](/architecture/surfaces.md) — **the one that had + rotted.** It said Qt was imported in "exactly three files"; it is nine + (`autoform_panel`, `chimol_widget`, `guided_tour`, `plots`, + `quencher_widget`, `theme` joined them), *all* still under `quest/gui/`. + The rule survived, the count did not — which is the argument for stating a + rule rather than a census. Also corrected: two sentences asserting the + checked environment has no PyQt5, untrue since base was retired. + + **The lesson is about which concepts get flagged.** The four on the list were + flagged because a refactor had moved their subject matter, and three of them + were fine. The two that were actually stale — `webui.md` and `gui.md` — were + *not* flagged, because nothing structural had moved: the surfaces had simply + changed behaviour while their concepts were left alone. A concept rots when + the code it describes changes, not when the tree is rearranged, and only the + second kind is visible to a path checker. + +## 2026-08-09 + +* **The web UI is AutoForm-only; the legacy hand-written form is gone.** + QuEst's two presentation surfaces now share one declarative view spec — the + desktop renders `quest.view.json` through ChiSurf's AutoForm, and the web + renders the same spec from `/api/autoform-spec` through the React + `components/autoform`. No form is hand-written in either toolkit. + + - `webui/frontend/src/components/AppLayout.tsx` dropped its three-way + `useAutoform ? : !showJson ? : ` ternary and the + AutoForm/JSON toggle pair; AutoForm is unconditional and only the JSON + overlay toggle remains. The whole `
` + legacy block (~540 lines) was deleted, along with the now-dead + `useAutoform` state, `Field`/`HelpBadge`/`getParameterHelp` imports and the + `chainSelectDisabled`/`residueSelectDisabled`/`atomSelectDisabled` vars. + - The scan residue picker + Calculate Scan button moved out of the deleted + sidebar into `webui/frontend/src/app/scan/page.tsx` (a new "Scan Settings" + card above the results), so the scan workflow survives AutoForm-only. + - **Bug fix (web AutoForm): flat `attr` names never matched the nested + project schema.** The view spec names fields by their `ProjectFormModel` + flat attribute (`attachment_chain`, `fret_enabled`, `fret_R0`), but the + project JSON stores `attachment.chain`, `fret.enabled`, + `fret.R0_matrix[0][1]`. The web AutoForm wrote/read flat keys that the + backend rejects. New `webui/frontend/src/lib/autoformPaths.ts` maps every + `attr` to its project path; `AutoSection` resolves through it. The write + path routes `fret.enabled` to `setFretEnabled` (which seeds the acceptor + dye and R0 — a bare `fret.enabled=true` left a one-dye project) and + `fret.R0_matrix.0.1` to `setForsterRadius` (a list cell `setNested` cannot + index). `test_autoform_blueprint.py` keeps the map in step with the catalog. + - **Browser e2e tests rewritten for AutoForm selectors** (`test_webui_e2e.py`): + the `_use_legacy_form` helper is deleted; helpers `_autoform_field` / + `_autoform_input` / `_autoform_check` locate AutoForm fields by label; + tests write chain/residue through the AutoForm number inputs or the JSON + editor; FRET tests toggle `fret.enabled` via the AutoForm checkbox. The + test id for the guide button is `guide-btn` (was `tour-btn`); the + `_server_is_up` timeout is 10 s (a Next.js dev server takes >3 s cold). + - **Two pre-existing baselines fixed along the way:** the i18n hardcoded- + string ratchet dropped 91 → 74 (the legacy form was most of the backlog), + and `test_backend_api.py`'s atom_count updated 1525 → 1385 (water + stripping, same as the earlier `test_runs_and_structure_info.py` fix). + + Baselines: **693 passed, 1 skipped** (library + Qt + backend) and **54 + passed** (browser e2e). The two previously-reported browser failures (tour + cross-page navigation and the FRET simulation 500) were both fixed: the FRET + 500 was the missing acceptor-seeding bug above, and the tour test now passes. + Concept: [specs/autoform-scheme.md](specs/autoform-scheme.md). + +## 2026-08-08 + +* **Plot-population tests for both GUI surfaces: verify the actual curves reach + the canvas, not just the model.** The existing tests checked that the model's + data series (`decay_series()`, `trajectory_series()`, …) were non-empty after + a run — which proves the simulation worked, but not that the user *sees* a + curve. New tests pin the rendering path end-to-end: + + - **PyQt** (`tests/test_gui_simulation.py`, 3 new): + `test_the_pyqtgraph_canvases_carry_curves` inspects the pyqtgraph + `PlotWidget`'s `listDataItems()` after `refresh()` — every canvas (decay, + trajectory, autocorrelation) must hold a curve with real points. + `test_a_fret_run_populates_two_decay_curves` checks the FRET case produces + two curves on the decay canvas. `test_a_screenshot_is_non_blank` grabs the + widget to a pixmap and verifies >10 distinct colours, proving something was + actually painted. + + - **Web** (`tests/test_webui_e2e.py`, 4 new `TestWebPlotsPopulate`): + `test_decay_path_has_coordinates`, + `test_trajectory_path_has_coordinates`, + `test_autocorrelation_path_has_coordinates` verify the SVG `` + elements (`path.donor-line`, `path.trajectory-line`, + `path.autocorr-line`) carry `d` attributes with >5 line segments after a + simulation. `test_plots_are_empty_before_a_run` verifies the empty-state + message shows and no `path.donor-line` exists before any run. + + Also fixed: the `_server_is_up` timeout was 3 s, but a Next.js dev server + takes 4-6 s on first request, causing the entire browser suite to skip. + Raised to 10 s. The `_use_legacy_form` helper now uses `evaluate()` to toggle + the AutoForm checkbox (the styled switch's real checkbox is hidden, so + Playwright's click times out intermittently). + +* **Fixed 5 test failures from in-flight changes and filled ZMQ transport gaps.** + - **Duplicate `pdb` in view spec** (`test_view_spec`): the read-only structure + display in the dock panel was bound to `attr: "pdb"`, same as the file picker. + Added `ProjectFormModel.structure_label` (a derived read-only property showing + the filename) and pointed the dock panel at it. Regenerated all three view + specs. The drift guard (`test_each_scalar_field_appears_exactly_once`) passes. + - **Atom-count baseline** (`test_runs_and_structure_info`): water stripping + changed `atom_count` from 1525 to 1385 and chain E residues from 291 to 164 + (HOH waters removed). Updated the assertion. + - **Missing `web.guide` i18n key** (`test_i18n`): the frontend references + `t("web.guide")` for the Guide button; added to en/de/fr locale files. + - **Missing OKF frontmatter** (`chisurf-autoform-integration.md`): added YAML + frontmatter to satisfy `okf_validate.py`. + - **ZMQ transport gap tests** (6 new in `test_zmq_rpc.py`): `quest.scan`, + `quest.dyes.save`, `quest.runs.get`, `quest.jobs.get` were tested in-process + only; now each has a ZMQ round-trip test. All 16 RPC methods are now covered + on at least two transports. + - **Browser e2e selector fixes** (`test_webui_e2e.py`): the AutoForm toggle + introduced two `.toggle-switch .switch` elements, breaking strict-mode + locators; `tour-btn` testid was renamed to `guide-btn`; tests that need the + hand-written form now call `_use_legacy_form(page)` to switch off AutoForm. + Result: 48 of 50 browser tests pass (was 27 of 50). + + Baseline: **669 passed, 1 skipped** (library + Qt + backend); **48 passed, + 2 failed** (browser e2e — tour cross-page navigation and a FRET simulation + 500, both pre-existing). OKF: 0 errors, 0 warnings without `--check-paths`. + +* **Comprehensive test coverage for the plugin blueprint: all 16 RPC methods, + the ZMQ wire transport, the API facade, and the autoform view-spec contract.** + Four new test files (139 tests total) pin the surfaces that make QuEst a + reusable ChiSurf plugin / webapp / Electron app / standalone PyQt app: + + - `tests/test_rpc_methods.py` (70 tests): every registered RPC method through + the in-process transport — success shape, error shape, JSON serializability, + envelope consistency. + - `tests/test_zmq_rpc.py` (24 tests, replaces the 1-test original): every + read-only method over a real ZMQ REQ/REP socket, the wire protocol (id + echo, unknown method, garbage payload), and `process_message` directly. + - `tests/test_api_facade.py` (25 tests): every public verb on `quest.api` + (`template`, `validate`, `simulate`, `scan`, `describe`, `parameter_catalog`, + `dyes`, `structure_metadata`), the `use_client` swap mechanism, error + propagation, and the native-vs-serialised boundary. + - `tests/test_autoform_blueprint.py` (20 tests): the view-spec generation + pipeline — committed JSON files vs. generated output (drift guard), the + form-model binding contract, and cross-surface consistency (catalog ↔ spec + ↔ project template ↔ TypeScript renderer types). + + **Bug fix in `quest/rpc/zmq_server.py`:** the ZMQ server used + `invalid_request` and `invalid_payload` as error codes, which are not in + `ERROR_CODES`; the resulting `ValueError` crashed the server thread and left + the REQ/REP socket permanently stuck. Fixed to use `operation_failed` (the + generic catch-all), and `serve_one` now catches any unhandled exception and + always sends a reply so the socket pairing never breaks. + + **Bug fix in `quest/rpc/zmq_server.py`:** the server now calls + `to_payload` before `json.dumps`, making it a proper transport per the + contract. Previously it tried to `json.dumps` a native `DecaySimulationResult` + (with numpy arrays), which raises `TypeError`. + + **Expanded `tests/test_webui_e2e.py`:** new `TestApiEndpoints` (11 browser + tests pinning every REST endpoint — health, template, parameter-catalog, + dyes, quenching-defaults, i18n, jobs, autoform-spec), plus + `TestStructureMetadataViaBrowser` and `TestJsonProjectEditor` for the upload + and JSON-editor workflows. + + Baseline with the new suite: **680 passed, 1 skipped** (library + Qt GUI + + web backend). The 6 pre-existing failures are from in-flight changes + (water stripping changed atom_count, view-spec has a duplicate `pdb` field) + and are not introduced by this work. Concept: + [specs/autoform-scheme.md](specs/autoform-scheme.md), + [specs/plugin-integration.md](specs/plugin-integration.md). + +## 2026-08-07 + +* **Water is now explicitly stripped after the IMP parse, as a defensive + guarantee.** `_strip_waters` in `quest/core/structure/reader.py` removes every + atom whose residue name identifies it as water (`HOH`, `WAT`, `TIP3`, `SOL`, + … — see `_WATER_RESIDUE_NAMES`). IMP's default PDB selector already drops + waters, but relying on that alone couples QuEst's correctness to an external + default. The filter runs in `_read_with_imp` and is case-insensitive, + whitespace-tolerant and safe on empty arrays. No numeric change — baselines + are identical because IMP was already stripping. Covered by + `tests/test_water_stripping.py` (10 tests). Concept: + [subsystems/structure-io.md](subsystems/structure-io.md). + +* **Tour is now exhaustive and cross-page; `before` hook drives routing.** + `Tour.tsx` runs `step.before?.()` when a step becomes current and then polls + the target selector up to ~3.5 s before showing a centred card, so a step can + route the app (e.g. to `/simulation`) and spotlight a sidebar panel that only + exists on that tab. `tourSteps.ts` grew from 4 steps to 24, walking the whole + workflow (welcome → PDB → upload → runs → labeling → FRET → AV → viewer → + run → simulation settings/results → scan settings/results → advanced → + JSON/preset/language/theme/cite/download), each routing to the page it + explains via a guarded `navigate` in `AppLayout`. `data-tour` hooks added to + the topbar, toolbar, sidebar and every page. Copy is localized en/de/fr + (`web.tour.*`). `TestTour` now walks through the cross-page routing; 34 browser + e2e and 531 unit/backend tests pass. Concept: [subsystems/webui.md](subsystems/webui.md). + +* **New concept: the declarative form scheme, with QuEst as the blueprint.** + `okf/specs/autoform-scheme.md` documents ChiSurf's AutoForm view-spec JSON + contract (the section vocabulary: panel/value/choice/toggle/table/dynamic + group/custom/plot/dock_area/wizard…, binding by `target`/`attr` string paths, + i18n as a single `tr()` parse seam, and `SettingsView` deriving a form from a + plain dict) and how QuEst generates one spec per language from a single + catalog — the invariant the next app ported from Python to web should copy. + Motivation: an upcoming Python→web port wants a similar scheme to halve + porting effort; QuEst is the working example. Drafted while reading + `chisurf/core/dataspec` and `chisurf/gui/autoform/auto_form.py`; sources are + cross-repo paths, so the concept intentionally documents the sibling contract + rather than quest code. Concept: [specs/autoform-scheme.md](specs/autoform-scheme.md). + +## 2026-08-07 + +* **Web UI gains a guided user tour, built to be shared with FPSIMP.** + `webui/frontend/src/components/tour/Tour.tsx` is a quest-agnostic overlay — + no quest imports, no i18n, pure `steps`/`labels` props — so FPSIMP can reuse + the file unchanged. It locks body scroll, `scrollIntoView`s each target, + measures it and dims everything else with a one-element spotlight (a + transparent box whose `0 0 0 9999px` box-shadow is the mask; no four-pane + cutout), then shows a tooltip card clamped into the viewport, repositioned on + resize/scroll. Keys: Esc closes, ←/→/Enter step. QuEst's shape is + `tourSteps.ts` (`getTourSteps`/`getTourLabels`), targeting `data-tour="…"` + hooks on the tabs, structure panel, labeling panel and the Run button, with + all copy in `web.tour.*` keys across en/de/fr (ratchet flat). Triggered by a + compass button (`data-testid="tour-btn"`) in the topbar. Verified in a real + browser: every step spotlights and stays in-view, Done/Esc close and restore + body scroll. TypeScript clean, i18n **50 passed**, browser e2e **34 passed** + (two new `TestTour` tests). Concept: + [subsystems/webui.md](subsystems/webui.md). + +## 2026-08-07 + +* **Web UI gains a light/dark theme switch.** A sun/moon button + (`data-testid="theme-toggle"`) in the topbar toggles `data-theme` on `` + and persists the choice in `localStorage["quest-theme"]`. Defaults to dark; + an explicit saved value outranks the OS `prefers-color-scheme` (the + `:root[data-theme=…]` blocks are declared after the media query, so they win). + The `button.primary` label-colour rules already had `data-theme` twins, so the + toggle path needed only the control itself — state + effects in + `AppLayout.tsx`, `.theme-toggle` CSS, and the `web.theme_toggle` key in all + three locales. Verified live in a browser: dark on load, flips to light on + click, survives a reload. i18n suite **50 passed**; translation ratchet flat. + Concept: [subsystems/webui.md](subsystems/webui.md). + +## 2026-08-07 + +* **Web UI accent/neutrals modernised — indigo + cool slate.** The first refresh + was too subtle to read as a change; this one changes the palette outright in + the four theme-token blocks plus the two hard-coded hover tints. Accent + `#00706b` teal → `#4f46e5` indigo (dark `#818cf8`), `--accent-2` rust + `#c9502c` → amber `#f59e0b` (dark `#fbbf24`), neutrals warm gray → cool slate + (`--bg #f5f6fa`, `--ink #0f172a`, slate-50/900 family; dark `#0b0f19`), + status cols re-tuned to modern green/red/amber. Hard-coded `#f0f7f7` / + `#fdf5f2` hovers replaced with `--accent-soft` / `color-mix`. Verified live on + the dev server (computed body bg `rgb(245,246,250)`, accent `#4f46e5`) and + suite green after the edit: **32 passed** (browser e2e). CSS-only again; no + class/id/text touched. Concept: [subsystems/webui.md](subsystems/webui.md). + +## 2026-08-07 + +* **Visual refresh of the web UI — denser and a little more modern, CSS-only.** + The stylesheet is the only place the look lives, so the change is confined to + `webui/frontend/src/app/globals.css`; every class name, id and visible string + is untouched because the browser suite pins them. New tokens (`--shadow-lift`, + `--font-ui`, `--accent-ink`) and a `:focus-visible` ring wired to the shared + `--focus` token, a layered (not flat) primary-button gradient and card + shadows, plus a real density pass: app-shell padding 12→8, brand 38→30, title + 22→18, control sidebar 320→296, panel sections 7/9→5/8, section headings + 12→10.5 with letter-spacing. Measured at 1440×900 across all four tabs: body + `scrollWidth == innerWidth` (1440, no horizontal overflow), topbar 38, tab + buttons 23, panel rows 51. Suite unchanged and verified after the edit: **32 + passed** (browser e2e). Concept: [subsystems/webui.md](subsystems/webui.md). + +## 2026-08-07 + +* **The web UI's own panel can overflow its card, and two bare ``s announced by a screen reader as + unlabelled listboxes. + + Fixes, both small and both *seen to fail* first ([workflows/testing.md]): + + 1. `min-width: 0` on `.quench-editor` — the grid item was refusing to shrink + below its content width (`min-width: auto`), so the wide + `quench-table-wrap` scroll container spilled the card instead of scrolling + inside itself. Measured: body `scrollWidth` 674 → 560, table scrolls in its + own 526 px window. + 2. `aria-label` on the dye and run selects. Both go through `t()` with new + `web.dye` / `web.run_select` keys in all three locales, so the + translation-backlog ratchet (90, unmoved) stays flat — a literal + `aria-label="…"` matches the ratchet's regex and would have grown the + count. + + Guards: `TestLayoutAndAccessibility::test_no_inner_container_overflows_its_box` + (parametrised over the four tabs) and `test_the_header_selects_have_accessible_names`. + Suite: **531 passed** (library + web backend), **32 passed** (browser e2e, + the prior 27 plus these 5), **50 passed** (i18n), TypeScript clean. + Concept: [subsystems/webui.md](subsystems/webui.md). + +## 2026-08-06 + +* **Commit cadence is a rule now: one verified piece, one commit.** Stated by + the owner and adopted in both repositories. It compounds with the rule this + bundle already had -- concept and `log.md` bullet in the same change as the + code -- because if that is true, *a commit* is the unit at which the bundle + stays true. Batching breaks it: the code lands and the concept follows later, + or does not. In [workflows/change-tracking.md](workflows/change-tracking.md) + and `CLAUDE.md`. + +* **The bundle moved to OKF v0.2, and the migration caught it describing a tree + that no longer exists.** All 31 concepts now carry `status`, `stale_after` and + `generated` in place of `timestamp`, plus a `sources` entry derived from each + concept's `resource` with that file's last-modified date; the two `# Citations` + lists in [overview.md](overview.md) and + [references/pet-quenching-theory.md](references/pet-quenching-theory.md) moved + into frontmatter `sources`; `okf_version` is `"0.2"`. `generated.by` is + **`process:okf-v0.1-import`** on every migrated concept — not a person and not + a model: v0.1 recorded no actor, and inventing one would corrupt the exact + signal the field exists to carry. Rules, and what v0.2 buys: + [references/okf-format.md](references/okf-format.md). + + **The `sources` step is what exposed the drift.** Deriving a source entry + requires the file to exist — and for seven concepts it did not. `quest/lib/` is + gone entirely, `quest/core.py` is now the package `quest/core/`, + `quest/jobs.py` is `quest/runs.py`, `quest/quest_gui.py` is + `quest/gui/app.py`, `imp_av.py` went into `IMP.bff.av.compute_av`, and + `quest/api/contract.py` is `quest/rpc/contract.py`. Nothing *looked* broken: + the frontmatter parsed, every link resolved, the prose read well. + + **Every path was then corrected against a `grep` for the symbol, not against a + guess** — `write_mrc` and `autocorr` to `core/simulation.py`, `fret_rate_trace` + and `compute_av` to `core/av.py`, `class Structure` to + `core/structure/model.py`, `quest/jobs.py`'s five verbs to `quest/runs.py`'s + renamed ones, `start_gui` to `quest/gui` per `pyproject.toml`. `overview.md`'s + source-layout table was rebuilt from the tree and now ends with the sentence + the refactor amounts to: **`core/` is what the science is; `cli`, `gui`, + `rpc`, `hosts` and `webui` are who is asking.** + + **Four concepts are marked stale on purpose** — `core-api`, `structure-io`, + `surfaces`, `simulation-pipeline` — each carrying `stale_after: 2026-08-06` + and a banner. Their subject *is* where things live, so correcting a path does + not make their mechanism trustworthy; the format now reports them as + unreviewed instead of trusting someone to read a note. The physics concepts + were deliberately **not** marked: the refactor relocated them without changing + what they describe, and marking everything makes the signal worthless. Full + accounting, with the verification behind each substitution: + [references/known-issues.md](references/known-issues.md). + + The check is mechanical, **vendored into this bundle** so it needs no sibling + checkout, and shared with FPSIMP: + `python3 okf/references/tools/okf_validate.py okf --version 0.2 + --check-paths "quest/,webui/,tests/,doc/"`. It exempts `log.md` by name and + honours a new `okf_check_paths: false` key for the two concepts that name dead + paths on purpose. **21 path warnings is the baseline**, and no `STALE` — all of it correct prose + about things that are gone; more than 20 means something new rotted. + Conformance: **0 errors**. + +* **The four stale concepts were re-read and cleared, and one was wrong rather + than merely dated.** `subsystems/structure-io.md` documented a `Structure` + with nine geometry methods -- `rmsd`, `super_impose`, `cluster`, `onRMSF`, + internal-coordinate conversion -- and **not one of them exists**; `reader.py` + was missing four of its seven documented entry points. IMP is the parser now, + `Structure` is a thin accessor over the atom array, and the alignment and + clustering machinery is gone by design (it is exactly what + `imp-tricks-dedup.md` argues against keeping a second copy of). The concept + now names the removals instead of dropping them silently, and records the + measured obstacle policy: ligands count, waters do not, because adding them + costs 17 % of every accessible volume. + + `subsystems/core-api.md` described `quest/api.py` as a re-export shim; since + `LAY-04` it is a verb facade over an RPC client, and that is the whole point + of it -- one registry, one validation path, one set of error codes behind + every surface. `architecture/surfaces.md` had three false claims, all of which + had improved in reality: the backend no longer borrows the CLI's + `_validate_project`, the Qt widget no longer inherits `DonorDecay`, and Qt is + no longer imported in `core/` behind a `try`/`except` -- it lives in exactly + three files under `quest/gui/`, which is a structural guarantee rather than a + defensive one. `architecture/simulation-pipeline.md` was verified and needed + almost nothing: every kernel it names is where it says. + + **The bundle is 0 errors and 0 warnings**; with `--check-paths` it reports 21, +all of them prose naming paths that are deliberately gone -- the new +`structure-io.md` and `core-api.md` add to that count precisely because they now +say what was removed instead of pretending it still exists. + +* **`quest/tasks.py` got the concept that `package-layout.md` had been linking + to all along.** That link was the bundle's only broken one; the module behind + it is the unified job mechanism from `LAY-07` — status vocabulary and + `to_dict()` shaped to match ChiSurf without importing it, cooperative + cancellation with `CANCELLING` deliberately distinct from `CANCELLED` because + a jitted `_simulate_traj` cannot poll a flag, and `canceller`/`reporter` + callables so `quest/core/` never learns what a job is. Written from the + source: [subsystems/tasks.md](subsystems/tasks.md). Recorded there too: + adoption is unfinished — `quest/rpc/services.py` is the only caller and the + web backend still runs its own `ThreadPoolExecutor`, so cancellation stops at + the RPC surface. That vocabulary is also the strongest candidate for the job + model a combined QuEst+FPSIMP server will need, since FPSIMP's states carry no + notion of cancellation at all. + +## 2026-07-28 + +* **Every decay curve was 72 % photons that were never emitted, and the + baselines said so in one number.** `get_histogram` and `get_histogram_fret` + histogrammed the whole photon trace, but `_photon_rate_walk` returns + `dt = 0.0` for a photon lost to quenching or transfer — so the non-emitted + fraction landed in bin 0. Both now count `dts[phs == 1]`, the rule + `simulation.py:1156` already used for the mean lifetime. Consequence: a decay + curve now totals `QY × n_photons` instead of `n_photons`, i.e. it carries + amplitude information for the first time; the plot no longer opens with a + ~300× first-bin spike on the log axis, and the D–A curve's amplitude reflects + the transfer. Reported as ChiSurf review finding **RF-689** (S1). + + **Baselines regenerated — every moved number, and only these** (decision 13): + `donor_counts_total` alone moved, in eight places, and each new value is + `quantum_yield_donor × 4000` to within the 0–1 photon whose lifetime falls + outside the 0–50 ns `tac_range` — + `imp_bff`: E96 4000→339, E129 3999→1327, E139 3999→3275, fret 4000→3955; + `labellib`: E96 3999→290, E129 4000→3878, E139 4000→3959, fret 4000→3783. + No quantum yield, lifetime, efficiency, volume or geometry number moved, + which is the check that the fix touches the histogram and nothing else. + Pinned by `tests/test_decay_histogram.py` (7 tests: the total is the emitted + count, bin 0 holds no quenched photon, a genuine zero-lifetime photon is + still counted, and a lower yield gives a smaller curve). Suite: + 531 passed, 1 skipped. Concept: + [subsystems/photon-decay.md](subsystems/photon-decay.md). + +* **A programme of work was agreed by interview, and it changed three of its own + premises before a line was written.** Scope: every open item in + [handover.md](handover.md) plus `LAY-04`, `LAY-07` and repository hygiene, + across QuEst, imp-tricks and ChiSurf, in thirteen phases with one commit each. + Three decisions are worth recording because they *reverse* what the specs said: + **`OBJ-02` takes the host route** (QuEst contributes a model; ChiSurf's + optimiser drives it — nothing implemented, the decision is the deliverable); + **`DUP-06` is promoted from "record only" to work**, because the coarse-grain + chain bug turned out not to be a one-line fix; and the **base environment is + retired** in favour of `arm64` alone, which reverses "both must stay green". + Full decision list and the questions behind them: + [specs/programme-2026-07.md](specs/programme-2026-07.md). + +* **Three items on that list were mis-scoped in the specs, and reading the code + found it before implementing did.** Recorded now so the phases inherit the + correction rather than rediscovering it: + + - **The half-voxel offset is not a LabelLib problem.** [known-issues] + (references/known-issues.md) described `AV.points` sitting half a voxel off + `AV.density` on the LabelLib path. There are **four** sites and two + conventions, and the trajectory is one of them: `_center_grid_indices` + (`av.py:557`) and `_points_from_centred_grid` (`av.py:265`) use the integer + `(ng-1)//2`, while `_simulate_traj*` (`av.py:801`, `av.py:862`), + `_sample_grid_at_trajectory` (`dye_diffusion.py:604`) and the LabelLib cloud + use the float `(ng-1)/2`. The trajectory pair is *self*-consistent, which is + why nothing caught it — but the grids it samples were stamped by the integer + kernel, so on an even `ng` **the walk reads the quenching and stickiness maps + half a voxel from where the quenchers were placed**, on *both* backends. + `ng` is 86 and 92 on the reference sites: even is the normal case. Which + convention is true is not a toss-up: on the IMP path + `x0 = grid_origin + ((ng-1)//2)·dg`, so voxel *i* sits at + `x0 + (i − (ng−1)//2)·dg` **by construction**. Integer wins; float is simply + wrong about where the voxels are. + - **The coarse-grain chain bug is a residue-identity bug.** known-issues + proposed matching `(chain, res_id)` in `move_center_of_mass`. That is a + symptom: **`residue_dict` itself is keyed on `res_id` alone** + (`structure.py:301`), as is `residue_ids` (`:323`), so chain B's residue 40 + overwrites chain A's atom-by-atom, and everything derived from it — the + CA/CB/C/N/H lookup tables, `sequence`, the dihedrals, which CB a labelling + site attaches to — carries the collapse. `l_residue` is also built in + `residue_dict` order while `move_center_of_mass` indexes it by position in + `residue_ids`: two independently constructed orderings that agree only + because both iterate `set()` of small ints. + - **`DUP-03` cannot be adopted, and κ² cannot be adopted at all.** + `IMP.bff.cgdye.analysis.fret.calculate_fret_exact` takes an `(nd × na)` + distance matrix plus **transition matrices for both dyes** and solves a + Markov kinetic ensemble via `np.kron(p_d, p_a)` — a rotamer-library model, + O((nd·na)²), against QuEst's ~10⁵-point clouds. It is not a slower drop-in, + it is a different model at a different scale. And it does not *compute* κ², + it *accepts* a κ² matrix; the real kernel, + `IMP.bff.cgdye.rotamer.scoring.kappa2_from_vectors`, needs transition dipole + vectors, which QuEst's structureless point-in-a-volume dye does not have. + **κ² is therefore blocked on a missing degree of freedom, not on missing + code**, and `OBJ-01` item 6 closes as *chosen and documented* (isotropic + 2/3, explicit), not as *modelled*. + +* **The package layout is by *kind*, not by prefix.** `quest/` had a flat top + level where the names carried the structure the directories did not: + + | was | is | + |---|---| + | `quest/structure_fetch.py` | `quest/core/structure/fetch.py` | + | `quest/structure_info.py` | `quest/core/structure/metadata.py` | + | `quest/core/structure.py` | `quest/core/structure/model.py` | + | `quest/core/pdb.py` | `quest/core/structure/reader.py` | + | `quest/imp_tricks.py` | `quest/hosts/imp_tricks.py` | + | `quest/chisurf_host.py` | `quest/hosts/chisurf.py` | + | `quest/backend/` | `quest/rpc/` | + + **The rule, now written down** in + [architecture/package-layout.md](architecture/package-layout.md): a module's + *directory* says what kind of thing it is, its *name* says which. A prefix + like `structure_fetch` is a directory that was never created — four aspects of + one subject were split across two packages, and `core/pdb.py` did not even + carry the prefix while reading mmCIF too. Likewise `imp_tricks.py` and + `chisurf_host.py` do the same job (splice a sibling checkout onto the import + path) and looked unrelated; they are `hosts/`. + + `backend/` → `rpc/` is the smaller one and is about matching what exists + already: ChiSurf plugins use `rpc/services.py`, QuEst's own plugin does, and + the manifest calls the entry point `services`. "Backend" already meant three + other things here — the *AV* backend, the *web* backend, the transport. + + **No boundary moved**, which is the point: `core/` still has no Qt, no host + and no job bookkeeping; `hosts/` is still optional in both directions; `rpc/` + is still where serialization stops. 51 files rewritten in QuEst plus 6 in the + ChiSurf plugin, verified across all four surfaces — **531 passed**, 16 + notebooks, 27 browser, 14 plugin. + + Two things the rename surfaced that the rewrite script could not: a layering + test still pointed at `quest/backend/` by path and would have gone quietly + vacuous had it been a glob rather than a list, and `quest/hosts/__init__.py` + needed the *whole* of `imp_tricks`'s public surface re-exported, not the one + name the package doc happened to mention. + +* **The browser suite found what the browser suite could not: κ² never reached + the web UI.** `fret.kappa2` landed in the parameter catalog, the project + template, the domain and the Qt form on 2026-07-28 — and **not** in the web + FRET panel, because that panel is hand-built React rather than generated from + the catalog, so a new parameter does not arrive on its own. Two surfaces had + it, one did not. + + 27 browser tests were green throughout; none of them could have noticed. It + was found by *rendering the panel and looking at it*, which is what + [workflows/testing.md](workflows/testing.md) says to do and the fourth time + this session that rule has paid. + + Fixed in `AppLayout.tsx`, `projectHelpers.ts` and `types/index.ts`, and pinned + by `TestFretPanel::test_the_orientation_factor_is_editable` — **seen to + fail** by deleting the field again. + + **And looking again caught a second thing.** The default rendered as + `0.6666666666666666`, sixteen digits in a spin box. It is displayed to four + figures now while the *stored* value stays exactly `2/3`, because the + neutrality guarantee is `kappa2 / (2/3) == 1` — rounding the stored value + would have quietly moved every FRET number by 5·10⁻⁵. The test asserts both + the value and the rendered *length*. + + The general point, worth more than the fix: **a parameter added to the + catalog reaches the docs and the Qt form automatically, and the web UI never.** + `quest/gui/quest.view.json` is generated; `AppLayout.tsx` is written. Until + the web panel is generated too, every new parameter needs a deliberate third + edit — and nothing fails if it is forgotten. + +* **Phase 12 closed as "not doing it": imp-tricks stays local**, reversing the + interview decision. The recipe is written and the version deliberately left at + `0.1.0`; nothing in the code waits on publication. + + **The recorded consequence was wrong, and overstated.** Both this log and the + handover said declaring `imp-tricks` turns "all four CI jobs red". It is + **two**: `pixi.toml` puts `imp-tricks = "*"` on the `py` feature, and only + `default` and `desktop` carry it, so the `test` and `gui` jobs cannot solve + while `frontend` (its own solve-group) and `package` (`no-default-feature`) + are unaffected. The original note even contained the contradiction — "every + pixi environment in the `py` solve-group … and therefore all four CI jobs" — + and nobody read `[environments]` against `ci.yml` until now. + + **Left unresolved on purpose, and flagged rather than fixed:** two + permanently red jobs are worse than two missing ones, because a light that is + always red gets ignored. Making `imp-tricks` an optional pixi feature would + restore a meaningful signal at the cost of stating plainly what CI then does + *not* cover. That is a decision, not a cleanup. + +* **Phase 13 (part) — `known-issues.md` pruned: 358 lines to 263, and every + entry in it is now closed.** Each fixed entry had accumulated a correction + *in front of* its obsolete original, which meant the wrong text was still the + bulk of the file. The originals are gone; the corrections stay, and so does + the reason each entry is kept rather than deleted — a backend whose faults + each hid the next, a diagnosis that was confidently wrong twice, a "genuine + judgement call" that turned out to have a right answer, a severity rating + that said "has not bitten yet" about something biting every multi-chain + structure. + + Two entries were still *asserting the opposite of the truth*. The + `-p no:pytest-qt` entry is **inverted**, not deleted: passing the flag is now + harmful, and it is still written into `pixi.toml`'s tasks and older notes, so + a reader who finds it there needs to be told. The README entry had been fixed + in phase 0 and never struck. + + What remains open is in [specs/assessment.md](specs/assessment.md) — `DUP-05`'s + `asa` remainder and `DUP-07`'s `payload.py` destination — and both are + decisions rather than defects. + +* **Phase 10 — the ChiSurf plugin declares itself, and stops costing ChiSurf's + startup. `LAY-05` closes on both sides** (chisurf `669fce499`). + + `chisurf/plugins/quenching_estimator/` was a single `__init__.py` with no + manifest, loading through the host's legacy AST discovery. It now follows the + `modelling/fps_json_editor` layout — `manifest.json`, `api/`, `rpc/`, `cli/`, + `gui/` — with **no `core/`**, because QuEst is an installable package and *is* + the core. Nothing in the plugin reimplements anything: + `rpc/services.py` hands ChiSurf's dispatcher to + `quest.rpc.services.register_services` (duck-typed on + `register(name, handler)` for exactly this, so both surfaces run the same + handlers), `api/contract.py` re-exports `quest.rpc.contract`, and + `rpc_methods` is **copied verbatim** from `quest/manifest.json` with a test + that fails if they diverge. + + **Nothing imports `quest` at module scope.** ChiSurf imports every plugin at + discovery, and the old file did `from quest.gui import + TransientDecayGenerator` at the top — so launching ChiSurf pulled in QuEst, + IMP and numba whether or not anyone opened the tool, and a broken QuEst + install became a broken ChiSurf startup. Two tests spawn a subprocess and + assert no `quest.*` or `IMP.*` module is in `sys.modules` after importing the + plugin. **Seen to fail**: restoring the eager import turns both red. + + The GUI is a `ChisurfDockTool` rather than a `QMainWindow` used as a central + widget with a hand-built `File` menu — a window pretending to be embedded. + `quest/gui/` stays in QuEst. + + **Rendering it caught something no assertion would have**: the first toolbar + repeated the embedded form's own *Load project* / *Save project* footer + buttons. It carries only *Load PDB…* now, and a test pins that. This is the + third time the "render it and look at the image" rule in + [workflows/testing.md](workflows/testing.md) has paid for itself. + +* **Phase 11 — i18n gets an end condition instead of a grind.** + + Two guards, both of which had been missing for different reasons. + + **The locale files were checked against each other but never against the code + that reads them.** `TestTheFrontendKeysResolve` extracts every `t("…")` from + the web UI and asserts it resolves in all three locales. A renamed key would + previously have surfaced as English text inside a German UI, with nothing + failing. It also asserts the extraction *finds* something, because a regex + that matches nothing would make the whole check vacuous. + + **The remaining hard-coded chrome is a ratchet, not an aspiration.** 90 + literal English strings are still in the TSX — panel titles, table headers, + empty states, buttons. `TestTheTranslationBacklogOnlyShrinks` counts them and + refuses to let the count grow, and a second test fails if the recorded number + is *stale*, so lowering it is part of translating rather than optional. + + Deliberately a ratchet rather than an assertion of zero: a test that has to + fail for weeks gets disabled, and a disabled test guards nothing. The number + is the work item. + + **Seen to fail**: adding one `t("totally.missing.key")` and one untranslated + panel turns 5 tests red. + +* **Phase 9 — one mechanism for long-running work, and "job" stopped meaning + two things. `LAY-07` closes, and with it the whole `LAY-*` table.** + + `quest/tasks.py` owns the mechanism: the status vocabulary, `progress`, + cooperative `should_cancel` and the `to_dict()` shape all match + `chisurf/server/jobs.py`, so the host recognises what QuEst reports — + **implemented here, not imported**, because a plugin that needs its host in + order to run standalone is not a plugin. + + **The vocabulary was split, and it had to be.** `quest/jobs.py` was finished + artefact *directories*; a host's `jobs` are *running tasks*. `quest.jobs.list` + would have handed a ChiSurf caller directories when it asked for its running + work. Artefacts are now `quest/runs.py`, `quest.runs.*`, `quest runs clean` + and a `runs` key in the listing payload; `jobs` means a running operation. + The frontend takes `data.runs ?? data.jobs ?? []`, so the browser contract + survives the rename. + + **The domain takes plain callables**, not a job or a manager: `scan_positions` + grew `should_cancel` and `report_progress`. That keeps `quest.core` free of + job bookkeeping and lets a caller with its own cancellation source — a host, a + Qt dialog — pass its own. + + **Cancellation is cooperative, and the limitation is documented rather than + hidden.** A scan's only checkpoint is between sites, so a cancel lands within + one site; a single `simulate` is effectively atomic, because `_simulate_traj` + computes a whole trajectory inside one `njit` call and a jitted kernel cannot + poll a Python flag. `CANCELLING` is a distinct state from `CANCELLED` for + exactly that reason — between the request and the worker noticing, the job is + still running and may still be touching shared state. A cancel button that + implies more than it delivers is worse than none. + + A cancelled scan returns the sites it *did* complete rather than failing, and + a worker that returns after observing cancellation is marked `cancelled`, not + `completed` — its result is partial, and saying otherwise would be a lie a + caller cannot detect. + + **Seen to fail**: replacing the checkpoint with `pass` turns the two + "actually stops" tests red while the other 21 stay green. Those two run the + real `scan_positions`, because a cancel flag nothing polls still reports + success. + +* **Phase 8 — `quest.api` is a facade, and serialization left the handlers. + `LAY-04` closes.** + + The verbs (`template`, `validate`, `simulate`, `scan`, `parameter_catalog`, + `dyes`, `structure_metadata`, `describe`) go through a **client**; + `api.use_client()` swaps in a remote one, which is the local/remote + resolution the row asked for and had never had. The web backend calls + `api.simulate` rather than reaching into `quest.core`. The domain re-exports + stay — a notebook wanting `build_donor_from_project` should have it — but the + verbs are the supported way in. + + **`result_payload` moved out of `simulate_handler`.** An in-process call now + returns a `DecaySimulationResult` with numpy intact, and only a transport + calls `to_payload`. This is not tidiness: `OBJ-02` chose a host optimiser as + QuEst's primary consumer, and it calls `simulate` thousands of times — a + numpy→list conversion of every decay channel per iteration is a tax paid + forever by exactly the caller the objective exists to serve. + + **The cost is real and is guarded rather than promised.** Payload shape now + depends on the transport, which is the "same capability, different path" + shape that produced `LAY-01`'s triplicated `simulate_site`. + `tests/test_contract.py` round-trips every method's native result through + `to_payload` and checks it against the schema `quest/manifest.json` declares. + **Seen to fail**: dropping a single `.tolist()` turns 4 tests red. + + **Errors carry a code now.** `service_error` attaches one of seven + `ERROR_CODES` plus the exception *type*, which `dispatch` no longer flattens + into a message string — a host that can only string-match breaks the first + time a message is improved. The web backend maps them onto HTTP status, so a + buried labelling site is a **422** rather than a 500, and `RemoteError` reads + the same fields ChiSurf's own does. An unknown code is refused at + construction, since a typo would otherwise produce an envelope no host + recognises and fail silently as "some error". + + `quest/rpc/contract.py` follows ChiSurf's per-plugin pattern — + `PLUGIN_ID`, `CONTRACT_VERSION`, `contract_descriptor()`, + `quest.contract.describe`. The descriptor is **built from the manifest** + rather than written beside it: a second hand-maintained copy of the method + list is the defect shape this project keeps finding. + +* **Phases 6 and 7 — the dedup rows close, and adopting a kernel meant fixing + it upstream first. Again.** + + **In imp-tricks** (`3dbefc8`, plus a rattler recipe — + `noarch: python`, since there are no compiled sources there): + + - **`av_pair_statistics` stopped returning ⟨R_DA⟩ under the name `R_mp`.** + Slot 1 is **NaN** now, and `mean_position_distance` — contributed from + QuEst's `dRmp` — takes the clouds and computes it properly. `|⟨a⟩−⟨b⟩|` is + not a function of the distribution of `|a−b|`, so no implementation taking + only distances can produce it; 51.53 Å was returned against a true 47.65 Å + on 148l E15/E90. **The upstream test asserted `r_mp == 50.0` and passed only + *because* of the bug** — the fourth time in this project a test has pinned + the defect it was meant to catch. + - **`split_av_acv` carried both of phase 3's registration defects**: the float + corner `(ng-1)/2` *and* `int()` truncation. Adopting it as written would + have re-introduced them wholesale. Fixed upstream, and its `r0` is now + documented as the grid **anchor** — it said "grid origin (attachment-site + coordinates)", which is ambiguous between three different points, and that + ambiguity is precisely what let the two conventions drift apart in the first + place. + - Its masks are **uint8** rather than float64: binary data, and at `ng = 92` a + float64 pair costs 12.5 MB per site against 1.6 MB, once per site in a scan. + + **In QuEst:** `subav` is now a thin adapter over `split_av_acv` and the + 93-line `_subav` kernel is **deleted**; `dRmp` delegates to the function it + contributed; and `HAS_IMP_BFF` asks the real question — the compiled + `IMP.bff.AV` class *and* an importable `compute_av` — closing `DUP-02`. + `compute_av` is *imported* rather than probed with `hasattr`, because + `IMP.bff.av` is a namespace subpackage spliced in at runtime and an attribute + lookup does not answer that. **All numbers unchanged**: kernel-equivalence + tests and both baselines pass untouched, which is the whole point of adopting + a kernel that was verified first. + + **One item was never a defect, and the error was mine.** "Fix the `IMP.cgmol` + import" entered the plan from a probe written as `import quest.hosts.imp_tricks` — + the module, without *calling* `enable_imp_tricks()`. `IMP.cgmol.sterics` + imports fine. In correcting it, + [workflows/environment.md](workflows/environment.md) turned out to be wrong + too: it claimed `import quest` bridges the checkout, and named + `quest.lib.imp_av`, which `DUP-01` deleted. Measured: `import quest` does + **not** splice; `quest.core`, `quest.core.av` and `quest.api` do. The rule + recorded there: when a checkout-only import fails, check the bridge was + invoked before concluding anything about the other repository. + + `asa`/`spherePoints` → `IMP.cgmol.sterics.asa` is the one row left open. It is + cold — once per simulation, for quencher SASA — and adopting it without the + same numerical verification the others got would be the mistake this phase + exists to avoid. + +* **Phase 5 — κ² is now *stated*. `DUP-03` is rejected and its direction + reversed, and `OBJ-02` is decided.** + + `fret.kappa2` is an explicit project field: in the template, in the parameter + catalog, translated into German and French, rendered in the Qt form, validated + to `[0, 4]` by `validate_project` **before a structure is resolved** — a + project carrying κ² = 9 would otherwise have multiplied the transfer rate by + 13.5 and surfaced only as an implausible efficiency. The rate carries + `κ²/(2/3)`, the literature's `1.5·κ²`. + + **The default changes no number**, by construction: a published Förster radius + is already quoted at the isotropic dynamic average, so 2/3 is neutral, and a + test asserts the two rate arrays are bit-identical with and without the + parameter. + + **`DUP-03` was wrong on both of its claims, and reading the upstream module is + what showed it.** `IMP.bff.cgdye.analysis.fret.calculate_fret_exact` takes an + `(nd × na)` distance matrix *plus transition matrices for both dyes*, forms + `np.kron(p_d, p_a)` and solves a Markov kinetic ensemble — a rotamer-library + formulation, O((nd·na)²), against QuEst's ~10⁵-point clouds. Not a slower + drop-in: **a different model at a different scale.** Nor does it "handle κ²"; + it *accepts* a κ² matrix. **The migration direction is reversed**: QuEst's + trajectory kernel is the general one and should go upstream, like `dRmp`. + + **κ² cannot be modelled here at all, and that is the finding worth keeping.** + The dye is a structureless point in a volume — no transition dipole, nothing + to orient. `kappa2_from_vectors` upstream *takes* the two dipole vectors. + Modelling it needs a new degree of freedom (rotational diffusion per dye, a + correlation time, schema, calibration), which is a project the size of the + acceptor-diffusion work. `OBJ-01` item 6 therefore closes as **chosen and + documented**, and both the objective and the tests say so in as many words, so + that a later reader does not mistake a ticked box for simulated physics. + + **`OBJ-02` is decided: the host route.** QuEst contributes a model; ChiSurf's + optimiser drives it. Nothing implemented — but it is already binding on + phase 8, because an optimiser calling `simulate` thousands of times must not + pay a numpy→list conversion per iteration. + + The i18n coverage test caught the missing German and French entries on the + first run, before any of this was committed. That is the mechanism `P1` exists + to provide, working as intended a phase early. + +* **Phase 4 — a residue is `(chain, number, insertion code)`. `DUP-06` is + closed, and its "low severity, has not bitten yet" was wrong.** + + Identity now comes from **IMP's hierarchy, at the reader**: + `quest/core/structure/reader.py` assigns a `residue_index` per distinct + `(chain, res_id, insertion_code)` in file order, and keeps the + `insertion_code` it had been discarding. `residue_dict`, `residue_indices`, + `n_residues`, the CA/CB/C/N/H lookup tables and `move_center_of_mass` all + group on it. `residue_ids` survives for *display*, with a docstring saying so. + + **The recorded fix would not have fixed it.** known-issues proposed matching + `(chain, res_id)` inside `move_center_of_mass`; that function was a symptom. + `residue_dict` was itself keyed on `res_id`, so the CA/CB/C/N/H tables, + `sequence`, the dihedrals and which CB a labelling site attaches to all + inherited the collapse. `l_residue` was additionally filled in `residue_dict` + order while `move_center_of_mass` indexed it by position in `residue_ids` — + two independently constructed orderings, agreeing only because both iterated + a `set()` of small integers. + + **The domain still passes plain numpy arrays.** No IMP object crosses into it, + which is what keeps the optional-dependency rule and the "do not import IMP at + module scope" constraint intact. That was the whole reason `B1` was chosen + over wrapping a live hierarchy. + + **Exactly one number moved**, which is the entire baseline diff for this + change: the CB centroid of `mc4r_dimer.cif`, + `[-1.400, 2.220, 1.264] → [0.733, -0.419, -0.851]`. `148l.pdb` is + byte-identical — it has three chains but **no colliding residue number**, + which is precisely what makes it the control. **Seen to fail**: reverting the + three groupings to `res_id` turns 3 of the 7 new tests red. + + Corrected while doing it: an earlier draft of the baseline docstring predicted + `n_residue_ids_with_more_than_one_cb` would fall from 534 to 0. It does not, + and should not — that counts how ambiguous `res_id` is in the *structure*, + which no code change alters. Confusing "the number is ambiguous" with "the + code merges them" is the same slip that made this look like a one-line fix. + +* **Phase 3 — one index map, and the "genuine judgement call" turned out not to + be one. Two defects, both backends, and the second was the larger.** + + There is now a single Ångström↔voxel map, `quest.core.av.grid_center_index`: + voxel *i* of a grid anchored at `x0` sits at `x0 + (i − npm)·dg` with + `npm = (ng−1)//2`, and the inverse is `floor((p − x0)/dg) + npm`. Five call + sites were brought onto it. + + **It was never a toss-up between the integer offset and the float corner.** On + the IMP path `x0 = grid_origin + npm·dg`, so voxel *i* is at + `grid_origin + i·dg` *by construction* — the integer offset is the map that + inverts that, and integer voxel indexing cannot express the float one. The + LabelLib branch anchored `x0` on the **attachment atom**, which sits on a node + only for odd `ng`. + + **The second defect was found by writing the test, not by reading the code.** + Asserting that the trajectory sampler and the kernels agree probe-for-probe + failed even after the offsets were unified: `_center_grid_indices` computed + `int((p − r0)/dg)`, and `int()` truncates **toward zero**, so a centre on the + negative side of the anchor was rounded *up* while every other map rounds + down. That is one voxel per axis for **half the grid**, on both backends, + independent of parity — strictly larger than the half-voxel this phase was + scoped for. Its mirror was in `_sample_grid_at_trajectory`, where `np.trunc` + maps `[-1, 0)` to `0`, so a dye up to one voxel *below* the grid was treated + as inside and read voxel 0's quenching rate. + + **The measurement that settles it**, and the one to repeat if this is ever + re-litigated: run every point of `AV.points` through the kernels' index + formula and ask whether it lands on a voxel `AV.density` calls occupied. + Before: **37478/37859 = 98.99 %** (LabelLib), 100 % (IMP). After: **100 % on + both**. That is a statement about registration; a quantum yield is not. + + **Numbers moved on both backends**, re-baselined in `tests/baselines/`: + + | site | LabelLib QY | IMP.bff QY | + |---|---|---| + | E96 | 0.0890 → **0.0728** | 0.4575 → **0.0848** | + | E139 | 0.7150 → **0.9898** | 0.8270 → **0.8190** | + | E129 | 0.9655 → **0.9695** | 0.2088 → **0.3320** | + | FRET E55→E124 | 0.4788 → **0.5469** | 0.4413 → **0.6369** | + + Corroboration, not proof, but worth recording: **the two independently + computed backends now agree far better.** At E96 they were 0.089 against + 0.458 — a factor of 5.1 — and are now 0.073 against 0.085, a factor of 1.2. + The point clouds and all distance metrics are **unchanged**; only the + registration of the stamped grids moved. + + Three things this broke, all of them correctly, and none fixed by relaxing an + assertion: + + - **`tests/test_grid_kernels.py`'s "reference implementation" was a copy of + the kernel**, `int()` and all — a self-comparison in the costume of an + independent check, structurally unable to detect defect 2. It derives the + index from the specification now. + - **`test_api.py` asserts that a tyrosine is in reach of the volume**, and + which sites satisfy that changed wholesale. Re-scanned residues 2–164 under + both backends rather than widening the assertion: `imp_bff` gives 24 sites, + `labellib` 10, the intersection is **{97, 160}**, and the previous fixture + E36 is in *neither*. Now E97. + - **`test_core_api.py` required `slow_factor < 0.2`**, i.e. an overlap between + two stickiness spheres, which after re-registration no longer falls inside + the contact volume. The minimum is now exactly 0.2. Requiring an overlap was + incidental to what that test is named for; that overlapping factors + *multiply* is now asserted directly (`0.5 × 0.2`). + + **The documented way to clear the numba cache was wrong**, found while chasing + the above. `tests/conftest.py` imports ChiSurf, which sets + `NUMBA_CACHE_DIR=~/.chisurf/cache` into `os.environ` — so under pytest numba + reads and writes *there*, not beside the source. There were **193** cached + kernels in it. Every "cold cache" run that used only the recorded + `find quest -name '__pycache__' …` command was warm. + [workflows/testing.md](workflows/testing.md) now clears both. + +* **Phase 2 — the numbers are pinned, and the two suites that had gone two + sessions unverified are green.** + + `tests/baselines/{labellib,imp_bff}.json` record what this tree computes: for + 148l chain E sites 96/139/129 under **each** backend — grid edge, point count, + occupied voxels, `x0`, the cloud **centroid** and its per-axis **extent**, then + the seeded simulation (QY, τ, collisions, AV and contact volume, photon + total), the E55–E124 distance metrics, one FRET run, and coarse-graining on + both `148l.pdb` and `mc4r_dimer.cif`. `tests/baselines/generate.py` rebuilds + them and clears the numba cache first; `tests/test_baselines.py` asserts. + + **Centroid and extent are separate assertions on purpose.** A cloud shifted + half a voxel has the same point count, the same volume and the same bounding + box — only the centroid moves. That is the defect phase 3 exists to fix, and + a baseline recording only sizes would not have seen it. + + **Seen to fail**, which is the only reason to believe any of it: adding + `+ 0.5·dg` to the LabelLib `x0` turns 7 tests red — the three centroid checks, + the three simulations and the FRET channel — and leaves every `imp_bff` case + and every size check green. That is exactly the blast radius the change should + have. + + Two generation bugs were caught by the baselines themselves before they were + trusted. **The first run produced identical simulation blocks for both + backends** while their accessible volumes differed by 7000 points, which is + impossible: `simulate_project` builds its own AV and reads `QUEST_AV_BACKEND` + from the environment, ignoring the backend passed to `AV()`. There is now a + canary test asserting the two baselines disagree. And `tests/__init__.py` was + briefly created so the generator could be imported as a module — that makes + `tests/` a package and changes pytest's import mode for every file in it; it + is loaded by path instead. + + Recorded because phase 4 will move it: `n_residue_ids_with_more_than_one_cb` + is **534** on `mc4r_dimer.cif` — every residue id appears in both chains and + `residue_dict` merges them — against **0** on `148l.pdb`. + + | suite | result | + |---|---| + | browser e2e (Playwright, both servers up) | **26 passed** | + | ChiSurf `quenching_estimator` | **1 passed** | + | baselines | 28 passed | + + Both italicised rows in [handover.md](handover.md) are now measured. The + browser suite ran under `arm64` for the first time — it needed base until + phase 1 — and neither had been run since the AV work of 2026-07-27. + +* **Phase 1 — one interpreter now runs all four surfaces, and the rule that used + to be enforced by an interpreter is now enforced by a test.** fastapi, + uvicorn, python-multipart, pytest-asyncio and httpx installed into `arm64` + from conda-forge; **playwright had to come from pip** — conda-forge's + `playwright` is the *Node* package, and installing it leaves `import + playwright` failing. Baseline in one command: **404 passed, 1 skipped** + (library + Qt GUI + web backend), against the previous 358 in `arm64` and 319 + in base separately. + + The consolidation broke four backend tests, all correctly: they monkeypatched + `backend_main.REPO_ROOT`, which phase 0 stopped consulting. They now set + `QUEST_JOBS_DIR`, which is the documented override, and `REPO_ROOT` is gone + from the module. + + **Retiring base takes the enforcement of "keep the optional dependencies + optional" with it.** That rule held because base genuinely lacked Qt and a + compiled `IMP.bff`, so every fallback ran for free; `arm64` has all three, so + nothing would enter those branches again on its own — the exact condition + under which `imp_av.py` shipped a `Model.get_particles()` call that does not + exist. `tests/test_optional_dependencies.py` simulates each absence instead: + backend resolution with `HAS_LABELLIB`/`HAS_IMP_BFF` forced false in each + combination, and `import quest.core` in a subprocess with `PyQt5`, `qtpy`, + `LabelLib` or `IMP` blocked at import. **Seen to fail**: adding a module-scope + `import IMP` to `quest/core/av.py` turns the `IMP` case red. + + Base was *not* measured to be broken — its web backend suite gave 16 passed + and `import quest.core` succeeded on the day it was retired. That is recorded + as an owner ruling in + [specs/programme-2026-07.md](specs/programme-2026-07.md) rather than dressed + up as a measurement. + +* **Phase 0 — the working tree can no longer accumulate run artefacts, and one + long-standing known issue turned out to have the wrong cause.** + + - **39 GB / 2870 run directories deleted**, and the cause fixed rather than + swept: `simulate_project(save_outputs=…)` now defaults to **False**, and an + opt-in run with no `project_dir` writes to + `quest.jobs.user_jobs_directory()` instead of `Path.cwd()`. The web backend + stopped passing `REPO_ROOT` — that is what had been steering browser runs + into the checkout — and its job list reads the same per-user root, so the + run list no longer depends on where uvicorn was started. `quest jobs clean` + / `pixi run clean` drive `quest.jobs.purge_jobs`, a domain function with + `dry_run=True` by default. Two suite tests were **asserting the old + default**, and one of them (`test_scalar_metrics_survive_the_fast_path`) + would have gone *vacuous* rather than red — it compared a "full" run against + a "fast" one, and both would now be fast. + - **`pytest tests -m notebooks` gives 16 passed as one command** — it had + given 6 failed / 10 passed since 2026-07-26. **The recorded diagnosis was + wrong twice.** It was not base-versus-`arm64` boost skew: with everything + under `arm64` the failure reproduced identically. It was not an ordering + effect between the two files: the two files together pass. The cause is that + **importing ChiSurf sets `DYLD_LIBRARY_PATH=/lib` into + `os.environ`** — the *base* prefix — which is inert in-process (dyld reads it + at exec) but is inherited by every subprocess, so an `arm64` child resolves + `libboost_filesystem.dylib` against base's copy and `import IMP` dies. It is + set during *collection*, by `test_chisurf_autoform.py` calling + `autoform_available()` at module scope, which is what made it look like an + ordering effect. Bisected: adding any other module keeps 16 passed; adding + that one gives 6 failed; `CHISURF_ROOT=/nonexistent` restores 16. Contained + in `tests/conftest.py` with a `pytest_collection_finish` hook that drops + loader paths outside `sys.prefix` — **a containment, not the fix**; ChiSurf + should not export a foreign prefix's `DYLD_LIBRARY_PATH` at all. + - **`quest/utils.py` deleted** — nothing imported it. It held a + `sitecustomize` coverage hook that wrote `.coverage.*` into the working + directory, a `set_search_paths` left over from the `sys.path` injection + `LAY-08` removed, and `unittest` monkey-patching for "Python 2.6". The claim + in [subsystems/structure-io.md](subsystems/structure-io.md) that + `quest/__init__.py` still calls it was stale and is corrected. + - **The numpy known-issue is stale**: `arm64` runs numpy **2.4.6** with IMP + **2.24.0**, so `pyproject.toml`'s `>=2.0` floor is met. The entry described + base. + - README: dead Travis badge replaced with the GitHub Actions one, and the + notebook links repointed from the vendored `modules/quest/notebooks/…` path + to the four notebooks that exist and are executed by the suite. + +* **`DUP-01` done — the largest deletion QuEst had left.** `quest/core/imp_av.py` + (329 lines) and `calculate1R` (69) are gone; `AV.__init__` makes one + `IMP.bff.av.compute_av` call with an explicit `backend=`. **AV numbers + verified unchanged**, which a green suite would not have shown: 148l + E36/E55/E118 under both backends give identical grid shape, identical binary + density voxel-for-voxel and identical point counts — 147 011 / 164 783 / + 67 889 (IMP.bff), 172 964 / 200 283 / 91 585 (LabelLib). +* **Adopting `compute_av` would have re-introduced the SWIG race.** It had no + thread safety at all, so a pooled scan would have died in + `XYZR_setup_particle` exactly as QuEst's own backend used to before + 2026-07-27. Contributed upstream (`9cd5c13`) with the same + construction-locked / resample-unlocked split rather than wrapping the whole + call, which would have cost a threaded scan 96 % of its parallelism. + **The first version of that test was vacuous** — 165 atoms over 4 workers + passed with the lock replaced by a no-op, because the construction window is + too short to overlap. It takes ~2000 atoms over 8 workers. Second time a + concurrency/grid test here has proved nothing until it was seen to fail. +* **Found while verifying `DUP-01`, left unfixed on purpose:** on the LabelLib + path `AV.points` sits **half a voxel off its own density grid** on every axis + (measured: centroid gap 0.25 Å per axis on 148l E55, `ng` 92). The grid + kernels offset by the integer `(ng-1)//2`; the LabelLib cloud uses the float + corner `(ng-1)/2`. Identical for odd `ng`, half a voxel apart for even. The + IMP path is consistent. Same class as the registration bug that silently + removed all quenching, so it is written up in + [references/known-issues.md](references/known-issues.md) — but which + convention is *correct* is a real judgement call, and unifying moves LabelLib + numbers, so it wants its own change and its own re-baseline. +* **The `DUP-*` numbers in [handover.md](handover.md) did not match + [specs/assessment.md](specs/assessment.md).** The handover called the + `density2points` adoption "DUP-02" (assessment: **DUP-05**) and the distance + metrics "DUP-03" (assessment: **DUP-04**), and commits `78dc4c8` / `9b1192e` + followed the handover, so their labels are wrong against the authoritative + table. Recorded there rather than rewritten; assessment.md is the table to + cite. +* **`simulation_type="AV3"` has been a crash, not a feature.** Found while + scoping `DUP-01`: the branch called `calculate3R`, **deleted in `7ecf209`**, + so a project field a scan can set raised `NameError: name 'calculate3R' is not + defined` from eight frames inside a simulation. Nothing caught it because no + test set the field and reachability analysis cannot see a value-driven branch. + Now validated in `AV.__init__` before the structure is even read, naming AV1 + as the only supported value. **This corrects + [subsystems/accessible-volume.md](subsystems/accessible-volume.md)**, which + claimed AV3 "only takes effect on the LabelLib path" — it took effect on + neither, and the concept was confidently wrong rather than merely silent. + Upstream has no AV3 either, so `DUP-01` loses no capability by not carrying + one. +* **`DUP-03` done: the RDA sampling is upstream's, and it is 5× slower.** + `RDAMean`/`RDAMeanE` now aggregate `IMP.bff.av._kernels.random_distances` + + `av_pair_statistics`; `_ran_dist` is deleted. Numbers agree inside sampling + noise (⟨R_DA⟩ 55.164 ± 0.037 vs 55.171 ± 0.032 Å on 148l E15/E90), but the + call costs **3.4 ms against 0.68 ms**: QuEst's kernel was `parallel=True` + while upstream's is sequential *because it seeds*, and numba's per-thread RNG + cannot be seeded reproducibly — determinism and parallelism genuinely conflict + here. Taken knowingly: this runs once per simulation, ~0.4 s over a 151-site + scan, and QuEst **gains reproducibility it did not have** (the old kernel gave + a different answer on every call). The rule it establishes: check where an + upstream symbol sits in the call graph before adopting it — the same trade on + the per-frame FRET rate path would be unacceptable, and that is what the spec + proposes moving next. +* **`dRmp` stays, and index 1 of `av_pair_statistics` is now documented as + unreadable.** Upstream returns `r_mp` as a copy of `r_da_mean`; R_mp cannot be + recovered from a sample of pair distances at all. QuEst reads indices 0 and 2. +* **The new tests had to change site to exist in both environments.** + `TestTheAdoptedDistanceKernelsBehave` first used E15/E90 — the pair this + project's own spec quotes everywhere — and errored under LabelLib, which + labels 43 of 148l chain E's 151 CB sites and not that one. Now E55/E124, the + widest-separated pair labelable under **both** backends (64.0 Å). Same class + of mistake as the `QUENCHED_SITES` re-pick earlier: a number measured under + one backend is not a fixture for a suite that runs under two. +* **`DUP-02` done: `density2points` is upstream's.** QuEst's `_density2points` + is deleted; `quest.core.av.density2points` is now an adapter over + `IMP.bff.av._kernels.density2points`. Same voxels on 5×7×9, 8×8×8 and + 11×11×11 grids. Two preconditions had to be created first, neither of which + the plan mentioned: upstream's kernels were bare `@nb.njit`, so adopting them + as-is would have **re-serialised threaded site scans on the GIL** in the loop + that visits every voxel (fixed upstream, `a49e17c`, contributing QuEst's + `cache=True, nogil=True`); and upstream enumerates `ix` outermost where QuEst + enumerated `iz`, so the cloud comes back **permuted** — safe only because + nothing reads `AV.points` positionally, which was checked against every + consumer rather than assumed. General rule for the rest of the migration: an + upstream kernel returning a collection may not return it in the same order. +* **A lazy import is now a load-bearing constraint on the domain layer.** + Importing `IMP.bff.av._kernels` at the top of `quest/core/av.py` failed + `test_importing_the_domain_does_not_import_qt` and `test_the_model_needs_no_qt` + — not with an `ImportError` but with the *documented* dylib conflict, where a + subprocess of a process that has loaded IMP resolves `libimp_kernel` against + the base environment's `libboost_filesystem`. Both tests probe the domain layer + in a subprocess, so a module-scope import promoted a latent environment fault + into a hard failure of the service layer. Every future adoption from imp-tricks + has to be imported on first use, or the web backend stops being able to run in + the base environment. Noted in + [references/known-issues.md](references/known-issues.md) that this is a + route-around, not a fix. +* **Decision 4 taken: imp-tricks is a declared dependency.** Unblocked by the + owner rather than by publication — installability is explicitly not a + constraint here. Declared in `rattler-recipe/recipe.yaml` and `pixi.toml`, + deliberately **not** in `pyproject.toml`, which is the convention `imp` itself + already follows: neither is pip-installable, so a pip install of QuEst has + never yielded a working science stack. **This turns every pixi environment in + the `py` solve-group unsolvable, and therefore all four CI jobs red**, until + imp-tricks reaches a public channel — the constraint is `*`, so publication + alone fixes it. Recorded rather than worked around; day-to-day work goes + through the `arm64` conda environment and the checkout shim, not pixi. + [specs/imp-tricks-dedup.md](specs/imp-tricks-dedup.md). +* **Decisions 1–3 implemented, one at a time, with a re-baseline between each** + — `1b997ec` (IMP.bff primary), `5b8fc2a` (keep HETATM, strip water), + `4f3dad2` (`allowed_sphere_radius` 2.1 Å), `ea74ca9` (pin against upstream). + Decision 4 is **blocked on packaging, not code**; see + [handover.md](handover.md). +* **Promoting a backend nobody had run found three silent defects.** The worst + was a **transposed** density grid: IMP numbers voxels x-fastest, so the + C-order reshape exchanged x and z. An accessible volume is globular enough + that the transpose still overlapped the truth by **83 %** of its voxels — the + point count, the bounding box and the total volume were all correct, and only + the *shape* was mirrored, so the contact volume landed on the wrong side of + the protein and donors came out unquenched. The lesson for any grid: compare + the density and the point cloud **against each other**, and only when they + come from independent sources. The first version of the upstream test derived + one from the other and passed with the bug deliberately reintroduced. + The other two: a grid origin one voxel out whenever the edge length is even + (86 on the reference site), and no thread safety — a pooled scan, which the + web backend runs, died in SWIG exactly as `pdb.py` already locks against. +* **A claim from decision 1 was wrong, and decision 3 disproved it.** Decision 1 + recorded that most of the 43-vs-147 labelability gap between the backends was + `allowed_sphere_radius` rather than the algorithm. Raising the default from + 0.5 to 2.1 Å left LabelLib at **exactly 43/151** — because + `calculate1R`/`calculate3R` accept a `linkersphere` argument and never pass it + on. LabelLib has no such parameter; it frees the attachment atom's own radius + and nothing else, so a CB hemmed in by CHARMM-sized neighbours has no route + out. Corrected in the constant, in + [subsystems/accessible-volume.md](subsystems/accessible-volume.md) and in the + commit message. +* **Both imp-tricks AV backends now work** (`936a17c`, `b95c000`, unpushed). + The `imp_bff` branch had **never produced a volume in its life**: it read its + density by handing the source particle to an `IMP.em.SampledDensityMap` + needing a `Mass` it never set, so every call raised — and with a mass it would + have sampled a blob around the attachment atom rather than the path map. Plus + no `allowed_sphere_radius`, the AV decorated onto the source particle itself + with `shift_xyz=False` (map left at the coordinate origin), and the same + transpose. `TestComputeAvBackends` is new upstream; there had been no test + touching `compute_av` at all, which is why a backend that could not work + looked fine. Upstream and QuEst now agree point-for-point on 148l E118, E36 + and E90 under both backends. +* **Decisions have consequences at the edges, and they surfaced as errors.** + Admitting HETATM broke `to_coarse` (`KeyError: 'FGA'` — untemplated residues + are now kept whole, since a bound sugar has no backbone-plus-CB reduction) and + revealed that every hetero atom was named `"HET:"`, IMP's prefix truncated by + the `|U5` field. Both are in + [specs/structure-io.md](specs/structure-io.md). +* **Two defects found and deliberately *not* fixed**, both recorded in + [references/known-issues.md](references/known-issues.md) because fixing either + changes numbers and deserves its own re-baseline: coarse-graining matches + residues by `res_id` alone, so in any multi-chain structure one chain's side + chains are folded into another's CB; and `pytest tests -m notebooks` fails as + a single selection (6 failed / 10 passed) while the two files pass separately + (9 + 7), from a dynamic-loader conflict in the child process. The second is + **pre-existing** — verified in a worktree at `1807e72` — and means the + previous handover's "16 passed" never came from that one command. + +## 2026-07-27 + +* **The work is committed, in nine pieces.** Everything that had accumulated in + the working tree — 138 paths, five threads — is now history rather than + uncommitted state. Nothing is pushed. The split, oldest first: + `5962ce3` .gitignore; `64aaebe` the OKF bundle and `CLAUDE.md`; `92ce43b` + `quest.lib` → `quest.core`; `d4d46d2` the service layer; `fde6731` the + parameter catalog and i18n; `790dc1d` the AutoForm GUI; `f34e9a2` the web UI; + `7f51688` notebooks and examples; `1fa4226` pixi and rattler-build. + Deliberately **not** bisectable: the tree was restructured wholesale, so the + middle commits do not stand alone. They are split to be *read*, and each + message records why the change was made rather than what the diff shows. + Two things were found while staging and fixed rather than committed: + `jobs/` had reached **2292 run directories and 32 GB** (now ignored, along + with the `out*.xyz` / `test.pdb` / `test.cif` / `sim_test.log` / + `webui-viewer-testpdb.png` leftovers), and `tests/data/148l.pdb` was a + byte-identical duplicate of `tests/148l.pdb` used only by `test_fps_json.py`, + which now reads the top-level copy. The index also carried a stale + `quest/core_new/` snapshot from an abandoned rename; it was superseded by + `quest/core/` and was cleared before staging. +* **Four architectural decisions taken, none implemented yet** — written up in + [handover.md](handover.md) as the next session's work list: `IMP.bff` becomes + the primary AV backend with LabelLib the Windows fallback; HETATM and water + are no longer stripped; `allowed_sphere_radius` defaults to 2.1 Å (just above + the ~2 Å cliff below which IMP's path search returns an empty volume without + complaining); and imp-tricks becomes a declared dependency, which unblocks + `DUP-01`–`DUP-03`. Decisions 1–3 each change the accessible volume, so they + must land one at a time with a re-baseline between them, or the number + changes cannot be attributed. Decision 4 depends on the upstream fixes in + `~/dev/imp-tricks` being committed and released first. +* **Radii now come from IMP, and the structure layer is one thin reader** + (`quest/core/structure/reader.py`, per [specs/structure-io.md](/specs/structure-io.md)). + `read_pdb` already decorates every particle with a radius, so the reader takes + `IMP.core.XYZR(p).get_radius()` and `IMP.atom.Mass(p).get_mass()` directly — + no helper, no fallback table, no `add_radii` call (redundant: the parser has + already done it). `quest/core/elements.py` is **deleted** (271 lines), and + with it the last table that made the two AV backends disagree. The dead + `assignCharge` path went too — no caller ever set it. + **This changes the science.** IMP's radii are CHARMM-style + (`get_all_atom_CHARMM_parameters`): C 2.10, N 1.85, O 1.71 against the + Bondi-ish 1.76 / 1.65 / 1.40 QuEst carried. ~19 % fatter atoms, ~72 % more + excluded volume, and accessible volumes shrink accordingly. On 148l chain E + **only 43 of 151 CB sites remain labelable** — pockets that were open at + Bondi radii are closed at CHARMM ones. Burial is also resolution-dependent: a + site can be labelable at `dg = 1.0` and buried at `0.5`, because the coarser + grid cannot resolve the atoms that close it (mc4r A1). +* **The two AV backends now converge.** Fed the same atom array with the same + radii, IMP.bff and LabelLib give 136 707 vs 151 869 points on 148l E36 — + ratio **0.90**, centroids within 0.5 Å. Before, with QuEst's own radii on one + side and IMP's on the other, the ratio was 0.78 and it was misread as an + algorithmic difference. The residual 10 % is the real algorithmic gap. +* **`imp_av.py` takes the atom array, not a filename.** It builds the IMP model + from `structure.atoms`, so coarse-graining can no longer be discarded and + mmCIF works wherever the reader works. It also shipped a + `Model.get_particles()` call that does not exist — **an entire backend with + no test coverage**, because `AV_BACKENDS` starts with LabelLib and nothing + ever entered that branch. `TestTheImpAvBackendRuns` now exercises it, and + guards on `HAS_IMP_BFF` rather than on `import IMP.bff` succeeding: in the + base environment the *source* `IMP.bff` imports (nothing compiled to shadow + it) while the C++ `AV` class this backend needs is absent. +* **Test baseline regenerated for the new radii.** Sites that no longer have an + accessible volume were replaced everywhere, and the choice is not arbitrary — + each test needs a site that satisfies *its own* assertion: + `test_api` asserts the quenching grid reaches 2.0 /ns with **only TYR** + quenching, so it needs a tyrosine within `critical_distance` (36 or 82 are + the only labelable sites that qualify); `test_simulation_performance` needs + `0 < QY < 1` under its own chemistry (18, 96, 36 — note 118 quenches under + the template project but not under that one); `test_fret_physics` needs a + pair with *intermediate* transfer so the two acceptor regimes can differ + (55→82: E 0.73 trajectory vs 0.77 averaged; the previous pair saturated at + 0.95 and the regimes agreed to within the tolerance). +* **A process note.** Three `str.replace` edits in a row silently no-oped + because the anchor text had already changed, and I only noticed when the test + kept failing on the old value. Assert the replacement changed the file, or + read the line back. +* **Tried to make IMP.bff the primary AV backend. It is not ready, and now we + know exactly why.** Flipping `AV_BACKENDS` and running the suite in `arm64` + produced four failures that are all one root cause: + `quest/core/imp_av.py::build_imp_accessible_volume` **re-reads the structure + file from disk** (`IMP.atom.read_pdb`) instead of using the structure it was + handed. Consequences, both measured: + - a coarse-grained project silently gets the **all-atom** volume — coarse and + all-atom came out byte-identical at 13883.805 ų, which is what + `test_coarse_grained` caught; + - `.cif` projects fail outright, because that re-read is `read_pdb` only + (`test_mc4r`: "No molecule read from file … mc4r_dimer.cif"). + Patching `imp_av.py` is the wrong fix. `IMP.bff.av.compute.compute_av` takes + plain arrays (`atoms_xyz`, `atoms_vdw`, `source_xyz`) and therefore *cannot* + re-read a file or miss an in-memory transformation. Routing through it is the + correct end state; it needs its own `imp_bff` backend fixed upstream first, + which currently resamples a density of the *attachment particle* rather than + the AV, and dies on a missing `mass` attribute before it gets there. + Order reverted to LabelLib-first; four tests in + `test_imp_tricks_bridge.py::TestTheImpBackendIsNotReadyToBePrimary` pin the + two defects so the ordering cannot stay wrong by inertia. +* **The empty IMP volume is solved: `allowed_sphere_radius`.** OKF had carried + this as "a third fault unresolved" since 2026-07-27. It is the radius around + the attachment atom inside which obstacles are ignored so the linker can leave + the atom it is tied to; at QuEst's default of 0.5 Å the attachment atom's own + neighbours block every starting voxel and the path search returns **an empty + volume with no error**. 2.0 Å gives 108 771 points. `MIN_IMP_ALLOWED_SPHERE_RADIUS` + now floors it. Same physical issue as the LabelLib attachment-radius bug fixed + upstream earlier today — LabelLib has no such parameter and zeroes the + attachment atom's radius instead. +* **The two backends disagree by ~20 % on volume.** 148l E15 all-atom, linker + 21.5/0.5, dye 3.5 Å, dg 0.5: IMP.bff ~14 500 ų, LabelLib ~17 500 ų, with + centroids within 0.6 Å — the same place, less of it. Widening + `allowed_sphere_radius` to 6 Å moves IMP only to 14 512 ų, so it is an + algorithmic difference, not a parameter one. It propagates to the contact + fraction and hence to the quenching, so promoting IMP.bff changes results and + must not be done quietly. +* **A false alarm worth recording.** `Structure.__init__` defaults to + `make_coarse=True`, so `Structure(path)` in a scratch script silently returns + a coarse-grained structure — which made QuEst's CB for 148l E15 look 1.5 Å + off the PDB. It is not: with `make_coarse=False` it matches the file exactly + (3.097, 47.598, 53.650), and the simulation path always passes the project's + flag explicitly. The AV comparison had to be redone apples-to-apples. +* **Acted on the imp-tricks evaluation.** Three fixes landed *upstream* in + `~/dev/imp-tricks`, and `compute_av` now reproduces QuEst's accessible volume + **bitwise** (167 196 points on 148l E15, identical after sorting) in both + environments: + `get_particle_index()` → a shim accepting `get_index()` too; the LabelLib + probe accepting `dyeDensityAV1` (current builds have no `LabelLib.AV`, so a + working install was reported missing); and — the reason it returned an empty + volume — the attachment atom's own vdW sphere left in the obstacle list, so + the linker source sat inside an obstacle and LabelLib returned nothing + without complaining. QuEst had always zeroed that radius. + Also upstream: `src/sitecustomize.py` now extends the `__path__` of + subpackages that are themselves compiled, which is why imp-tricks' own test + suite could not import `IMP.bff.av` (28 collection errors → **191 passed, 5 + failed, 24 skipped**); QuEst had solved the same problem privately in + `quest/hosts/imp_tricks.py`. Two of its tests asserted `ImportError` "without a + backend" and passed only *because* of the LabelLib probe bug; they now + monkeypatch the flags instead. The 5 residual failures (rotamer R0, dye_io, + polymer PDF) reference none of this and had never been collected before. + `tests/test_imp_tricks_bridge.py::TestTheUpstreamAvMatchesQuEsts` pins the + equivalence — the precondition for deleting QuEst's `AV`. +* **What now blocks `DUP-01` is packaging, not capability.** `IMP.bff.av` + resolves in the base interpreter too (nothing compiled there to shadow it), + so the only thing stopping the deletion is that imp-tricks is a development + path shim rather than a declared dependency. That is a decision about what + QuEst depends on. +* **`quest/core/structure/model.py`: 623 → 345 lines.** RMSD, clustering, the torsion + subsystem (`coord_i`, `internal_coordinates`, `phi`/`psi`/`omega`/`chi`) and + the geometry primitives behind them had no readers. Three traps, all caught by + *running* rather than reading: "no callers outside this module" is the wrong + question for helpers the class itself calls; cutting a function span up to the + next `def` swallows the module constants that follow it (`a2id`, `res2id`, + `internal_keys`); and the cut left an orphaned `@njit` that silently decorated + the next function written below it, which then failed to type-infer. +* **One `density2points`, not two.** QuEst carried a flat/centre-origin variant + for its own AV and a 3-D/corner-origin one for LabelLib's grid, differing only + by a shift. Now one kernel plus `_points_from_centred_grid`, with the argument + order matching `IMP.bff.av._kernels.density2points` so the eventual swap is a + thin adapter. +* **Re-measured the imp-tricks split, by running it rather than reading it** + ([specs/imp-tricks-dedup.md](/specs/imp-tricks-dedup.md)). Four findings that + change the plan: + 1. **The blockers are two lines, and they are upstream.** `compute_av` fails + in `arm64` on *both* backends: `av/compute.py:162` calls + `Particle.get_particle_index()` where this IMP has `get_index()`, and + `av/compute.py:231` refuses LabelLib because it looks for `LabelLib.AV` + while the installed LabelLib exposes `dyeDensityAV1`. Its signature is + already the right shape (plain arrays, no IMP particles), so fixing those + two lines deletes QuEst's `imp_av.py` and its `AV` class outright. + 2. **Two duplicates are adoptable today**, nothing blocking: + `IMP.bff.av._kernels.density2points` (numerically identical to QuEst's, + and a superset — arbitrary dimensions, keeps voxel weights, while QuEst + carries *two* lesser copies) and `random_distances` + + `av_pair_statistics` for ⟨R_DA⟩ / ⟨R_DA⟩_E (agree within sampling noise). + 3. **One duplicate points the other way.** `av_pair_statistics` returns + `r_mp` = ⟨R_DA⟩ — its docstring admits "same as `r_da_mean` here" — but + R_mp is |⟨r_D⟩ − ⟨r_A⟩| and cannot be recovered from a distance sample. + On 148l E15/E90: QuEst 47.65 Å, upstream 51.53 Å. QuEst is right; + `dRmp` should be contributed upstream, not deleted. + 4. **`structure.py` is mostly dead.** Zero callers anywhere in the tree for + `rmsd`, `cluster`, `calc_internal_coordinates`, `move_center_of_mass`, + `r2i`, `make_residue_lookup_table`, `get_residue_sequence`, and for the + `Structure` methods `internal_coordinates`, `radius_gyration`, + `update_dist`, `update_coordinates`, `b_factors`, `atom_types`, + `residue_dict`, `n_residues`, `phi`/`psi`/`omega`/`chi`. That is a QuEst + cleanup needing no upstream fix. (One apparent `.phi` hit was in a + vendored `ngl.js` — grep the source tree, not `webui/frontend/public`.) +* **The acceptor diffuses and sticks, with its own dye properties (`OBJ-01` + item 2).** It was a static cloud that the per-frame rate averaged over — the + fast-acceptor limit. It now walks its own accessible volume with its own + `D`, `slow_radius` and `amino_acid_interactions` (each defaulting to the + donor's), and `k_FRET(t)` uses the instantaneous pair separation + (`quest/core/av.py::fret_rate_pair_trace`). The old regime stays reachable as + `fret.acceptor_dynamics: "averaged"`. + **This changes what QuEst computes for existing FRET projects**: on 148l + E15→E90 with a sticky acceptor (D = 2.5 Ų/ns, slow radius 11 Å) E moved + 0.73 → 0.78. Not a bug fix on either side — the two answer different + questions. The cloud is weighted uniformly; a trajectory is weighted by where + the dye dwells, and a sticky dye dwells near the surface. Which way that + moves E depends on the geometry; there is no fixed bias, and an earlier draft + of the docstring claimed one until the numbers said otherwise. + The acceptor's walk carries no quenching: QuEst reports the *donor's* decay, + and the acceptor's own PET would change how bright the acceptor is. Its seed + is offset from the donor's, or the two dyes would move in lockstep. + New catalog entries (translated, as the completeness test demands): + `fret.acceptor_dynamics`, `fret.dyes.1.slow_radius`, + `fret.dyes.1.amino_acid_interactions`. Reachable from the web FRET panel and, + via the generated view spec, from the Qt form. 18 new tests in + `test_fret_physics.py`. +* **A cold numba cache failed the suite, and a warm one hid it.** After editing + `quest/core/av.py`, one full run failed in `density2points_ll` with + `RuntimeError: Cannot set NUMBA_NUM_THREADS to a different value once the + threads have been launched (currently have 7, trying to set 8)`; the next + three passed. It reproduces **exactly** on a cold cache + (`find quest -name '__pycache__' -exec sh -c 'rm -f "$1"/*.nbi "$1"/*.nbc' _ {} \;`) + and never on a warm one, because only a fresh compile makes numba re-read its + configuration. Nothing in QuEst sets the variable — traced with an + `os.environ` watcher and a `set_num_threads` wrapper, both silent — so the + launched count came from elsewhere in the process. Fixed by pinning + `NUMBA_NUM_THREADS` in `tests/conftest.py` beside `NUMBA_THREADING_LAYER`: + an explicit value removes the recomputation. Three cold runs green in both + environments. **A green suite proves nothing about numba here unless the + cache was cold.** +* **FRET is reachable and *tested* on all three surfaces.** It had landed on the + web UI earlier (enable toggle, acceptor site selectors, `R0 [Å]`, and a + browser test that runs a full FRET simulation and asserts `0 < E ≤ 1`), and it + survived the AutoForm rewrite — but every desktop test set + `fret_enabled = False`, so the Qt path was working by inspection only. + `test_gui_simulation.py::TestTheFormRunsFret` closes that: both decays, a + partial efficiency on a chosen site pair, `E = 1 − QY_DA/QY_D` agreeing with + the reported number, a larger R0 transferring more (a nanometre R0 would not), + the toggle gating the channel, and save/load round-tripping the acceptor. + E = 0.77 on 148l E15→E90 at R0 = 52 Å. Still open in + [specs/objectives.md](/specs/objectives.md): the acceptor does not move + (fast-acceptor limit) and κ² is not modelled. +* **`locale.getdefaultlocale()` is removed in Python 3.15**, and QuEst was + calling it — the deprecation warning showed up in the GUI test output the day + it was written. `quest.i18n.system_locale()` now reads `LC_ALL`, `LC_MESSAGES`, + `LANG`, `LANGUAGE` directly, which is all that function did anyway; + `locale.getlocale()` is *not* a substitute, since it reports the current + locale, `(None, None)` until something calls `setlocale`. `LANG=C` means "no + localisation", not "a language", so it resolves to English. +* **English, German and French (`quest/i18n.py`).** Because the catalog is the + single description of every parameter, translating *it* translates the docs, + the Qt form and the web UI at once — no gettext, no per-surface dictionary. + `quest/settings/locales/{en,de,fr}.json` hold the translated labels and + descriptions plus a `ui` section for everything that is not a parameter. + `python -m quest.gui.generate_view_spec` now writes one view spec per language + and `doc/generate_parameter_docs.py` one doc page per language; + `/api/parameter-catalog?locale=` and a new `/api/i18n` (RPC: `quest.locales`, + and `locale` on `quest.parameter_catalog`) serve the browser, which has a + language selector in the header. Full picture: + [subsystems/i18n.md](/subsystems/i18n.md). +* **The backend defaults to English, not to the server's locale.** A shared + backend answering in whatever language its host machine is configured for + would be a surprise no client asked for; `resolve_locale()` (env → OS → + English) is for the *desktop*, and the RPC handlers deliberately do not call + it. Pinned by a test that sets `QUEST_LOCALE=de` and asserts the RPC still + answers in English. +* **German column headers did not fit the quencher table.** Every assertion was + green; rendering the German form and looking at it showed "Löschrate kQ + (1/ns)" clipped to "öschrate kQ (1/n". Table headers now use their own short + `table.*` strings and keep the full wording as the tooltip. The reason + CLAUDE.md says to look at the images. +* **Locale files are cached per process**, so editing one while uvicorn runs + changes nothing until it restarts — the same trap as uvicorn not reloading, + and it cost one confused round of browser checks. Recorded in + [subsystems/i18n.md](/subsystems/i18n.md); `i18n.clear_cache()` exists for + tests. +* **The `.ui` files are gone; the Qt form is generated (`LAY-06`, `LAY-10`, + `LAY-11` all closed).** `quest/gui/quest.view.json` is generated from + `quest/settings/parameter_catalog.json` by `quest/gui/generate_view_spec.py` + and rendered by ChiSurf's `AutoForm`. Deleted: `dye_diffusion2.ui`, + `pdb_widget.ui`, `ui/av_property.ui`, `ui/dye_diffusion.ui`, + `ui/dye_diffusion3.ui`, `widgets.py`, `dye_diffusion.json`, and + `ui/rescource_rc.py` (98 kB of generated base64 that nothing imported); the + window icon survives as `quest/gui/icons/dye-diffusion.ico`. + `dye_widget.py` went from 1,899 lines to ~130. The quencher table now edits + `amino_acid_interactions` directly (that is LAY-10 — there is no legacy + `{residue: {atoms, kQ}}` shape left to disagree), and the three plots are + `plot` sections rendered through `chiplot` (LAY-11 — QuEst owns no plotting + code at all). Details in [subsystems/gui.md](/subsystems/gui.md). +* **The form's state *is* a project (`quest/gui/form_model.py`).** The old + widget kept state in ~40 Qt controls and converted to a project dict and back + by hand — and the conversion is exactly where the GUI drifted from the CLI + before (it once shipped different quenching chemistry). `ProjectFormModel` + presents a project dict as flat attributes, so what the desktop saves is + byte-for-byte what `quest simulate` runs and the web UI posts. It imports no + Qt: `tests/test_form_model.py` runs in the base environment, which has no Qt + binding, with a subprocess guardrail that importing it pulls none in. +* **One description per parameter, now including the desktop.** The catalog + already generated `doc/parameters.md` and fed the web UI; it generates the Qt + form too. `tests/test_view_spec.py` regenerates in memory and fails if the + committed `quest.view.json` differs; `tests/test_form_model.py` fails if the + catalog documents a parameter the form does not bind, or the reverse. A new + input can no longer reach the docs and the web UI while missing from the + desktop. Also normalised two catalog entries that said `"Angstrom"` where + every other said `"Å"`, and regenerated `doc/parameters.md` (which was stale + by 323 lines). +* **`save_outputs` was doing two jobs, and the GUI lost its plots to it.** + Writing `jobs//` and building the thinned trajectory/AV clouds were + behind the same flag. The Qt form passes `save_outputs=False` so an + interactive run leaves nothing behind — and silently got no trajectory, AV or + autocorrelation data to plot. `simulate_project` now takes a separate + `render_data` (default `True`); `quest/scan.py` passes `render_data=False`, + which is what actually wanted the fast path. Found by a GUI test, not by + reading the code. +* **`tests/test_gui_simulation.py` was testing an unquenched site.** It labelled + 148l chain E residue 55, where nothing quenches: QY came out exactly 1.0 and + the assertion `0 < QY <= 1` passed anyway. Moved to residue 15 (one of + `QUENCHED_SITES` in `test_simulation_performance.py`) and tightened to + `0 < QY < 1`, so the test now fails if the quenching path breaks. +* **The AutoForm seam exists in the tree (`LAY-06`).** + `quest/gui/autoform_panel.py::build_method_panel(name)` renders any of the + eleven methods declared in `quest/manifest.json` through ChiSurf's + `AutoForm.from_rpc_method`, and the form it returns yields + `model.params()` shaped exactly like the RPC params — so a panel and its + handler cannot drift apart, and the parameter half of the form needs no + QuEst-side UI code. Additive on purpose: `dye_diffusion2.ui` still loads, + because the manifest cannot describe the structure picker, the quencher + table, the plots or the 3D view. Those need a `quest.view.json` scheme + (AutoForm has `path_list` and `state_table` for the first two); the `.ui` + files go when it covers them. Four tests added + (`tests/test_chisurf_autoform.py::TestQuestPanelHelper`), including one that + asserts the helper lists *exactly* what the manifest declares, so adding a + method without a renderable schema fails. +* **`tests/test_pdb_id_support.py` imported FastAPI unguarded**, so it aborted + collection of the whole suite in `arm64` — which has IMP and Qt but not the + web extra. Now an `importorskip`, matching every other optional-dependency + test. This was masked until the full `tests/` tree was run in `arm64`. +* **The Qt GUI uses chimol, and now finds it by itself.** QuEst's own PyMOL + viewer was deleted earlier today; what remained was that chimol was only + discovered when ChiSurf happened to be on `sys.path`, so the default silently + fell back to the placeholder. `quest/gui/dye_widget.py` now calls + `enable_chisurf()` at import — the same bridge everything else uses — and the + viewer preference defaults to `chimol` rather than `pymol`, which named a + widget that no longer exists. + + Verified from `/tmp`, with no `PYTHONPATH` set: `_HAS_CHIMOL` is true and the + live widget reports `_ChimolAdapter`. 208 tests pass in `arm64`. + + +* **QuEst now resolves to this checkout from anywhere — and that immediately + found a break.** The base environment's editable install mapped `quest` to + `chisurf/modules/quest/quest`, a separate older checkout, via a meta-path + finder that outranks the current directory; `arm64` had no QuEst installed and + worked only because the shell sat in the repo. Both are fixed: the editable + install re-points here, and `arm64` gets a `quest-src.pth`. Verified from + `/tmp` in both. + + `chisurf/modules/quest` is a **git submodule with its own `.git`**, so it was + *not* replaced by a symlink — it may carry unpushed work, and deleting a + checkout to save a path lookup is the wrong trade. It is simply no longer what + gets imported. + + With the live tree actually in play, ChiSurf's `quenching_estimator` plugin + failed to import: it still referenced `quest.lib.tools.dye_diffusion`, removed + by today's relocation. Pointed at `quest.gui`; **46 ChiSurf plugin tests pass** + (quenching_estimator + fps_json_editor). The breakage had existed all day and + was masked by the stale copy — which is the argument for linking the two + repositories rather than vendoring a snapshot. + + +* **Three follow-ups recorded rather than started** (end of a long session; a + half-done UI migration is worse than none): + delete the `.ui` files in favour of AutoForm over the manifest, render the Qt + plots through ChiSurf's `chiplot` instead of hand-built pyqtgraph (`LAY-11`), + and verify that ChiSurf's own test runs use the live `src` checkout rather + than its stale installed copy. All three are written up with what is already + known in [plugin-integration.md](/specs/plugin-integration.md). + + +* **The 3D viewer now says what its colours mean.** Magenta spheres marked the + quenching centres — the same atoms the simulation uses — but nothing on screen + said so, which made the most informative thing in the view read as decoration. + A three-line legend (quenching centre / labeling site / accessible volume) + sits bottom-left of the stage, `pointer-events: none` so it never intercepts a + drag. Verified in the browser; 22 browser tests still pass. + + Deliberately **not** changed: the default labeling site of `1 MET`. It looked + wrong next to a "pick the largest chain" comment, but it is a legitimate site + with a CB, and every alternative available client-side (middle of the chain, + first non-terminal residue) is arbitrary. A real improvement would rank sites + by solvent exposure, which is a simulation-side feature, not a default. + + +* **Examples finished, and tested by running them.** `02_fret_pair.py` (donor + and acceptor, efficiency, E(t), and a check that a smaller R0 transfers less) + and `03_labeling_scan.py` (four candidate sites ranked by yield, lifetime, + contact and dominant quencher) join `01_donor_quenching.py`. The scan output + is the argument for the whole tool in four lines: + + ``` + site QY tau [ns] contact quenched by + E:15 0.997 4.19 0.2% TYR 100% + E:55 0.988 4.17 0.6% PRO 60% + E:100 0.731 4.02 27.2% TRP 96% + E:132 0.967 4.14 2.5% TYR 79% + ``` + + Writing 02 caught a real trap: E(t) computed from the first histogram bins + came out as **-11**, because the leading bins carry the excitation spike where + the ratio of two decays means nothing. The window now starts at 1 ns, and the + reason is in the code. + + `tests/test_examples.py` runs each script as its docstring says to and + requires it to print something and to document how it is run — carrying the + `notebooks` marker, so it is deselected by default and runs under + `pixi run test-notebooks` with the notebooks. 7 tests. + + +* **Recorded the release state** ([release-state.md](/references/release-state.md)): + QuEst is unreleased, so breaking changes are free — rename, delete, reshape + formats, no deprecation periods, no compatibility branches. The page is + explicit about the three things this does *not* license: silent changes to the + science, breaking ChiSurf without saying so, and skipping OKF. `CLAUDE.md` + points at it. + +* **Web backend tidied against the domain it now delegates to.** `main.py` went + from 500 to 373 lines: `POST /api/dyes` had its own read-merge-write of the + dye library *and* its own defaults, both of which `quest.settings.save_dye` + already does — it now delegates and maps `ValueError`/`OSError` onto 400/500. + With that gone, `DEFAULT_DYE_STICKINESS`, `_with_dye_stickiness_defaults`, + `_with_dye_library_defaults` and `DYE_REPOSITORY_PATH` were dead and were + deleted, as were the direct imports of `quest.core.dye_diffusion` internals + (`DEFAULT_QUENCHER_ATOMS`, `REFERENCE_PET_QUENCHING`, + `STANDARD_AMINO_ACID_RESIDUES`) that `quest.settings.quenching_defaults()` + replaced, and the unused `PARAMETER_CATALOG_PATH`. The backend no longer + reaches past the facade for anything but `REPO_ROOT`, which it needs for the + job directories. + + 16 backend tests and 22 browser tests pass against the restarted server. + + +* **Web UI: verified working, and one leak fixed.** The browser suite passes + (22), and a screenshot confirms the real thing — upload, viewer, labeling + controls, FRET panel. Looking at it showed a defect no assertion covered: the + structure was displayed as + `3b7f5e05-43eb-49fb-8e0d-214d60de8bf7_148l.pdb` in **three** places — the + topbar status, the STRUCTURE card and the viewer footer. Uploads are stored as + `_` so two users cannot collide, and that bookkeeping was reaching + the user. + + `POST /api/structure/metadata` now reports the uploaded name. All three + display sites read `metadata.filename`, so one backend change fixed all of + them, and a backend test pins it. + + +* **Fixed the browser-suite failure, and it was not the browser.** After the + day's changes the 22 Playwright tests passed alone but failed at the end of a + combined run with a bare `Page crashed`. Bisected: the pair + `test_pdb_id_support.py` + `test_webui_e2e.py` reproduces it in 13 s, and + `CHISURF_ROOT=/nonexistent` makes the same pair pass — so the first suspect was + the ChiSurf import that `conftest.py` had started doing, which drags in + tttrlib, mdtraj, pandas and pyarrow. + + That was half of it. ChiSurf is now imported **only where a Qt binding exists**, + which is the only place it is used (the AutoForm tests) and the only place the + SWIG import-order fix matters — the web environment gains nothing from it and + pays a large footprint. But the full suite still crashed Chromium, because the + cause is cumulative: IMP, numba, FastAPI and four executed notebooks in one + interpreter leave too little for a renderer. + + So the separation the pixi tasks already implied is now **enforced**: the + browser tests carry a `browser` marker, `pyproject.toml` sets + `addopts = "-m 'not browser'"`, and `pixi run test-e2e` asks for them + explicitly. A combined run now reports **201 passed, 22 deselected** rather + than 22 red — and "deselected" is honest in a way that skipping would not be, + because it names a suite that still has to be run. + + Verified: base combined **201 passed, 22 deselected**; browser in its own + process **22 passed**; `arm64` **220 passed**. + + +* **The notebooks work again — and now they are tested by being run.** Every + notebook in the folder imported `mfm`, a package that has not existed for + years, and the test suite was green anyway because it only asserted that each + file *had cells*. Documentation that claims to work, and does not, is worse + than none. + + Rewritten on the current API, from the science the old ones contained: + + - `01_quenching.ipynb` — the donor decay, quantum yield, contact fraction and + the per-residue attribution, contrasting a site next to a tryptophan with + one that barely quenches. + - `02_fret.ipynb` — donor and FRET decays, the efficiency, **E(t) = f_DA/f_D0**, + and a check that shrinking R0 reduces transfer. + - `03_et_distance_distribution.ipynb` — the E(t)-paper analysis: deconvolve + E(t) into p(R_DA) with a transfer matrix and non-negative least squares plus + a smoothness penalty (the old `mfm.fluorescence.calc_transfer_matrix` and + `solve_nnls` are a few lines of NumPy/SciPy). It then **cross-checks the + recovered distance against ⟨R_DA⟩_E computed from the accessible volumes** — + two independent routes to the same number, which is the point of the + exercise. + - `04_diffusion_modulated_fret.ipynb` — the Haas-Steinberg PDE notebook, + renumbered into the series with text explaining what it adds: it takes p(R) + as given and integrates directly, where QuEst answers the same question by + Monte Carlo. + + Eight stale files removed: the three `mfm` ones, two empty, one with invalid + JSON, and two duplicates (`... (1).ipynb`, `... (2).ipynb`). + + Shared setup lives in `notebooks/quest_notebook.py` — checkout discovery, the + example structure, and `quick_project` / `fret_project` builders — so the four + notebooks do not each repeat it. + + `tests/test_notebooks.py` now **executes** each notebook through nbclient and + additionally requires it to carry prose and a title. Nine tests, 23 s. + + +* **Packaging and CI migrated to pixi + rattler-build.** `pixi.toml` grew four + Python environments beside the existing Node one — `default` (library, CLI, + web backend), `desktop` (adds Qt), `frontend`, and a `build` environment + holding nothing but rattler-build, so CI does not solve the science stack + merely to package it. Tasks: `test`, `test-web`, `test-gui`, `test-e2e`, + `serve`, `gui`, `build-pkg`. Verified with `pixi task list`; all twenty + resolve. + + `rattler-recipe/recipe.yaml` replaces `conda-recipe/meta.yaml`. The old recipe + had gone stale in a way that mattered: its entry point was + `quest=quest.quest_gui:start_gui`, a module that no longer exists and which + was in any case the *GUI* bound to the plain `quest` command. The new one + declares `quest = quest.cli:cli` and `cs.quest = quest.gui:start_gui`, adds + IMP (now the structure reader, not only the AV backend), requires numpy >= 2, + and tests the built package by importing `quest.api`/`core`/`backend` and + actually running `quest --help` and `quest template`. + + **The old CI had stopped running at all**: every trigger was filtered on + `paths: modules/quest/**`, the path QuEst has when vendored inside ChiSurf, + which matches nothing in this repository. `.github/workflows/ci.yml` replaces + it with four jobs — library+backend across three OSes, the Qt GUI offscreen + (with the X libraries a headless Qt still needs), the frontend typecheck and + build, and the rattler package as an artifact. It also exports + `NUMBA_THREADING_LAYER=omp`, the setting that stops the interpreter aborting + when ChiSurf's tttrlib OpenMP runtime meets numba's. + + Neither the recipe nor the workflow can be executed here — no rattler-build in + either environment, and no GitHub runner — so both are **unverified beyond + parsing**: the manifest through `pixi task list`, the workflow through a YAML + load. First CI run should be treated as the real test. + + +* **The RCSB fetch is now shared, in ChiSurf core.** Moved out of the + `fps_json_editor` plugin into **`chisurf/core/fio/structure/fetch.py`** — + library code, wanted by more than one plugin. The move also merged the two + behaviours: ChiSurf's version only tried `.pdb`, QuEst's fell through to + `.cif` for entries too large to have a PDB file, and the shared one does the + latter. The plugin re-exports from core and keeps its own cache directory, so + its 45 tests still pass. + + QuEst's `structure_fetch.download_pdb_id` delegates to it whenever a ChiSurf + checkout is reachable, keeping its own implementation as the standalone + fallback. The two tests that cover that fallback now pin themselves to it + explicitly, rather than silently testing whichever path happened to be live. + + This follows the user's ruling that **plugins may depend on ChiSurf core and + on core plugins** — which is what made the sharing legitimate rather than a + coupling hack. + +* **Correction to yesterday's claim: MRC writing is *not* duplicated.** + ChiSurf's `save_av_mrc` voxelises a **point cloud** through `IMP.em`; QuEst's + `write_mrc` writes an already-computed **density grid** (the AV, the ACV, the + diffusion-coefficient and quenching-rate grids). Same file format, different + inputs — not a drop-in, and not a duplicate. `DUP-07` is narrowed to fps.json + payload handling, which does still overlap. + +* Suites after the day's relocation: **216 passed, 1 skipped** in `arm64`, + **222 passed** in base, **22 passed** for the browser suite. Note again that + uvicorn does not reload — the browser suite reported 22 failures until the + backend was restarted on the relocated package. + + +* **`quest/lib` is gone; the domain is `quest/core/`.** Ten modules relocated + and renamed for what they are — `simulation`, `dye_diffusion`, `photon`, `av`, + `structure`, `pdb`, `elements`, `imp_av`, `fps_json`, `io` — with + `quest/core/__init__.py` keeping the service-layer surface (`simulate_project` + and friends) so `from quest.core import …` still reads the same. The tree now + says what the architecture is: `core/` the domain, `backend/` the RPC, + `gui/` the form, `cli.py`, `api.py`, `manifest.json` — the layout ChiSurf's + own plugins use (`burst_selection` is the fullest example: `api/ backend/ + cli/ gui/ server/ manifest.json`). + +* **The PDB parser is IMP's now (`DUP-06` closed for reading).** + `quest/core/structure/reader.py` went from ~400 hand-written lines of PDB/PQR/mmCIF + parsing to a reader over `IMP.atom.read_pdb` / `read_mmcif`. IMP is present in + **both** environments (2.24 in `arm64`, 2.17 in base), so this needed no new + dependency. + + Two details decided the swap rather than assumed it. **Selection:** none of + IMP's stock selectors matches what QuEst read — `AllPDBSelector` gives 1525 + atoms on 148L, `NonWater*` 1363, while QuEst's parser accepted **ATOM records + only**, 1322. A five-line `PDBSelector` subclass reproduces exactly 1322, and + it has to answer both APIs: IMP 2.17 hands `get_is_selected` a raw line, 2.24 + a `PDBRecord`. **Radii:** IMP assigns CHARMM-style values (N 1.85 Å) where + QuEst uses Bondi-style (N 1.65 Å), and the radius is what the accessible + volume tests against — so the parsing is IMP's and the chemistry stays + QuEst's. Verified field by field against the old parser on 148L: chain, + res_id, res_name, atom_name, element, radius and mass **identical**, + coordinates within 4e-06 Å. + + Two problems surfaced and were fixed: IMP builds decorators through SWIG, + which is **not thread-safe** (a scan's worker pool hit *"Wrong number or type + of arguments for overloaded function 'new_Atom'"*), and parsing became the + dominant cost because a scan re-reads the structure per site. One lock plus a + small parse cache fixed both — and made the suite **faster than before the + swap**: base 70 s → 20 s. + +* **ChiSurf now runs in QuEst's test process, and the abort is understood.** + Importing ChiSurf is harmless; *building its Qt forms and then running QuEst's + numba-parallel kernels* aborted the interpreter. The cause is the threading + layer: ChiSurf brings tttrlib with its own OpenMP runtime, and numba's + **`workqueue`** layer in the same process aborts, while **`omp`** and `tbb` + are stable. `tests/conftest.py` now sets `NUMBA_THREADING_LAYER=omp`, exports + `CHISURF_ROOT` and `IMP_TRICKS_SRC`, and imports ChiSurf **before** anything + touches IMP. The AutoForm tests are back in-process: 216 passed in `arm64`. + +* **More duplication found, this time against ChiSurf (`DUP-07`).** Its + `fps_json_editor` plugin carries `payload.py` (fps.json normalise/validate), + `pdb.py` (RCSB download and cache) and `mrc.py` (`save_av_mrc`) — the same + three things as `quest/core/fps_json.py`, `quest/core/structure/fetch.py` and + `write_mrc`. It cannot be consumed where it is: a plugin is not a library, and + QuEst's domain importing another plugin would couple them through the host's + plugin tree and pull tttrlib/mdtraj/pandas into a headless run. They belong in + `chisurf.core.*`; then QuEst deletes its copies. + +* Suites: **216 passed, 1 skipped** in `arm64` (library + Qt GUI + IMP + + AutoForm in-process) and **222 passed** in base; the browser suite passes + **22** when the servers are up and it is not racing a backend restart. + + +* **More of `quest/lib` removed by relying on the host (7673 → 4460 lines).** + With the presentation arrow reversed, three things stopped being QuEst's job: + + - **`lib/math`** — 38 lines of FFT autocorrelation. ChiSurf has + `core.math.signal.autocorr`, but importing a host application to correlate + an array is absurd, so the twelve lines that matter are now inlined in + `quest/core.py` beside their only caller and the module is gone. Removing a + module, not adding a dependency. + - **`gui/plots/MolView.py`** (415 lines of embedded PyMOL) — ChiSurf's chimol + renders the same thing. Deleted; the viewer now comes from the host, and + `_NoMolView` says so plainly when there is no host instead of letting the + calls fail one at a time. + - **`gui/plots/lineplot.py`, `plotbase.py`, `genealogy.py`** and their `.ui` + files — zero references. Deleted. + + **Deleting QuEst's viewer exposed two dormant bugs in the chimol adapter**, + which had never run because the PyMOL fallback always won: + `_ChimolAdapter.cmd` was a property returning `self.cmd` (instant + `RecursionError`), shadowing the correct one defined earlier in the same + class; and `_ChimolCmdShim` had no `orient()`, which the form calls on every + 3D update. Both fixed — the chimol path now works for the first time. + +* **The suite runs in three configurations, all green**: `arm64` standalone + (204 passed, no host — null viewer), `arm64` with the ChiSurf checkout on the + path (204 passed — chimol viewer *and* AutoForm), and base with the web layer + (222 passed). + +* **ChiSurf must not be imported into QuEst's test process.** The first version + of `tests/test_chisurf_autoform.py` imported it at collection, which pulls + tttrlib, mdtraj, pandas and pyarrow into the interpreter; the run then + **aborted** (`Fatal Python error: Aborted`) once the numba-parallel simulation + kernels ran alongside IMP and Qt. Plain import order is not the problem — + `IMP` then `chisurf` and the reverse both import cleanly — so the renderer now + runs in a **subprocess** and reports back as JSON. That is also the more + honest test: it checks that a host can render QuEst, not that the two + libraries can share an interpreter. + +* **Still redundant, and blocked on one decision: `lib/io/PDB.py` + + `lib/common.py` (~670 lines).** Both ChiSurf + (`core.fio.structure.coordinates`) and IMP (`IMP.atom.read_pdb`) can read a + structure, so QuEst's parser is a third copy. Neither is a free swap: + ChiSurf is absent from `arm64` unless `CHISURF_ROOT` is set and drags + tttrlib/mdtraj/pandas into every headless simulation for the sake of a PDB + parse; IMP is absent from the base environment, which is where the web layer + runs. **Recommendation: IMP.atom**, since QuEst already depends on IMP for + accessible volumes and it costs nothing extra in the environment that does the + science — but it means the web/base environment needs IMP, which is a real + installation decision rather than a refactor. + + +* **The dependency arrow is reversed for presentation, and the UI dedup is + proven.** QuEst may now import ChiSurf — optionally — so the host's + **AutoForm** renders QuEst's forms instead of QuEst carrying `.ui` files and + hand-built Qt widgets. The fluorescence arrow is unchanged: QuEst → imp-tricks, + never the reverse. + + The lever is that `AutoForm.from_rpc_method()` consumes an `rpc_methods` entry + **from `quest/manifest.json`** — the very declaration a host reads to learn + what QuEst offers. QuEst already ships all eleven methods with full JSON-Schema + parameters, so the same artefact serves as the UI description: one declaration, + not two. Verified in `arm64` with the ChiSurf checkout on the path — every one + of the eleven renders; `quest.simulate` comes out as project / pdb_path / + nbins / tac_range / project_dir plus a `save_outputs` checkbox, with **no + QuEst-side UI code**. Screenshotted and read back through + `form.model.params()`. + + `quest/hosts/chisurf.py` reaches the checkout the same way `quest.hosts.imp_tricks` + does (source tree, `CHISURF_ROOT`, never fatal), and deliberately **never + overrides a ChiSurf already imported** — a host that loaded QuEst as a plugin + is already running its own copy. Nothing outside `quest.gui` imports it, so + QuEst still runs standalone; the in-tree form remains the fallback. + + Environment note worth keeping: no environment has both out of the box. `arm64` + has Qt and IMP but no ChiSurf; the `chisurf` env's installed ChiSurf predates + AutoForm; base has ChiSurf but no Qt. `PYTHONPATH=~/dev/chisurf` (or + `CHISURF_ROOT`) closes it in `arm64`, which is now the documented way to run + the AutoForm tests. `tests/test_chisurf_autoform.py` skips cleanly without it. + + Staged from here, not big-bang: the manifest covers parameter entry; the + structure picker, quencher table, plots and 3D view still need a + `quest.view.json` scheme before the `.ui` files and the hand-built form can be + deleted (LAY-06, now in progress). + + +* **`quest/lib` slimmed from 7673 to 4511 lines, and the legacy `lib.*` import + spelling is gone (LAY-08).** The library was a self-contained toolkit + shadowing both imp-tricks and ChiSurf; a minimal one is legitimate for a + standalone app, but this was neither minimal nor compatible with either. + + **The Qt parts left**: `lib/plots/`, `lib/widgets.py`, `lib/ui/` and + `lib/genealogy.py` (~2400 lines) moved to `quest/gui/`, where their only + callers already were. The orphaned `avWidget.ui` went with the dead + `AvWidget`. + + **668 unreachable lines were deleted**, found by a reachability analysis from + the real entry points rather than by eye: `AvPotential` (an AV restraint — + `IMP.bff.restraints` territory), the unused `Pdb` wrapper, three curve + utilities in `datatools`, nine structure-analysis functions (`Universe`, + RMSD, superposition, clustering, internal coordinates — IMP/ChiSurf work), + and the two legacy boolean-collision photon kernels superseded by + `simulate_photon_trace_rate`. + + **The `lib.*` spelling is retired.** Every internal import is now + `quest.lib.…` and `quest/__init__.py` no longer injects the package directory + onto `sys.path`. This was not cosmetic: with both spellings live, + `lib.structure.Structure` and `quest.lib.structure.Structure` were **two + different classes**, so an `isinstance` check across the boundary failed and a + `Structure` was wrapped twice — a real `TypeError` that surfaced the moment + the GUI moved to `quest.gui`. + + The full module-by-module verdict — keep, move, or blocked on imp-tricks — is + in [imp-tricks-dedup](/specs/imp-tricks-dedup.md). + +* Suites after the slimming: **202 passed, 1 skipped** in `arm64` (library + + Qt GUI + IMP) and **222 passed, 3 skipped** in base (library + web backend + + browser). + + +* **LAY-02 closed, then made structural: the GUI and the domain are separate + files, and importing QuEst no longer imports Qt.** Two steps. + + First the class split. `TransientDecayGenerator` stopped inheriting + `DonorDecay`; it now **builds** one per run from the form + (`build_model()`, driven by an explicit `MODEL_ARGUMENT_SOURCES` table mapping + the model's 28 constructor arguments to the 17 Qt-backed properties and 11 + plain attributes that supply them) and reads results back through delegating + properties. Rebuilding per run is deliberate: the controls are the authority, + so a stale model can never be what gets simulated. + + Then the file split, which the class split made possible: 1600 lines of widget + moved to **`quest/gui/dye_widget.py`**, `quest_gui.py` became + `quest/gui/app.py`, the `.ui` and settings resources moved with them, and + `quest/lib/tools/` stopped re-exporting the widget — which was what dragged Qt + into every import of the library. The dead `AvWidget` in `quest/lib/fps` went + too; it was unused and the only reason that module imported a GUI toolkit. + + The last Qt in the domain was a **`QProgressDialog` driven from inside + `DonorDecay.update_all`** — the simulation rendering its own UI. It now takes + a `progress(fraction, message)` callback; the widget passes one that drives + the dialog. A subprocess guardrail asserts that importing `quest.api`, + `quest.rpc`, `quest.core` and `quest.lib.tools` loads **no** Qt binding, + so "the service layer is GUI-free" is now checked rather than intended. + + Verified before and after by 11 characterisation tests written first + (`tests/test_gui_simulation.py`), plus a rendered screenshot of a real run: + decay drawn, QY 0.91, 16.2 % contact. + +* **Two GUI defects the characterisation tests exposed.** + `PDBSelector.chain_id`, `.residue_id` and `.atom_name` had setters that were + literally `pass` — so nothing could select a labeling site programmatically, + and **loading a saved project silently ignored its donor and acceptor sites**. + They now select by index (which is also what repopulates the dependent + combos); picking a value the structure does not contain is refused rather than + accepted as free text. Separately, `quantum_yield` raised `ZeroDivisionError` + when the photon count was zero — reachable from the GUI, since its spin box + counts photons in *millions* and rounds 4 000 to 0.00. + +* **Examples started.** `examples/01_donor_quenching.py` runs in ~3 s and shows + the whole story at one site: decay, quantum yield, mean lifetime, contact + fraction, and which residue types did the quenching. It labels T4 lysozyme + residue 100, next to a tryptophan, where the answer is unambiguous — + QY 0.73, 27 % contact, **96 % of the quenching from TRP**. `examples/_common.py` + puts the repo root first on `sys.path`, because this machine has `quest` + installed editable from *another checkout* (`chisurf/modules/quest`) and an + example run from `examples/` would otherwise silently exercise that one. + + +* **LAY-09 closed, and with it LAY-03: the RPC surface is complete at eleven + methods.** Two capabilities existed only inside the web backend and were + therefore reachable only from a browser. Both are now domain modules: + + - `quest/core/structure/metadata.py::structure_metadata` — the ~150-line PDB/mmCIF + chain–residue–atom extraction that populates labeling-site pickers, moved + verbatim (extracted programmatically rather than retyped) and given a real + error for a missing file; + - `quest/jobs.py` — listing, summarising, reading and archiving the + `jobs//` directories, including the paging clamp and the rule that a + run *is* a UUID directory (anything else in `jobs/` is ignored rather than + half-parsed). + + `quest.structure.metadata`, `quest.jobs.list` and `quest.jobs.get` are + registered and declared in the manifest, so **the eleven methods in the + registry, in `METHODS`, and in `manifest.json` now agree** — which the + manifest tests enforce. The FastAPI routes became adapters; the ZIP download + route lost its hand-rolled archiver to `jobs.archive_job`, which also fixed a + latent oddity — the archive no longer risks containing a previous copy of + itself. + + 14 new domain tests replace what could previously only be exercised through + HTTP. One backend test pointed at `backend_main.MAX_JOB_LIST_LIMIT`, which now + lives in `quest.jobs`; updated rather than deleted. + +* **imp-tricks now works from source in both environments, with no install.** + ChiSurf's mechanism turned out to be two things: imp-tricks ships a + `sitecustomize.py` that extends `IMP.__path__` when `src` is on `PYTHONPATH`, + and its release installer does `pip install --no-deps`. The first + is enough for subpackages IMP does not ship (`IMP.cgmol`, `IMP.finite`, …) but + **not** for `IMP.bff`: a compiled regular package beats a namespace directory + of the same name whatever the path order, so `import IMP.bff.av` still fails. + A real install *was* tried in `arm64`, confirmed working, and then **reverted** + on the user's instruction — imp-tricks is changing, so the source tree is what + has to work. + + `quest.lib.imp_av` therefore calls `enable_imp_tricks()` **on import**, which + extends both `IMP.__path__` and the compiled `IMP.bff.__path__`. Importing + QuEst is now enough to reach `IMP.bff.av`, `IMP.bff.distance_metrics` and + `IMP.cgmol.*` from the live checkout — verified in `arm64` (compiled + `IMP.bff.AV` still present alongside) and in base (no compiled bff at all). + +* **But imp-tricks' own AV cannot be used yet, and now we know exactly why.** + Calling `IMP.bff.av.compute_av` on 148L in `arm64` fails on **both** backends, + each from version skew inside imp-tricks: + + - `labellib` — its guard requires `LabelLib.AV`; the installed LabelLib + exposes only `dyeDensityAV1` (which is what QuEst's own working path calls), + so the backend declares itself unavailable; + - `imp_bff` — `'Particle' object has no attribute 'get_particle_index'`; + IMP 2.24 spells it `get_index()`. + + So `DUP-01` — delete QuEst's duplicate and delegate to `compute_av` — is + **blocked on imp-tricks**, not on QuEst, and the fix belongs in that + repository. Recorded with the evidence in + [imp-tricks-dedup](/specs/imp-tricks-dedup.md) and + [known-issues](/references/known-issues.md). The symmetry is worth stating: + *both* codebases carry an IMP AV integration written against an API that has + moved, and in both cases it went unnoticed because the environment that would + exercise it was not the one being tested. + + Two new tests pin the distinction that caused the original mess — + `HAS_IMP_BFF` (compiled decorator) is **not** the same question as "is + imp-tricks' `compute_av` importable", and `imp_tricks_av_available()` now + answers the second one explicitly. + +* **Ran the suite in the canonical `arm64` environment for the first time: 34 + failures.** The user identified `/Users/tpeulen/mambaforge/envs/arm64/bin/python` + as the environment to use — Python 3.12, numpy 2.4.6, PyQt5, LabelLib **and a + compiled `IMP.bff`** (IMP 2.24). That last one matters: `HAS_IMP_BFF` is true + there, so QuEst selected its IMP accessible-volume backend, a path that had + never executed anywhere. It does not work. Three faults: + + 1. `path_map.get_path_map_header()` raises `AttributeError` — IMP 2.24 binds + it to a C symbol absent from the compiled `_IMP_bff`. **Fixed** by using the + writable accessor, which is bound to a different symbol. + 2. `get_xyz_density()` returns a NumPy array that the code truth-tested. + **Fixed.** + 3. With those out of the way the backend returns an **empty** volume: every + tile's `PM_TILE_PATH_LENGTH` is the 50000 "unreachable" sentinel. Stopped + there rather than reverse-engineering IMP's current contract. + + So **backend selection is now explicit**: `resolve_av_backend()` defaults to + **LabelLib** — what QuEst has always actually run and what its tests pin — with + IMP.bff opt-in through `QUEST_AV_BACKEND=imp_bff`. An unavailable or + misspelled backend raises immediately, naming the usable ones, instead of + producing an empty volume later; `AV.av_backend` records the choice. This is + the strongest argument yet for + [imp-tricks-dedup](/specs/imp-tricks-dedup.md): the duplicated integration was + broken and invisible, because the environment that would have exercised it was + never the one being tested. 34 failures → 1. + +* **The last failure was a genuinely flaky test, and pre-existing.** + `test_an_unseeded_project_still_varies` compared `quantum_yield_donor` across + four unseeded runs — but at a site where the dye rarely reaches a quencher the + yield saturates at exactly 1.0, so four independent runs legitimately report + the same scalar. Confirmed by isolating it: the flake occurs with *and* + without today's changes. It now compares the **decay curves**, which differ + every run because the photon arrival times do — a sharper statement of "the + Monte-Carlo run did not repeat". Stable over three consecutive runs in both + environments. + + While chasing it, a real defect surfaced in `arm64`: unseeded runs there were + **byte-identical** every time, because numba initialises each worker thread's + RNG state deterministically per process — four "independent" runs returning + the same answer reads as precision that is not there. + `_seed_worker_threads()` now seeds one prange iteration per thread from + `os.urandom` before each unseeded trace, which keeps the fast parallel kernel + *and* restores independence. Seeded runs are untouched and still reproduce. + +* **imp-tricks can be spliced into the live interpreter** — + `quest/hosts/imp_tricks.py::enable_imp_tricks()`, at the user's request. The obvious + approach does not work: imp-tricks ships `IMP//` as *namespace* + directories, and in `arm64` the compiled `IMP` and `IMP.bff` are **regular** + packages that shadow them completely, so `PYTHONPATH` alone leaves + `import IMP.bff.av` failing. The helper appends to the already-imported + package's `__path__` instead, so the checkout's `IMP.bff.av` and + `IMP.bff.distance_metrics` resolve *alongside* the compiled `IMP.bff.AV` + rather than replacing it. Verified in both environments (compiled `AV` still + present in `arm64` afterwards), idempotent, and returns `[]` instead of + raising when there is no checkout. Six tests. + +* **Environment and testing concepts rewritten around the two-interpreter + reality.** `arm64` is canonical and the only place Qt *and* IMP.bff exist, but + it has **no fastapi/uvicorn/playwright**, so the web suites still run in the + mambaforge base interpreter. Both must be green, and the commands for each are + in [workflows/testing.md](/workflows/testing.md). Running only the base + environment hides real breakage — that is precisely how the IMP backend stayed + broken. `CLAUDE.md` now says to use `arm64`, and — at the user's instruction — + that **OKF is updated in the same change as the code, always**, including + correcting entries that turn out to be wrong. + +* Suites: **186 passed, 1 skipped** in `arm64` (library + Qt GUI, IMP present) + and **221 passed, 2 skipped** in base (library + web backend + browser, servers + up and restarted after the route changes). + +* **FRET now follows the diffusion (OBJ-01 items 1–4).** `calc_fret_rate` + reduced both accessible volumes to **one scalar** rate and added it to every + frame, so the FRET channel was completely independent of the trajectory QuEst + exists to simulate — the donor could be anywhere and transfer would not + change. It is replaced by `calc_fret_rate_trace`, a per-frame rate + + k_FRET(t) = (1/tau0) · ⟨ (R0 / |r_D(t) − r_A|)^6 ⟩_A + + computed by a new numba kernel `fps.fret_rate_trace` (parallel over frames, + acceptor cloud subsampled by an even stride to bound the `n_frames × + n_acceptor` cost). The donor is resolved in time; the acceptor is averaged + over its volume, which is the fast-acceptor limit and is now stated as such + rather than implied. `calc_photons_fret` adds `k_quench + k_fret` frame by + frame — parallel de-excitation channels — and feeds the existing photon + kernel. + + On T4L E55 → E132 the efficiency moves **0.377 → 0.662** at the same R0: the + rate average over ⟨(R0/r)^6⟩ is not the efficiency implied by ⟨R_DA⟩_E, and + only the former uses the simulated dynamics. + + Two more OBJ-01 items closed with it. **One efficiency definition**: the + analytic `_fret_efficiency` (from ⟨R_DA⟩_E, ignoring quenching entirely) took + precedence over the photon-based one whenever it had been computed, and the + two disagreed; it is deleted, `fret_efficiency` is now always + `1 − QY_DA/QY_D`, and `rda_mean_e()` survives purely as a diagnostic distance + nothing consumes. **No more silent degradation**: a missing acceptor raised + nothing and produced a donor-only result inside a bare `except Exception`; it + now raises with an error naming what to set. + + Also handled: both clouds hold dye *centres* and can overlap in space, where + `(R0/r)^6` diverges. The distance is floored at the sum of the two dye radii, + since the spheres cannot interpenetrate. + + `tests/test_fret_physics.py` (14 cases) pins the kernel against the Förster + relation — rate at r = R0 is exactly 1/tau0, twice the distance is 64× slower, + the *rate* is averaged over the acceptor cloud rather than the distance, + coincident clouds stay finite — and pins the regression itself: the rate + **varies along the trajectory** by more than 1.5×, which the old scalar could + never do. + +* **LAY-05 closed: QuEst declares itself.** `quest/manifest.json` gives the + identity, entry points (`gui`, `cli`, `services`) and all eight RPC methods + with params/result schemas and `long_running` flags — what a host reads to + learn what QuEst offers **without importing it**. Five tests keep it honest: + the declared method set must equal the registry exactly, summaries must match, + every method must document its shapes, the long-running pair must be flagged, + and the entry points must resolve. Version is checked against + `pyproject.toml`. (Note: the ChiSurf-side `quenching_estimator` plugin folder + still has no manifest of its own — that is a change in the other repository + and was deliberately not made from here.) + +* **Wrote the imp-tricks dependency direction to OKF, at the user's + instruction**: [specs/imp-tricks-dedup.md](/specs/imp-tricks-dedup.md). + **General fluorescence machinery belongs in imp-tricks under `IMP.bff`**; + QuEst is the application on top — project schema, PET workflow, surfaces, + scanning, artefacts. The arrow points one way: nothing in imp-tricks may + depend on QuEst. + + Surveying `~/dev/imp-tricks/src/IMP/bff/` showed the overlap is already large: + `av.compute_av` performs **the same IMP.bff → LabelLib → raise dispatch QuEst + reimplements** (plus a `backend=` override QuEst lacks); `av.BasicAV`/`ACV` + model AV and contact volumes; `av._kernels` has `density2points`, + `average_distance`, `mean_fret_distance`, `split_av_acv`; + `distance_metrics.av_pair_statistics` returns ⟨R_DA⟩, R_mp, R_E and ⟨E⟩ in one + weighted pass where QuEst has three separately-resampling functions; and + `cgdye.analysis.fret` already handles **κ²** and exact efficiencies from rate + matrices. Six rows opened as `DUP-01`…`DUP-06`. The `fret_rate_trace` written + today is itself general code in the wrong repository (`DUP-03`) — its natural + home is beside `cgdye.analysis.fret`, which would bring κ² with it, the thing + OBJ-01 item 6 still wants. + + **Corrected a known-issue while checking this.** The recorded reason the + preferred AV backend never runs — "`IMP.bff` is missing" — was only half of + it. `IMP.bff` is a *namespace package provided by imp-tricks*: with + `PYTHONPATH=~/dev/imp-tricks/src` it imports and exposes `av.compute_av` and + `distance_metrics`. QuEst still would not use it, because + `HAS_IMP_BFF = hasattr(IMP.bff, "AV")` gates on a **compiled top-level + attribute the package does not have**. So there are two compounding faults: + imp-tricks is not installed, and the capability check asks the wrong question. + +* Suites: **199 passed, 2 skipped** (library + backend + browser, servers up, + backend restarted after the FRET change so the browser really exercised it) + and **8 passed** for the Qt GUI. + +## 2026-07-26 + +* **The Qt GUI was simulating different physics from every other surface.** + Rendering the widget headlessly for the first time (the default interpreter + has no Qt; the `arm64` and `chisurf` conda environments do, and both import + quest straight from this tree) and **reading the screenshot** showed a + quencher table listing *MET with atom CB* — which the domain model puts on SD. + `dye_diffusion.json` turned out to carry a legacy chemistry block: PRO, MET, + TRP, TYR all on **CB**, a single global `kQ = 2.0`, `critical_distance = 6.5`, + and no HIS or CYS at all. The CLI, API and web UI meanwhile run the + residue-resolved model (TRP 3.5 on the indole ring, TYR 2.0 on the phenol, + MET 1.67 on SD, HIS 1.0, CYS 0.8, PRO 2.0). **The same project gave different + answers depending on which surface you opened it in.** + + The settings file now describes the *session* only — paths, times, photon + counts. `default_quencher_table()` derives the chemistry from the same + `REFERENCE_PET_QUENCHING` and `DEFAULT_QUENCHER_ATOMS` everything else uses, + and the widget fills `quencher` from it unless a user's own settings file says + otherwise; `critical_distance` moved 6.5 → 8.5 to match the project template. + Verified in the re-rendered GUI: TRP with the indole atoms at 3.5, quench + radius 8.50. The residual divergence — the legacy `quencher` shape has no + per-residue radius or stickiness, and the widget still runs + `stickiness_mode="global"` — is now **LAY-10**. + +* **FRET is reachable from the browser for the first time.** The web UI had *no + FRET controls at all*: it could plot a FRET curve, but nothing could switch + FRET on, choose an acceptor site, or set R0 (`projectHelpers.ts` shipped + `R0_matrix: []`). The Qt GUI had acceptor geometry but no R0 either. Both now + have it — an `R0 [Å]` spin box in the Qt FRET group, and a FRET acceptor panel + in the web UI with an enable toggle, chain/residue/atom selectors, R0 and the + acceptor diffusion coefficient. + + **A full FRET run now works end to end in the browser**: T4L donor E55, + acceptor auto-seeded, donor QY 0.911 → FRET QY 0.416, **E = 0.553**, with both + decays drawn. I screenshotted the chart and looked at it: the two curves are + clearly separated, the FRET channel decaying much faster, which is what E≈0.55 + should look like. + + Looking at that screenshot also caught a bug the assertions had passed: the + acceptor seeded on **`542 HOH` atom O** — a water molecule — because "last + residue of the chain" is a water in most structures. `lastLabelableResidue` + now walks back to the last residue with a CB (162 LYS in 148L), and an e2e + case pins that a water is never chosen. + +* **Testing is now defined as all three surfaces.** Recorded in + [workflows/testing.md](/workflows/testing.md) and `CLAUDE.md`: library + web + backend, the browser suite with both servers up, and the Qt widget under + `QT_QPA_PLATFORM=offscreen` in the `arm64` environment — plus the rule to + render the GUI and the charts and *read the images*, which is what found both + defects above. New `tests/test_gui_widget.py` (8 cases: quencher atoms and + rates match the reference chemistry, all PET-active residues present, contact + radius 8.5, the R0 control edits the model and round-trips into a project, + its range covers Ångström values, and the widget paints); it skips where Qt is + absent. Two Qt-free guardrails in `test_service_layer.py` pin that the GUI + settings file carries no chemistry and that the derived table matches the + reference. Five new e2e cases cover the FRET panel and a full FRET run. + + Suites: **179 passed, 2 skipped** (library + backend + browser, servers up) + and **8 passed** for the GUI. Also noted: uvicorn does not reload, so a + backend change needs a restart before the browser suite means anything. + +* **R0 is in Ångström, and the template no longer switches FRET off.** The unit + question raised by yesterday's finding is settled by the user: Ångström, like + every other length in a project. `template_project` wrote + `R0_matrix: 5.5` — a nanometre value — into a field consumed as Ångström, so a + template-derived FRET project ran at a transfer rate of order 1e-6 and + reported no transfer, with no error anywhere. It now writes + `DEFAULT_FORSTER_RADIUS = 52.0`, a named constant in `quest/project.py` whose + docstring states the unit and the failure mode. + + Measured end to end on T4L (148L), donor E55 → acceptor E132: **E = 0.377** + (donor QY 0.940, donor-with-acceptor QY 0.585). At the old value the same + geometry gives E < 1e-4 — indistinguishable from having no acceptor. + + The unit is now written down where people and agents actually look: a new + `fret.R0_matrix` entry in `quest/settings/parameter_catalog.json` (regenerated + into `doc/parameters.md`), a units section in + [architecture/project-schema.md](/architecture/project-schema.md), and + comments at the two consuming sites — `calc_fret_rate`, where R0 meets the + Ångström AV clouds, and `RDAMeanE`, which also gained a docstring saying it + returns the *Förster-averaged* distance and is not interchangeable with + `RDAMean` or `dRmp`. + + **The tests were the reason this survived**: `test_use_case_fret` and + `test_simulate_project_with_fret` assert `0 <= E <= 1`, which is true of every + number the model can emit. `tests/test_fret_units.py` (5 cases) now pins the + unit instead of the range — R0 within the 20–80 Å band a real pair occupies, + the matrix symmetric with an empty diagonal, no matrix without an acceptor, + `build_donor_from_project` actually picking the value up, and the Förster + relation giving E = 0.5 at r = R0 while a nanometre value gives < 1e-4 at 40 Å. + + Still open, tracked in [OBJ-01](/specs/objectives.md): the web UI has no R0 + field at all — `projectHelpers.ts` ships `R0_matrix: []`, so a project built in + the browser silently uses the 52 Å code default and a user cannot enter the + Förster radius of their actual dye pair. Suite: 171 passed, 1 skipped. + +* **LAY-01 closed: project logic left the CLI, and a triplicated scan + implementation collapsed into one.** `template_project`, `validate_project` + and `ProjectValidationError` now live in `quest/project.py` and are exported + from `quest.api`. The CLI keeps `_validate_project` as a four-line translator + to `ClickException`, so its behaviour and tests are unchanged; the web backend + no longer imports `quest.cli` at all; and `quest/lib/fps_json.py` — a + *library* module that was importing the CLI — now calls the domain. + + Chasing that import surfaced the real damage: **three copies** of "simulate one + labeling site and report it" (CLI `scan`, the web backend's `simulate_site`, + and `run_fps_scan`), which had **already drifted**. The library copy omitted + `dominant_quencher`, `dominant_quencher_fraction` and `quenchers`, so + `api.run_fps_scan` silently reported less than `quest scan` did; and the CLI + copy wrote fps.json AV overrides into the project without also applying them to + `av_parameter`, so per-site linker geometry was partly ignored. All three now + call `quest/scan.py::simulate_site`, which also fixes both defects. Concurrency + stays with the callers, because how many sites run at once is a transport + concern (the web backend keeps its GIL-aware `SCAN_WORKERS` pool). + +* **LAY-03 in progress: QuEst has an RPC surface.** `quest/rpc/` adds a + `ServiceDispatcher`, an `InProcessClient` and `register_services(dispatcher)` + registering **eight methods** — `quest.template`, `quest.validate`, + `quest.simulate`, `quest.scan`, `quest.parameter_catalog`, `quest.dyes.list`, + `quest.dyes.save`, `quest.quenching_defaults` — behind one envelope + (`{"ok": True, "result"}` / `{"ok": False, "error"}`). Registration is + duck-typed on `register(name, handler)`, so ChiSurf's own dispatcher works + without QuEst importing the host. Re-registering a name raises rather than + overwriting: a silent overwrite would make which implementation runs depend on + import order. + + Two shared definitions came out of it. `quest/settings/__init__.py` now loads + the parameter catalog and dye library **package-relative** — the web backend + had been resolving them through a `parents[3]` repo-root guess with a + cwd-relative fallback, which cannot work from an installed wheel or a frozen + bundle. And `result_payload()` is now the single definition of a simulation + result on the wire, used by both `quest.simulate` and `POST /api/simulate`. + `quest.structure.metadata` and `quest.jobs.*` are **not** registered yet: their + implementations are still inside the web backend (now tracked as LAY-09). + +* **Three pre-existing backend test failures fixed.** + `webui/backend/tests/test_backend_api.py::TestTopQuenchers` called + `backend_main._top_quenchers`, which has not existed since `top_quenchers` + moved into `quest.core` — the tests had never been updated and the whole class + was erroring. They now call the real name and pass. + +* **Suites: 166 passed, 1 skipped**, with the web UI running + (`tests/` + `webui/backend/tests/`, `-p no:pytest-qt`). The 16 browser tests + were re-run against a **restarted** backend afterwards — uvicorn does not + reload, so the first green run had exercised the pre-refactor process — and + passed 16/16 against the new code, including the scan workflow that now goes + through the shared `simulate_site` and the simulate route that now returns + `result_payload`. New: `tests/test_service_layer.py` (19 cases) covering the + envelope, the registry, the method behaviours, the scan record shape, and + three layering guardrails (no surface imports another surface's helpers; the + library never imports the CLI; the service layer imports no Qt). + +* **Objectives recorded** in [specs/objectives.md](/specs/objectives.md), at the + user's request and deliberately **not implemented**: + + **OBJ-01 — make FRET first class.** It is degraded, not dead: two tests pass + and the T4L project gives E = 0.96 at R0 = 52 Å. But `calc_fret_rate` computes + **one scalar** `k_fret` from ⟨R_DA⟩_E over the *static* AV clouds and adds it + to every frame, so the donor's diffusion — the entire point of QuEst — does not + modulate FRET at all; the acceptor never moves; `fret_efficiency` has two + definitions that can disagree (analytic 0.9598 vs photon-based 0.9578 in the + same run, and the analytic one ignores quenching); a failure to build the + acceptor degrades **silently** to a donor-only result inside a bare + `except Exception`; and R0 has no parameter-catalog entry, so it is neither + documented nor editable in the UI. + + While measuring that, found a concrete defect now in + [known-issues](/references/known-issues.md): the shipped template writes + `R0_matrix: 5.5`, which `calc_fret_rate` consumes as Ångström — at realistic + D–A distances that is a transfer rate of ~1e-6, i.e. **no FRET**. 5.5 is a + plausible Förster radius in *nanometres*, so it reads as a unit mismatch. The + tests miss it because they only assert `0 <= E <= 1`. + + **OBJ-02 — fit dye parameters to measured decays.** Load an experimental decay + and optimise `kQ`, contact radii, `slow_factor`, `D` and linker geometry until + the simulation describes it — turning the shipped chemistry from "starting + values" into calibrated ones. Two routes: rely on the host's fitting/sampling + stack as a first-class ChiSurf plugin (preferred — it already has optimisers, + error analysis, global analysis and IRF/background handling), or implement an + optimiser in QuEst. The user's observation that **first-class plugin status + serves this objective** is now written into the plugin-integration spec: the + RPC/manifest split is what lets a host drive QuEst as a *model* instead of + launching it as a *window*. The spec also lists what this implies for work done + before it starts — cheap repeatable parameterised runs, controllable noise, + name-addressable parameters, and a decay comparable to a measured curve. + +* **The web UI layer is verified for the first time in this environment: 16/16 + browser tests pass.** Brought the stack up — `uvicorn + webui.backend.app.main:app` on :8000 and `pixi run -e frontend dev` on :3000 + (Next.js 16.2.6, ready in 357 ms; the frontend proxies `/api/*` and `/health` + to the backend via `next.config.ts` rewrites) — and ran + `tests/test_webui_e2e.py`: **16 passed in 26 s**, no console errors, no + horizontal overflow. That covers page rendering, the quenching editor + (PET-active filter, kQ editing, atom editing and restore, clear/reset), the + full upload → simulate → read-results workflow including that quench shares + sum to 100 %, the scan workflow with dominant-quencher reporting and column + filtering, and the run-picker's server-side cap. Combined with the 116 unit + tests, **132 of the repository's tests now pass with nothing failing**. + + One trap worth recording: `--timeout=` is not available — pytest-timeout is not + installed, and passing it makes pytest exit with an argument error that looks + like a test failure. + +* **Adopted the ChiSurf plugin split as QuEst's target architecture, and opened + the gap backlog.** New [specs](/specs/index.md) group: + [plugin-integration.md](/specs/plugin-integration.md) is the north star — + `core/` (Qt-free domain) → `backend/services.py` (named RPC methods with one + `{"ok", "result"|"error"}` shape) → facade → thin `cli/` and `gui/`, with a + `manifest.json` declaring identity, entry points and method shapes, and a + declarative view spec. The reference implementation studied was + `chisurf/plugins/fcs/fcs_calculator/`. + + The method table falls out of what the FastAPI backend already exposes — nine + routes map one-to-one onto `quest.simulate`, `quest.scan`, `quest.validate`, + `quest.template`, `quest.parameter_catalog`, `quest.dyes.*`, + `quest.quenching_defaults`, `quest.structure.metadata`, `quest.jobs.*` — which + is the evidence that this surface is real and merely under-spelled. QuEst is + unusually cheap to convert because its boundary contract is already plain + serializable data ([the project JSON](/architecture/project-schema.md)) and its + parameter catalog is already half a view spec. + + [assessment.md](/specs/assessment.md) itemises **8 open gaps**, verified + against the tree rather than guessed: the web backend importing the *private* + CLI helpers `_validate_project`/`_template_project` at four call sites + (LAY-01); `TransientDecayGenerator` inheriting `DonorDecay`, so the Qt widget + *is* the model (LAY-02); no RPC registry at all (LAY-03); `quest.api` being a + re-export shim that callers reach past anyway (LAY-04); the ChiSurf + `quenching_estimator` plugin shipping **no `manifest.json`** — only + `__init__.py`, `README.md` and `test/`, so it loads through the host's legacy + AST discovery, exactly the case ChiSurf's own plugin spec complains about + (LAY-05); two hand-built forms describing the same parameters (LAY-06); three + different long-running mechanisms, none cancelable from outside (LAY-07); and + the `sys.path` injection that would collide inside a host application + (LAY-08). Migration order is in the spec; nothing was implemented yet. + +* **Created the QuEst OKF bundle — the repository now has a persistent memory + layer.** `okf/` is an Open Knowledge Format bundle modelled on the sibling + ChiSurf repository's: plain-markdown concepts with YAML frontmatter, grouped + as [architecture](/architecture/index.md), [subsystems](/subsystems/index.md), + [workflows](/workflows/index.md) and [references](/references/index.md) under + a root [index](/index.md), plus this append-only log. A root `CLAUDE.md` points + every session at it and states the loop in + [workflows/change-tracking.md](/workflows/change-tracking.md): update the + owning concept, append here, keep `doc/` in step, commit. + + The bundle was **populated from the code**, not from the README: the + three-stage pipeline and its invariants, the project-JSON contract and the + parameter catalog that documents it, the four surfaces over one service layer, + the job-artefact layout, and one concept per subsystem (core service layer, + accessible volume, dye diffusion, quenching model, photons/decay, structure + I/O, CLI, web UI, Qt GUI). + + Things worth having written down that are not obvious from the source: + the AV backend priority is **IMP.bff → LabelLib → RuntimeError** and is not + configurable; quenching centres sit on the redox-active moiety while + stickiness stays on the residue, which is why `calc_slow_av` takes two sets of + centres; quenching rates **add** across overlapping contacts while stickiness + factors **multiply**; the photon seed is deliberately offset from the walk's + (`base + 7919 mod 2³¹−1`) so photons do not replay the trajectory they score; + `update_all` avoids `gc.collect()` because the ~20 ms it cost is paid hundreds + of times by a scan; `save_outputs=False` exists because job artefacts dominate + scan runtime; and `quest/__init__.py` inserts the package directory onto + `sys.path`, which is what makes the legacy `import lib.fps` spellings resolve. + +* **Environment and suite state recorded as a baseline.** Suite: + **116 passed, 17 skipped** in ~20 s, via + `python -m pytest tests/ -q -p no:pytest-qt`. The flag is mandatory here — no + Qt binding is installed and pytest-qt otherwise aborts collection before any + test runs; `-p no:qt` does not match the plugin name. Of the skips, 16 are the + Playwright web-UI tests, which skip unless the backend and frontend are + already running: **a green run does not mean the browser layer was + exercised.** Interpreter: mambaforge CPython 3.10.14 with numpy 1.26.4; + LabelLib, numba, fastapi and playwright present; `IMP.bff` and PyQt5 absent. + +* **Six known issues captured** in + [references/known-issues.md](/references/known-issues.md) rather than left in + a chat log: `IMP.bff` missing so the preferred AV backend silently never runs; + `pyproject.toml` declaring `numpy>=2.0` while the installed IMP extensions are + compiled against numpy 1.x and abort under numpy 2 (the failure is recorded in + `tests/sim_test.log`); the pytest-qt collection abort; 806 stray `jobs/` + run directories and 30 `.coverage.*` files accumulating in the working tree + because `simulate_project` writes to `cwd` and `quest/utils.py` installs a + Python-2-era coverage hook; and README links pointing at the vendored + `modules/quest/notebooks/…` path that only exists inside the ChiSurf tree. + +* **State of the tree at bundle creation.** The working tree carries a large + amount of uncommitted work — 20 modified files (~4.2k insertions, notably + `dye_diffusion.py`, `core.py`, `fps/__init__.py`, `cli.py`) plus untracked + `webui/`, `quest/core/structure/fetch.py`, `quest/settings/*.json`, `pixi.toml` and + twelve new test modules. None of it was committed as part of creating this + bundle. Anything that touches git here must assume other work is in flight + ([workflows/change-tracking.md](/workflows/change-tracking.md)). diff --git a/okf/overview.md b/okf/overview.md new file mode 100644 index 0000000..487da6d --- /dev/null +++ b/okf/overview.md @@ -0,0 +1,96 @@ +--- +type: Codebase +title: QuEst +description: Structure-based simulator of dynamic PET quenching and FRET for dyes tethered to proteins by flexible linkers. +resource: https://github.com/Fluorescence-Tools/quest +tags: [fluorescence, pet-quenching, fret, accessible-volume, brownian-dynamics, python] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: peulen-2017 + resource: https://doi.org/10.1021/acs.jpcb.7b03441 + title: Peulen, Opanasyuk & Seidel, J. Phys. Chem. B 121, 8211-8241 (2017) -- the QuEst method paper + - id: dimura-2016 + resource: https://doi.org/10.1016/j.sbi.2016.11.012 + title: Dimura et al., Curr. Opin. Struct. Biol. 40, 163-185 (2016) -- accessible contact volumes +--- + +# What it is + +QuEst (QUenching ESTimation) predicts the fluorescence decay of a dye tethered +to a protein by a flexible linker, from the protein structure alone. It models +photo-induced electron transfer (PET) quenching by nearby amino acids and, +optionally, FRET to a second dye. The method is described in +[Peulen et al., J. Phys. Chem. B 2017](https://doi.org/10.1021/acs.jpcb.7b03441). + +The simulation runs in three stages — accessible volume, Brownian diffusion, +photon generation — described in +[architecture/simulation-pipeline.md](/architecture/simulation-pipeline.md). + +Its practical uses are choosing labeling positions for FRET experiments, and +calibrating accessible *contact* volumes (ACVs) against a measured donor +lifetime. + +# Source layout + +Rebuilt from the tree on 2026-08-06. The old `quest/lib/` toolkit — which mixed +the PET workflow with a general-purpose structure library shadowing imp-tricks +and ChiSurf — no longer exists; its contents live under `quest/core/`, whose own +`__init__` carries the authoritative module table. + +| Path | Role | +|------|------| +| `quest/api.py` | The facade: the verbs, resolved to a **local or a remote** backend. The stable import surface | +| `quest/core/` | The domain — Qt-free and host-free. Everything the simulation needs and nothing about who is driving it | +| `quest/core/simulation.py` | The pipeline: `simulate_project`, `load_project`, `build_donor_from_project`, and the residue-resolved quenching analysis | +| `quest/core/dye_diffusion.py` | `SimulateDiffusion`, `DonorDecay`, and the PET chemistry | +| `quest/core/av.py` | Accessible volumes, the grid kernels, FRET rate traces | +| `quest/core/photon.py` | Photon-trace and decay-curve kernels (numba) | +| `quest/core/structure/` | The `Structure` object (`model.py`), reading through IMP (`reader.py`), labeling-site metadata, and PDB-ID fetch with an on-disk cache (`fetch.py`) | +| `quest/core/fps_json.py`, `quest/core/io.py` | `fps.json` labeling files; point-cloud xyz output | +| `quest/project.py` | The project document: creation and validation | +| `quest/scan.py` | Scanning labeling sites — one site simulated, one record reported | +| `quest/runs.py` | Reading back what a run *wrote*: the artefacts, not the running work | +| `quest/tasks.py` | The one mechanism for long-running work: observable, cooperatively cancelable ([subsystems/tasks.md](subsystems/tasks.md)) | +| `quest/rpc/` | `contract.py` (names, envelopes, error codes), `dispatcher.py`, `services.py` — the operations every front end shares | +| `quest/hosts/` | Optional bridges to a host checkout: `chisurf.py`, `imp_tricks.py` | +| `quest/cli.py` | The Click CLI (`quest simulate/scan/template/validate/gui`) | +| `quest/gui/` | The Qt GUI: `app.py` (`start_gui`), the autoform panel, the dye widget, and the generated `quest.view*.json` | +| `quest/i18n.py` | Translations, from one place, for every surface | +| `quest/settings/` | `parameter_catalog.json` (parameter help, one source of truth), `dye_repository.json` (dye presets), and the locale files | +| `webui/backend/` | FastAPI service wrapping the same `quest.api` calls | +| `webui/frontend/` | Next.js UI (Node toolchain via pixi) | +| `webui/desktop/` | Electron shell around the local backend + frontend | +| `doc/` | User documentation; the parameter pages are **generated** from the parameter catalog | +| `notebooks/` | Library-usage examples | +| `okf/` | This knowledge bundle — the durable memory layer | + +The one-word summary of the refactor: **`core/` is what the science is, and +everything beside it — `cli`, `gui`, `rpc`, `hosts`, `webui` — is who is asking.** + +# Entry points + +- `quest simulate|scan|template|validate|gui` — the CLI (`quest.cli:cli`). +- `from quest.api import load_project, simulate_project` — the Python API. +- `cs.quest` / `quest gui` — the Qt GUI (`quest.gui:start_gui`). +- `uvicorn webui.backend.app.main:app` + `pixi run -e frontend dev` — the web UI. + +# Relationship to imp-tricks + +General fluorescence and structural machinery — accessible volumes, dye +distributions, FRET distance metrics and rates — belongs in the sibling +**imp-tricks** repository under `IMP.bff`, and QuEst depends on it rather than +carrying its own copy. QuEst today duplicates a good deal of it; the direction +and the migration map are in +[specs/imp-tricks-dedup.md](/specs/imp-tricks-dedup.md). + +# Where to go next + +- The [simulation pipeline](/architecture/simulation-pipeline.md) — what actually + runs when a project is simulated. +- The [project schema](/architecture/project-schema.md) — the JSON contract every + surface reads and writes. +- The [subsystems](/subsystems/index.md) — the code areas. +- The [workflows](/workflows/index.md) — environment, testing, and how changes + get recorded. diff --git a/okf/references/index.md b/okf/references/index.md new file mode 100644 index 0000000..b153ee4 --- /dev/null +++ b/okf/references/index.md @@ -0,0 +1,7 @@ +# References + +* [PET quenching theory](pet-quenching-theory.md) - The physics QuEst implements, the approximations it makes, and what the numbers can and cannot be trusted to mean. +* [Release state](release-state.md) - QuEst is unreleased: breaking changes are free, and what that does *not* license. +* [Known issues](known-issues.md) - Defects and environment problems that are real, understood, and not yet fixed. +* [User documentation](user-docs.md) - Where the human-facing manual lives and which parts are generated. +* [OKF format](okf-format.md) - This bundle is OKF v0.2 since 2026-08-06: what the migration changed, how to validate it, and where the rules shared with FPSIMP live. diff --git a/okf/references/known-issues.md b/okf/references/known-issues.md new file mode 100644 index 0000000..371f401 --- /dev/null +++ b/okf/references/known-issues.md @@ -0,0 +1,375 @@ +--- +type: Reference +title: Known issues +description: Defects and environment problems that are real and understood - the open ones, and the closed ones whose *failure mode* is worth keeping. +resource: okf/log.md +tags: [known-issues, environment, technical-debt] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2026-10-26 +okf_check_paths: false # this file lists paths that are gone, on purpose +--- + +Each entry states what is wrong, how it shows up, and what the fix would be. +Remove an entry when it is fixed **and its failure mode teaches nothing** — and +say so in [okf/log.md](../log.md). + +Several entries here are struck through rather than deleted. They are kept for +one reason each, and it is never sentiment: a backend whose faults each hid the +next, a diagnosis that was confidently wrong twice, a "genuine judgement call" +that turned out to have a right answer, a severity rating that said "has not +bitten yet" about something biting every multi-chain structure. **The rule +they add up to: a plausible explanation is not a diagnosis until it has been +defeated and seen to restore the failure.** + +Pruned on 2026-07-28 — the superseded original text of every fixed entry was +removed, leaving the correction. **Every entry in this file is now closed**; +what remains open is in [specs/assessment.md](/specs/assessment.md), and both +items there are decisions rather than defects. + +# Environment + +## ~~QuEst's IMP.bff accessible-volume backend does not work~~ — fixed + +**Resolved 2026-07-27. IMP.bff is now the primary backend** +([subsystems/accessible-volume.md](/subsystems/accessible-volume.md)). Kept +here because the sequence of faults is the record of how a backend with no test +coverage fails: each fix revealed the next, and the last two produced *plausible +wrong answers* rather than errors. + +1. `path_map.get_path_map_header()` raises `AttributeError` — IMP 2.24 binds it + to a C symbol (`DensityMap_get_path_map_header`) absent from the compiled + `_IMP_bff`. Fixed by falling back to the writable accessor. +2. `path_map.get_xyz_density()` returns a NumPy array, and the code truth-tested + it (`if xyz_density:`) → `ValueError`. Fixed. +3. The backend returned an *empty* volume. Cause: `allowed_sphere_radius` was + left at QuEst's 0.5 Å default, and below ~2 Å IMP's path search starts + nowhere and reports nothing. Fixed by the + `MIN_IMP_ALLOWED_SPHERE_RADIUS = 2.0` floor. It was originally written up + here as "the path search is not producing a reachable region", which was the + symptom, not the cause. +4. The backend re-read the structure from disk, discarding coarse-graining and + failing on mmCIF. Fixed by taking the atom array + ([specs/structure-io.md](/specs/structure-io.md)). +5. It shipped a `Model.get_particles()` call that does not exist. Fixed, and + `TestTheImpAvBackendRuns` now exercises the path. +6. The density grid was **transposed** (x↔z) and its origin was one voxel out. + Found only when the backend became the default and quenching quietly + vanished from the reference sites. See the registration section of + [subsystems/accessible-volume.md](/subsystems/accessible-volume.md). +7. It was not thread-safe, so a pooled scan died in SWIG. Fixed with + `_IMP_BUILD_LOCK`. + +*Still true:* the goal remains to delete this integration in favour of +`IMP.bff.av.compute_av` rather than maintain a second copy — `DUP-01`/`DUP-02` +in [specs/assessment.md](/specs/assessment.md), direction in +[specs/imp-tricks-dedup.md](/specs/imp-tricks-dedup.md). That is blocked on the +upstream backend below. + +## ~~imp-tricks' own AV backends do not run in `arm64` either~~ — fixed + +Verified 2026-07-27 by calling `IMP.bff.av.compute_av` from the checkout: + +- `backend="labellib"` — its guard requires `LabelLib.AV`; the installed + LabelLib has only `dyeDensityAV1`, so the backend reports itself unavailable + (and would call a missing function if forced). **Fixed** in the local + imp-tricks checkout, along with the attachment atom being left in its own + obstacle list — which made that backend return an empty volume with no error. + It is now verified point-for-point identical to QuEst's LabelLib path + (`TestTheUpstreamAvMatchesQuEsts`). +- `backend="imp_bff"` — **had never produced an accessible volume in its life.** + `'Particle' object has no attribute 'get_particle_index'` (IMP 2.24 spells it + `get_index()`) was only the first layer. Underneath: it read its density by + feeding the source particle to an `IMP.em.SampledDensityMap` requiring an + `IMP.atom.Mass` it never set, so every call raised `UsageException` — and with + a mass it would have sampled a Gaussian blob around the attachment atom rather + than the path map's accessible density. It never passed + `allowed_sphere_radius`, leaving it below the ~2 Å cliff; it decorated the AV + onto the source particle and resampled with `shift_xyz=False`, leaving the map + at the coordinate origin; and it reshaped the flat tile values in the wrong + axis order. **All fixed** (imp-tricks `b95c000`), with `TestComputeAvBackends` + added upstream — there had been no test touching `compute_av` at all, which is + why a backend that could not work looked fine. + +Both were version skew and defects in **imp-tricks**, not in QuEst, and both are +now verified point-for-point identical to QuEst's on 148l E118, E36 and E90. +`DUP-01` is no longer blocked on correctness — only on packaging, since QuEst +still reaches imp-tricks through a path shim rather than a declared dependency. + +*Not* an issue: reaching imp-tricks from source. `quest.hosts.imp_tricks` splices the +checkout in automatically, deliberately **without installing** it, since the +source tree is what is changing +([workflows/environment.md](/workflows/environment.md)). + +## ~~`pytest -m notebooks` fails as one selection~~ — fixed 2026-07-28, and the diagnosis below was wrong + +**Resolved.** `pytest tests -m notebooks` under `arm64` now gives **16 passed** +as one command. Kept here because the recorded cause was wrong in two separate +ways, and the way it was wrong is the lesson. + +The real cause: importing ChiSurf sets **`DYLD_LIBRARY_PATH=/lib`** +— the *base* prefix — into `os.environ`. In-process that is inert, since dyld +reads the variable once at exec. But **every subprocess inherits it**, so an +`arm64` child resolves `libboost_filesystem.dylib` against base's copy and +`import IMP` dies with `Symbol not found: …filename_v3E`. It is set during +*collection*, by `tests/test_chisurf_autoform.py` calling `autoform_available()` +at module scope — which is why the failure depended on what else was collected +and looked like an ordering effect. + +Bisected 2026-07-28: `test_examples.py` + `test_notebooks.py` together give 16 +passed; adding `test_pdb_id_support.py`, `test_mc4r.py`, `test_use_cases.py`, +`test_imp_tricks_bridge.py`, `test_service_layer.py` or `test_grid_kernels.py` +still gives 16 passed; adding **`test_chisurf_autoform.py`** gives 6 failed. +`CHISURF_ROOT=/nonexistent` restores 16. + +Fixed in `tests/conftest.py` with a `pytest_collection_finish` hook that drops +loader paths pointing outside `sys.prefix`. **That is a containment, not the +fix** — ChiSurf should not export a foreign prefix's `DYLD_LIBRARY_PATH` into +`os.environ` at all, and the proper fix belongs there. + +What the old entry got wrong: + +- It blamed **base-versus-`arm64` skew**. It is not: with base retired and + everything running under `arm64`, the failure reproduced identically + (6 failed / 10 passed). +- It blamed **ordering between the two files** ("whichever runs second fails"). + It is not: the two files together pass. + +Both readings were consistent with the symptom, and neither was tested by +defeating it. **That is the lesson worth keeping**: a diagnosis that explains +the symptom is not a diagnosis until it has been defeated and seen to restore +the failure. + +## ~~`pyproject.toml` requires `numpy>=2.0`; the working env has numpy 1.26.4~~ — stale + +**Measured 2026-07-28:** the canonical `arm64` environment has **numpy 2.4.6** +with **IMP 2.24.0**, and both import and run. The declared floor is therefore +met, and the entry below described the *base* environment (numpy 1.26.4, +IMP 2.17.0) — which is being retired. The `tests/sim_test.log` failure it cites +was an older IMP build compiled against numpy 1.x, not a property of numpy 2. + +## ~~`pytest` cannot collect without `-p no:pytest-qt`~~ — inverted 2026-07-28 + +**The opposite is now true, and passing the flag is harmful.** The entry was +about the base environment, which had no Qt binding, so pytest-qt aborted the +session at collection. Base is retired; `arm64` *has* pytest-qt, and the flag +removes the `qtbot` fixture — which is what made ChiSurf's own widget tests +error when it was passed reflexively to another project's suite. + +Kept, inverted rather than deleted, because the flag is still written into +`pixi.toml`'s tasks and into older notes, and a reader who finds it there needs +to know it is now wrong here. See [workflows/testing.md](/workflows/testing.md). + +## ~~On the LabelLib path the point cloud sits half a voxel off its own grid~~ — fixed 2026-07-28, and it was two defects, on both backends + +**Fixed**, and the entry below understated it in three ways. There is now one +index map everywhere — `quest.core.av.grid_center_index` — and +`tests/test_grid_registration.py` holds it. + +1. **It was not confined to LabelLib.** The float corner was also used by + `_simulate_traj`, `_simulate_traj_grid` and + `_sample_grid_at_trajectory`, so on **both** backends the walk read the + quenching and stickiness grids at indices half a voxel from where + `_center_grid_indices` had stamped them, whenever `ng` was even — which is + the normal case (86 and 80 at the reference site). +2. **There was a second, larger defect underneath it.** `_center_grid_indices` + computed `int((p - r0) / dg)`, and `int()` truncates **toward zero**: for any + centre on the negative side of the anchor it rounded *up*, while every other + map in the project rounds down. That is a one-voxel error per axis for half + the grid, on both backends, independent of parity. It was found by asserting + that the two index maps agree — not by a number looking wrong. +3. **The "genuine judgement call" was not one.** On the IMP path + `x0 = grid_origin + ((ng-1)//2)·dg`, so voxel *i* is at `grid_origin + i·dg` + *by construction*; the integer offset is the map that inverts that, and + integer voxel indexing cannot express the float corner. LabelLib anchored + `x0` on the **attachment atom**, which lands on a voxel node only for odd + `ng`. + +The decisive measurement, which is the one to repeat if this is ever +re-litigated: run every point of `AV.points` through the *kernels'* index +formula and ask whether it lands on a voxel `AV.density` calls occupied. +Before: **37478/37859 = 98.99 %** on LabelLib, 100 % on IMP. After: **100 % on +both**. + +**Numbers moved on both backends**, and are re-baselined in +`tests/baselines/`. Corroboration rather than proof, but worth recording: the +two independently-computed backends agree far better than they did — donor +quantum yield at 148l E96 was 0.089 (LabelLib) against 0.458 (IMP.bff), a +factor of 5.1; it is now 0.073 against 0.085, a factor of 1.2. + +## ~~Coarse-graining matches residues by `res_id` alone, ignoring the chain~~ — fixed 2026-07-28, and it was not one function + +**Fixed**, and the proposed fix below (*"match on `(chain, res_id)`"* in +`move_center_of_mass`) would have left the defect standing. That function was a +symptom. **`Structure.residue_dict` was itself keyed on `res_id`**, as was +`residue_ids`, so *every* consumer inherited the collapse — the CA/CB/C/N/H +lookup tables built from it, `sequence`, the dihedrals, and which CB a labelling +site attaches to. `l_residue` was also filled in `residue_dict` order while +`move_center_of_mass` indexed it by position in `residue_ids`: two +independently constructed orderings that agreed only because both iterated a +`set()` of small integers. + +Residue identity now comes from **IMP's hierarchy, at the reader**: +`quest/core/structure/reader.py` assigns a `residue_index` per distinct +`(chain, res_id, insertion_code)` in file order, and adds an `insertion_code` +column it had been discarding. Everything groups on `residue_index`; +`residue_ids` survives for *display* with a docstring saying so. + +The domain still passes plain numpy arrays — no IMP object crosses into it, +which is what keeps the optional-dependency rule and the lazy-import constraint +intact. + +**What moved, and only this:** the CB centroid of `tests/data/mc4r_dimer.cif`, +`[-1.400, 2.220, 1.264] → [0.733, -0.419, -0.851]`. `148l.pdb` is +byte-identical — it has three chains but no colliding residue *number*, which +is what makes it the control. The whole baseline diff for this change is those +three numbers. + +Note that `n_residue_ids_with_more_than_one_cb` stays **534** on the dimer. That +counts how ambiguous `res_id` is in the *structure*, which the fix does not +change; the CB coordinates are what the fix corrects. + +This closes `DUP-06` in [specs/assessment.md](/specs/assessment.md). + +## ~~Simulation output accumulates in the working tree~~ — fixed 2026-07-28 + +**Fixed at the cause, not with a broom.** `simulate_project`'s `save_outputs` +now defaults to **False**, and when a caller does ask for artefacts and gives no +`project_dir` they go to `quest.jobs.user_jobs_directory()` — the per-user data +directory — never `Path.cwd()`. The web backend stopped passing `REPO_ROOT`, +which is what had been steering the browser's runs into the checkout, and its +job list now reads the same per-user root, so a run list no longer depends on +where uvicorn was started. The CLI passes `save_outputs=True` explicitly, since +its user asked for a run record. + +`quest.jobs.purge_jobs(project_dir, older_than_days=…, dry_run=True)` is the +domain operation behind `quest jobs clean` and `pixi run clean`; it deletes only +UUID-named directories and reports without deleting unless told otherwise. +`QUEST_JOBS_DIR` overrides the root for tests and bulk work. + +The accumulated **2870 directories / 39 GB** were deleted on 2026-07-28. + +## ~~30 `.coverage.*` files in the repo root~~ — fixed 2026-07-28 + +`quest/utils.py` is **deleted**. Nothing in the tree imported it: it was a +`sitecustomize.py` coverage hook writing into `os.getcwd()`, a `set_search_paths` +helper left over from the `sys.path` injection `LAY-08` removed, and +`unittest.TestCase` monkey-patching for "Python 2.6". The stale claim in +[subsystems/structure-io.md](/subsystems/structure-io.md) that +`quest/__init__.py` calls `utils.set_search_paths` is corrected there. + +# Documentation + +## ~~README points at a vendored path that does not exist here~~ — fixed 2026-07-28 + +The notebook links pointed at `modules/quest/notebooks/…`, the path QuEst has +when vendored inside the sibling ChiSurf tree, not in this standalone +repository. They now name the four notebooks that exist and are executed by +`tests/test_notebooks.py`, plus the scripted equivalents in `examples/`. The +dead Travis badge — still referencing the pre-rename `master` branch — is +replaced by the GitHub Actions one. + +# Still open + +## Upstream: `IMP.bff`'s C++ fps.json reader collapses a 3-radius AV to 1 radius — logged 2026-08-10 + +**Not QuEst's bug, and it does not change a QuEst number** — recorded because +QuEst *writes* the affected fields, so a consumer of a QuEst fps.json inherits +it. + +ChiSurf found (`chisurf 47eb871cf`, PRD-95) that `AV::set_av_parameter` +(`AV.cpp:208-210`) does `set_radius2(r[0]); set_radius3(r[0])` — radius2 and +radius3 are parsed from the file into `r[1]`/`r[2]` and then overwritten with +radius1. **Every three-radius AV built from an fps.json through that reader is +silently a one-radius AV.** The fix belongs in imp.bff. + +Why QuEst is unaffected, checked rather than assumed: + +- QuEst never calls that setter. `quest/core/av.py` passes + `dye_radii=(radius1, radius2, radius3)` straight into + `IMP.bff.av.compute_av` from Python; the C++ fps.json path is not on its + route. +- QuEst is **AV1-only** — `simulation_type` is validated in `AV.__init__` and + anything but `"AV1"` raises, so `radius2`/`radius3` reach no kernel that + reads them ([subsystems/accessible-volume.md](/subsystems/accessible-volume.md)). + +**What to watch**: `quest/core/fps_json.py` writes `radius2` and `radius3` into +the fps.json it emits (defaults 4.5 and 3.5). Those values are honest, and a +reader with this bug will discard them without saying so. If an fps.json round +trip ever disagrees about dye size, this is the first thing to check — and it +will look like a QuEst export bug. + +## This bundle points at files that no longer exist — found 2026-08-06 + +**The concepts describe the pre-refactor tree.** `quest/lib/` is gone entirely, +`quest/core.py` became the package `quest/core/`, `quest/jobs.py` became +`quest/runs.py`, `quest/quest_gui.py` became `quest/gui/app.py`, `imp_av.py` +disappeared into `IMP.bff.av.compute_av`, and `quest/api/contract.py` is now +`quest/rpc/contract.py`. The frontmatter parses, every link resolves, the prose +reads well — nothing *looks* broken, which is why it drifted silently. + +**How it was found**, and how to re-check: + +```bash +python3 okf/references/tools/okf_validate.py okf --version 0.2 \ + --check-paths "quest/,webui/,tests/,doc/" +``` + +Every path a concept names is tested for existence. `log.md` is exempt — +history is supposed to mention paths that are gone. + +**Fixed on 2026-08-06 — paths, not descriptions.** Every substitution below was +made only after locating the symbol with `grep`; nothing was guessed: + +| Was | Is | Verified by | +|---|---|---| +| `quest/core.py` (`write_mrc`, `autocorr`, the trajectory walk) | `quest/core/simulation.py` | `def write_mrc`, `calculate_aa_quenching` | +| `quest/lib/tools/dye_diffusion/dye_diffusion.py` | `quest/core/dye_diffusion.py` | `core/__init__` module table | +| `quest/lib/tools/dye_diffusion/photon.py` | `quest/core/photon.py` | module docstring | +| `quest/lib/fps/__init__.py`, `quest/lib/imp_av.py`, `quest/core/imp_av.py` | `quest/core/av.py` | `fret_rate_trace`, `compute_av` | +| `quest/lib/structure/Structure.py` | `quest/core/structure/model.py` | `class Structure` | +| `quest/lib/io/PDB.py` | `quest/core/structure/reader.py` | `core/__init` table | +| `quest/lib/fps_json.py` | `quest/core/fps_json.py` | file exists | +| `quest/jobs.py` (`list_jobs`, `job_summary`, `read_job`, `archive_job`, `is_job_id`) | `quest/runs.py` (`list_runs`, `run_summary`, `read_run`, `archive_run`, `purge_runs`, `is_run_id`) | `grep '^def ' quest/runs.py` | +| `quest/quest_gui.py:start_gui` | `quest/gui:start_gui` | `pyproject.toml [project.gui-scripts]` | +| `quest/api/contract.py` | `quest/rpc/contract.py` | file exists; the spec row now records both | + +`overview.md`'s source-layout table was rebuilt from the tree in the same pass. + +**Marked stale, then re-read -- all four cleared on 2026-08-06.** Each was +checked name by name against the tree, and one of them was not merely +path-stale but wrong: + +| Concept | Verdict | +|---|---| +| `subsystems/core-api.md` | **Rewritten.** It described `quest/api.py` as a re-export shim. Since `LAY-04` it is a verb facade over an RPC client -- `simulate`, `scan`, `template`, `validate`, `describe` going through `quest.rpc`, results staying native with serialization at the transport. The domain re-exports still work, and are documented as such. | +| `architecture/surfaces.md` | **Rewritten.** Three claims were false: the backend no longer borrows the CLI's `_validate_project` (rules live in `quest/project.py`), `TransientDecayGenerator` is a `QWidget` around a `ProjectFormModel` rather than inheriting `DonorDecay`, and `core/av.py` and `core/dye_diffusion.py` no longer import `qtpy` at all. Qt now lives in exactly three files, all under `quest/gui/` -- a structural guarantee, stronger than the try/except one it replaced. | +| `subsystems/structure-io.md` | **Rewritten, and it was the worst.** `Structure` had **none** of the nine geometry methods it documented (`rmsd`, `super_impose`, `cluster`, `onRMSF` ...), and `reader.py` was missing four of seven entry points. IMP is the parser now; `Structure` is a thin accessor over the atom array; the alignment and clustering machinery is gone by design. The concept now names the removals rather than dropping them silently. | +| `architecture/simulation-pipeline.md` | **Verified, barely changed.** Every kernel it names is where it says: `calc_slow_av` and the `_simulate_traj` kernels in `core/av.py`, `_photon_rate_walk` in `core/photon.py`, `get_histogram` in `core/dye_diffusion.py`. The three-stage structure survived the move; only file names changed. | + +The physics concepts — `photon-decay`, `quenching-model`, `dye-diffusion`, +`accessible-volume` — were **not** marked stale: the refactor relocated them +(`core/__init__`: "Relocated from the old in-tree `quest/lib` toolkit") without +changing the behaviour they describe, and marking everything would make the +signal worthless. + +**The remaining 21 `--check-paths` warnings are the baseline, and all are +correct prose:** sentences that name a path *because it is gone* +("`quest/lib` was removed outright on 2026-07-27", "`quest/utils.py` deleted", +"`elements.py` **deleted** (271 lines)"), a completed task ("Delete the `.ui` +files"), the `doc/parameters*.md` glob, and imp-tricks' own `tests/bff`. A run that reports +more than 21 has found something new. + +**Exempt by frontmatter:** this file and `architecture/package-layout.md` carry +`okf_check_paths: false` — one is an audit of what rotted, the other cites names +that were deliberately never created. Flagging either trains readers to ignore +the warnings. + +The lesson is one this bundle already states and did not survive: a concept is +updated **in the same change as the code**, or it quietly becomes fiction. + +## Decisions, not defects + +The two remaining defects live in +[specs/assessment.md](/specs/assessment.md) as `DUP-05`'s `asa` remainder and +`DUP-07`'s `payload.py` destination, and both are decisions rather than bugs. diff --git a/okf/references/okf-format.md b/okf/references/okf-format.md new file mode 100644 index 0000000..589b96d --- /dev/null +++ b/okf/references/okf-format.md @@ -0,0 +1,84 @@ +--- +type: Convention +title: OKF format and shared conventions +description: This bundle is OKF v0.2; the rules it follows are shared with FPSIMP, and this is where they live. +resource: https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md +tags: [okf, convention, fpsimp, migration] +status: stable +generated: { by: claude-code/opus-5, at: 2026-08-06T09:10:00Z } +stale_after: 2027-02-06 +sources: + - id: spec + resource: https://github.com/GoogleCloudPlatform/knowledge-catalog/blob/main/okf/SPEC.md + title: Open Knowledge Format v0.2 specification + author: team:google-cloud-knowledge-catalog + last_modified: 2026-07-01 + - id: fpsimp-conventions + resource: ../../../fpsimp/okf/references/okf-conventions.md + title: FPSIMP -- the shared convention, written out in full + author: claude-code/opus-5 + last_modified: 2026-08-06 +--- + +# This bundle is v0.2 + +Migrated from v0.1 on 2026-08-06. The full rule set -- taxonomy, frontmatter, +actor convention, link style, and how attested computations work -- lives once, +in FPSIMP's +[`okf/references/okf-conventions.md`](../../../fpsimp/okf/references/okf-conventions.md). +The two projects are heading for one server and deliberately follow the same +rules; duplicating them here would only let them drift. + +# What the migration changed + +| v0.1 | v0.2 | +|---|---| +| `timestamp: '2026-07-26T00:00:00Z'` | `generated: { by: , at: 2026-07-26T00:00:00Z }` | +| a `# Citations` list in the body | `sources:` in the frontmatter | +| — | `status:` on every concept | +| — | `stale_after:` on every concept | +| — | `sources:` derived from each concept's `resource`, with `last_modified` | +| `okf_version: "0.1"` | `okf_version: "0.2"` | + +**`generated.by` is `process:okf-v0.1-import` on every migrated concept.** The +v0.1 bundle recorded no actor, and inventing one -- a person, a model -- would +corrupt the exact signal the field exists to carry. The import marker says only +what is known: this text came from the v0.1 bundle, producer unrecorded. +Re-attribute a concept when you next materially change it. + +`stale_after` was set to six months from each concept's own timestamp, and three +months for the ones that track work in flight: `handover.md`, +`references/known-issues.md`, `references/release-state.md`, +`specs/programme-2026-07.md`, `specs/assessment.md`. + +# Checking the bundle + +The validator is vendored into this bundle (canonical copy lives in FPSIMP; +sync by copying, and `diff` them when either changes): + +```bash +python3 okf/references/tools/okf_validate.py okf --version 0.2 +python3 okf/references/tools/okf_validate.py okf --version 0.2 \ + --check-paths "quest/,webui/,tests/,doc/" +``` + +Errors are the spec's section 11 conformance rules only. `--check-paths` warns +about source paths a concept names that no longer exist -- which is how the +post-refactor drift in [known-issues.md](known-issues.md) was found. `log.md` is +exempt from that check, because history is supposed to mention paths that are +gone. + +# What v0.2 buys that is worth using + +- **`stale_after`** makes "is this still true?" a date comparison instead of a + judgement. When it passes, the concept is not wrong -- it is *unreviewed*. +- **`sources` with `last_modified`** lets a reader see that a concept was + written against a file that has changed since. +- **`verified`** records that a human or a named process actually checked a + concept. Nothing in this bundle carries it yet, which is honest: the trust + tier of every concept here is *unverified*. +- **`Attested Computation`** would let QuEst's own numbers -- quantum yield, + mean lifetime, transfer efficiency -- be re-derived from a receipt and checked + mechanically. `tests/baselines/` already does half of this informally. See + FPSIMP's [computations](../../../fpsimp/okf/computations/index.md) for a + worked pair. diff --git a/okf/references/pet-quenching-theory.md b/okf/references/pet-quenching-theory.md new file mode 100644 index 0000000..f3d61b0 --- /dev/null +++ b/okf/references/pet-quenching-theory.md @@ -0,0 +1,84 @@ +--- +type: Reference +title: PET quenching theory +description: The physics QuEst implements, the approximations it makes, and what its numbers can and cannot be trusted to mean. +resource: https://doi.org/10.1021/acs.jpcb.7b03441 +tags: [pet, photophysics, fret, theory, approximations] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: peulen-2017 + resource: https://doi.org/10.1021/acs.jpcb.7b03441 + title: Peulen, Opanasyuk & Seidel, Combining Graphical and Analytical Methods with Molecular Simulations, J. Phys. Chem. B 121, 8211-8241 (2017) + - id: dimura-2016 + resource: https://doi.org/10.1016/j.sbi.2016.11.012 + title: Dimura et al., Quantitative FRET studies and integrative modeling, Curr. Opin. Struct. Biol. 40, 163-185 (2016) +--- + +# The model + +A dye tethered by a flexible linker samples an accessible volume around its +attachment point. While it is in van der Waals contact with an electron-rich +side chain, photo-induced electron transfer (PET) opens a non-radiative channel: +the excited-state decay rate becomes + +``` +k(t) = 1/tau0 + k_Q(r(t)) +``` + +with `k_Q` a **step function** of position — the residue's `kQ` inside its +contact radius, zero outside — summed over all residues in contact. Averaging +over a Brownian trajectory in the accessible volume gives the observable decay, +which is generally multi-exponential even though the underlying photophysics has +one unquenched lifetime. + +PET is a short-range, wavefunction-overlap process; its rate falls off roughly +exponentially with distance over ~1 Å. A step function at contact is therefore a +crude but defensible stand-in: the process is essentially all-or-nothing at the +distances the dye actually samples. + +Residue reactivity for a xanthene dye follows the reference ordering +TRP > PRO ≈ TYR > MET > HIS > CYS (values in `REFERENCE_PET_QUENCHING`). + +# Why the diffusion matters + +If quenching were fast compared to the dye's exploration of its volume, the +decay would report on the *equilibrium* fraction of quenched configurations. It +is not: contact events last nanoseconds and the walk is diffusive, so the decay +depends on the **dynamics** — how often the dye reaches a quencher and how long +it stays. That is why QuEst simulates a trajectory rather than integrating over +the AV, and why the slow-factor grid (unspecific stickiness near the surface) is +not a cosmetic detail: it changes the residence times that set the decay. + +The same trajectory yields the accessible **contact** volume (ACV) — the +fraction of the AV in which the dye is surface-associated — which is the +quantity a measured donor lifetime can calibrate. + +# Approximations, stated plainly + +From the README's warnings, restated as modelling assumptions: + +1. **The dye is one sphere.** No orientation, no internal structure, no + dye–protein chemistry beyond a contact radius. +2. **The protein is a single rigid structure.** No side-chain rearrangement, no + backbone dynamics, no conformational ensemble. +3. **No specific interactions.** Binding pockets, stacking geometries and + electrostatic steering are absent; the only "affinity" is the isotropic + `slow_factor`. +4. **Parameters are transferable starting values, not constants.** The reference + `kQ` and contact distances are for a xanthene dye and are meant to be + calibrated against measured lifetimes. +5. **Precision is not accuracy.** The simulation returns tightly reproducible + numbers; their agreement with experiment is a separate question. + +The honest use of a QuEst number is comparative — this labeling site versus that +one, this ACV calibration versus that one — rather than absolute. + +# FRET + +With a second dye, the donor–acceptor distance is sampled from the two AV point +clouds and converted to a rate through `R0`. `RDAMeanE` (the Förster-weighted +average) is the quantity that corresponds to a FRET-efficiency measurement; +`RDAMean` and `dRmp` (mean-position distance) are different averages and are not +interchangeable with it. diff --git a/okf/references/release-state.md b/okf/references/release-state.md new file mode 100644 index 0000000..a5e4277 --- /dev/null +++ b/okf/references/release-state.md @@ -0,0 +1,49 @@ +--- +type: Reference +title: Release state +description: QuEst is unreleased — breaking changes are free, and backwards compatibility is not a constraint. +resource: pyproject.toml +tags: [process, versioning, compatibility] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-27T00:00:00Z } +stale_after: 2026-10-27 +sources: + - id: pyproject-toml + resource: ../../pyproject.toml + title: pyproject.toml + author: human:tpeulen + last_modified: 2026-07-27 +--- + +# QuEst is not released + +There are no users on a published build, so **there is nothing to stay +compatible with**. Prefer the clean change over the compatible one: + +- Rename anything. Module paths, function names, project keys, RPC method names + and manifest fields may all change; no deprecation period is owed. +- Delete anything unused. Shims, aliases and "kept for compatibility" wrappers + are debt with no creditor. `quest/lib` was removed outright on 2026-07-27 for + exactly this reason. +- Change file formats. The project JSON, `fps.json` handling and the job + directory layout can be reshaped when the current shape is wrong — the + `R0_matrix` unit fix landed as a straight correction rather than a migration. +- No back-compat branches in code. A second code path "for old projects" is a + second thing to test and a second thing to get wrong. + +What this does **not** license: + +- **Silent behaviour changes in the science.** Renaming a function is free; + quietly changing what a simulation computes is not. When the physics moves, + measure it, say so in [the log](../log.md), and pin it with a test — as with + the per-frame FRET rate (E 0.377 → 0.662) and the IMP reader (verified + field-for-field *identical* before it was accepted). +- **Breaking a sibling repository without saying so.** ChiSurf imports QuEst. + Changes that move an entry point are fine, but they must be recorded so the + host can follow — the GUI entry point moved to `quest.gui:TransientDecayGenerator` + on 2026-07-27 and the manifest was updated in the same change. +- **Leaving OKF behind.** The freedom to change fast only works if what changed + is written down. + +Revisit this page the moment a version is published; from then on the rules +invert. diff --git a/okf/references/tools/okf_validate.py b/okf/references/tools/okf_validate.py new file mode 100644 index 0000000..e43e339 --- /dev/null +++ b/okf/references/tools/okf_validate.py @@ -0,0 +1,323 @@ +#!/usr/bin/env python3 +"""Conformance checker for OKF v0.2 bundles (SPEC section 11). + +VENDORED COPY. The canonical file is `fpsimp/okf/references/tools/okf_validate.py` +in the sibling FPSIMP repository; this copy exists so that QuEst validates itself +without a sibling checkout -- CI clones one repo, not two. Sync by copying, and +`diff` the two when either changes. + + python3 okf/references/tools/okf_validate.py okf + python3 okf/references/tools/okf_validate.py ../quest/okf --version 0.1 + +Exit code 0 when the bundle is conformant, 1 when it is not. Warnings never +fail the run: the spec is explicit that consumers must not reject a bundle for +missing optional fields, unknown types, unknown keys, broken links or missing +index files, so those are reported and tolerated. + +# Errors (section 11 conformance) + +* a non-reserved `.md` file without a parseable YAML frontmatter block +* a frontmatter block without a non-empty `type` +* `okf_version` outside the bundle-root `index.md` (section 12) +* a `log.md` date heading that is not ISO `YYYY-MM-DD` (section 9) + +# Warnings (soft guidance, sections 4-8) + +* missing `description`, `generated.by`, `status`, `stale_after` +* an actor that does not match the section 7 convention +* `status` outside draft|stable|deprecated +* a bundle-relative or relative markdown link with no target on disk +* `stale_after` in the past (the concept is stale, not invalid) +* `sources[]` entries with no `resource` +* an `Attested Computation` missing `runtime`, or naming a `computation`, + `executor.resource` or `attester.resource` that does not exist + +The point of running it in CI is that "this bundle is conformant" stays a +measured fact rather than a claim in a README. +""" +from __future__ import annotations + +import argparse +import datetime as _dt +import re +import sys +from pathlib import Path +from typing import Any, Dict, List, Tuple + +try: + import yaml # type: ignore +except ImportError: # pragma: no cover + print("PyYAML is required: pip install pyyaml", file=sys.stderr) + raise SystemExit(2) + +RESERVED = {"index.md", "log.md"} +SOURCE_SUFFIXES = ( + ".py", ".md", ".json", ".yml", ".yaml", ".toml", ".cfg", ".ini", ".txt", + ".js", ".cjs", ".mjs", ".ts", ".tsx", ".html", ".css", ".sh", ".ui", + ".pdb", ".cif", ".fasta", ".tsv", ".dat", ".png", ".lock", +) +VALID_STATUS = {"draft", "stable", "deprecated"} +ACTOR_RE = re.compile(r"^(human:[\w.@-]+|process:[\w.-]+|[\w.-]+/[\w.:-]+)$") +DATE_RE = re.compile(r"^\d{4}-\d{2}-\d{2}$") +LOG_HEADING_RE = re.compile(r"^##\s+(.+?)\s*$", re.MULTILINE) +LINK_RE = re.compile(r"(? None: + self.errors: List[Tuple[str, str]] = [] + self.warnings: List[Tuple[str, str]] = [] + + def error(self, where: str, msg: str) -> None: + self.errors.append((where, msg)) + + def warn(self, where: str, msg: str) -> None: + self.warnings.append((where, msg)) + + +def split_frontmatter(text: str) -> Tuple[Dict[str, Any] | None, str, str | None]: + """Return (frontmatter, body, parse_error).""" + match = FRONTMATTER_RE.match(text) + if not match: + return None, text, None + try: + data = yaml.safe_load(match.group(1)) + except yaml.YAMLError as exc: + return None, text[match.end():], str(exc) + if data is None: + data = {} + if not isinstance(data, dict): + return None, text[match.end():], "frontmatter is not a mapping" + return data, text[match.end():], None + + +def check_actor(report: Report, where: str, field: str, value: Any) -> None: + if not isinstance(value, str) or not ACTOR_RE.match(value): + report.warn(where, f"{field}: {value!r} does not match the section 7 actor convention") + + +def check_trust(report: Report, where: str, fm: Dict[str, Any], today: _dt.date) -> None: + generated = fm.get("generated") + if generated is None: + report.warn(where, "no 'generated' -- provenance of the concept is unrecorded") + elif isinstance(generated, dict): + if "by" not in generated: + report.warn(where, "generated has no 'by'") + else: + check_actor(report, where, "generated.by", generated["by"]) + else: + report.warn(where, "'generated' should be a mapping {by, at}") + + verified = fm.get("verified") + if verified is not None: + events = verified if isinstance(verified, list) else [verified] + for event in events: + if isinstance(event, dict) and "by" in event: + check_actor(report, where, "verified[].by", event["by"]) + else: + report.warn(where, f"verified entry is not a {{by, at}} mapping: {event!r}") + + status = fm.get("status") + if status is None: + report.warn(where, "no 'status' (defaults to stable)") + elif status not in VALID_STATUS: + report.warn(where, f"status: {status!r} is not draft|stable|deprecated") + + stale_after = fm.get("stale_after") + if stale_after is None: + report.warn(where, "no 'stale_after' -- freshness cannot be judged") + else: + date = stale_after if isinstance(stale_after, _dt.date) else None + if date is None: + if not (isinstance(stale_after, str) and DATE_RE.match(stale_after)): + report.warn(where, f"stale_after: {stale_after!r} is not YYYY-MM-DD") + return + date = _dt.date.fromisoformat(stale_after) + if today >= date: + report.warn(where, f"STALE: stale_after {date.isoformat()} has passed") + + for entry in fm.get("sources") or []: + if not isinstance(entry, dict) or not entry.get("resource"): + report.warn(where, f"source entry without 'resource': {entry!r}") + + +def check_computation(report: Report, where: str, path: Path, bundle: Path, fm: Dict[str, Any], body: str) -> None: + if not fm.get("runtime"): + report.warn(where, "Attested Computation without 'runtime' (section 10.2 requires it)") + for field, value in ( + ("computation", fm.get("computation")), + ("executor.resource", (fm.get("executor") or {}).get("resource")), + ("attester.resource", (fm.get("attester") or {}).get("resource")), + ): + if not value: + continue + target = (bundle / str(value).lstrip("/")) if str(value).startswith("/") else (path.parent / str(value)) + if not target.exists(): + alt = bundle / str(value) + if not alt.exists(): + report.warn(where, f"{field} -> {value} does not exist") + if not fm.get("computation") and "# Computation" not in body: + report.warn(where, "no 'computation' path and no '# Computation' body section (section 10.3)") + + +def check_repo_paths(report: Report, where: str, repo: Path, text: str, prefixes: List[str]) -> None: + """Warn about source paths a concept names that no longer exist. + + This is what catches a bundle drifting behind a refactor: the frontmatter + still parses, every link still resolves, and yet the concept points at files + that were moved or deleted. Paths are matched by prefix (`quest/`, `src/`, + ...) so prose and tables are covered, not just the `resource` field. + + Off by default: a concept may legitimately name a path that does not exist + -- a proposal, a counter-example, a file that was deleted on purpose -- so + this is a review aid, never an error. `log.md` is exempt entirely: history + is supposed to mention paths that no longer exist. + """ + pattern = re.compile( + r"(? None: + for target in LINK_RE.findall(body): + if target.startswith(("http://", "https://", "mailto:", "#")): + continue + clean = target.split("#", 1)[0] + if not clean: + continue + resolved = (bundle / clean.lstrip("/")) if clean.startswith("/") else (path.parent / clean) + if not resolved.exists(): + report.warn(where, f"broken link -> {target}") + + +def check_log(report: Report, where: str, body: str) -> None: + headings = LOG_HEADING_RE.findall(body) + if not headings: + report.warn(where, "log has no '## ' entries (section 9)") + for heading in headings: + if not DATE_RE.match(heading): + report.error(where, f"log date heading is not ISO YYYY-MM-DD: '## {heading}'") + + +def check_index(report: Report, where: str, is_root: bool, fm: Dict[str, Any] | None, body: str) -> None: + if fm is not None and not is_root: + report.error(where, "only the bundle-root index.md may carry frontmatter (section 12)") + if fm is not None and is_root and "okf_version" not in fm: + report.warn(where, "root index.md carries frontmatter but declares no okf_version") + if not LINK_RE.search(body): + report.warn(where, "index lists no links (section 8)") + + +def validate( + bundle: Path, + declared_version: str | None, + today: _dt.date, + path_prefixes: List[str] | None = None, +) -> Report: + report = Report() + repo = bundle.parent + files = sorted(p for p in bundle.rglob("*.md") if p.is_file()) + if not files: + report.error(str(bundle), "no markdown files found") + return report + + root_index = bundle / "index.md" + if not root_index.exists(): + report.warn(str(bundle), "no bundle-root index.md") + + for path in files: + where = str(path.relative_to(bundle.parent)) + text = path.read_text(encoding="utf-8") + fm, body, parse_error = split_frontmatter(text) + + # `okf_check_paths: false` opts a concept out of the existence check. + # Some documents name dead paths on purpose -- an audit of what rotted, + # a naming-convention concept citing files that were never created -- + # and flagging those trains readers to ignore the warnings. + opted_out = bool(fm is not None and fm.get("okf_check_paths") is False) + if path_prefixes and path.name != "log.md" and not opted_out: + check_repo_paths(report, where, repo, text, path_prefixes) + + if parse_error: + report.error(where, f"unparseable YAML frontmatter: {parse_error}") + continue + + if path.name == "index.md": + check_index(report, where, path == root_index, fm, body) + if fm and path == root_index: + version = str(fm.get("okf_version", "")) + if declared_version and version and version != declared_version: + report.warn(where, f"okf_version {version!r} != expected {declared_version!r}") + continue + + if path.name == "log.md": + if fm is not None: + report.warn(where, "log.md carries frontmatter; the spec defines none for it") + check_log(report, where, body) + check_links(report, where, path, bundle, body) + continue + + if fm is None: + report.error(where, "no YAML frontmatter block (section 11.1)") + continue + if not str(fm.get("type", "")).strip(): + report.error(where, "frontmatter has no non-empty 'type' (section 11.2)") + if not str(fm.get("description", "")).strip(): + report.warn(where, "no 'description'") + + check_trust(report, where, fm, today) + if str(fm.get("type", "")).strip() == "Attested Computation": + check_computation(report, where, path, bundle, fm, body) + check_links(report, where, path, bundle, body) + + return report + + +def main(argv: List[str] | None = None) -> int: + parser = argparse.ArgumentParser(description=__doc__.splitlines()[0]) + parser.add_argument("bundle", nargs="?", default="okf", help="path to the bundle root (default: okf)") + parser.add_argument("--version", default="0.2", help="expected okf_version (default: 0.2)") + parser.add_argument("--strict", action="store_true", help="treat warnings as failures") + parser.add_argument("--today", default=None, help="override today's date (YYYY-MM-DD) for staleness checks") + parser.add_argument( + "--check-paths", + default=None, + metavar="PREFIXES", + help="comma-separated source prefixes (e.g. 'fpsim/,src/') to check for existence; " + "catches a bundle drifting behind a refactor. Warnings only.", + ) + args = parser.parse_args(argv) + + bundle = Path(args.bundle).resolve() + if not bundle.is_dir(): + print(f"not a directory: {bundle}", file=sys.stderr) + return 2 + + today = _dt.date.fromisoformat(args.today) if args.today else _dt.date.today() + prefixes = [p.strip() for p in args.check_paths.split(",") if p.strip()] if args.check_paths else None + report = validate(bundle, args.version, today, prefixes) + + for where, msg in report.errors: + print(f"ERROR {where}: {msg}") + for where, msg in report.warnings: + print(f"warn {where}: {msg}") + + n_files = sum(1 for _ in bundle.rglob("*.md")) + print( + f"\n{n_files} concept file(s); {len(report.errors)} error(s), {len(report.warnings)} warning(s) " + f"-- {'CONFORMANT' if not report.errors else 'NOT CONFORMANT'} with OKF v{args.version}" + ) + if report.errors: + return 1 + return 1 if (args.strict and report.warnings) else 0 + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/okf/references/user-docs.md b/okf/references/user-docs.md new file mode 100644 index 0000000..204f0d3 --- /dev/null +++ b/okf/references/user-docs.md @@ -0,0 +1,43 @@ +--- +type: Reference +title: User documentation +description: Where the human-facing manual lives and which parts are generated. +resource: doc/index.md +tags: [documentation, generated] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: doc-index-md + resource: ../../doc/index.md + title: doc/index.md + author: human:tpeulen + last_modified: 2026-07-27 +--- + +`okf/` is the knowledge layer for agents. `doc/` and `README.md` are the manual +for people, and a change to user-visible behaviour updates both +([workflows/change-tracking.md](/workflows/change-tracking.md)). + +| Path | Content | Generated? | +|---|---|---| +| `README.md` | Project overview, install, quickstart for every surface, citations | hand-written | +| `doc/index.md` | Documentation entry point | hand-written | +| `doc/cli.md` | CLI reference | hand-written | +| `doc/quenching_manual.md` | The quenching model explained for users | hand-written | +| `doc/parameters.md` | Full parameter reference | **generated** | +| `doc/generate_parameter_docs.py` | The generator | — | +| `doc/img/`, `doc/logo.png` | Figures | — | +| `notebooks/` | Library-usage examples, checked by `tests/test_notebooks.py` | — | + +# The generated page + +`doc/parameters.md` is produced from `quest/settings/parameter_catalog.json`: + +```bash +python doc/generate_parameter_docs.py +``` + +Edit the catalog, then regenerate. Hand edits to `doc/parameters.md` are +overwritten and will also drift from the web UI, which reads the same catalog +([architecture/project-schema.md](/architecture/project-schema.md)). diff --git a/okf/specs/assessment.md b/okf/specs/assessment.md new file mode 100644 index 0000000..690169c --- /dev/null +++ b/okf/specs/assessment.md @@ -0,0 +1,93 @@ +--- +type: Specification +title: Assessment +description: The gap backlog — where the current tree diverges from the target architecture, itemised with ids and status. +resource: okf/specs/plugin-integration.md +tags: [backlog, assessment, layering, technical-debt] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2026-10-26 +--- + +Gaps between the tree and +[the target split](plugin-integration.md). Each row is a discrete, landable +unit. Update the row and the totals in the same change that closes it, and say +so in [okf/log.md](../log.md). + +**Status: 11 of 11 closed** (opened 2026-07-26; LAY-02, LAY-03, LAY-05, LAY-08 +and LAY-09 closed 2026-07-27; LAY-06, LAY-10 and LAY-11 closed 2026-07-27 by the +AutoForm migration; **LAY-04 and LAY-07 closed 2026-07-28**). + +**Still open elsewhere:** LAY-05's ChiSurf half — the `quenching_estimator` +plugin folder still has no manifest of its own and loads through the host's +legacy AST discovery. That is phase 10 of +[programme-2026-07.md](programme-2026-07.md). + +| Id | Severity | Status | Gap | +|---|---|---|---| +| LAY-01 | high | **closed 2026-07-26** | ~~The web backend imports **private CLI helpers**.~~ Project template and validation now live in [`quest/project.py`](/subsystems/core-api.md) (`template_project`, `validate_project`, `ProjectValidationError`), exported from `quest.api`. The CLI keeps `_validate_project` as a thin translator to `ClickException`; the web backend and `quest/lib/fps_json.py` — which imported the CLI *from inside the library* — now call the domain. Guardrail: `tests/test_service_layer.py::TestLayering`. | +| LAY-02 | high | **closed 2026-07-27** | ~~The GUI owns a domain object.~~ `TransientDecayGenerator` no longer inherits `DonorDecay`. It **builds** one per run from the form (`build_model()`, driven by `MODEL_ARGUMENT_SOURCES`) and reads results back through delegating properties. The model is a plain object with no Qt in it; a guardrail test asserts `DonorDecay not in TransientDecayGenerator.__mro__`. Behaviour is unchanged, pinned by 11 characterisation tests written before the change. | +| LAY-03 | high | **closed 2026-07-27** | ~~No RPC registry.~~ `quest/rpc/` provides a `ServiceDispatcher`, an `InProcessClient` and a duck-typed `register_services(dispatcher)` registering **all eleven** methods behind one `{"ok", "result"\|"error"}` envelope. The last three (`quest.structure.metadata`, `quest.jobs.list`, `quest.jobs.get`) landed with LAY-09. | +| LAY-04 | medium | **closed 2026-07-28** | ~~`quest.api` is a re-export shim.~~ It is verb-oriented (`template`, `validate`, `simulate`, `scan`, `describe`, …), every verb goes through a **client**, and `use_client` swaps in a remote one — the local/remote resolution the row asked for. The web backend calls `api.simulate` instead of reaching into `quest.core`, and maps `error_code` onto HTTP status. **Serialization moved to the transport**: handlers return native results and only `to_payload` at a boundary converts them, because `OBJ-02`'s host optimiser calls `simulate` thousands of times and was paying a numpy→list conversion of every decay channel per iteration. The domain re-exports stay — a notebook that wants `build_donor_from_project` should have it — but the verbs are the supported way in. Contract, error codes and `quest.contract.describe` landed with it; guardrail `tests/test_contract.py` (30 tests). | +| LAY-10 | medium | **closed** (2026-07-27) | **The GUI edited a legacy quenching shape.** `DonorDecay.quencher` (`{residue: {atoms, kQ}}`) carried no per-residue contact radius and no per-residue stickiness, so the Qt table could not express what `amino_acid_interactions` does, and the widget ran `stickiness_mode="global"` while every other surface ran `"amino_acid"`. Closed by the AutoForm migration, not by a fix to the old table: the form's state *is* the project, so its quencher table edits `amino_acid_interactions` directly — kQ, contact radius, quenching atoms and slow factor per residue. There is no second shape left to disagree. | +| LAY-09 | medium | **closed 2026-07-27** | ~~Domain logic living in the web backend.~~ The PDB/CIF chain–residue parser moved to `quest/core/structure/metadata.py::structure_metadata`, and job listing/reading/archiving to `quest/jobs.py`. The routes are now adapters; the capabilities are reachable from the CLI, notebooks and a host, and are covered by 14 domain tests instead of only through HTTP. | +| LAY-05 | medium | **closed 2026-07-27** | ~~QuEst declares nothing.~~ `quest/manifest.json` carries the identity, the `gui`/`cli`/`services` entry points and all eleven RPC methods with params/result schemas and `long_running` flags; five tests fail if it and the registry disagree. **The ChiSurf half closed 2026-07-28** (chisurf `669fce499`). `chisurf/plugins/quenching_estimator/` now follows the `modelling/fps_json_editor` layout — `manifest.json`, `api/`, `rpc/`, `cli/`, `gui/` — with **no `core/`**, because QuEst is the core and nothing there reimplements it: `rpc/services.py` hands the host's dispatcher to `quest.rpc.services.register_services`, `api/contract.py` re-exports `quest.rpc.contract`, and `rpc_methods` is copied verbatim from `quest/manifest.json` with a test that fails if the two diverge. The GUI is a `ChisurfDockTool` instead of a `QMainWindow` used as a central widget, and **nothing imports `quest` at module scope** — the old single file did, so ChiSurf startup pulled in QuEst, IMP and numba whether or not anyone opened the tool. | +| LAY-11 | medium | **closed** (2026-07-27) | **The Qt form drew its own plots.** It built pyqtgraph widgets by hand for the decay, the trajectory and the autocorrelation. Closed with LAY-06, as predicted: the three plots are now `plot` sections in `quest.view.json`, rendered by AutoForm through ChiSurf's `chiplot`, and QuEst supplies only the data (`decay_series`, `trajectory_series`, `autocorrelation_series` on the form model). QuEst owns no plotting code at all. | +| LAY-06 | medium | **closed** (2026-07-27) | ~~No declarative view spec.~~ The Qt form is `quest/gui/quest.view.json`, **generated** from `quest/settings/parameter_catalog.json` by `quest/gui/generate_view_spec.py` and rendered by ChiSurf's `AutoForm`. Every `.ui` file is gone — `dye_diffusion2.ui`, `pdb_widget.ui`, `ui/*.ui` — and with them the 1,899-line widget, `widgets.py` and the 98 kB generated Qt resource module; `quest/gui/dye_widget.py` is now ~130 lines that put an AutoForm in a QWidget. The form binds to `quest.gui.form_model.ProjectFormModel`, whose state **is** a project dict, so the hand-written `to_project_dict`/`load_project_dict` pair — where the GUI drifted from the CLI before — no longer exists. `quest/gui/autoform_panel.py` remains for rendering a single RPC method's parameters from the manifest. Covered by `tests/test_view_spec.py`, `tests/test_form_model.py`, `tests/test_gui_widget.py` and `tests/test_gui_simulation.py`. | +| LAY-07 | medium | **closed 2026-07-28** | ~~Long-running work has three mechanisms.~~ `quest/tasks.py` owns one: statuses, `progress`, cooperative `should_cancel`, and a `to_dict()` shape all matching `chisurf/server/jobs.py` so a host recognises them — implemented in QuEst, not imported, because a plugin that needs its host to run standalone is not a plugin. `scan_positions` takes a `should_cancel` predicate and a `report_progress` callback (plain callables, so `quest.core` knows nothing about job bookkeeping), `quest.scan` registers a job and returns its `job_id`, and `quest.jobs.list/get/cancel` drive it. **The word was also split:** run artefacts are `quest/runs.py` and `quest.runs.*`; `jobs` now means a running operation, as it does to the host — `quest.jobs.list` would otherwise have handed a ChiSurf caller directories. **Stated limitation:** cancellation is cooperative and a scan's only checkpoint is between sites, so a single `simulate` is effectively atomic — `_simulate_traj` computes a whole trajectory in one `njit` call and a jitted kernel cannot poll a Python flag. `CANCELLING` is a distinct state for exactly that reason. | +| LAY-08 | low | **closed 2026-07-27** | ~~`sys.path` injection.~~ Every internal import is spelled `quest.lib.…` and `quest/__init__.py` no longer touches `sys.path`. This was not merely cosmetic: `lib.structure.Structure` and `quest.lib.structure.Structure` were **two different classes**, so an `isinstance` check across the boundary failed and a `Structure` got wrapped twice. | + +# Deduplication against imp-tricks + +Target: [imp-tricks-dedup.md](imp-tricks-dedup.md). General fluorescence +machinery belongs in `IMP.bff`; QuEst carries a second copy of much of it. + +> **Numbering warning, 2026-07-28.** The `DUP-*` labels in this table are the +> authoritative ones, and [handover.md](../handover.md) used a *different* set: +> it called the `density2points` adoption "DUP-02" (here **DUP-05**) and the +> distance metrics "DUP-03" (here **DUP-04**). The commit messages +> `78dc4c8` and `9b1192e` follow the handover's numbering and are therefore +> mislabelled against this table. The work is right; the labels in those two +> commits are not. Cite this table, not the handover, for a row number. + +| Id | Severity | Status | Gap | +|---|---|---|---| +| DUP-01 | high | **DONE** (2026-07-28) | **The AV backend dispatch exists twice.** `AV.__init__` + `quest/lib/imp_av.py` reimplement `IMP.bff.av.compute_av`, down to the same backend ordering — and QuEst's copy **does not work**: in `arm64`, where a compiled `IMP.bff` exists, neither backend of `compute_av` runs: `av/compute.py:162` calls `Particle.get_particle_index()` (this IMP spells it `get_index()`), and `av/compute.py:231` rejects LabelLib because it looks for `LabelLib.AV` while this LabelLib exposes `dyeDensityAV1`. Both are one-line fixes **in imp-tricks**, and they unblock the largest deletion QuEst has left. Selection now defaults to LabelLib explicitly (`resolve_av_backend`, `QUEST_AV_BACKEND`, `AV.av_backend`), which contains the damage but does not remove the duplicate. | +| DUP-02 | high | **DONE** (2026-07-28) | ~~The capability check asks the wrong question.~~ `HAS_IMP_BFF` now asks both halves of the real question: the compiled `IMP.bff.AV` class **and** an importable `IMP.bff.av.compute_av` that drives it. `hasattr(IMP.bff, "AV")` was the compiled half only, so an environment with a compiled IMP.bff but no imp-tricks reported the backend available and failed on first use. `compute_av` is *imported* rather than probed with `hasattr`, because `IMP.bff.av` is a namespace subpackage spliced in at runtime and an attribute lookup does not answer that question. | +| DUP-03 | medium | **rejected, and re-specced** (2026-07-28) | ~~`fret_rate_trace` belongs with `IMP.bff.cgdye.analysis.fret`, which additionally handles κ².~~ **Both halves of that were wrong.** `calculate_fret_exact` takes an `(nd × na)` distance matrix *plus transition matrices for both dyes*, forms `np.kron(p_d, p_a)` and solves a Markov kinetic ensemble — a rotamer-library formulation, O((nd·na)²), against QuEst's ~10⁵-point clouds. It is not a slower drop-in; it is **a different model at a different scale**. Nor does it *handle* κ²: it accepts a κ² matrix as input. The real kernel, `IMP.bff.cgdye.rotamer.scoring.kappa2_from_vectors`, needs transition dipole vectors, which a structureless point in a volume does not have. **Direction reversed:** QuEst's trajectory kernel is the general one and should go *upstream* — same as `dRmp` under `DUP-04`. What moved instead is the assumption: `fret.kappa2` is now an explicit, validated, documented project field defaulting to the isotropic 2/3. | +| DUP-04 | medium | **DONE** (2026-07-28; `dRmp` contributed upstream 2026-07-28) | **Distance metrics are duplicated.** ⟨R_DA⟩ and ⟨R_DA⟩_E: adopt `random_distances` + `av_pair_statistics` — verified to agree with `RDAMean`/`RDAMeanE` within sampling noise, and nothing blocks it. **`dRmp` goes the other way:** upstream's `r_mp` returns ⟨R_DA⟩ (its own docstring says "same as `r_da_mean` here"), which is a different quantity — 47.65 vs 51.53 Å on 148l E15/E90 — and it cannot be computed from a distance sample at all. QuEst's implementation is the correct one and should be contributed upstream. | +| DUP-05 | low | **mostly done** (2026-07-28) | `density2points` and the contact-volume split are upstream's: `subav` is a thin adapter over `IMP.bff.av._kernels.split_av_acv` and the 93-line `_subav` kernel is deleted. **Neither adoption was a drop-in** — `split_av_acv` carried the float-corner *and* truncate-toward-zero registration defects QuEst had just been fixed for, and returned float64 masks (12.5 MB per site at ng=92 against 1.6 MB); all three were fixed upstream first (imp-tricks `3dbefc8`). Numbers verified unchanged. **Remaining:** `asa`/`spherePoints` → `IMP.cgmol.sterics.asa`, which is cold (once per simulation, for quencher SASA) and not yet adopted. | +| DUP-07 | medium | **partly closed 2026-07-27** | ~~RCSB fetching duplicated with ChiSurf.~~ Moved into `chisurf/core/fio/structure/fetch.py` (merging QuEst's `.cif` fallback into it), re-exported by the `fps_json_editor` plugin, and QuEst delegates to it when a checkout is reachable. **Remaining:** fps.json payload handling — ChiSurf's `payload.py` drags its `FpsJsonModel` along, so moving it to core is the next step. **Not a duplicate after all:** MRC writing — ChiSurf voxelises point clouds via `IMP.em`, QuEst writes precomputed density grids. | +| DUP-06 | ~~low~~ **high** | **DONE** (2026-07-28) | ~~QuEst carries its own PDB/CIF parser and `Structure`.~~ Severity was wrong: this was filed "low — a hazard that has not bitten yet", and it had bitten every multi-chain structure QuEst ever read. The parser half was already IMP's ([specs/structure-io.md](structure-io.md)); the **residue model** was not, and `Structure.residue_dict`/`residue_ids` keyed on `res_id` alone, which restarts per chain. On `mc4r_dimer.cif` all 534 numbers occur in both chains, so each entry held two residues' atoms and `move_center_of_mass` folded both side chains into one CB. Identity now comes from IMP's hierarchy at the reader — a `residue_index` per `(chain, res_id, insertion_code)`, plus the `insertion_code` column the reader had been discarding — and the domain still passes plain numpy arrays, so no IMP object crosses into it. Moved exactly one number: the dimer's CB centroid. Guarded by `tests/test_residue_identity.py`. | + +# Severity + +- **high** — blocks the integration outright, or is an active layering + violation that new code will copy. +- **medium** — real duplication or a missing contract; costs correctness over + time rather than today. +- **low** — a hazard that has not bitten yet. + +# Notes + +The cheap half is done: project logic is in the domain (LAY-01), the method +surface is complete and declared (LAY-03, LAY-05), and the capabilities that +only the browser could reach are now domain functions (LAY-09). + +**LAY-02 is closed**, so the model is a plain object on every surface and a host +can drive it without a form — the structural prerequisite for +[OBJ-02](objectives.md). LAY-04 (a real facade) is the natural next step, and +LAY-10 is now cheap: the widget builds its model through one place +(`build_model`), so switching the quencher table to `amino_acid_interactions` +touches that method and the table, not the whole widget. + +Closing LAY-01 also removed a **triplicated** implementation of "simulate one +labeling site and report it": the CLI, the web backend and +`quest/lib/fps_json.py` each had their own copy, and they had drifted — the +library's copy omitted the quencher attribution the other two reported, and the +CLI's copy dropped the fps.json AV overrides into the project without also +applying them to `av_parameter`. All three now call `quest.scan.simulate_site`. + +None of these are correctness bugs in the simulation. For those see +[references/known-issues.md](/references/known-issues.md); for where QuEst is +headed scientifically see [objectives.md](objectives.md). diff --git a/okf/specs/autoform-and-plugin-architecture.md b/okf/specs/autoform-and-plugin-architecture.md new file mode 100644 index 0000000..96aa4eb --- /dev/null +++ b/okf/specs/autoform-and-plugin-architecture.md @@ -0,0 +1,97 @@ +--- +type: Specification +title: AutoForm Web Support & ChiSurf Multi-Interface Plugin Architecture for QuEst +description: Comprehensive PRDs, architecture specifications, and implementation checklist for bringing dynamic AutoForm support to the Web UI and standardizing QuEst on the ChiSurf 5-way interface plugin contract (API, CLI, RPC JSON, ZMQ, Web AutoForm). +resource: quest/rpc/zmq_server.py, quest/rpc/services.py, quest/gui/generate_view_spec.py, webui/frontend/src/components/autoform +tags: [autoform, chisurf, plugins, zmq, rpc, cli, api, webui, prd, architecture] +status: draft +generated: { by: human:tpeulen, at: 2026-08-07T00:00:00Z } +stale_after: 2026-11-07 +--- + +# Architecture Overview: ChiSurf Plugin Compatibility & Web AutoForm + +This specification defines how **QuEst** implements the **ChiSurf Plugin Standard** across 5 unified execution interfaces, bringing desktop-grade AutoForm declarative rendering to modern web applications. + +```mermaid +flowchart TD + subgraph Single Core Science Engine ["QuEst Python Core Science Engine"] + API["1. Python API\n(quest.api / quest.project)"] + Catalog["Parameter Catalog\n(parameter_catalog.json)"] + end + + subgraph Interface Seams ["ChiSurf Plugin Interfaces"] + CLI["2. CLI\n(quest.cli:cli)"] + RPC["3. RPC JSON (HTTP)\n(quest.rpc.services)"] + ZMQ["4. ZMQ Server\n(quest.rpc.zmq_server)"] + ViewGen["5. AutoForm Spec Generator\n(generate_view_spec.py)"] + end + + subgraph Web UI Engine ["Web UI Client"] + WebAutoForm["Web AutoForm Engine\n(React / TS)"] + RestAPI["FastAPI / REST Client"] + end + + API --> CLI + API --> RPC + API --> ZMQ + Catalog --> ViewGen + ViewGen -->|quest.view.json| WebAutoForm + WebAutoForm -->|State & RPC Callbacks| RestAPI + RestAPI --> RPC +``` + +--- + +# PRD 1: Web AutoForm Engine (React / WebUI) + +### Objective +Provide a native, schema-driven React **Web AutoForm** component tree that dynamically renders complex hierarchical configuration forms directly from ChiSurf AutoForm view-spec JSON (`quest.view.json` or any plugin `.view.json`). + +### Requirements +1. **Dynamic Section Dispatching**: + - `panel`: Accordion / collapsible container holding an ordered list of child sections. + - `value`: Scalar input (`kind`: int, float, str, text) with unit labels, help badges, step sizes, and dirty state tracking. + - `choice`: Dropdown/radio selector supporting inline options or dynamic catalog parameter options. + - `toggle` / `toggle_row`: Checkbox toggle inputs. + - `button_row`: Action trigger buttons. + - `table` / `custom`: Tabular record displays and bespoke extension slot renderers. +2. **State & Event Binding**: + - Accepts `spec` (JSON tree), `data` (current project JSON object), `onChange(path, value)`, `onSave(path)`, and `catalog`. + - Resolves target paths (e.g. `attachment.chain`, `fret.R0_matrix`) using dot-notation getters/setters. +3. **Localisation Seam**: + - Integrates with `t(key, fallback)` or uses translated text directly from localized view specs (`quest.view.de.json`, `quest.view.fr.json`). + +--- + +# PRD 2: ChiSurf 5-Way Plugin Interface Compatibility + +### Objective +Ensure QuEst serves as the gold-standard blueprint for ChiSurf plugins by exposing all 5 standard plugin execution surfaces: + +| Surface | Interface Module | Description | +|---|---|---| +| **1. API** | `quest.api` / `quest.project` | Direct Python function imports for scripts and notebooks. | +| **2. CLI** | `quest.cli:cli` | Command-line interface for headless batch runs and pipeline scripting. | +| **3. RPC JSON** | `quest.rpc.services` / `dispatcher.py` | Standalone JSON-RPC 2.0 service dispatcher over HTTP (FastAPI `/api/rpc`). | +| **4. ZMQ** | `quest.rpc.zmq_server` | ZeroMQ REQ/REP server allowing out-of-process RPC execution from any language (C++, Julia, Rust, Python). | +| **5. Web AutoForm** | `quest.view.json` + `webui/frontend` | Dynamic schema-driven web UI form generation replacing PyQt-specific widgets. | + +--- + +# Implementation Checklist + +- [x] **Phase 1: Architecture Specification & PRDs** + - [x] Document ChiSurf 5-way interface standard and Web AutoForm PRDs (`okf/specs/autoform-and-plugin-architecture.md`). +- [ ] **Phase 2: Python Backend ZMQ & RPC Extensions** + - [ ] Implement `quest.rpc.zmq_server` (ZeroMQ RPC server for QuEst RPC methods). + - [ ] Extend `quest.rpc.services` and FastAPI backend to expose `/api/autoform-spec` and ZMQ endpoints. +- [ ] **Phase 3: Web AutoForm React Engine (`webui/frontend`)** + - [ ] Build `src/components/autoform/AutoForm.tsx`. + - [ ] Build `src/components/autoform/AutoSection.tsx` & `AutoPanel.tsx`. + - [ ] Build `src/components/autoform/AutoValue.tsx`, `AutoChoice.tsx`, `AutoToggle.tsx`, `AutoButtonRow.tsx`. + - [ ] Add AutoForm mode toggle / component view in Web UI sidebar. +- [ ] **Phase 4: Tests & Verification** + - [ ] Python unit tests for ZMQ server (`tests/test_zmq_rpc.py`). + - [ ] Backend tests for `/api/autoform-spec` & RPC services. + - [ ] E2E browser tests for Web AutoForm rendering and interactions. diff --git a/okf/specs/autoform-scheme.md b/okf/specs/autoform-scheme.md new file mode 100644 index 0000000..63ce81a --- /dev/null +++ b/okf/specs/autoform-scheme.md @@ -0,0 +1,145 @@ +--- +type: Specification +title: Declarative form scheme — ChiSurf AutoForm and QuEst as the blueprint +description: The view-spec JSON contract for declaring editors without GUI code, and how QuEst already implements it — the blueprint for porting a Python app to a web app. +resource: webui/frontend/src/components, quest/settings/parameter_catalog.json, quest/gui/generate_view_spec.py +tags: [autoform, scheme, forms, web, chisurf, blueprint, porting] +status: draft +generated: { by: human:tpeulen, at: 2026-08-07T00:00:00Z } +stale_after: 2026-11-07 +sources: + - id: chisurf-dataspec + resource: ../../chisurf/chisurf/core/dataspec/__init__.py + title: chisurf/core/dataspec (section vocabulary + parser) + author: human:tpeulen + last_modified: 2026-08-07 + - id: chisurf-autoform + resource: ../../chisurf/chisurf/gui/autoform/auto_form.py + title: chisurf/gui/autoform (renderer) + author: human:tpeulen + last_modified: 2026-08-07 + - id: quest-view-spec + resource: quest/gui/generate_view_spec.py + title: quest/gui/generate_view_spec.py (generator) + author: human:tpeulen + last_modified: 2026-08-07 + - id: quest-catalog + resource: quest/settings/parameter_catalog.json + title: quest/settings/parameter_catalog.json + author: human:tpeulen + last_modified: 2026-08-07 +--- + +# Why this exists + +A Python desktop app and its web twin should not each hand-write a form. QuEst +already proves the alternative: **one declarative JSON scheme, generated from a +single source of truth, rendered by two unrelated toolkits.** This concept +documents that scheme so a new app being ported from Python to the web can reuse +it instead of inventing a second way to describe an editor. + +The scheme predates QuEst: it is ChiSurf's AutoForm view-spec. What QuEst adds, +and what the port should copy, is the *derivation* — one catalog driving the +desktop spec, the docs and the web UI so none of them can silently diverge. + +# The scheme (ChiSurf AutoForm view spec) + +An editor is a plain, toolkit-free JSON tree of typed **sections**. The parser +lives in `chisurf/core/dataspec/__init__.py`; the renderer in +`chisurf/gui/autoform/auto_form.py`. + +``` +{ "sections": [ ... ], "plots": [ ... ] } +``` + +Section primitives (`"type"` field): + +| type | role | +|---|---| +| `panel` | foldable group box holding an ordered list of child sections | +| `value` | one scalar field (`kind`: int / float / str / text / expression / file / directory / date) | +| `choice` | one-of-N selector (combo/radio), options inline or via `options_source` | +| `toggle` / `toggle_row` | a boolean / a run of booleans | +| `button_row` | a row of action buttons | +| `table` | record table with declared columns, `source`, optional `update_call` | +| `parameter_group` / `parameter_group_table` | a `FittingParameterGroup`'s params as a grid or table | +| `dynamic_group` | variable-length list of rows with add/del | +| `curve_input` | a data-curve picker (e.g. an IRF) | +| `custom` | bespoke widget referenced by string `key` + registry + `options` | +| `plot` | an inline plot whose data comes from a named `source` method | +| `dock_area` | rearrangeable/floatable panels with `split`/`sizes`/`persist` | +| `info` | read-only HTML/Markdown block | +| `wizard` / `wizard_step` | directed two-column multi-step form | + +Three properties make it work: + +- **Binding by name, not reference.** A section resolves `target`/`attr` + against the model via `getattr`/`setattr`, or dispatches a `set_action`. + `custom` sections reference a GUI widget by `key` + a GUI-side registry. The + spec never imports a toolkit. +- **Localisation is a single parse seam.** On load, the text-carrying fields + (`title`, `label`, `description`, `add_label`, `column`… — the lists + `_TEXT_KEYS` / `_ITEM_TEXT_KEYS` in the parser) run through the i18n layer + `tr()`, one seam every spec passes through. +- **A plain dict is a form for free.** `SettingsView(dict)` derives a + `ModelView` from the dict's structure (nest → `panel`; scalar → typed field), + and `ParameterGroupView(group)` derives one from a param group — zero authored + JSON for the common case. + +## QuEst as the blueprint + +QuEst stands on a source of truth and *generates* every surface's schema: + +- `quest/settings/parameter_catalog.json` — one entry per parameter: `type`, + `unit`, `label`, `description`, `options`, `category`. +- `quest/settings/locales/{en,de,fr}.json` — the catalog + UI strings in each + language; `quest/gui/generate_view_spec.py` emits **one AutoForm view spec per + language** (`quest.view.json`, `quest.view..json`) that the desktop's + `quest/gui/autoform_panel.py` hands straight to ChiSurf's renderer. +- The web UI serves the **same** spec: `/api/autoform-spec` returns + `build_view_spec(locale)` and a small React autoform + (`webui/frontend/src/components/autoform/`) renders it by section `type` — + the port's = `Field` per spec type. `doc/generate_parameter_docs.py` writes + the docs. + +Since 2026-08-09 the web form is **AutoForm-only**: the hand-built React form +that used `Field.tsx` (from the catalog) was deleted, so both the desktop and +the web render the same authored spec. `lib/autoformPaths.ts` maps each spec +`attr` (the flat `ProjectFormModel` name) to its nested project path. + +So the invariant the port wants: **change the catalog and the desktop form, the +web form, the docs and the translated labels all follow — asserted by +`test_view_spec.py` which regenerates in memory and fails on drift.** + +The reusable pieces the port should copy: + +1. A single parameter catalog (authored in one place). +2. AutoForm view-spec emission from that catalog (the shared contract). +3. A small schema→field renderer per toolkit (e.g. one React `Field` per spec + `type` — what `AutoSection.tsx` plus the `.view.json` together are). +4. All user-facing text at the parse/localisation seam. + +# Decision aids for a port + +| python app | port via | +|---|---| +| parameters on model/group | `SettingsView`/`ParameterGroupView` derivation + catalog | +| output fields / states | `value` read-only / `info` | +| tables of records | `table` with `source` + `update_call` | +| bespoke panel | `custom` `key` + registry | +| multi-page setup | `wizard` | +| plot windows | `plot` `key` + options | + +# Open questions + +- Whether the port's web renderer can consume the view-spec JSON *directly* (a + React autoform by spec `type`) or whether the spec should back to a second, + tabular catalog first. QuEst's web UI today uses the catalog, the desktop the + spec: unifying on the spec both renderers is the cleaner target. +- Where the reusable tour + i18n ratchet settle (they are siblings of this). + +# Related + +- The limits of "flat" parameters vs the spec's `custom`/table primitives. +- [project-schema.md](/architecture/project-schema.md) — the *project JSON* + contract (data), distinct from the *view spec* (the form over it). \ No newline at end of file diff --git a/okf/specs/chisurf-autoform-integration.md b/okf/specs/chisurf-autoform-integration.md new file mode 100644 index 0000000..1ed6977 --- /dev/null +++ b/okf/specs/chisurf-autoform-integration.md @@ -0,0 +1,86 @@ +--- +type: Specification +title: ChiSurf AutoForm dependency & integration architecture +description: The ChiSurf AutoForm components QuEst consumes as a host-integrated plugin and as a standalone desktop app, and the in-tree fallback. +resource: quest/gui/dye_widget.py +tags: [autoform, chisurf, dependency, gui, standalone, plugin] +status: draft +generated: { by: human:tpeulen, at: 2026-08-07T00:00:00Z } +stale_after: 2026-11-07 +sources: + - id: chisurf-autoform + resource: ../../chisurf/chisurf/gui/autoform/auto_form.py + title: chisurf/gui/autoform (renderer) + author: human:tpeulen + last_modified: 2026-08-07 +--- + +# ChiSurf AutoForm Dependency & Integration Architecture + +This specification details the ChiSurf AutoForm components available to QuEst as an allowed dependency, explaining how QuEst consumes them both as a host-integrated ChiSurf plugin and as a standalone desktop application. + +--- + +## 1. Overview & Dependency Scope + +ChiSurf provides a complete, production-grade declarative AutoForm engine under `chisurf.gui.autoform` and `chisurf.core.dataspec`. QuEst imports these components whenever ChiSurf is reachable on `sys.path` (via `quest.hosts.enable_chisurf()`), and provides a lightweight in-tree fallback (`InTreePyQtAutoForm`) when running standalone without ChiSurf. + +--- + +## 2. Primary ChiSurf AutoForm Classes + +### `chisurf.gui.autoform.auto_form.AutoForm` +The master `QWidget` AutoForm container that walks a model's declarative `view_spec()` / `DataSet` and builds the control panel by composition. + +- **`AutoForm(model)`**: Renders a bound control panel for any model object (such as `ProjectFormModel`) from its `view_spec()`. +- **`AutoForm.from_rpc_method(method, parent=None, **kwargs)`**: Renders a parameter form for any declared plugin RPC method in `quest/manifest.json` (e.g. `quest.simulate`). +- **`AutoForm.from_parameter_group(group, parent=None, **kwargs)`**: Renders a `FittingParameterGroup` parameter grid without authored JSON. +- **`form.sync_fields()`**: Re-reads model attributes into controls without rebuilding the Qt widget layout. +- **`form.refresh_plots()`**: Triggers live redraw across all embedded plot widgets. +- **`form.state()` / `form.apply_state(values)`**: Serializes and restores complete form state as JSON mappings. + +--- + +## 3. Available AutoForm Sections & Widgets + +ChiSurf registers 27 section/plot factories in `chisurf.gui.autoform.sections`: + +| Section Key / Class | ChiSurf Module | Description & QuEst Usage | +| :--- | :--- | :--- | +| **`panel`** (`PanelSection`) | `chisurf.gui.widgets.collapsible_box` | Collapsible accordion group boxes with auto-fold timers (`CollapsibleBox`). | +| **`dock_area`** (`DockAreaSection`) | `chisurf.gui.widgets.dock_area` | Rearrangeable, floatable dock tab containers authored in `.view.json`. | +| **`value`** (`ValueSection`) | `chisurf.gui.autoform.sections.builtin` | Scalar value inputs (spin boxes, line edits) with min/max, step, and unit badges. | +| **`choice`** (`ChoiceSection`) | `chisurf.gui.autoform.sections.builtin` | Dropdown selection combo boxes bound to model attributes. | +| **`toggle`** (`ToggleSection`) | `chisurf.gui.autoform.sections.builtin` | Checkbox toggles. | +| **`toggle_row`** (`ToggleRowSection`) | `chisurf.gui.autoform.sections.builtin` | Horizontal row of checkable toggles. | +| **`button_row`** (`ButtonRowSection`) | `chisurf.gui.autoform.sections.builtin` | Action button rows. | +| **`plot`** (`PlotSection`) | `chisurf.gui.autoform.sections.builtin` | Live inline pyqtgraph plots for fluorescence decays, dye trajectories, and ACFs. | +| **`table`** (`TableSection`) | `chisurf.gui.autoform.sections.builtin` | List-of-dict table section editor (e.g. `quencher_rows`). | +| **`chimol`** (`chimol_section`) | `chisurf.gui.autoform.sections.chimol_section` | Embedded 3D Molecular structure viewer canvas. | +| **`help`** (`help_section`) | `chisurf.gui.autoform.sections.help_section` | Inline markdown/HTML help documentation panels. | +| **`embed`** (`embed_section`) | `chisurf.gui.autoform.sections.embed_section` | Adopt existing custom Qt widgets into the AutoForm layout. | +| **`progress`** (`progress_section`) | `chisurf.gui.autoform.sections.progress_section` | Simulation progress bar and cancellation controls. | +| **`background_run`** (`background_run_section`) | `chisurf.gui.autoform.sections.background_run_section` | Asynchronous background worker execution wrapper. | + +--- + +## 4. QuEst Dual-Mode Architecture + +``` + ┌────────────────────────────────┐ + │ quest.view.json │ + │ (AutoForm View Schema) │ + └───────────────┬────────────────┘ + │ + ┌───────────────────────┴───────────────────────┐ + │ │ + ChiSurf Host Present Standalone / Fallback + │ │ + ┌───────────────▼───────────────┐ ┌───────────────▼───────────────┐ + │ chisurf.gui.autoform.AutoForm │ │ InTreePyQtAutoForm │ + │ (Full ChiSurf Engine) │ │ (QuEst In-Tree Fallback) │ + └───────────────────────────────┘ └───────────────────────────────┘ +``` + +1. **Host-Integrated Mode**: `dye_widget.py` and `autoform_panel.py` import `chisurf.gui.autoform.auto_form.AutoForm` when ChiSurf is installed/linked. +2. **Standalone Fallback Mode**: When ChiSurf is absent, `InTreePyQtAutoForm` parses `quest.view.json` and renders native PyQt widgets (`InTreeCollapsiblePanel`, `QuEstPlotCanvas`, `QuencherTableWidget`), preserving identical GUI definitions across desktop and web endpoints. diff --git a/okf/specs/imp-tricks-dedup.md b/okf/specs/imp-tricks-dedup.md new file mode 100644 index 0000000..4cf67b0 --- /dev/null +++ b/okf/specs/imp-tricks-dedup.md @@ -0,0 +1,459 @@ +--- +type: Specification +title: Deduplication against imp-tricks +description: General fluorescence and structural machinery belongs in imp-tricks under IMP.bff; QuEst is the application on top of it. +resource: https://github.com/fluorescence-tools/imp-tricks +tags: [target, dedup, imp, imp-bff, layering, accessible-volume] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-27T00:00:00Z } +stale_after: 2027-01-27 +--- + +> Target. Companion to [plugin-integration.md](plugin-integration.md): that one +> is about *how QuEst is called*, this one is about *what QuEst should own*. + +# The rule + +**General fluorescence machinery lives in imp-tricks, under `IMP.bff`.** +QuEst depends on it rather than carrying its own copy. Anything that is not +specific to "estimate PET quenching for this project document" is a candidate to +move: accessible volumes, dye distributions, FRET distance metrics and rates, +labelling geometry, structure handling. + +What stays in QuEst: + +- the [project schema](/architecture/project-schema.md) and its validation, +- the PET-quenching *workflow* — grids, trajectory, photon generation, residue + attribution — insofar as it is not already in `IMP.bff`, +- the [surfaces](/architecture/surfaces.md): CLI, web UI, Qt GUI, RPC, +- scanning, [job artefacts](/architecture/job-artefacts.md), the parameter + catalog and dye library. + +Nothing in imp-tricks may depend on QuEst. The arrow points one way. + +> **Watch: ChiSurf is moving its AV backend into imp.bff too (PRD-97, 2026-08-10).** +> ChiSurf's `av.py` (742 lines — the LabelLib/IMP backend *selection*) and its +> fps.json round-trip are classified to move into imp.bff, on the same rule this +> page states. Its own PRD notes the consequence: three accessible-volume paths +> would then sit in one repository (`av.py`'s selection, `IMP.bff.av`'s +> BasicAV/ACV, the C++ `AV`/`PathMap`) — **four counting QuEst's +> `resolve_av_backend`**, which is a fourth copy of the same choice. +> +> That makes QuEst's backend selection a deletion candidate rather than a thing +> to maintain: QuEst already dispatches through `IMP.bff.av.compute_av`, so what +> `resolve_av_backend` adds is the *preference* plumbing +> (`QUEST_AV_BACKEND`, `available_av_backends`) and its error messages. Nothing +> to do until PRD-97's stage 2 actually lands — but when it does, the question is +> whether QuEst keeps a selector at all or just passes `backend=` through. +> Do not add a fifth path in the meantime. + +# What imp-tricks already has + +Checked against `~/dev/imp-tricks/src/IMP/bff/` on 2026-07-27: + +| Module | Provides | +|---|---| +| `IMP.bff.av.compute_av` | AV from atoms + attachment site, **with the same IMP.bff → LabelLib backend dispatch QuEst reimplements** (`_av_imp_bff`, `_av_labellib`), and an explicit `backend=` override QuEst lacks | +| `IMP.bff.av.BasicAV` / `ACV` | AV and accessible **contact** volume objects: point clouds, density grids, mean position, slow centres, trapped fraction | +| `IMP.bff.av._kernels` | `density2points`, `random_distances`, `average_distance`, `mean_fret_distance`, `weighted_mean`, `split_av_acv` | +| `IMP.bff.distance_metrics` | `fret_efficiency`, `distance_from_fret_efficiency`, `av_pair_statistics` (⟨R_DA⟩, R_mp, R_E, ⟨E⟩ in one pass), `chi2_score` | +| `IMP.bff.cgdye` | Coarse-grained dye simulation: labelling, rotamers, sampling, and `analysis/fret.py` with **κ²-aware** rates and an exact efficiency from a rate matrix | +| `IMP.bff.polymer`, `.distributions`, `.label`, `.restraints` | Chain models, distance distributions, labelling, restraints | + +# Historical: what `quest/lib` was, module by module + +`quest/lib` no longer exists — it became `quest/core/` on 2026-07-27. The audit +below is kept because it records *why* each piece survived or died; the current +verdict is the re-measured one further down. + +A minimal in-tree library is legitimate — QuEst must run standalone — but it has +to be *minimal*, and today's is neither that nor compatible with the two +libraries it shadows. Audited 2026-07-27: + +| Module | Lines | Verdict | +|---|---|---| +| `lib/tools/dye_diffusion/` | ~1700 | **Keep.** This is QuEst: the PET workflow, `SimulateDiffusion`, `DonorDecay`, the photon kernels. | +| `lib/fps/` | ~1190 | **Mostly duplicate** of `IMP.bff.av` + `IMP.bff.distance_metrics` (`DUP-01`, `DUP-03`–`DUP-05`). Blocked on imp-tricks. `AvPotential` was dead and is gone. | +| `lib/structure/Structure.py` | ~640 | **Keep the reader, drop the analysis.** RMSD, superposition, clustering, internal coordinates and `Universe` were unreachable and are gone — that is IMP/ChiSurf work. What remains is the atom array QuEst simulates on. | +| `lib/io/PDB.py` | ~400 | **Duplicate** of IMP's readers *and* ChiSurf's `core.fio.structure.coordinates` (`DUP-06`) — a third copy. Blocked on a dependency decision, not on code: IMP is missing from the base environment (where the web layer runs), and ChiSurf is missing from `arm64` and would pull tttrlib/mdtraj/pandas into every simulation. Recommended home: **IMP.atom**. | +| `lib/common.py` | 271 | Chemical reference data (atomic weights, VDW radii, charges) for the parser. Moves out with `DUP-06`. | +| ~~`lib/math/`~~ | — | **Gone.** The twelve lines of FFT autocorrelation are inlined in `quest/core/simulation.py`; ChiSurf's `core.math.signal.autocorr` is the same thing, but a headless run must not import a host application for a primitive. | +| `lib/imp_av.py` | ~200 | The broken IMP integration (`DUP-01`/`DUP-02`). Delete when `compute_av` works. | +| `lib/fps_json.py` | 112 | fps.json labeling files. QuEst-specific enough to keep. | +| ~~`lib/plots/`, `lib/widgets.py`, `lib/ui/`, `lib/genealogy.py`~~ | ~2400 | **Moved to `quest/gui/`** — they were Qt, used only by the form. | + +`quest/lib` went from **7673 to 4511 lines** on 2026-07-27: ~2400 moved to +`quest/gui/`, and **668 lines of unreachable code deleted** (found by +reachability analysis from the real entry points, not by eye). + +# Duplication against ChiSurf + +The presentation arrow points at ChiSurf, so its code is fair game too. Three +QuEst modules are shadowed by ChiSurf's **`fps_json_editor` plugin** +(`chisurf/plugins/modelling/fps_json_editor/core/`): + +| QuEst | ChiSurf equivalent | +|---|---| +| `quest/core/fps_json.py` — load and normalise fps.json positions | `core/payload.py` — `normalize_payload`, `validate_payload`, `summarize_payload` | +| `quest/core/structure/fetch.py` — RCSB download and cache | `core/pdb.py` — `download_pdb_file`, `default_cache_dir`, `pdb_source_url` | +| `write_mrc` in `quest/core/simulation.py` | `core/mrc.py` — `save_av_mrc` | + +**It cannot be consumed as it stands.** All three live inside a ChiSurf +*plugin*, and a plugin is not a library: QuEst's domain importing +`chisurf.plugins.modelling.fps_json_editor.core.payload` would couple two +plugins through the host's plugin tree, and would drag the whole ChiSurf import +(tttrlib, mdtraj, pandas) into a headless simulation. + +The fix belongs on the ChiSurf side: fps.json handling, RCSB fetching and MRC +writing are **library** concerns, so they belong in `chisurf.core.*` (or, for +the labelling parts, imp-tricks). Once they are there, QuEst deletes its copies. +Recorded as `DUP-07`. + +# Verdict, module by module (re-measured 2026-07-27) + +Everything below was **run**, not read: imports attempted, kernels compared +numerically, the AV built both ways. The evidence is in `okf/log.md` for the +same date. + +## Stays in QuEst — it *is* the application + +| module | lines | why it stays | +|---|---|---| +| `dye_diffusion.py` | 1551 | The PET quenching model, sticky diffusion grids, `DonorDecay`. This is the science QuEst exists for; nothing upstream has it. | +| `simulation.py` | 1323 | Project → result orchestration, `aa_residence`, job artefacts. Application logic. | +| `photon.py` | 212 | Monte-Carlo photon trace against a per-frame quenching rate. Coupled to the quenching trajectory model. | +| `pdb.py` | 228 | Already delegates to `IMP.atom.read_pdb`; what remains is QuEst's radii, the parse cache and the SWIG lock. | +| `fps_json.py` | 112 | Scan glue. The payload half already moved to `chisurf.core`. | + +## Belongs in imp-tricks — and is adoptable **today** + +| what | upstream | evidence | state | +|---|---|---|---| +| `density2points` | `IMP.bff.av._kernels.density2points` | Selects exactly the same voxels on 5×7×9, 8×8×8 and 11×11×11 grids. Theirs is a strict superset: it keeps the per-voxel weight, which QuEst throws away. | **`DUP-02` done 2026-07-28** | +| `RDAMean`, `RDAMeanE`, `_ran_dist` | `random_distances` + `av_pair_statistics` | Agree within sampling noise on 148l E15/E90: ⟨R_DA⟩ 55.164 ± 0.037 vs 55.171 ± 0.032 Å, ⟨R_DA⟩_E 54.467 ± 0.022 vs 54.473 ± 0.029 Å. | **`DUP-03` done 2026-07-28** | + +Neither is blocked by anything. `IMP.bff.av._kernels` and +`IMP.bff.distance_metrics` import and run in `arm64` today. + +### What `DUP-02` actually cost + +The stale claim above — "two copies" of `density2points` — was already wrong +when it was written: an earlier change had merged the flat/centre-origin and +3-D/corner-origin variants into one kernel plus +`_points_from_centred_grid`. Only one copy was deleted. + +Two things had to be fixed before the swap was a swap rather than a regression: + +- **Upstream's kernels were bare `@nb.njit`.** QuEst's carried + `cache=True, nogil=True`. `nogil` is what keeps a threaded site scan — the web + backend — from serialising on the GIL in the loop that visits every voxel; + `cache` is what stops a short CLI run paying a fresh compile. Contributed + upstream (`a49e17c`) rather than worked around: the annotations belong with the + kernel, not with one of its callers. +- **The enumeration order differs**, so the point cloud comes back permuted. It + is safe here only because nothing reads `AV.points` positionally — checked + rather than assumed. Rule for the rest of this migration: **an upstream kernel + that returns a collection may not return it in the same order**, and that has + to be verified against every consumer before the swap, not after. + +### What `DUP-03` cost: a 5× slowdown, taken knowingly + +`RDAMean`/`RDAMeanE` now aggregate `random_distances` + `av_pair_statistics`, +and `_ran_dist` is gone. The numbers agree inside sampling noise, but upstream +costs **3.4 ms a call against 0.68 ms**, for two structural reasons that will +recur elsewhere in this migration: + +- QuEst's kernel was `parallel=True`; upstream's is **sequential because it + seeds**, and numba's per-thread RNG cannot be seeded reproducibly. Determinism + and parallelism are in direct conflict in this kernel, and upstream chose + determinism — correctly, for a *reported* distance. QuEst gains reproducibility + it did not have. +- Upstream's signature takes `(N, 4)` weighted points, so a binary QuEst cloud + has to be widened first (0.87 ms of the 3.4). The weights are then all ones and + the weighted mean reduces to the plain one. + +Accepted because this runs **once per simulation** (~0.4 s across a 151-site +scan). **The general rule this establishes: check where the upstream symbol sits +in the call graph before adopting it.** The same trade on a per-frame path — the +FRET rate trace, the trajectory kernels — would be unacceptable, and those are +exactly what this document proposes moving next. + +A second, smaller lesson: `TestTheAdoptedDistanceKernelsBehave` first used +E15/E90, the pair quoted throughout this document, and errored in the base +environment. Any test that must pass in both has to pick sites labelable under +**both** backends, and E15 is not among LabelLib's 43 of 151. It uses E55/E124. + +And one that surfaced only by running it: importing `IMP.bff.av._kernels` at +module scope broke `test_importing_the_domain_does_not_import_qt` and +`test_the_model_needs_no_qt`, via the dylib conflict in +[references/known-issues.md](/references/known-issues.md). **Every adoption in +this document has to be imported lazily**, or the domain layer stops being +importable without IMP — which is the property that lets the web backend run in +the base environment at all. + +## Unblocked 2026-07-27 — fixed upstream + +The three faults below were fixed **in imp-tricks**, and +`IMP.bff.av.compute.compute_av` now reproduces QuEst's accessible volume +**bitwise** on 148l E15 (167 196 points, identical after sorting). Pinned by +`tests/test_imp_tricks_bridge.py::TestTheUpstreamAvMatchesQuEsts`, which skips +where LabelLib or the checkout is missing. + +1. `av/compute.py` — `Particle.get_particle_index()` did not exist on this IMP, + which spells it `get_index()`. Now goes through a `_particle_index()` shim + that accepts either, because the two spellings are both in the wild. +2. `av/compute.py` — the LabelLib probe required `LabelLib.AV`. Current LabelLib + exposes only the `dyeDensityAV1` kernel, so a perfectly working install was + reported as missing and the backend was unreachable. The probe now accepts + either, and `_av_labellib` drives `dyeDensityAV1` when the high-level entry + point is absent, converting its centre-origin Fortran grid to the + corner-origin convention `density2points` expects. +3. `av/compute.py` — **the reason it returned an empty volume**: the attachment + atom's own van-der-Waals sphere was left in the obstacle list. The linker + starts *at* that atom, so the source sits inside an obstacle and LabelLib + returns nothing — no error, just an empty cloud. QuEst had always zeroed it; + upstream had not. + +Two more upstream fixes went with them: + +- `src/sitecustomize.py` extended `IMP.__path__` but not the `__path__` of + subpackages that are **also compiled and installed**. `IMP.bff` is a regular + package whose `__path__` points at site-packages, so Python never consulted + `IMP.__path__` for its children and `import IMP.bff.av` failed however + `sys.path` was arranged — imp-tricks' own test suite could not import its own + AV code (28 collection errors). QuEst had solved this independently in + `quest/hosts/imp_tricks.py`; the same handling is now upstream. Its `bff` suite goes + from *uncollectable* to **191 passed, 5 failed, 24 skipped**. +- Two tests asserted `ImportError` "without a backend" and passed only *because* + of fault 2 — a usable LabelLib was being reported as missing. They now + monkeypatch the availability flags to create the condition they describe. + +The 5 remaining failures (`cgdye/rotamer` R0-vs-FRETpredict, `dye_io` +PDB→mmCIF, `polymer` Gaussian-chain PDF) touch none of this — zero references to +`av.compute`, LabelLib or `compute_av` — and had never run before, since the +suite could not be collected. Newly *visible*, not newly broken. + +## Declared 2026-07-28 — imp-tricks is a dependency, and it does not resolve yet + +`IMP.bff.av` resolves in **both** environments once the checkout is on the path — +including the base interpreter, where there is no compiled `IMP.bff` to shadow +it. So the barrier was never "it does not work"; it was that imp-tricks was a +development path shim (`quest/hosts/imp_tricks.py`) rather than a declared dependency. + +**It is now declared**, on the owner's instruction that installability is not a +constraint ("nobody installs quest; imp-tricks goes public later"). Declared in +`rattler-recipe/recipe.yaml` (run) and `pixi.toml` (`feature.py.dependencies`), +**not** in `pyproject.toml` — which is the convention `imp` itself already +follows here, because neither is pip-installable. A `pip install quest` has +never produced a working science stack and still does not. + +**Consequence, stated plainly:** `imp-tricks` is on a private GitLab and is on +no public channel, so every pixi environment in the `py` solve-group now fails +to solve, and with it **all four CI jobs** — library, GUI, frontend-adjacent and +packaging — not merely the packaging one. This is accepted, not overlooked. The +fix is publication, and then nothing else: the version constraint is `*`, so a +package appearing on conda-forge under the name `imp-tricks` is enough. + +Day-to-day work is unaffected because it does not go through pixi: the canonical +`arm64` conda environment reaches the checkout through `quest/hosts/imp_tricks.py` +([workflows/environment.md](/workflows/environment.md)). That shim stays until +publication — it is what makes the source tree, rather than a stale install, the +thing that runs. + +## Superseded — the original diagnosis, for reference + +`AV` (in `av.py`) and `imp_av.py` should both become +`IMP.bff.av.compute.compute_av`, whose signature is already the right shape — +plain arrays (`atoms_xyz`, `atoms_vdw`, `source_xyz`), no IMP particles. + +**Unblocked 2026-07-27.** Both backends now work and both are verified against +QuEst's, so the precondition for `DUP-01`/`DUP-02` is met. What it took, in +imp-tricks (commits `936a17c` and `b95c000`): + +*LabelLib branch* — the availability probe required `LabelLib.AV`, which current +builds do not ship (they expose `dyeDensityAV1`); the attachment atom kept its +own exclusion sphere, so the linker started inside an obstacle and the backend +returned an empty volume with no error; and `Particle.get_particle_index()` does +not exist in IMP 2.24, which spells it `get_index()`. + +*IMP.bff branch* — **had never run at all.** It raised +`UsageException: Can't get attribute that is not there: mass` on every input, +because it read its density by handing the source particle to an +`IMP.em.SampledDensityMap` that needs an `IMP.atom.Mass` it never set — and with +a mass, that samples a Gaussian blob around the attachment point rather than the +accessible volume. It also never passed `allowed_sphere_radius`, decorated the +AV onto the source particle itself and resampled with `shift_xyz=False` (leaving +the map at the coordinate origin), and reshaped the flat tile values in the +wrong axis order. + +Acceptance: upstream and QuEst return point-for-point identical clouds on 148l +E118, E36 and E90 under **both** backends, pinned by +`TestTheUpstreamAvMatchesQuEsts`, which is now parametrised over both. + +**Done 2026-07-28.** `quest/core/imp_av.py` (329 lines) and `calculate1R` (69) +are deleted; `AV.__init__` makes one `compute_av` call with an explicit +`backend=`. AV numbers verified unchanged on 148l E36/E55/E118 under both +backends — identical grid shape, identical binary density voxel-for-voxel, +identical point counts. What QuEst keeps is the application: site selection, the +cubic/binarisation adapter, and `AV`'s derived grids. + +One blocker was found only by looking: `compute_av` had **no thread safety**, so +adopting it would have re-introduced the SWIG race QuEst had just fixed. +Contributed upstream (`9cd5c13`) with the same construction/resample split, so +the lock moved rather than vanished. + +## The arrow points the other way — QuEst is right, upstream is wrong + +`av_pair_statistics` returns four numbers, and its second, `r_mp`, is +documented as *"Distance between mean positions (same as `r_da_mean` here)"* — +it returns `r_da_mean` again. **R_mp is not ⟨R_DA⟩.** R_mp is +|⟨r_D⟩ − ⟨r_A⟩|, the distance between the two cloud centroids, and it cannot be +recovered from a sample of pair distances at all: the sampling destroys the +information. Measured on 148l E15/E90, QuEst's `dRmp` gives **47.65 Å** and +upstream's `r_mp` gives **51.53 Å** — 8 % apart, and the smaller number is the +correct one. + +So `dRmp` does not get deleted. It gets **contributed upstream**, and +`av_pair_statistics` should either take the two clouds or stop claiming to +return R_mp. Anyone who trusted that field has a systematically wrong R_mp. + +## Deleted 2026-07-27 — dead weight, now gone + +`structure.py` went **623 → 345 lines**. What went: `rmsd`, `cluster`, +`calc_internal_coordinates`, `move_center_of_mass`'s geometry primitives +(`_norm`, `_angle`, `_dihedral`, `r2i`), and the whole torsion subsystem — +`coord_i`, `internal_coordinates`, and the `phi`/`psi`/`omega`/`chi` accessors, +which nothing read. What stayed: the constructor, `to_coarse` (reached through +`make_coarse=`), `xyz`, `vdw`, `atoms`, `residue_names`, `residue_ids`, `write`, +and the three helpers the class itself calls. + +**A caution learned doing it.** "No callers outside this module" is the wrong +question for a module-level helper: `make_residue_lookup_table`, +`get_residue_sequence` and `move_center_of_mass` had none, and are called from +`Structure.__init__`. Deleting them broke construction immediately. A second +trap: cutting a function span up to the next `def`/`class` swallows the +module-level constants that follow it — `a2id`, `res2id`, `internal_keys` went +with the first cut. And a third: the deletion left an orphaned `@njit` that +silently decorated the next function added below it. Each was caught by running +the code, none by reading the diff. + +The original survey, for reference: + +- module level, zero callers: `rmsd`, `cluster`, `calc_internal_coordinates`, + `move_center_of_mass`, `r2i`, `make_residue_lookup_table`, + `get_residue_sequence`; +- `Structure` methods, zero callers: `internal_coordinates`, + `radius_gyration`, `update_dist`, `update_coordinates`, `b_factors`, + `atom_types`, `residue_dict`, `n_residues`, and the `phi`/`psi`/`omega`/`chi` + torsion accessors. + +What is live: the constructor, `to_coarse` (through `make_coarse=`), `xyz`, +`vdw`, `atoms`, `residue_names`, `residue_ids`, `write`. This is a QuEst-side +cleanup with no upstream dependency — it does not need imp-tricks fixed first. + +## No counterpart yet + +`fret_rate_trace` and `fret_rate_pair_trace` have none. +`IMP.bff.cgdye.analysis.fret` computes *efficiencies* (and κ², which QuEst +lacks — `OBJ-01` item 6), not a per-frame rate along a trajectory. The right +home eventually, but that is a new function upstream, not a move. + +## Order of work, cheapest first + +1. Delete the dead half of `structure.py`. No dependency on anything. +2. Adopt `_kernels.density2points` and drop both QuEst copies. +3. Adopt `random_distances` + `av_pair_statistics` for ⟨R_DA⟩ and ⟨R_DA⟩_E, + keeping `dRmp` local until upstream is fixed. +4. Fix the two imp-tricks lines; then delete `imp_av.py` and QuEst's `AV`. +5. Move the FRET rate kernel up once κ² is wanted. + +# Do not install it — work from `src` + +imp-tricks is under active development, so the **source tree is what has to +work**; an installed copy goes stale the moment the checkout changes. A real +`pip install` was tried and reverted for exactly that reason. + +# Reaching a checkout from the live interpreter + +`quest.hosts.imp_tricks.enable_imp_tricks()` splices a checkout in at runtime +(`~/dev/imp-tricks/src`, or `$IMP_TRICKS_SRC`), returning the subpackages it +made importable. **It runs automatically** when `quest.lib.imp_av` is imported — +which every QuEst entry point does — so using QuEst is enough to reach +`IMP.bff.av`, `IMP.bff.distance_metrics` and `IMP.cgmol.*` from source, in both +environments. It is never fatal: no checkout means an empty list. + +This mirrors what imp-tricks does for itself: it ships a `sitecustomize.py` +that extends `IMP.__path__` when `src` is on `PYTHONPATH`, which is how ChiSurf +consumes it. That mechanism is enough for subpackages IMP does not ship +(`IMP.cgmol`, `IMP.finite`, …) but **not** for `IMP.bff`, because a compiled +regular package always beats a namespace directory of the same name no matter +which comes first on the path. Reaching `IMP.bff.av` needs the *subpackage's* +`__path__` extended too, which is what the helper adds. + +**`PYTHONPATH` alone is not enough.** imp-tricks ships `IMP//` as +*namespace* directories. In the base environment, where nothing else provides +`IMP.bff`, adding `src` to the path works. In the canonical `arm64` +environment, `IMP` and `IMP.bff` are **compiled regular packages** with their +own `__init__.py`, and a regular package shadows a namespace directory of the +same name completely — `import IMP.bff.av` fails no matter what is on the path. + +The helper therefore appends to the *already-imported* package's `__path__`, +which is where Python looks for submodules. The checkout's `IMP.bff.av` and +`IMP.bff.distance_metrics` then resolve **alongside** the compiled +`IMP.bff.AV`, not instead of it. Verified in both environments; idempotent; a +missing checkout returns `[]` rather than raising. + +# The capability check is looking for the wrong thing + +`quest/lib/imp_av.py` decides whether the preferred backend exists with: + +```python +HAS_IMP_BFF = hasattr(IMP.bff, "AV") +``` + +`IMP.bff` here is the **namespace package from imp-tricks**, not a compiled +module — with `PYTHONPATH=~/dev/imp-tricks/src` it imports fine, exposes +`IMP.bff.av.compute_av` and `IMP.bff.distance_metrics`, and has **no top-level +`AV` attribute**. So QuEst concludes "IMP.bff is unavailable" and falls back to +LabelLib even when imp-tricks is present and could serve the request. + +Two separate things to fix, in this order: + +1. **Install imp-tricks into the environment** (it is not installed here; only + the path trick works), and +2. **ask for the capability, not the attribute** — call + `IMP.bff.av.compute_av`, which already performs the backend dispatch itself. + +Until then the LabelLib path is what actually runs — now **by explicit default** +rather than by accident, since QuEst's own IMP integration turned out to return +an empty accessible volume when it finally got selected in `arm64`. That is the +strongest argument for this whole document: the duplicated integration was +broken and nobody could tell, because the environment that would have exercised +it was never the one being tested. See +[references/known-issues.md](/references/known-issues.md). + +# Rules for the migration + +1. **Move, don't copy.** A symbol lands in `IMP.bff` and QuEst imports it; two + maintained copies is the state being fixed, not a milestone toward it. +2. **Keep the LabelLib fallback reachable.** QuEst must still run where the + compiled IMP is absent — that is the current development environment. +3. **Migrate behind QuEst's own names first** where a signature differs, so the + swap is one edit and one test run rather than a rewrite of call sites. +4. **The tests move with the code.** `tests/test_grid_kernels.py` and + `tests/test_fret_physics.py` pin behaviour that will live in imp-tricks; + their assertions belong beside the implementation, with QuEst keeping only + an integration-level check. +5. **Nothing moves without a green run on both sides** — QuEst's suites and + imp-tricks' (`PYTHONPATH=src` from its root). + +# Where the FRET rate trace should land + +`fret_rate_trace` computes `k_FRET(t) = (1/tau0)·⟨(R0/|r_D(t) − r_A|)^6⟩_A` +for a donor trajectory against an acceptor cloud. `IMP.bff.distance_metrics` +already owns the static counterparts, and `IMP.bff.cgdye.analysis.fret` owns +κ²-aware rates and exact efficiencies from rate matrices — **that module is the +natural home**, and merging into it would bring κ² with it, which QuEst's +implementation lacks ([objectives.md](objectives.md) OBJ-01 item 6). + +Tracked as `DUP-03` in [assessment.md](assessment.md). diff --git a/okf/specs/index.md b/okf/specs/index.md new file mode 100644 index 0000000..03f51cb --- /dev/null +++ b/okf/specs/index.md @@ -0,0 +1,16 @@ +# Specs + +Target ("north star") architecture for QuEst, and the backlog tracking where +today's code diverges from it. Consult these before large refactors — a change +that moves the tree toward the target is worth more than one that merely works. + +* [The 2026-07 programme](programme-2026-07.md) - The decisions scoping the current programme of work, with the alternative each one rejected — and the three places where it reverses what this bundle previously asserted. Read before proposing work in these areas. +* [Objectives](objectives.md) - Where QuEst is going scientifically: FRET as a first-class observable, and fitting dye parameters to measured decays. Not implemented — shape new work so these get cheaper, not harder. +* [Plugin integration — target](plugin-integration.md) - The core / rpc / api / cli / gui split QuEst adopts from the ChiSurf plugin contract, so the same code serves the CLI, the web UI, the desktop GUI, and a ChiSurf plugin without a second implementation. +* [Deduplication against imp-tricks](imp-tricks-dedup.md) - General fluorescence machinery belongs in imp-tricks under `IMP.bff`; QuEst is the application on top of it. What already exists there, what QuEst duplicates, and the rules for moving it. +* [Assessment](assessment.md) - The gap backlog: where the current tree diverges from the target, itemised with ids and status. +* [Declarative form scheme — AutoForm and the QuEst blueprint](autoform-scheme.md) - The view-spec JSON contract for declaring editors without GUI code, how QuEst generates one spec per language from a single catalog, and what a Python→web port should copy to stop hand-writing two forms. +* [AutoForm Web Support & ChiSurf Multi-Interface Plugin Architecture](autoform-and-plugin-architecture.md) - PRDs, architecture specifications, and implementation checklist for bringing Web AutoForm support and 5-way ChiSurf plugin interfaces (API, CLI, RPC JSON, ZMQ, Web AutoForm) to QuEst. +* [ChiSurf AutoForm Integration & Dependency Specification](chisurf-autoform-integration.md) - Comprehensive mapping of ChiSurf AutoForm classes (`AutoForm`, `CollapsibleBox`, `DockArea`), section types, and dual-mode host vs standalone PyQt execution. + + diff --git a/okf/specs/objectives.md b/okf/specs/objectives.md new file mode 100644 index 0000000..de2dcb2 --- /dev/null +++ b/okf/specs/objectives.md @@ -0,0 +1,174 @@ +--- +type: Specification +title: Objectives +description: Where QuEst is going as a scientific tool — restoring FRET as a first-class observable, and fitting dye parameters to measured decays. +resource: okf/specs/plugin-integration.md +tags: [objectives, roadmap, fret, optimization, fitting] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +--- + +The scientific direction, as distinct from +[the architectural target](plugin-integration.md). **Nothing here is +implemented yet.** They are recorded so that every refactor and every new +feature is shaped to make them cheaper rather than harder — a change that +blocks one of these is the wrong change, even if it is locally tidy. + +# OBJ-01 — FRET as a first-class simulated observable + +QuEst simulated FRET historically, and the machinery is still present: +`DonorDecay.calc_acceptor_av`, `calc_fret_rate`, `calc_photons_fret`, +`get_histogram_fret`, and the `fret` block of the +[project schema](/architecture/project-schema.md). Two tests exercise it +(`test_use_cases.py::test_use_case_fret`, `test_api.py::test_simulate_project_with_fret`) +and it does produce a second decay curve. **It is not dead — it is degraded**, +and the degradations are quiet ones. + +Measured on 2026-07-26 with the T4L test project at R0 = 52 Å: donor QY 0.9944, +FRET-channel QY 0.042, E = 0.96. So the path runs end to end. + +What is wrong with it today: + +1. ~~**FRET does not see the diffusion.**~~ **Done 2026-07-27.** + `calc_fret_rate_trace` evaluates `k_FRET(t) = (1/tau0)·⟨(R0/|r_D(t) − r_A|)^6⟩_A` + per frame; the donor is resolved in time and the acceptor averaged over its + volume. E on T4L E55→E132 moved 0.377 → 0.662 as a result. +2. ~~**The acceptor never moves.**~~ **Done 2026-07-27.** The acceptor is a dye + in its own right: it walks its own accessible volume with its own diffusion + coefficient, its own slowing radius and its own per-residue interaction + table, and `k_FRET(t)` uses the instantaneous separation of the two + trajectories (`fret_rate_pair_trace`). The fast-acceptor limit is still + reachable as `fret.acceptor_dynamics: "averaged"`. **The default changed**, + so FRET numbers move: on 148l E15→E90 with a sticky acceptor + (D = 2.5 Ų/ns, slow radius 11 Å) E went 0.73 → 0.78. The two differ because + a cloud is weighted uniformly while a trajectory is weighted by where the + dye dwells — the direction depends on geometry, not on a fixed bias. +3. ~~**`fret_efficiency` has two definitions.**~~ **Done 2026-07-27.** The + analytic one is deleted; efficiency is always `1 − QY_DA/QY_D` from the two + simulated decays. `rda_mean_e()` remains a diagnostic distance only. +4. ~~**Failure is silent.**~~ **Done 2026-07-27.** A missing acceptor raises with + a message naming what to set, instead of yielding a donor-only result. +5. ~~**R0 is barely reachable.**~~ **Done 2026-07-26.** The unit is settled + (Ångström), documented in the parameter catalog, and editable in both UIs: + an `R0 [Å]` spin box in the Qt FRET group and an `R0 [Å]` field in the web + UI's FRET acceptor panel, which also gained the enable toggle and acceptor + site selectors it never had. A browser FRET run now reports E = 0.55 on T4L. +6. ~~**No orientation factor.**~~ **Closed 2026-07-28 as *chosen and + documented*, which is not the same as modelled — read this before assuming + κ² is simulated.** `fret.kappa2` is an explicit project field, validated to + `[0, 4]` when the project is read, translated in all three languages, and + defaulting to the isotropic dynamic average **2/3**. Because a published + Förster radius is already quoted at 2/3, the default reproduces every number + computed before the field existed; the rate carries `κ²/(2/3)`, the + literature's `1.5·κ²`. + + **It cannot be modelled in the current dye model, and that is the real + finding.** QuEst's dye is a structureless point diffusing in an accessible + volume: it has no transition dipole, so there is nothing to orient. Adopting + code does not help — `kappa2_from_vectors` upstream *takes* the two dipole + vectors. Modelling κ² needs a **new degree of freedom**: a rotational + diffusion of a dipole per dye, its own correlation time, its own schema + entries, and its own calibration. That is a project the size of the + acceptor-diffusion work, and it is what would move item 6 from *documented* + to *modelled*. + +"Working" means, at minimum: a per-frame D–A distance, one definition of +efficiency, an error when the acceptor cannot be built, R0 in the catalog and +the UI, and a test that pins a known geometry to a known efficiency rather than +asserting `0 <= E <= 1`. + +**Reachability, confirmed 2026-07-27 after the AutoForm migration.** FRET is +live on all three surfaces and each is covered by a test that *runs* it, not +merely one that builds a project: + +| surface | how it is reached | test | +|---|---|---| +| library / CLI | the `fret` block of the project | `test_fret_physics.py`, `test_fret_units.py` | +| web UI | enable toggle, acceptor chain/residue/atom selectors, `R0 [Å]` | `test_webui_e2e.py::TestFretPanel` (5) and `::TestFretSimulation` — a full browser run asserting `0 < E ≤ 1` | +| Qt form | the FRET panel of `quest.view.json`, bound to the same keys | `test_gui_simulation.py::TestTheFormRunsFret` (8) | + +The desktop tests were the gap: the rebuilt form bound FRET through the shared +project keys, but every GUI test set `fret_enabled = False`, so nothing ran it. +They now pin both decays, an efficiency strictly between 0 and 1 on a chosen +site pair, `E = 1 − QY_DA/QY_D` agreeing with the reported value, a larger R0 +transferring more (a nanometre R0 would not), the toggle actually gating the +channel, and a FRET project surviving save/load. Measured E = 0.77 on +148l E15→E90 at R0 = 52 Å. + +**Progress.** *2026-07-26* — reachability: R0 in the catalog and both UIs, the +web UI can switch FRET on and choose an acceptor site, the unit mismatch that +zeroed transfer is fixed, and a full FRET run works from the browser. +*2026-07-27* — the physics of items 1, 3 and 4: a per-frame transfer rate, one +efficiency definition, and a loud failure when the acceptor is missing; then +item 2, a diffusing and sticking acceptor with per-dye properties. + +**All six items are now closed** — item 6 as *documented*, not as *modelled*; +see above, and do not read the checked box as "QuEst simulates κ²". + +The claim that `IMP.bff.cgdye.analysis.fret` "already handles κ², which is one +more reason the rate kernel should move there" was **wrong on both counts** and +is retracted: that module solves a Markov kinetic ensemble over rotamer +libraries and merely *accepts* a κ² matrix. See `DUP-03` in +[assessment.md](assessment.md); the direction of that migration is now +reversed. + +# OBJ-02 — Fit dye parameters to measured decays + +The direction that makes QuEst quantitative rather than illustrative: + +> experiment on a system → optimise the model parameters until the simulation +> describes the measurement. + +Concretely: load a measured fluorescence decay, vary the dye and quenching +parameters (`kQ` per residue type, contact radii, `slow_factor`, the diffusion +coefficient, linker geometry), and find the values that reproduce it. The +shipped chemistry is explicitly *starting values to be calibrated* +([references/pet-quenching-theory.md](/references/pet-quenching-theory.md)) — +this objective is what turns them into calibrated ones, and it is the same loop +that would calibrate an accessible contact volume against a donor lifetime. + +**Decided 2026-07-28: the host route.** QuEst contributes a *model*; ChiSurf's +existing optimiser, error analysis, global analysis and decay-data handling +drive it. Nothing is implemented — the decision is the deliverable +([specs/programme-2026-07.md](programme-2026-07.md), decision 1) — but it is +binding on work done before it starts, and it has already shaped two things: +`quest.api` becomes a verb facade over the RPC client rather than a re-export +shim (`LAY-04`), and **serialization moves to the transport boundary** so an +in-process call returns native arrays. That second one is not tidiness: an +optimiser calls `simulate` thousands of times, and converting every decay +channel to a Python list per iteration is a tax paid forever by the caller this +objective exists to serve. + +The two routes as they were weighed: + +- **Rely on the host.** As a first-class ChiSurf plugin, QuEst reaches an + existing fitting and sampling stack — optimisers, error analysis, global + analysis over several datasets, and a decay-data model that already knows + about IRFs, background and scatter. QuEst would contribute a *model* whose + parameters the host varies. This is the reason + [plugin-integration.md](plugin-integration.md) matters beyond tidiness: the + RPC/manifest split is what lets the host drive QuEst as a model rather than + launch it as a window. +- **Own optimiser.** Keeps QuEst standalone at the cost of reimplementing + fitting, uncertainties and data handling. + +**The host route was taken on 2026-07-28**, as recorded above. + +## What this implies for work done before it starts + +- **A simulation must be callable as a function of its parameters**, cheaply and + repeatedly. `save_outputs=False` already exists for that reason; anything that + makes a run write, log or allocate unconditionally works against it. +- **Runs must be reproducible.** Seeding is already threaded through the walk + and the photon trace ([subsystems/dye-diffusion.md](/subsystems/dye-diffusion.md)); + an optimiser needs the noise to be controllable, or it will chase Monte-Carlo + scatter. +- **Parameters need to be addressable by name.** The dotted paths of the project + schema are already the right shape for "vary `amino_acid_interactions.TRP.kQ`". +- **The decay is the fit target**, so it must be comparable to a measured curve: + the same time axis, and eventually convolution with an IRF plus background. + That machinery exists in the host — another argument for the plugin route. +- **The service layer is how a fitter drives QuEst.** `quest.simulate` returning + a plain payload ([subsystems/core-api.md](/subsystems/core-api.md)) is already + most of the interface an optimiser needs. diff --git a/okf/specs/plugin-integration.md b/okf/specs/plugin-integration.md new file mode 100644 index 0000000..735614f --- /dev/null +++ b/okf/specs/plugin-integration.md @@ -0,0 +1,245 @@ +--- +type: Specification +title: Plugin integration — target +description: The core / rpc / api / cli / gui split QuEst adopts from the ChiSurf plugin contract, so one implementation serves every surface. +resource: quest/ +tags: [target, architecture, plugin, rpc, layering, chisurf] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: quest + resource: ../../quest + title: quest/ + author: human:tpeulen + last_modified: 2026-07-28 +--- + +> The target. Current shape: [architecture/surfaces.md](/architecture/surfaces.md). +> Current-state gaps: [assessment.md](assessment.md). + +# Why + +Beyond keeping the surfaces in step, this split is the **enabler for +[OBJ-02](objectives.md)**: a host application can only drive QuEst as a fittable +model — varying parameters, scoring the decay against a measurement — if QuEst +exposes named operations over plain data. Today it exposes a window. + +QuEst has four surfaces today and is *also* embedded in the sibling ChiSurf +application as its `quenching_estimator` plugin. That plugin is currently a bare +Qt wrapper: it imports `quest.lib.tools.dye_diffusion.TransientDecayGenerator` +and puts it in a `QMainWindow`. Nothing of QuEst's headless capability — +simulate, scan, validate, the parameter catalog, the dye library — is reachable +from ChiSurf's RPC layer, its CLI, or its automation. The plugin also ships no +`manifest.json`, so it loads through ChiSurf's legacy AST-based discovery path. + +ChiSurf's own plugins solve this with a layered split that QuEst should adopt. +The payoff is not tidiness: it is that **one implementation serves the QuEst +CLI, the QuEst web UI, the QuEst desktop GUI, and the ChiSurf plugin** — with +the same method names, the same shapes, and the same error contract. + +# The split + +The reference layout, as used by ChiSurf plugins (e.g. +`chisurf/plugins/fcs/fcs_calculator/`): + +```text +manifest.json identity, entrypoints (gui / cli / services), rpc_methods +core/ Qt-free, host-free domain code — the algorithms +backend/services.py RPC handlers: register_services(dispatcher) +backend/state.py session state owned by the service layer +cli/main.py CLI entry point -> calls core (or the facade) +gui/client.py the client wrapper — the ONLY way the GUI reaches the backend +.view.json declarative form/panel description rendered by the host +test/ +README.md +``` + +The layering rule, in one line each: + +- **core** knows nothing about Qt, HTTP, ChiSurf, or the CLI. Pure functions and + domain objects over plain data. +- **backend** exposes core as named RPC methods returning a single shape: + `{"ok": True, "result": …}` or `{"ok": False, "error": …}`. It is the only + writer of session state. +- **api / facade** is the one door presentation calls. It resolves in-process or + remote *internally* — callers never branch on "am I local". +- **cli** parses arguments and formats output. No domain logic. +- **gui** renders and calls `client.call("quest.", params)`. It never + imports a domain object. + +Everything crossing the boundary is plain serializable data with stable +identifiers; live domain objects do not cross. + +# QuEst's method surface + +The RPC methods fall out of what the FastAPI backend already exposes — which is +the evidence that this surface is the real one, it is just currently spelled +only as HTTP routes: + +| RPC method | Today's spelling | Long-running | +|---|---|---| +| `quest.simulate` | `POST /api/simulate` | yes, cancelable | +| `quest.scan` | `POST /api/scan` | yes, cancelable | +| `quest.validate` | `POST /api/validate` → `cli._validate_project` | no | +| `quest.template` | `GET /api/template` → `cli._template_project` | no | +| `quest.parameter_catalog` | `GET /api/parameter-catalog` | no | +| `quest.dyes.list` / `quest.dyes.save` | `GET`/`POST /api/dyes` | no | +| `quest.quenching_defaults` | `GET /api/quenching-defaults` | no | +| `quest.structure.metadata` | `POST /api/structure/metadata` | no | +| `quest.jobs.list` / `quest.jobs.get` | `GET /api/jobs`, `/api/jobs/{id}` | no | + +Each carries documented params/result shapes in the manifest. The web backend +then becomes a **transport over the registry** rather than a parallel +implementation of it — one place to add a method, four places it appears. + +`quest.simulate` and `quest.scan` are the long-running pair and need the uniform +start / observe / cancel mechanism, not three ad-hoc ones (a thread pool in the +web backend, a blocking call in the CLI, a `QProgressDialog` in the GUI). + +# Target layout for this repository + +```text +quest/ + manifest.json id "quest", entrypoints, rpc_methods, state schema + core/ the domain, Qt-free + simulation.py simulate_project & the pipeline (today: core.py) + analysis.py residue attribution, autocorrelation + project.py the project schema: template, validate, normalise + grids.py MRC + density writers + rpc/services.py register_services(dispatcher) -> the table above + (was `backend/`; renamed 2026-07-28 to match ChiSurf's + plugin layout and the manifest's `services` entry + point — see architecture/package-layout.md) + api.py the facade: verb-oriented, plain data in and out + cli/ Click commands -> facade + gui/ widget + client.py + quest.view.json declarative parameter form, generated from the catalog +``` + +Two QuEst-specific notes: + +- **The parameter catalog is already half of a view spec.** + `quest/settings/parameter_catalog.json` carries label, category, type, unit and + description per dotted parameter id, and both the web UI and the docs render + from it. Generating `quest.view.json` from the catalog — rather than + hand-writing a second description of the same fields — keeps the Qt form, the + browser form, and the docs from drifting. +- **The project JSON is already the boundary contract.** + [architecture/project-schema.md](/architecture/project-schema.md) is plain + serializable data with dotted addressing. It crosses the wire unchanged; there + is no object to marshal. That is why this split is cheap for QuEst. + +# The dependency arrow, and where it points + +Two different directions, decided deliberately: + +- **Fluorescence machinery: QuEst → imp-tricks.** Accessible volumes, distance + metrics, dye models. QuEst must never be imported by imp-tricks + ([imp-tricks-dedup.md](imp-tricks-dedup.md)). +- **Presentation: QuEst → ChiSurf.** The host's **AutoForm** renders QuEst's + control panels, so QuEst stops carrying `.ui` files and hand-built Qt forms. + +The second is the reversal of the earlier "QuEst never imports the host" rule, +and it is what makes the UI deduplication possible at all: without it, a +declarative form means QuEst reimplementing a form renderer. + +**It is optional, and that is what keeps QuEst standalone.** ChiSurf is reached +through `quest.hosts.chisurf.enable_chisurf()` — a source checkout, resolved from +`CHISURF_ROOT`, never fatal, and never overriding a ChiSurf already imported by a +host that loaded QuEst as a plugin. Nothing outside `quest.gui` imports it. + +## AutoForm renders the manifest QuEst already ships + +`AutoForm.from_rpc_method(entry)` takes an `rpc_methods` entry from +`quest/manifest.json` and produces a bound Qt form: labels, types, defaults, +JSON-Schema `description`s as tooltips, and the entered values read back with +`form.model.params()`. QuEst already declares all eleven methods with full +parameter schemas, so **the declaration a host reads to learn what QuEst offers +is also the UI description** — one artefact, not two. + +Demonstrated 2026-07-27 in `arm64` with the ChiSurf checkout on the path: every +one of the eleven declarations renders, `quest.simulate` showing +project / pdb_path / nbins / tac_range / project_dir plus a `save_outputs` +checkbox, with no QuEst-side UI code. Pinned by +`tests/test_chisurf_autoform.py` (14 cases), which skips where Qt or the +checkout is absent. + +## The `.ui` files are gone (2026-07-27) + +The migration ran in the three stages planned here, and finished: + +1. Render the parameter groups from the manifest — `quest/gui/autoform_panel.py`, + still there for rendering one RPC method's parameters. +2. Author the rest as a view scheme — `quest/gui/quest.view.json`, **generated** + from the parameter catalog by `quest/gui/generate_view_spec.py`. AutoForm's + own section types cover everything QuEst needed: `value kind=file` for the + structure picker, an editable `table` for the quencher chemistry, the + `chimol` custom section for the 3D view, and `plot` sections (chiplot) for + the decay, trajectory and autocorrelation. +3. Delete the `.ui` files and the hand-built form. Done — 1,899 lines of widget + became ~130. + +There is no in-tree fallback renderer: where ChiSurf is absent, the desktop +surface says so and the CLI, API and web backend carry on unaffected. That is a +deliberate consequence of the reversed presentation arrow — one renderer, not +two that can disagree. See [subsystems/gui.md](/subsystems/gui.md). + +## The remaining hand-built pieces, and where each one goes + +Three instructions arrived for this migration and are recorded here rather than +started, because each is a substantial change and half of one is worse than +none: + +1. **Delete the `.ui` files.** `quest/gui/dye_diffusion2.ui`, `pdb_widget.ui` + and `ui/*.ui` describe the same parameters the manifest already declares. + `AutoForm.from_rpc_method` covers the parameter groups today (proven); the + structure picker, quencher table and plots need a `quest.view.json` scheme + first — AutoForm has section types for tables, and `path_list`/`state_table` + look like the right primitives for the picker and the quencher grid. +2. **Plot through `chisurf/gui/chiplot/`.** The widget hand-builds pyqtgraph + plots for the decay, the trajectory and the autocorrelation; ChiSurf's own + tools use chiplot, so QuEst carrying a third plotting style is the same + duplication as the molecule viewer was. Tracked as `LAY-11`. +3. **Check ChiSurf tests run against the current `src`.** QuEst reaches ChiSurf + through a checkout (`CHISURF_ROOT`), and the `chisurf` conda environment's + *installed* copy predates AutoForm — so a ChiSurf test run there may be + exercising a stale package, exactly the trap that hid QuEst's own broken IMP + backend. Worth verifying on the ChiSurf side before either project relies on + the other's test results. + +# Rules + +1. `core/` MUST NOT import Qt, FastAPI, Click, or ChiSurf. +2. Presentation (CLI, web, GUI, plugin) MUST reach the domain through the facade + or the RPC client — never by importing `quest.lib.*` internals, and never by + importing another surface's private helpers. +3. Every operation is reachable under exactly one name. A second spelling is a + second contract to keep in step. +4. Local and remote results for the same method MUST have the same shape, and + failure MUST be distinguishable from success by the contract, not by sniffing + fields. +5. The plugin declares itself in a `manifest.json` that validates against the + host's schema — identity, entry points, RPC methods with their shapes. +6. Long-running work uses one mechanism to start, observe and cancel it. +7. The GUI may own its own windows and widgets; it MUST NOT own domain objects. + +# Migration order + +Each step is independently valuable and leaves the tree working: + +1. **Move project logic out of the CLI.** `_validate_project` and + `_template_project` become `quest.core.project.validate/template`; the CLI and + the web backend both call that. Removes the web backend's import of a private + CLI function (`LAY-01`). +2. **Add `backend/services.py`** with the method table above, wrapping the + facade. The FastAPI routes become thin adapters onto it (`LAY-03`). +3. **Add `manifest.json`** and point its `gui`/`cli`/`services` entry points at + the real ones, so ChiSurf discovers QuEst the same way it discovers every + other plugin (`LAY-05`). +4. **Give the GUI a client.** `TransientDecayGenerator` stops inheriting + `DonorDecay` and holds a client instead (`LAY-02`) — the largest step, and the + one that finally makes the Qt widget testable headlessly. +5. **Generate `quest.view.json` from the parameter catalog** (`LAY-06`). + +Progress is tracked in [assessment.md](assessment.md). diff --git a/okf/specs/programme-2026-07.md b/okf/specs/programme-2026-07.md new file mode 100644 index 0000000..92880db --- /dev/null +++ b/okf/specs/programme-2026-07.md @@ -0,0 +1,102 @@ +--- +type: Specification +title: The 2026-07 programme +description: Every decision taken in the interview that scoped the current programme of work — what was chosen, what was rejected, and what each choice reverses. +resource: okf/handover.md +tags: [programme, decisions, roadmap, scope] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-28T12:00:00Z } +stale_after: 2026-10-28 +--- + +The work agreed on 2026-07-28, decided question by question before any code was +written. Each row is a decision with its alternative, because the alternative is +what a later session will otherwise re-propose. + +**Read this with [assessment.md](assessment.md)** (the `LAY-*`/`DUP-*` tables) +and [objectives.md](objectives.md) (the science). This file says what was +*decided*; those say what the gaps *are*. + +# Scope + +Everything open in [handover.md](../handover.md) — items 1–7 — plus `LAY-04`, +`LAY-07` and the repository-hygiene entries in +[known-issues.md](../references/known-issues.md), across **three repositories**: +`quest`, `imp-tricks` and `chisurf`. + +Out of scope, deliberately: implementing `OBJ-02` (the fitting loop itself), and +`DUP-07`'s remaining half (moving ChiSurf's fps.json `payload.py` — the owner +is not convinced `chisurf/core` is the right destination, so it stays open). + +# Decisions + +| # | Decision | Rejected alternative | +|---|---|---| +| 1 | **`OBJ-02` takes the host route.** QuEst contributes a *model*; ChiSurf's existing optimiser, error analysis and decay-data stack drive it. Recorded only — no fitting code in this programme | An own optimiser, which means reimplementing fitting, uncertainties and IRF handling | +| 2 | **One grid-offset convention: the integer `(ng-1)//2`, everywhere** | The float corner `(ng-1)/2`, which is geometrically prettier and is what LabelLib reports, but cannot be expressed by integer voxel indexing | +| 3 | **Residue identity comes from IMP's hierarchy, at the reader** — `(chain, res_id, insertion_code)` — and `Structure` keeps plain numpy arrays. `DUP-06` is promoted from "record only" to work | Wrapping a live IMP hierarchy in `Structure` (puts IMP objects in the domain layer, against the optional-dependency rule); or deleting `Structure` outright (collides with `LAY-04`) | +| 4 | **`arm64` is the only environment.** fastapi, uvicorn, playwright and pytest-asyncio move into it; base is retired | Keeping base for the web/browser layer, which is what "both must stay green" required | +| 5 | **The optional-dependency rule survives the environment it was enforced by.** Qt, LabelLib and IMP stay behind `try`/`except`; absence is *simulated* in tests instead of provided by an interpreter that genuinely lacks them | Making them hard requirements and deleting the LabelLib backend — which contradicts fixing that backend's registration in the same programme | +| 6 | **`DUP-03` is rejected, and κ² is documented rather than modelled.** Upstream's `calculate_fret_exact` is a Markov ensemble model over rotamer libraries; QuEst's trajectory kernel is the general one and should go *upstream* instead. κ² = 2/3 becomes an explicit project field | Adopting upstream (a different model, infeasible at cloud scale); or giving the dye an orientation now (real physics, a programme of its own) | +| 7 | **`quest.api` becomes a verb facade over a client**, and **serialization moves to the transport boundary** so an in-process call returns native objects | Keeping `result_payload` in the handlers, which taxes every local call — including a fitting loop, which decision 1 just made the primary consumer | +| 8 | **The contract mirrors ChiSurf's**: `quest/api/contract.py` (implemented at `quest/rpc/contract.py`) with `PLUGIN_ID`, `CONTRACT_VERSION`, `service_success`/`service_error` carrying `error_code`, a `contract_descriptor()` and a `quest.contract.describe` method — guarded by a per-method round-trip test asserting the payload validates against the manifest schema | Trusting review to keep local and remote behaviour identical | +| 9 | **Long-running work gets one manager, mirroring ChiSurf's `JobManager` contract** — same statuses, `progress`, cooperative `should_cancel` — implemented in QuEst so it still runs standalone | Importing ChiSurf's manager (a plugin depending on its host); or a bare cancellation token, which leaves `LAY-07`'s three mechanisms standing | +| 10 | **"job" is freed for the async sense; run artefacts are renamed `runs`** | Keeping `quest.jobs.*` for artefacts and calling async work `quest.tasks.*` — no churn now, a permanent vocabulary mismatch with the host | +| 11 | **The ChiSurf plugin is rewritten from scratch** on the `modelling/fps_json_editor` template — manifest, `api/contract.py`, `rpc/services.py` registering QuEst's methods into the host dispatcher, lazy import, and a dockable widget instead of a `QMainWindow`. It reuses ChiSurf's own machinery rather than duplicating it. **`quest/gui/` stays in QuEst**; the plugin embeds it | Manifest-only (leaves the host unable to drive QuEst as a model); or moving `quest/gui/` into ChiSurf (QuEst loses its standalone GUI) | +| 12 | **imp-tricks is NOT published — everything stays local** (owner ruling, 2026-07-28, reversing the interview decision). The recipe and the target channel are recorded for whenever that changes; the version is decided **at release**, not bumped per change. Consequence, accepted: **the `test` and `gui` CI jobs cannot solve** and stay red | Publishing to anaconda.org (`tpeulen`, noarch) and PyPI, which is what the interview chose and what would turn those jobs green | +| 13 | **Verification is a committed numeric baseline.** `tests/baselines/*.json` over a fixed set; a number-moving phase diffs against it and regenerates it **in the same commit whose log entry accounts for every moved number**. Every fix must be *seen to fail* first. Cold numba cache before each baseline run; the IMP-backend half gates locally, CI covers LabelLib | Continuing with a green suite plus ad-hoc spot measurements — which is what let a transposed grid overlap the truth by 83 % and pass | +| 14 | **Run artefacts are opt-in and never land in `cwd`** | A cleanup script alone, which treats the symptom | +| 15 | **i18n gets a coverage test** across en/de/fr and the parameter catalog; UI chrome is translated; scientific help text falls back to English *visibly* | Machine-translating parameter help with no reviewer; or dropping de/fr | + +# What these reverse + +Three of the above contradict something this bundle previously asserted. They +are called out so a reader who trusts the older text is corrected: + +- **Decision 4 reverses "both environments must stay green"** + ([workflows/environment.md](../workflows/environment.md), + [workflows/testing.md](../workflows/testing.md), and the root `AGENTS.md`, + named `CLAUDE.md` when this was written). + The owner ruled base out of scope. Recorded honestly: **no defect in base was + reproduced here** — its web backend tests gave 16 passed and `import + quest.core` succeeded on 2026-07-28. This is an owner ruling, not a + measurement. +- **Decision 3 reverses `DUP-06`'s "low severity, long-term, has not bitten + yet"** in [assessment.md](assessment.md). It has bitten: every multi-chain + structure gets one chain's side chains folded into another's CB. +- **Decision 6 reverses `DUP-03`'s premise** in [assessment.md](assessment.md) + and [objectives.md](objectives.md), both of which say adopting + `IMP.bff.cgdye.analysis.fret` "would bring κ² with it". It would not. + +# Phases + +Ordered by dependency, not by size. One commit each; OKF updated in the same +commit. + +| # | Phase | Depends on | +|---|---|---| +| 0 | Hygiene and the write-side default | — | +| 1 | Consolidate on `arm64` | 0 | +| 2 | Numeric baseline; run the two unverified suites | 1 | +| 3 | One grid-offset convention | 2 | +| 4 | Residue identity from IMP | 2 | +| 5 | FRET respec and explicit κ² | 3, 4 | +| 6 | Remaining dedup rows | 3, 7 | +| 7 | imp-tricks upstream fixes | — | +| 8 | `LAY-04` facade and the JSON-RPC contract | 1 | +| 9 | `LAY-07` cancellation; `runs`/`jobs` rename | 8 | +| 10 | Rewrite the ChiSurf plugin | 8, 9 | +| 11 | i18n coverage | — | +| 12 | Publish imp-tricks; CI green | 7 | +| 13 | OKF closeout | all | + +The baseline sits at phase 2 **before** anything moves numbers, on purpose: the +browser suite and the ChiSurf plugin had gone two sessions unverified across +changes that touched every accessible volume, and discovering a break after +three number-moving commits makes attribution impossible. + +# Still undecided + +- Where ChiSurf's fps.json `payload.py` belongs (`DUP-07` remainder). +- Whether the leftover scratch files in the tree (`out.xyz`, `out_slow.xyz`, + `test.pdb`, `test.cif`, `webui-viewer-testpdb.png`, `tests/sim_test.log`) go. diff --git a/okf/specs/structure-io.md b/okf/specs/structure-io.md new file mode 100644 index 0000000..01c6657 --- /dev/null +++ b/okf/specs/structure-io.md @@ -0,0 +1,163 @@ +--- +type: Specification +title: One seam for structure input +description: Every structure enters QuEst through a single loader that yields an atom array; nothing downstream ever sees a filename or a format. +resource: quest/core/structure/reader.py +tags: [io, structure, pdb, cif, radii, architecture] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-27T00:00:00Z } +stale_after: 2027-01-27 +sources: + - id: quest-core-structure-reader-py + resource: ../../quest/core/structure/reader.py + title: quest/core/structure/reader.py + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# The rule + +**One module turns a structure *source* into an atom array. Everything else +takes the array.** No other code opens a structure file, knows a format, or +decides a radius. + +A "source" is any of: a path to PDB/mmCIF, a four-character RCSB ID, bytes, or +an already-parsed structure. A caller says *what* it wants labelled; it never +says *how to read it*. + +# Why — three bugs from one cause, all found 2026-07-27 + +Every structure-input defect this project has hit is the same shape: something +downstream re-derived the structure instead of being handed it. + +1. **`imp_av.py` re-reads the file.** `build_imp_accessible_volume` calls + `IMP.atom.read_pdb(path)` rather than using the structure it was given, so a + coarse-grained project silently gets the **all-atom** volume — coarse and + all-atom measured byte-identical at 13883.805 ų. +2. **The same re-read is `read_pdb` only**, so `.cif` projects fail outright + under that backend ("No molecule read from file … mc4r_dimer.cif") while + working perfectly through `quest/core/structure/reader.py`, which handles mmCIF. One + format, two answers, depending on which backend you happened to pick. +3. **Two radius tables.** LabelLib was fed QuEst's Bondi-like radii (C 1.76, + N 1.65, O 1.40) and IMP.bff its own (C 2.10, N 1.85, O 1.71) — 19 % larger + carbon, **72 % more excluded volume**, and hence AVs differing by ~20 % + (14 500 vs 17 500 ų on 148l E15). That was misread for a whole session as an + *algorithmic* difference between the backends. It was an input difference. + The backends agree on where the dye is (centroids within 0.6 Å); they were + never asked the same question. + +The same argument applies to `fps.json`: the format is somebody else's standard +and it will change. One reader, one writer, one place to fix. + +# The seam + + load_structure(source, *, coarse=False, radii=..., selector=...) -> Atoms + +`Atoms` is the structured array QuEst already simulates on — `coord`, `radius`, +`atom_name`, `res_name`, `res_id`, `insertion_code`, `residue_index`, `chain`, +`mass`. **Group on `residue_index`**, which is the identity; `res_id` is for +display and is ambiguous in any multi-chain structure. Downstream consumers take +that array and nothing else: + +| consumer | takes today | must take | +|---|---|---| +| `AV` / LabelLib backend | a `Structure` | the array | +| `imp_av.py` | **a filename** | the array | +| `IMP.bff.av.compute_av` | already arrays ✔ | — | +| quenching / diffusion grids | a `Structure` | the array | + +`compute_av`'s signature (`atoms_xyz`, `atoms_vdw`, `source_xyz`) is the model +to copy: a function that takes coordinates *cannot* re-read a file, miss a +coarse-graining, or disagree about a format. + +# Reading is IMP's job; radii are QuEst's decision + +Two separable things that got conflated: + +- **Parsing** — use IMP. It handles mmCIF, altlocs, insertion codes and hetero + records, and it is maintained. QuEst's own parser should go. + + **And take the residue *identity* from it too, not just the coordinates** + (2026-07-28). The reader had IMP's `Chain`, `Residue.get_index()` and + `Residue.get_insertion_code()` in hand and wrote only a bare `res_id`, so + everything downstream re-derived residues from a number that restarts per + chain. It now assigns a `residue_index` per distinct + `(chain, res_id, insertion_code)` and carries the insertion code as a column. + The general rule: **if the parser already knows something, do not make the + domain re-infer it** — every structure-input defect in this project is that + shape. +- **Radii** — inherit IMP's. **Decided 2026-07-27 and implemented**: the reader + takes `IMP.core.XYZR(p).get_radius()` off the particle IMP decorated, and + `quest/core/elements.py` is gone. (An earlier draft of this spec argued the + opposite — keep a QuEst table because IMP's are ~19 % larger than the + Bondi-like values the FPS convention assumes. That was overruled: one source + of radii matters more than matching the older convention, and having two was + what made the backends look like they disagreed.) + + The cost is real and measured: IMP's are CHARMM-style (C 2.10 Å against + 1.76), so accessible volumes shrink and **only 43 of 151 CB sites on 148l + chain E remain labelable**. Numbers are no longer comparable to published FPS + work computed at Bondi radii. Both backends are fed the same array, so the + backend choice is availability only — IMP.bff preferred, LabelLib where + IMP.bff is not built (Windows). + +**Decided and implemented 2026-07-27: HETATM is not stripped; water still is.** +A bound ligand occludes the dye, so the loader passes **no selector** and takes +IMP's default — everything but waters and hydrogens. `_atom_record_selector` is +deleted. On 148l that is 1363 atoms against 1322, the extra 41 being `FGA`, +`API`, `DAL`, `MUB`, `NAG` and `BME`. + +Both candidates were measured over all 151 CB sites of 148l chain E, because +atom counts do not decide this — what the volumes do decides it: + +| selector | atoms | labelable | mean AV | +|---|---|---|---| +| ATOM records only (before) | 1322 | 148/151 | 9485 ų | +| **no selector / `NonWaterNonHydrogen`** | **1363** | **150/151** | **9320 ų** | +| `NonHydrogenPDBSelector` (waters in) | 1503 | 148/151 | 7900 ų | + +Waters cost **17 % of every accessible volume**, and crystallographic solvent is +mobile on the timescale a tethered dye explores — treating it as a rigid wall is +a stronger claim than the physics supports. Rejected. + +Admitting ligands cost 1.7 % of mean volume and, counter-intuitively, *gained* +two labelable sites. More obstacles cannot open a pocket; what changes is the +grid IMP sizes around the site, so a path search that previously started nowhere +can succeed. Worth remembering when a labelability count moves the wrong way. + +## Two things HETATM broke on arrival + +Both were latent, and both are the same shape: code that had only ever seen +standard amino acids. + +- **`to_coarse` raised `KeyError: 'FGA'`.** Residues with no coarse template are + now kept **whole** — coarse-graining reduces an amino acid to backbone plus + CB, and a bound sugar has no such reduction. Dropping them would have + reinstated the stripping this decision removed, at a different layer. + `move_center_of_mass` needed the same guard. +- **Every hetero atom was named `"HET:"`.** IMP names them `"HET: C1 "`, and the + `atom_name` field is `|U5`, so the real name was truncated away and all of + them collided on one string. `_atom_name()` strips the prefix. This matters + because atom names are how the quenching chemistry and the coarse templates + identify atoms. + +# Done, and what remains + +Done 2026-07-27: + +- `quest/core/elements.py` **deleted** (271 lines) — radii and masses come off + the IMP particle, and the `assignCharge` path it also served had no caller. +- `quest/core/structure/model.py` 623 → ~345 lines: RMSD, clustering and the torsion + subsystem had no readers. +- `imp_av.py` takes the atom array; its file handling is gone, which fixed both + the discarded coarse-graining and the mmCIF failure above. +- The acceptance test passed: with identical radii the two backends converge to + a **0.90 ratio** on 148l E36, centroids within 0.5 Å. Before, with a table + each, it was 0.78 — and that gap was misread as algorithmic. + +Remaining: + +1. The loader still has no single `load_structure(...)` entry point; `AV` and + the quenching grids still take a `Structure` rather than an array. +2. Same treatment for `fps.json`: one reader, one writer. +3. The decisions in [handover](../handover.md) — none implemented. diff --git a/okf/subsystems/accessible-volume.md b/okf/subsystems/accessible-volume.md new file mode 100644 index 0000000..8846c2e --- /dev/null +++ b/okf/subsystems/accessible-volume.md @@ -0,0 +1,308 @@ +--- +type: Subsystem +title: Accessible volume +description: AV enumeration, the IMP.bff/LabelLib backend split, and the derived slow-factor and quenching-rate grids. +resource: quest/core/av.py +tags: [accessible-volume, av, grid, numba, labellib, imp] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-27T00:00:00Z } +stale_after: 2027-01-27 +sources: + - id: quest-core-av-py + resource: ../../quest/core/av.py + title: quest/core/av.py + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# What the AV is + +The set of positions the dye **centre** can occupy: reachable from the +attachment atom along a linker of `linker_length` × `linker_width`, without the +dye sphere (`radius1`, or `radius1..3` for AV3) overlapping protein atoms. +Represented as a cubic density grid of spacing `dg` plus the corresponding point +cloud. `quest/core/av.py::AV` owns it. + +# Backend selection + +`resolve_av_backend(preference)` decides, from the `av_backend` argument, else +the `QUEST_AV_BACKEND` environment variable, else `"auto"`: + +| Value | Behaviour | +|---|---| +| `"imp_bff"` | `quest/core/av.py::build_imp_accessible_volume` — **the default** | +| `"labellib"` | `calculate1R` (AV1) / `calculate3R` (AV3), thin wrappers over `ll.dyeDensityAV*` | +| `"auto"` (default) | IMP.bff if a *compiled* one is present, else LabelLib, else `RuntimeError` | + +An unavailable or misspelled backend raises immediately, naming what *is* +usable, rather than failing later with an empty volume. `AV.av_backend` records +which one ran, and `verbose=True` prints it. + +**Both rows in that table go through imp-tricks, so "LabelLib is the fallback" +does not mean QuEst can compute an AV without imp-tricks.** The single call is +`IMP.bff.av.compute_av(..., backend=…)` — the dispatch is *upstream's*, and +`density2points` comes from `IMP.bff.av._kernels` too. Measured 2026-08-10 with +`IMP_TRICKS_SRC` pointed at nothing: 98 tests fail and 8 error, including the +`labellib`-parametrised baselines. The choice in the table is a choice *inside* +imp-tricks, not a way to do without it. `imp_tricks_av_available()` is the +predicate for "can this interpreter compute an accessible volume at all", and +what `tests/conftest.py` uses to skip rather than fail +([workflows/testing.md](/workflows/testing.md)). + +**`simulation_type` must be `"AV1"`; anything else raises.** This concept +previously said AV3 "only takes effect on the LabelLib path" — it took effect on +neither. The LabelLib branch called `calculate3R`, which was deleted in +`7ecf209`, so `simulation_type="AV3"` raised `NameError: name 'calculate3R' is +not defined` from inside a running simulation; the IMP.bff branch ignores +`simulation_type` outright. Since `simulation_type` is a project field a scan can +set, it is now validated in `AV.__init__` **before the structure is read**, and +names AV1 as the only supported value. QuEst has no three-radius dye model, and +`IMP.bff.av.compute_av` has none either — its LabelLib branch also drives +`dyeDensityAV1` and uses `dye_radii[0]` alone. + +**IMP.bff is primary as of 2026-07-27**; LabelLib is the fallback for platforms +without a compiled `IMP.bff`, Windows above all. Before that flip the IMP path +re-read structures from disk, which discarded coarse-graining and broke mmCIF; +it now takes the atom array +([specs/structure-io.md](/specs/structure-io.md)). + +## The two backends do not agree, and the choice is visible in the results + +Fed the same atom array with the same radii they differ by algorithm alone: +**136 707 (IMP.bff) against 151 869 (LabelLib) points on 148l E36 — a 0.90 +ratio, centroids 0.63 Å apart.** + +That 10 % is the small part. Measured over all 151 CB sites of 148l chain E +under the reference project: + +| | labelable sites | quenching (0 < QY < 1) | +|---|---|---| +| LabelLib | 43 / 151 | 21 | +| IMP.bff, `allowed_sphere_radius` 2.0 | 147 / 151 | 60 | +| IMP.bff, `allowed_sphere_radius` 2.1 (current) | **151 / 151** | **67** | + +So the flip does not merely shift volumes by 10 % — it more than triples how +many sites can carry a dye at all. + +**Why, and a correction.** When IMP.bff was promoted this was attributed mostly +to the two backends receiving different `allowed_sphere_radius` values. That was +wrong, and measuring it is what showed it: raising the project default from +0.5 Å to 2.1 Å left LabelLib's count at exactly 43/151, because +`calculate1R`/`calculate3R` accept a `linkersphere` argument and **never pass it +on** — `ll.dyeDensityAV1` has no such parameter. The real cause is how each +backend frees the attachment site: LabelLib zeroes the attachment atom's own vdW +radius and nothing else, so a CB hemmed in by CHARMM-sized neighbours has no +route out; IMP ignores *every* obstacle inside the sphere. Fatter radii made +that difference decisive. + +**Results are not comparable across backends**; anything pinned to a number has +to say which one produced it. + +## It is `compute_av` now (`DUP-01`, 2026-07-28) + +**QuEst no longer implements either backend.** `AV.__init__` makes one call to +`IMP.bff.av.compute_av`, passing `backend=` explicitly so the choice is never +implicit, and both in-tree implementations are deleted: `quest/core/av.py` +(329 lines) and `calculate1R` (69). QuEst keeps the site selection, the cubic-grid +and binarisation adapter, and `AV`'s grids — the application, not the algorithm. + +Verified before the swap and again after, on 148l E36/E55/E118 under **both** +backends: identical grid shape, identical binary density voxel-for-voxel, +identical point counts — 147 011 / 164 783 / 67 889 (IMP.bff) and +172 964 / 200 283 / 91 585 (LabelLib), unchanged to the last point. A green suite +was not treated as evidence here; the volumes were compared directly. + +Two things had to go upstream first, both contributed rather than worked around: + +- **A build lock.** `compute_av` had no synchronisation, so a threaded scan died + in `XYZR_setup_particle` exactly as QuEst's own backend used to. imp-tricks + `9cd5c13` adds `_IMP_BUILD_LOCK` with the same construction/resample split + described below, so QuEst's lock moved rather than disappeared. +- **A test that reproduces the race.** The first version used the 165-atom slab + and four workers and **passed with the lock defeated** — the construction + window is too short to overlap. It takes ~2000 atoms and 8 workers. + +`simulation_type` is validated separately; upstream has no AV3 either. + +An empty AV raises with a diagnostic naming the residue ("might be buried inside +the protein"), because a zero-point volume otherwise fails much later and much +less legibly. + +## Grid registration: the four ways to get it silently wrong + +The first two were live in the IMP path until 2026-07-27; the second two on +**both** paths until 2026-07-28. All four were invisible for the same reason — +the failure mode is a plausible volume in the wrong place, not an error. + +**The rule that resolves all of them: there is one map between Ångström and a +voxel index, `quest.core.av.grid_center_index`.** Voxel *i* of a grid anchored +at `x0` sits at `x0 + (i − grid_center_index(ng)) · dg`, and the inverse is +`floor((p − x0)/dg) + grid_center_index(ng)`. Anything that converts between the +two and does not use that map is a bug, not a variant. + +The measurement that decides it, and the one to repeat rather than argue: +run every point of `AV.points` through the *kernels'* index formula and check it +lands on a voxel `AV.density` calls occupied. It must be 100 %. On 2026-07-28, +before the fix, LabelLib gave **37478/37859 = 98.99 %**. + +1. **Axis order.** IMP numbers voxels with *x* fastest + (`i = x + nx*y + nx*ny*z`), so reshaping the flat tile values C-order into + `(nx, ny, nz)` transposes the volume, exchanging x and z. An accessible + volume is globular enough that the transpose still overlapped the truth by + **83 %** of its voxels: the point count, the bounding box and the total + volume were all right, and only the *shape* was mirrored. Downstream, the + contact volume then landed on the wrong side of the protein, so quenchers in + reach were not seen and donors came out unquenched. +2. **Grid origin.** IMP sizes the map itself, and the attachment atom is on the + middle voxel only when the edge length is odd — it is 86 on 148l E36. The + origin must be read from the PathMap header + (`IMPAccessibleVolumeResult.origin`), never reconstructed from the + attachment atom. +3. **Two offset conventions** (fixed 2026-07-28, both backends). The kernels and + the point cloud used the integer `(ng - 1) // 2`; the two trajectory kernels + and `_sample_grid_at_trajectory` used the float corner `(ng - 1) / 2`; and + the **LabelLib** branch anchored `x0` on the attachment atom, which is on a + node only for odd `ng`. For even `ng` — 86 and 80 at the reference site, so + the normal case — the walk therefore read the quenching and stickiness grids + half a voxel from where they had been stamped. The trajectory pair was + *self*-consistent, which is exactly why nothing caught it. +4. **Truncation toward zero** (fixed 2026-07-28, both backends, larger than 3). + `_center_grid_indices` used `int((p - r0)/dg)`. `int()` rounds toward zero, + so a centre on the **negative** side of the anchor was rounded *up* while + every other map rounds down — a one-voxel error per axis for half the grid, + independent of parity. `DonorDecay._sample_grid_at_trajectory` had the mirror + of it: `np.trunc` maps `[-1, 0)` to `0`, so a dye up to one voxel *below* the + grid was treated as inside and read voxel 0's quenching rate. + +The tests that catch these: `tests/test_grid_registration.py` (every cloud point +indexes to an occupied voxel; the two index maps agree probe-for-probe; the +anchor is on a lattice node; and an assertion that `ng` is *even* here, since +none of it is detectable on an odd edge), plus +`AV(av_backend="imp_bff").points` equalling `build_imp_accessible_volume(...) +.points` **exactly**, as a set — comparing counts or centroids alone passes with +the grid transposed. + +**A caution about "reference implementations".** `tests/test_grid_kernels.py` +compared the kernels against a hand-written reference that had *copied* the +kernels' `int()`. It could not detect defect 4 at all: it was a self-comparison +wearing the costume of an independent check. If you write a reference, derive it +from the specification, not from the code under test. + +## Threading — the lock lives upstream now + +`IMP` builds its decorators through SWIG, which is not safe from several +threads at once — `quest/core/structure/reader.py` already serialises the parse for this +reason, and the AV path hits the identical failure one layer down +(`'XYZR_setup_particle'` receiving a particle *name*) as soon as a scan runs +sites in a pool, which the web backend does. + +`_IMP_BUILD_LOCK` is in **`IMP.bff.av.compute`** as of `DUP-01`; QuEst's copy went +with `imp_av.py`. It guards object construction and density extraction but +**not** `av.resample()`: measured on 148l E36, resample is 636 ms of a 662 ms +build (96 %) and the SWIG construction is 22 ms (3 %), so locking the compute +would cost a threaded scan nearly all its parallelism to guard the phase that is +not failing. + +**Do not assume a thread-safety test is testing anything.** The upstream one +first used a 165-atom system over four workers and passed with the lock replaced +by a no-op — the construction window was too short for two threads to collide. +It needs ~2000 atoms over 8 workers to fail reliably, and the docstring says so. +Same trap as the vacuous grid test of 2026-07-27: a concurrency test that has +never been seen to fail is not evidence. + +# The three grids + +`AV.calc_slow_av` derives everything the diffusion stage needs, in one place: + +| Grid | Built by | Meaning | +|---|---|---| +| `density_fast` | AV backend | the accessible volume itself | +| `density_slow` | `subav` | the accessible **contact** volume (ACV) — voxels within `slow_radius` of a slow centre | +| `slow_factor_grid` | `_slow_factor_grid` | per-voxel diffusion scaling; overlapping centres **multiply** | +| `k_quench_grid` | `_additive_factor_grid` | per-voxel PET rate; overlapping centres **add** | + +`slow_centers` and `quench_centers` are passed separately, with their own radii, +so stickiness can sit on the residue while quenching sits on its redox-active +moiety ([quenching-model.md](quenching-model.md)). + +# Kernels + +All hot loops are `@njit` in `quest/core/av.py`, most with +`parallel=True`: `_subav`, `_slow_factor_grid`, `_additive_factor_grid`, +`_center_grid_indices`, `_ran_dist` (RDA sampling), `_asa` (solvent +accessibility), and the trajectory kernels `_simulate_traj` / +`_simulate_traj_grid`. `tests/test_grid_kernels.py` pins their equivalence and +behaviour — that is the file to extend when a kernel changes. + +## `density2points` is upstream's now (`DUP-02`, 2026-07-28) + +`quest.core.av.density2points` is a thin adapter over +`IMP.bff.av._kernels.density2points`; QuEst's own `_density2points` is deleted. +The two select exactly the same voxels — verified on 5×7×9, 8×8×8 and 11×11×11 +grids — and upstream's is a strict superset, keeping the per-voxel weight +QuEst's signature discards. The adapter drops that column and the oversized +buffer's slack. + +Two things had to be true first, and neither was: + +1. **Upstream's kernels were bare `@nb.njit`.** QuEst's carried + `cache=True, nogil=True`, and both are load-bearing: this loop visits every + voxel and is the most expensive step of a site computation, so a threaded + scan — which the web backend runs — would have re-serialised on the GIL + exactly where the work is. Contributed upstream (imp-tricks `a49e17c`) rather + than worked around, so the swap is not a regression. +2. **The enumeration order differs** — upstream runs `ix` outermost, QuEst's ran + `iz` outermost — so the rows come back permuted. Safe *only* because nothing + reads `AV.points` positionally: the walk runs on the density grid, + `_ran_dist` samples indices at random, `Rmp` averages, and the acceptor cloud + is averaged over in full. The single visible effect is the row order of a + saved `.xyz`. `TestDensityToPoints` was the only thing asserting a sequence + and now compares sorted. + +**The import is lazy, and that is not an optimisation.** `_density2points_kernel()` +imports on first use and caches in a module global, because importing +`IMP.bff.av` pulls in `IMP`, and `import quest.core` must not. A module-scope +import failed `test_importing_the_domain_does_not_import_qt` and +`test_the_model_needs_no_qt` — not with an `ImportError`, but with the dylib +conflict in [references/known-issues.md](/references/known-issues.md), because +both probe the domain layer in a subprocess. It would have promoted a documented +latent environment fault into a hard failure of the service layer. + +# FRET distance observables + +`RDAMeanE` (⟨R_DA⟩_E via a Förster-averaged sample), `RDAMean` and `dRmp` +(mean-position distance) sample pairs of AV point clouds. `R0` comes from the +project's `fret.R0_matrix`. + +## The sampling is upstream's (`DUP-03`, 2026-07-28) + +`RDAMean` and `RDAMeanE` are aggregations over +`IMP.bff.av._kernels.random_distances` + `IMP.bff.distance_metrics.av_pair_statistics`; +QuEst's `_ran_dist` is deleted. Measured on 148l E15/E90 (64 969 × 71 873 +points, 50 000 samples), the two agree inside their own sampling noise: +⟨R_DA⟩ 55.164 ± 0.037 Å against 55.171 ± 0.032, ⟨R_DA⟩_E 54.467 ± 0.022 against +54.473 ± 0.029. + +Two things changed, and both are deliberate: + +- **It is ~5× slower** — 3.4 ms a call against 0.68 ms. QuEst's kernel was + `parallel=True`; upstream's is sequential because it seeds explicitly, and + numba's per-thread RNG cannot be seeded reproducibly. A further 0.87 ms is the + `(N, 3) → (N, 4)` widening upstream's signature requires; QuEst's grids are + binary, so that weight column is all ones and the weighted mean reduces to the + plain one. Acceptable **only because this runs once per simulation** — ~0.4 s + across a 151-site scan. Do not adopt this kernel on a per-frame path. +- **Results are reproducible, which they were not.** The old parallel kernel drew + from an unseeded per-thread RNG, so two calls on the same clouds disagreed. The + seed is now a parameter (`RDA_SAMPLING_SEED`, default 0). + +**`dRmp` stays local, and index 1 of `av_pair_statistics` must never be read.** +Upstream returns `r_mp` as a copy of `r_da_mean` — its own docstring concedes it +— and R_mp = |⟨r_D⟩ − ⟨r_A⟩| cannot be recovered from a sample of pair distances +at all, because the sampling destroys exactly that information. 47.65 Å (QuEst) +against 51.53 Å (upstream) on 148l E15/E90. QuEst reads indices 0 and 2 only. + +`TestTheAdoptedDistanceKernelsBehave` pins the three properties the swap could +have broken. It uses **E55/E124**: a test spanning both environments must pick +sites labelable under *both* backends, and E15 — the pair the spec quotes — is +not among LabelLib's 43 of 151. diff --git a/okf/subsystems/chisurf-widgets.md b/okf/subsystems/chisurf-widgets.md new file mode 100644 index 0000000..39de159 --- /dev/null +++ b/okf/subsystems/chisurf-widgets.md @@ -0,0 +1,62 @@ +--- +type: Subsystem +title: ChiSurf widget reuse — what to embed, not rebuild +description: ChiSurf already ships widgets for sequences, code editing, structure viewing and labeling-site tables. QuEst embeds those instead of carrying a second copy. +resource: quest/gui/ +tags: [gui, chisurf, dedup, widgets] +status: stable +generated: { by: human:tpeulen, at: 2026-08-07T00:00:00Z } +stale_after: 2027-02-07 +sources: + - id: chisurf-gui + resource: ../../chisurf/chisurf/gui/ + title: chisurf/gui/ and chisurf/plugins/ + author: human:tpeulen + last_modified: 2026-08-07 +--- + +# ChiSurf already has these widgets + +QuEst's desktop GUI lives inside ChiSurf's host environment. Every Qt widget +below already exists in ChiSurf — QuEst embeds the original, not a re-creation. + +## The mapping + +| QuEst feature | ChiSurf widget | Import path | +|---|---|---| +| 3D structure viewer | `MolView` | `chisurf.plugins.chimol.chimol.renderer.view.MolView` | +| Sequence bar | `SequenceDock` | `chisurf.plugins.chimol.chimol.app.sequence_dock.SequenceDock` | +| JSON view / editor | `SimpleCodeEditor(language="JSON")` | `chisurf.plugins.core.code_editor.SimpleCodeEditor` | +| Labeling-site table | `PositionPanel` | `chisurf.plugins.modelling.fps_json_editor.gui.position_panel.PositionPanel` | +| Code editor (full) | `CodeEditor` | `chisurf.plugins.core.code_editor.CodeEditor` | +| Decay/trajectory plots | chiplot | `chisurf.gui.widgets.chiplot` | + +## Why not a second copy + +QuEst shipped its own `QPlainTextEdit` for JSON, a custom `ResidueButton` +sequence bar, and hand-built pyqtgraph plots. Each duplicates something +ChiSurf already provides and tests. Two copies drift — exactly what happened +with the quenching chemistry, where the GUI shipped different `kQ` values than +the CLI for months. The rule is the same one that governs imp-tricks: +**general machinery belongs upstream, the application embeds it.** + +## What was dedup'd + +- **JSON view**: replaced `QPlainTextEdit` with `SimpleCodeEditor(language="JSON")` + — gives syntax highlighting and line numbers. The old code is gone. +- **Sequence bar**: replaced custom `ResidueButton` HBox with ChiSurf's + `SequenceDock` — QListWidget with proper scrolling, residue numbers, and + the same wiring pattern `MolViewPluginWindow` uses. + +## What remains in QuEst (application-specific) + +The donor/acceptor toggle and the `_apply_selection` logic are QuEst-specific: +ChiSurf's `PositionPanel` tracks arbitrary labeling sites, while QuEst has +exactly one donor and one optional acceptor. That adapter lives in +`quest/gui/chimol_widget.py` and calls into the reused widgets. + +## Fallback when ChiSurf is absent + +Each chisurf import is behind `try/except`. Where it fails, the widget shows a +placeholder label and the rest of the GUI continues. This is the same pattern +as every other optional dependency (`IMP`, `LabelLib`). diff --git a/okf/subsystems/cli.md b/okf/subsystems/cli.md new file mode 100644 index 0000000..a5722b5 --- /dev/null +++ b/okf/subsystems/cli.md @@ -0,0 +1,69 @@ +--- +type: Subsystem +title: CLI +description: quest simulate/scan/template/validate/gui, dotted-path overrides and grid sweeps. +resource: quest/cli.py +tags: [cli, click, batch] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: quest-cli-py + resource: ../../quest/cli.py + title: quest/cli.py + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# Commands + +```bash +quest template --with-fret > project.quest.json # emit a valid starter +quest validate -p project.quest.json # check required keys + structure +quest simulate -p project.quest.json -o decay.csv # one run +quest scan -p project.quest.json -l fps.json -o scan.json # one run per labeling site +quest gui # launch the Qt GUI +``` + +Entry point `quest = quest.cli:cli` (Click group). Output format follows the +`-o` extension: `.csv` or `.json`. + +# Overrides and sweeps + +- `--set a.b.c=value` — override any project field by dotted path. Values are + parsed as JSON when possible, so `--set fret.enabled=true` and + `--set attachment.residue=42` do the right thing. +- `--grid a.b.c=v1,v2,v3` — sweep. Multiple `--grid` options form the + **Cartesian product**, and each run's output path is tagged with the values + that produced it (`_resolve_output_path` / `_sanitize_tag_value`). + +`_set_path`, `_clone_with_overrides`, `_expand_grid`, `_cartesian` and +`_build_runs` implement this; they operate on the plain project dict and are the +reason the [project schema](/architecture/project-schema.md) keeps dotted paths +addressable. + +# `scan` + +Takes a project **and** an `fps.json` labeling file, then simulates every +position in it, reporting per site: lifetime, quantum yield, contact fraction, +AV and contact volumes, contact-to-free ratio, and the dominant quencher with +its `quench_rate_fraction` (from `top_quenchers`). Progress is a `tqdm` bar. + +Two design points: + +- **Failures are data, not exits.** A site that raises is recorded with + `status: "failed"` and the error string, with the metric fields present and + null. A buried residue must not abort a 300-site scan. +- **`save_outputs=False`.** The scan reads only scalars and `aa_residence`; the + job directory would dominate the runtime + ([job-artefacts.md](/architecture/job-artefacts.md)). + +`tests/test_scan_reporting.py` pins both the quencher attribution and the +failure diagnostics. + +# Validation + +`_validate_project` is shared with the web backend, so the browser and the +terminal agree on what a valid project is. It checks the required keys, resolves +the structure (path **or** PDB ID), requires a donor dye with `D`, and sanity +checks `t_max > t_start`. diff --git a/okf/subsystems/core-api.md b/okf/subsystems/core-api.md new file mode 100644 index 0000000..c20d935 --- /dev/null +++ b/okf/subsystems/core-api.md @@ -0,0 +1,142 @@ +--- +type: Subsystem +title: Core service layer +description: quest/core/ and the quest.api facade — project loading, simulate_project, DecaySimulationResult, residue-resolved analysis. +resource: quest/core/ +tags: [api, service-layer, headless] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-02-06 +sources: + - id: quest-core + resource: ../../quest/core/ + title: quest/core/ + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# `quest.api` is a facade, not a re-export + +Until 2026-07-28 (`LAY-04`) this module forwarded names from `quest.core` and +had no notion of *where* a call runs, so the web backend reached past it into +`quest.core` directly and a host had nothing single to drive. It is now the +supported way in, and every verb goes through a **client**: + +```python +from quest import api + +project = api.template(with_fret=False) +result = api.simulate(project, pdb_path="tests/148l.pdb") +``` + +| Verb | Does | +|---|---| +| `describe()` | The contract: method names, versions, error codes | +| `template(*, with_fret=True)` | A valid project document to start from | +| `validate(project, *, pdb_path=None)` | Raises `ProjectValidationError` | +| `simulate(project, *, pdb_path, nbins, tac_range, mode, ...)` | One run; returns `DecaySimulationResult` | +| `scan(project, positions, *, pdb_path, ...)` | One run per labeling site | +| `parameter_catalog(locale=None)`, `dyes()` | The shipped data, translated | +| `structure_metadata(pdb_path)` | Chains, residues and atoms a dye could attach to | + +`client()` returns the active client -- `InProcessClient` by default -- and +`use_client(other)` swaps in a remote one. That indirection is the point: the +CLI, the web backend, the GUI and a ChiSurf host all exercise the same registry, +the same validation and the same error codes, rather than four near-copies. + +**Results stay native.** `simulate` hands back a `DecaySimulationResult` with +its numpy arrays intact; serialization happens at a *transport* +(`quest.rpc.contract.to_payload`), not in a handler, because a fitting loop is +now a primary consumer and converting every decay channel to a Python list per +iteration is a tax it would pay forever. `tests/test_contract.py` round-trips +each method's native result through `to_payload` and validates it against the +manifest schema, so payload and contract cannot drift quietly. + +**The domain is still importable.** `load_project`, `build_donor_from_project`, +`simulate_project`, `DecaySimulationResult`, `top_quenchers` and the FPS-JSON +helpers remain re-exported from `quest.api`; a notebook that wants them should +have them. The difference is that the verbs are the supported entry point. + +# What lives where + +`quest/core/` is the domain: Qt-free, host-free, and it takes plain data plus +callables (`should_cancel` is a predicate, not a `Job` -- see [tasks.md](tasks.md)). +Its `__init__` carries the authoritative module table; in summary: + +| Module | Owns | +|---|---| +| `quest/core/simulation.py` | The pipeline -- `simulate_project`, `load_project`, `build_donor_from_project`, `DecaySimulationResult`, the residue-resolved analysis, the MRC/grid writers | +| `quest/core/dye_diffusion.py` | `SimulateDiffusion`, `DonorDecay`, the PET chemistry | +| `quest/core/av.py` | Accessible volumes, grid kernels, FRET rate traces | +| `quest/core/photon.py` | Photon-trace and decay-curve kernels (numba) | +| `quest/core/structure/` | `Structure` (`model.py`), reading through IMP (`reader.py`), labeling-site metadata, PDB-ID fetch with an on-disk cache | +| `quest/core/fps_json.py`, `quest/core/io.py` | `fps.json` labeling files; point-cloud xyz output | + +Neighbouring modules, reachable directly: + +| Module | Owns | +|---|---| +| `quest/project.py` | The project document: `template_project`, `validate_project`, `ProjectValidationError`, `REQUIRED_TOP_LEVEL_KEYS` | +| `quest/scan.py` | One labeling site: `site_project`, `simulate_site` (never raises), `scan_positions` | +| `quest/runs.py` | Past runs: `list_runs`, `run_summary`, `read_run`, `archive_run`, `purge_runs`, `runs_directory`, `is_run_id`. Renamed from `quest/jobs.py` when "job" was reserved for *running* work ([tasks.md](tasks.md)) | +| `quest/tasks.py` | The running work itself: `Job`, `JobManager`, cooperative cancellation ([tasks.md](tasks.md)) | +| `quest/rpc/` | `contract.py` (names, envelopes, error codes), `dispatcher.py` (`ServiceDispatcher`, `InProcessClient`), `services.py` | +| `quest/hosts/` | Optional bridges: `chisurf.py`, and `imp_tricks.enable_imp_tricks()` splicing a checkout into the live interpreter | +| `quest/settings/` | The shipped data: `parameter_catalog()`, `dye_repository()`, `save_dye()`, `quenching_defaults()`, resolved package-relative | +| `quest/i18n.py` | Translations, from one place, for every surface | + +None of it touches Qt, so it is safe in notebooks, servers and CI. + +# The three calls that matter + +| Call | Does | +|---|---| +| `load_project(path)` | JSON → mutable dict. Nothing more; there is no project class | +| `build_donor_from_project(project, pdb_path=None)` | dict → configured `DonorDecay`. This is where the top-level-vs-dye-entry precedence lives | +| `simulate_project(project, …)` | The whole pipeline; returns `DecaySimulationResult` | + +`simulate_project` keyword arguments worth knowing: `nbins`, `tac_range`, +`mode`/`n_curves`/`dt_tac`/`n_tac` (see [photon-decay.md](photon-decay.md)), +`project_dir`, `save_outputs` and `render_data` +([architecture/job-artefacts.md](/architecture/job-artefacts.md)). + +# `DecaySimulationResult` + +A dataclass, not a dict: + +- decay — `time`, `donor_counts`, `fret_counts` +- scalars — `quantum_yield_donor`, `quantum_yield_fret`, `fret_efficiency`, + `collisions_fraction`, `lifetime_donor`, `av_volume`, `contact_volume`, + `contact_to_free_ratio` +- trajectory — `trajectory_distance_to_mean`, `trajectory_time_ns`, + `trajectory_autocorr`, `trajectory_autocorr_lag_ns` (thinned for display) +- clouds — `trajectory_points`, `av_points`, `acv_points` (thinned) +- provenance — `project`, `job_id` +- attribution — `aa_residence` ([quenching-model.md](quenching-model.md)) + +# Analysis helpers in `core/simulation.py` + +- `calculate_aa_quenching`, `calculate_aa_residence`, `_residue_type_metrics`, + `aa_residence_from_model` — the residue-resolved statistics. +- `autocorr_to_tau_window` — autocorrelates the full distance-to-mean series and + truncates to a `tau0`-scaled lag window (correlate everything, thin only what + is plotted). +- `sampled_density_grid`, `diffusion_coefficient_grid`, `write_mrc` — the + voxel outputs. +- `_subsample_points` — the one place display thinning happens. + +Verified against the tree on 2026-08-10, mechanically: every symbol named in +this concept was resolved with `hasattr` against its module, and +`DecaySimulationResult`'s dataclass fields were compared to the list above in +both directions — nothing documented is absent and nothing present is +undocumented. `simulate_project` still takes the keyword arguments listed +above. This concept was marked unverified on 2026-08-06 because the tree had +moved under it; it had not in fact rotted. + +# FPS-JSON scanning + +`quest/core/fps_json.py` reads an `fps.json` labeling file +(`load_fps_json`), normalises its entries to positions +(`normalize_to_fps_positions`) and runs one simulation per site +(`run_fps_scan`). This is what `quest scan` and the web `/api/scan` drive; +they run with `save_outputs=False`. diff --git a/okf/subsystems/dye-diffusion.md b/okf/subsystems/dye-diffusion.md new file mode 100644 index 0000000..84e846e --- /dev/null +++ b/okf/subsystems/dye-diffusion.md @@ -0,0 +1,79 @@ +--- +type: Subsystem +title: Dye diffusion +description: SimulateDiffusion and DonorDecay — the Brownian walk inside the AV and the model object that owns a run. +resource: quest/core/dye_diffusion.py +tags: [brownian-dynamics, trajectory, donor-decay, numba] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: quest-core-dye-diffusion-py + resource: ../../quest/core/dye_diffusion.py + title: quest/core/dye_diffusion.py + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# `DonorDecay` — the model object + +One instance owns a whole simulation: structure, AV, diffusion, photons, and the +optional FRET channel. `update_all()` runs the sequence: + +1. `calc_av()` — the accessible volume +2. `_calc_slow_av()` — the ACV, the slow-factor grid, the k_quench grid +3. `simulate_diffusion()` — the Brownian walk +4. `diffusion.critical_distance = …` — resolve which frames count as contact +5. `calc_photons()` — the decay + +If a Qt application happens to be running it drives a progress dialog; headless +it is a plain sequence. `update_all` deliberately does **not** call +`gc.collect()`: the grids it replaces are refcounted NumPy buffers freed on +rebind, and a forced collection cost ~20 ms per run — which a residue scan pays +hundreds of times. + +`TransientDecayGenerator` (the Qt widget) *inherits* `DonorDecay`, so the GUI and +the headless path share one model rather than two implementations. + +# `SimulateDiffusion` — the walk + +Constructed from the `AV`, it runs `fps.simulate_traj` and keeps: + +- `_traj` — the (n_frames, 3) walk; +- `k_quench` — the per-frame quenching rate, read out of the AV's `k_quench` + grid along the trajectory; +- `quenched` / `_is_quenched` — the boolean contact trace; +- `distance_to_mean`, `mean` — the observables the trajectory plots use. + +Two kernels back it: `_simulate_traj_grid` (a spatial slow-factor grid, the +amino-acid stickiness mode) and `_simulate_traj` (a scalar slow factor over a +binary slow-AV, the older mode). `DonorDecay.simulate_diffusion` picks the grid +variant whenever `stickiness_mode == 'amino_acid'` and the AV carries a +`slow_factor_grid`. + +When `k_quench` is available the contact trace is derived from it +(`k_quench > 0`) rather than from a distance loop, which keeps the decay and the +contact statistics consistent with the grids by construction. + +# Reproducibility and parallelism + +- `random_seed` in the project (or on the donor dye) seeds the walk. It is + honoured by both trajectory kernels. +- The photon trace uses a **different but derived** seed + (`_photon_seed`, base + 7919 mod 2³¹−1) so the photon draws do not replay the + same sequence as the trajectory they score. With no seed set it returns + `None`, which keeps the faster multi-threaded photon kernel in play. +- `parallel_trajectories` (project key, `-1` = all cores, capped by + `MAX_PARALLEL_TRAJECTORIES = 8`) runs independent walks concurrently. +- `_preserved_numba_environment()` exists because numba resolves settings such + as `NUMBA_NUM_THREADS` **once at import time** — the context manager keeps a + temporary change from leaking into the rest of the process. + +`tests/test_simulation_performance.py` covers the scan fast path and seeded +reproducibility; treat it as the guard when touching any of the above. + +# Coarse graining + +`coarse_grained: true` (project or donor dye) makes `DonorDecay.structure` build +its `Structure` with `make_coarse=True` — fewer atoms in the steric test, faster +AV, coarser contacts. Covered by `tests/test_coarse_grained.py`. diff --git a/okf/subsystems/gui.md b/okf/subsystems/gui.md new file mode 100644 index 0000000..365e1ee --- /dev/null +++ b/okf/subsystems/gui.md @@ -0,0 +1,220 @@ +--- +type: Subsystem +title: Qt GUI +description: The desktop form — generated from the parameter catalog, rendered by ChiSurf's AutoForm, bound to a project dict. +resource: quest/gui/ +tags: [qt, gui, autoform, view-spec] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-27T00:00:00Z } +stale_after: 2027-01-27 +sources: + - id: quest-gui + resource: ../../quest/gui + title: quest/gui/ + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# What it is + +`quest/gui/` is four small files and one generated one: + +| file | what it is | +|---|---| +| `form_model.py` | `ProjectFormModel` — the state. **Qt-free.** | +| `quest.view.json` | the layout. **Generated**; never hand-edit. | +| `generate_view_spec.py` | the generator, run by hand like `doc/generate_parameter_docs.py`. | +| `dye_widget.py` | puts an AutoForm in a `QWidget`. | +| `app.py` | the standalone window and its menu bar. | +| `autoform_panel.py` | renders one RPC method's parameters from `manifest.json`. | +| `chimol_widget.py` | the 3D viewer + sequence bar, both **embedded from ChiSurf**. | +| `quencher_widget.py`, `plots.py`, `theme.py`, `guided_tour.py` | the table, the canvases, the palette, the tour. | + +Entry points: `quest gui` (CLI subcommand), the `cs.quest` gui-script, and +ChiSurf's `quenching_estimator` plugin, which puts `TransientDecayGenerator` in +a `QMainWindow` and connects its File menu to `onLoadPDB`, `onSaveProject` and +`onLoadProject`. + +# The form's state is a project — there is no conversion + +`ProjectFormModel` presents a project dict as flat attributes. `model.tau0 = 3.5` +writes `project["tau0"]`; `model.acceptor_chain = "B"` writes +`project["fret"]["dyes"][1]["attachment"]["chain"]`. :data:`FIELD_PATHS` is that +map, and the attribute names are the catalog's own paths, shortened where they +hurt (`av_parameter.` → `av_`, `fret.dyes.1.` → `acceptor_`). + +This is the whole reason the migration was worth doing. The old widget kept its +state in ~40 Qt controls and converted to a project on the way out +(`to_project_dict`) and back on the way in (`load_project_dict`) — two +hand-written directions, and **the conversion is where the GUI drifted away from +the CLI**. It once shipped an entirely different quenching chemistry. There is +now no conversion step in which to drift: what the form saves is byte-for-byte +what `quest simulate` runs and what the web UI posts. + +Two consequences worth knowing: + +- The model imports no Qt, so it is testable — and usable — headless. A + subprocess guardrail asserts that importing it pulls no Qt binding in. (It + used to be phrased as "runs in the *base* environment"; base is retired — + [workflows/environment.md](/workflows/environment.md).) +- Save/load is `save_project` / `load_project`, writing plain project JSON. + AutoForm's generic `save_state`/`load_state` also work, but the project file + is the one that means something to another surface. + +Two derived members exist so that the form does not need special cases: + +- **`structure_label`** is a read-only property returning the loaded file's + name. Without it the dock's structure display and the file picker were both + bound to `pdb`, i.e. two controls on one value — which the drift guard + `test_each_scalar_field_appears_exactly_once` fails on. +- **`auto_attach_to_structure`** runs on `load_project_dict`. The template's + default site (chain A, residue 1) frequently does not exist in the structure + just opened, which left a project that validates but cannot run. It only + overwrites an attachment that is missing or invalid, prefers `CB`/`CA`/`OG`/ + `SG`, and never selects a non-standard residue — a water could otherwise be + chosen, the same class of error as + [`lastLabelableResidue`](/subsystems/webui.md) on the web. + +# The layout is generated from the parameter catalog + +`quest/settings/parameter_catalog.json` already named every input by its project +path and carried its label, type, unit and description; `doc/parameters.md` and +the web UI were generated from it. `generate_view_spec.py` now generates the Qt +form from it too, so a parameter is described **once**: + + python -m quest.gui.generate_view_spec + +What the generator derives: one panel per catalog *category*, one field per +parameter, labels with units, descriptions as tooltips. What is authored in the +generator: the arrangement — which panels share a dock, where the 3D view and +the plots sit, what the toolbar does. Those are judgements about a form, not +facts about a parameter. + +One spec is generated per language — `quest.view.json`, +`quest.view.de.json`, `quest.view.fr.json` — and `ProjectFormModel(locale=…)` +picks the matching one ([subsystems/i18n.md](/subsystems/i18n.md)). + +`tests/test_view_spec.py` regenerates in memory and fails if any committed file +differs, and `tests/test_form_model.py` fails if the catalog documents a +parameter the form does not bind (or the reverse). A new input therefore cannot +reach the docs and the web UI while quietly missing from the desktop. + +Single-column panels throughout: the parameter dock is narrow by default and +QuEst's labels are long ("Donor diffusion coefficient (Ų/ns)"), so two columns +clipped the field being typed in. + +# QuEst owns no Qt widgets and no plotting code + +Everything the form draws is an AutoForm section type: + +- the structure picker — `value` of `kind: "file"`; +- the quencher table — an editable `table` over `quencher_rows`, writing back + through `update_quencher_cell`; +- the 3D view — the `chimol` custom section, bound to `preview_models`, backed + by `ChiMolStructureWidget`, which embeds ChiSurf's `MolView` *and* + `SequenceDock` and emits `residueSelected(chain, residue)` when either is + clicked; donor/acceptor toggle buttons say which attachment the next click + sets. The widget is a host of ChiSurf's widgets, not a re-implementation — + the mapping of what to embed is + [subsystems/chisurf-widgets.md](/subsystems/chisurf-widgets.md); +- the three plots (decay, trajectory, autocorrelation) — `plot` sections, + rendered through ChiSurf's `chiplot`. QuEst supplies only series data + (`decay_series`, `trajectory_series`, `autocorrelation_series`). + +That closed `LAY-06`, `LAY-10` and `LAY-11` in one change, and deleted: +`dye_diffusion2.ui`, `pdb_widget.ui`, `ui/av_property.ui`, `ui/dye_diffusion.ui`, +`ui/dye_diffusion3.ui`, `widgets.py` (`PDBSelector`), `dye_diffusion.json` and +`ui/rescource_rc.py` (98 kB of generated base64). The window icon survives as a +plain file, `quest/gui/icons/dye-diffusion.ico`. + +# The quencher table edits the real chemistry + +`LAY-10` was that the Qt table bound to `DonorDecay.quencher` +(`{residue: {atoms, kQ}}`), which has no per-residue contact radius and no +per-residue stickiness — so the desktop could not express what +`amino_acid_interactions` does, and ran `stickiness_mode="global"` while every +other surface ran `"amino_acid"`. The table now edits `amino_acid_interactions` +itself: kQ, contact radius, quenching atoms and slow factor, per residue. There +is no second shape left to disagree. + +A blank contact radius means **null** — "fall back to `critical_distance`" — not +zero, which would switch quenching off. Bad input in a cell is dropped rather +than raised: the user is mid-typing, and a traceback out of a cell editor is not +a useful way to say "not a number". + +# Running goes through the service layer + +The ▶ button calls `ProjectFormModel.run_simulation()`, which calls +`quest.api.simulate_project(project, save_outputs=False)` — the same entry point +the CLI and the web backend use. The form contributes no physics of its own; +that is the rule the old GUI broke. + +`save_outputs=False` keeps a GUI run from writing `jobs//` into whatever +directory the app started in. That flag used to *also* suppress the thinned +trajectory and point clouds, so the desktop silently had no plots to draw; +`render_data` is now a separate parameter (see +[simulation-pipeline](/architecture/simulation-pipeline.md)). + +**The run is a job, and the window stays alive** (since 2026-08-10). `LAY-07` +closed on 2026-07-28 by building `quest/tasks.py`, but the desktop went on +calling `simulate_project` on the GUI thread — the mechanism existed and the +surface that motivated it did not use it. Now: + +| Call | Thread | Does | +|---|---|---| +| `start_simulation()` | caller's | registers a `quest.tasks` job, spawns the worker, returns the `job_id` | +| `wait_simulation(timeout)` | caller's | joins with a timeout, so a GUI can pump events in between | +| `poll_simulation()` | **GUI thread** | applies the outcome and notifies listeners; returns the terminal status once | +| `cancel_simulation()` | caller's | asks; see the honesty note below | +| `run_simulation()` | caller's | the three above, joined — the synchronous entry point, unchanged for headless callers, still raising | + +**The worker never notifies.** A listener redraws widgets, and touching a +widget off the GUI thread is undefined; that split is the whole reason this is +several methods instead of one, and `test_the_worker_never_notifies` pins it by +recording the thread every listener fires on. + +`TransientDecayGenerator.update_all` pumps the event queue between joins, so +the window keeps painting and Cancel keeps responding, and still returns the +result. Re-entrant clicks are ignored rather than queued — pumping events means +the button can re-enter the handler that started the run. + +**What it buys, honestly.** The trajectory kernels are `njit(nogil=True)` +deliberately, so the GUI thread does get the interpreter back during the +dominant cost; the AV grid kernels are `parallel=True` without `nogil` and +still hold it, so a very large volume can still stutter. A smaller freeze, not +none. And **cancellation cannot interrupt a single simulation**: `_simulate_traj` +computes the whole trajectory inside one `njit` call and a jitted kernel cannot +poll a Python flag, so Cancel marks the job `CANCELLING`, the form stops waiting +and the result is *discarded* when the kernel returns. A scan, which checks +between sites, really does stop ([tasks.md](tasks.md)). + +One user-visible consequence: clicking ▶ on a broken project no longer raises +out of the Qt slot — the failure is reported in the status line. The exception +is still raised by `run_simulation()`, where a caller can act on it. + +# ChiSurf is required for the desktop surface, and only for it + +QuEst's Qt form is rendered by the host. Without a ChiSurf checkout there is no +form: `dye_widget.py` shows a panel saying so, because there is no second +in-tree renderer to fall back to and an empty window explains nothing. The host +is found through `quest.hosts.chisurf.enable_chisurf()`, so no caller has to set +`PYTHONPATH`. + +This does **not** weaken the optional-Qt rule. Qt lives in `quest/gui/` and +nowhere else; the domain (`quest/core/`), the service layer and the web backend +import no Qt binding — checked by a subprocess guardrail in +`tests/test_service_layer.py`. That is what lets the CLI, the API and the web +backend run in the base environment, where **PyQt5 is not installed**. + +Practical consequences: + +- The GUI cannot be launched or screenshotted from an interpreter without a Qt + binding; `arm64` — the one environment — has PyQt5 and imports quest from + this tree ([workflows/testing.md](/workflows/testing.md)). +- **Do not pass `-p no:pytest-qt`.** It was mandatory only while the retired + base environment had no binding; in `arm64` it removes the `qtbot` fixture + and breaks the widget tests. +- `quest/gui/__init__.py` resolves the Qt-bearing names lazily, so + `from quest.gui.form_model import ProjectFormModel` works with no Qt at all. +- A change that makes a `qtpy` import unconditional breaks the headless + surfaces. Do not. diff --git a/okf/subsystems/i18n.md b/okf/subsystems/i18n.md new file mode 100644 index 0000000..83636eb --- /dev/null +++ b/okf/subsystems/i18n.md @@ -0,0 +1,134 @@ +--- +type: Subsystem +title: Translations +description: English, German and French — translated once in the parameter catalog's locale files, consumed by the docs, the Qt form and the web UI. +resource: quest/i18n.py +tags: [i18n, locales, catalog, gui, webui, docs] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-27T00:00:00Z } +stale_after: 2027-01-27 +sources: + - id: quest-i18n-py + resource: ../../quest/i18n.py + title: quest/i18n.py + author: human:tpeulen + last_modified: 2026-07-27 +--- + +# Why this is small + +QuEst describes each parameter exactly once, in +`quest/settings/parameter_catalog.json`, and everything a user reads is +generated from it: `doc/parameters.md`, the web UI's labels and help badges, and +— since the AutoForm migration — the Qt form. Translating the catalog therefore +translates all three. There is no gettext, no `.po` files and no per-surface +dictionary, because there is no per-surface text. + +# Where the strings live + +`quest/settings/locales/.json`, beside the catalog they translate: + +| key | holds | +|---|---| +| `parameters` | per catalog path, a translated `label` and `description` | +| `categories` | the catalog's category names | +| `ui` | everything that is *not* a parameter: panel titles, buttons, plot axes, dialog captions, the help text, the doc-page chrome, the web chrome | + +`en.json` carries only `ui` and `categories` — the catalog itself *is* English, +so repeating it would create a second English to drift from the first. + +Fallbacks are per key, in both directions: an untranslated parameter keeps its +English text, an unknown `ui` key renders as the key. A partial translation is +useful and must never be an error. + +# Choosing a language + +`quest.i18n.resolve_locale()` prefers an explicit argument, then `QUEST_LOCALE`, +then the operating system's language, then English. The system language is read +from `LC_ALL` / `LC_MESSAGES` / `LANG` / `LANGUAGE` directly — *not* through +`locale.getdefaultlocale()`, which is removed in Python 3.15 and only read those +anyway; `locale.getlocale()` is no substitute, as it reports the current locale, +`(None, None)` until something calls `setlocale`. `LANG=C` means "no +localisation", not "a language", so it yields English. `de_DE.UTF-8` normalises to +`de`; an unknown code resolves to English rather than raising — a user with +`LANG=cs_CZ` wants QuEst to start, not to explain itself. + +**The backend does not do this.** `/api/parameter-catalog` and +`quest.parameter_catalog` default to *English*, not to the server's locale: a +shared backend must not answer differently depending on how the machine it runs +on happens to be configured. The browser asks for a language explicitly. + +# What each surface does + +**Qt form.** One generated view spec per language — `quest.view.json`, +`quest.view.de.json`, `quest.view.fr.json` — written by +`python -m quest.gui.generate_view_spec`. `ProjectFormModel(locale=…)` picks the +matching file, falling back to English if that language's spec was never +generated. `TransientDecayGenerator(locale=…)` and `QuEstWindow(locale=…)` pass +it through; with nothing passed, `QUEST_LOCALE` decides. + +**Docs.** `python doc/generate_parameter_docs.py` writes `doc/parameters.md` +plus `doc/parameters.de.md` and `doc/parameters.fr.md`, including the page +chrome (headings, table columns). + +**Web.** `/api/parameter-catalog?locale=de` returns the translated catalog and +`/api/i18n?locale=de` returns the available languages plus the `ui` strings. +The React context holds the locale, refetches both when it changes, remembers +the choice in `localStorage`, and starts from `navigator.language` when there is +a translation for it. The header has the selector. + +In English the web UI keeps its **hand-written** field labels (`t max [ns]` +rather than `Simulation time`): they are terser than the catalog's prose and +were chosen for that layout. In any other language there is no hand-written +label to prefer, so `fieldLabel()` uses the catalog's translation. + +# What is *not* translated, deliberately + +- **Units.** Å is Å in every language. A translated unit symbol would be wrong. +- **Project keys.** Descriptions name real keys (`critical_distance`, + `slow_factor`); those survive translation, and a test checks it. +- **The citation.** It is copied verbatim into a manuscript. +- **The project JSON.** A project saved in German is byte-identical to the same + project saved in English — pinned by a test. Language changes what a user + reads, never what QuEst computes. + +# Table headers get their own strings + +The quencher table uses short `table.*` keys rather than the catalog's form +labels. A column header has a column's worth of room, and *Löschrate kQ (1/ns)* +does not fit in it; the full wording stays as the tooltip, where it is readable. +This was found by rendering the German form and looking at it — the assertions +were all green. + +# Gotchas + +- **Locale files are cached per process** (`lru_cache` in `quest/i18n.py`). + Editing one while uvicorn is running has no effect until it restarts — the + same class of trap as [uvicorn not reloading](/workflows/testing.md). Tests + that write locale files call `i18n.clear_cache()`. +- **Regenerate after editing.** A locale file edit is not visible in the Qt form + or the docs until `python -m quest.gui.generate_view_spec` and + `python doc/generate_parameter_docs.py` have run. `tests/test_view_spec.py` + fails when a committed spec is stale, so this cannot be forgotten silently. + +# Adding a language + +1. Copy `quest/settings/locales/de.json`, translate `parameters`, `categories` + and `ui`, set `locale` and `name` (the name **in that language** — a picker + that says "German" is unreadable to the reader who needs it). +2. Run the two generators above. +3. `pytest tests/test_i18n.py tests/test_view_spec.py`. The completeness tests + are parametrised over whatever locale files exist, so the new language is + checked automatically: every parameter translated, no invented ones, the `ui` + key set identical to English, `{placeholders}` preserved. + +# Coverage today + +Complete: every parameter label and description, every category, the whole Qt +form, the generated docs, and the web UI's parameter labels, help badges, title, +tagline, tabs, sidebar headings and language selector. + +Still English in the browser: the plot card titles ("Decay Curve", "Quenching by +residue type"), the derived-quantity row names, the empty-state messages and the +toolbar buttons. These are hardcoded in the React components; `t()` is in the +context and wiring them is mechanical, one key at a time. diff --git a/okf/subsystems/index.md b/okf/subsystems/index.md new file mode 100644 index 0000000..bb51a27 --- /dev/null +++ b/okf/subsystems/index.md @@ -0,0 +1,14 @@ +# Subsystems + +* [Core service layer](core-api.md) - `quest/core/` and the `quest.api` facade: project loading, `simulate_project`, `DecaySimulationResult`, residue-resolved analysis, plus the `project`/`scan`/`settings` domain modules. +* [RPC service layer](rpc.md) - `quest/rpc/`: the named methods every surface shares, the result envelope, and how a host application registers them. +* [Tasks](tasks.md) - `quest/tasks.py`: the one job mechanism every surface is meant to drive - observable progress, cooperative cancellation, and why `CANCELLING` is a state of its own. +* [Accessible volume](accessible-volume.md) - AV enumeration, the IMP.bff/LabelLib backend split, and the derived slow-factor and quenching-rate grids. +* [Dye diffusion](dye-diffusion.md) - `SimulateDiffusion` and `DonorDecay`: the Brownian walk in the AV and the model object that owns a run. +* [Quenching model](quenching-model.md) - Residue-type-specific PET quenching: contact radii, quenching centres, additive rates, multiplicative stickiness, and the per-type attribution. +* [Photons & decay](photon-decay.md) - The numba photon-trace kernels and the photon/curve decay modes. +* [Structure I/O](structure-io.md) - PDB/CIF/PQR parsing, the `Structure` object, coarse-graining, and PDB-ID fetching. +* [CLI](cli.md) - `quest simulate/scan/template/validate/gui`, dotted-path overrides and grid sweeps. +* [Web UI](webui.md) - The FastAPI backend, the Next.js frontend, and the Electron shell. +* [Qt GUI](gui.md) - The legacy desktop GUI and its optional-Qt story. +* [Translations](i18n.md) - English, German and French, translated once in the catalog's locale files and consumed by the docs, the Qt form and the web UI. diff --git a/okf/subsystems/photon-decay.md b/okf/subsystems/photon-decay.md new file mode 100644 index 0000000..7921274 --- /dev/null +++ b/okf/subsystems/photon-decay.md @@ -0,0 +1,101 @@ +--- +type: Subsystem +title: Photons & decay +description: The numba photon-trace kernels and the two decay modes (photon, curve). +resource: quest/core/photon.py +tags: [monte-carlo, photons, decay, tcspc, numba] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: quest-core-photon-py + resource: ../../quest/core/photon.py + title: quest/core/photon.py + author: human:tpeulen + last_modified: 2026-07-27 +--- + +# From trajectory to decay curve + +The excited dye de-excites at rate `1/tau0 + k_quench(t)`, where `k_quench` is +read frame by frame off the trajectory. Everything in +`quest/core/photon.py` is a numba kernel over that array. + +| Function | Use | +|---|---| +| `simulate_photon_trace_rate` | The production path — a per-frame **rate** trace; used by `DonorDecay.calc_photons` | +| `simulate_photon_trace_kQ` | Boolean collision trace × a single `kQ` | +| `simulate_photon_trace` | Legacy binary-quenching variant | +| `simulate_decay_quench` | Integrates a decay histogram over `n_curves` — the "curve" mode | + +`_simulate_trace_rate` is `parallel=True`; `_simulate_trace_rate_seeded` is the +sequential, reproducible variant, chosen when the project sets a `random_seed`. +The walk starts at a random frame offset (`_photon_rate_walk`) so photons sample +the trajectory rather than always its beginning. + +# Two decay modes + +`simulate_project(mode=…)`, or `project["decay_mode"]`: + +- **`"photon"`** (default) — Monte-Carlo photon trace, histogrammed into + `n_bins` over `tac_range`. The donor quantum yield is the fluorescent fraction + of the absorbed photons. +- **`"curve"`** — legacy accumulation. `_curve_decay_from_model` integrates the + decay over `n_curves` curves at bin width `dt_tac` with `n_tac` bins; when + `dt_tac` and `n_tac` are both given and the caller did not override + `tac_range`, the range is derived as `(0, dt_tac × n_tac)`. `n_curves` also + scales the effective `n_photons`. + +Curve mode falls back to the plain histogram if the model has no usable +diffusion object — a deliberate degradation, not an error path. + +## Only emitted photons are histogrammed + +`_photon_rate_walk` returns `dt = 0.0` with its emitted flag **clear** for a +photon lost to quenching or to transfer, so `dts` and `phs` are the same length +whatever the quantum yield. `get_histogram` and `get_histogram_fret` therefore +count `dts[phs == 1]` only. Histogramming the whole trace — which both did until +2026-07-28 — piles every non-emitted photon into the first bin: a spike of +photons that were never emitted, and a curve whose total is the *excitation* +count rather than `QY × n_photons`. On the D–A channel that is the larger half +of the trace (`1 − QY_DA`), so the transfer efficiency was invisible in the +amplitude of a decay that always summed to `n_photons`. + +The curve therefore carries amplitude information: `donor_counts.sum() ≈ +QY × n_photons`, short only by the photons whose lifetime falls outside +`tac_range`. This is the same rule `simulation.py` already applied to the mean +lifetime (`dts[phs == 1]`). + +# FRET channel + +When `fret.enabled`, `DonorDecay` computes the acceptor AV and then a **rate per +trajectory frame** (`calc_fret_rate_trace`): + +``` +k_FRET(t) = (1/tau0) · ⟨ (R0 / |r_D(t) − r_A|)^6 ⟩_A +``` + +The donor is resolved in time — which is the reason its diffusion is simulated +at all — and the acceptor is averaged over its accessible volume, i.e. the +fast-acceptor limit (not valid for an immobilised acceptor). Quenching and +transfer are parallel de-excitation channels, so `calc_photons_fret` adds +`k_quench + k_fret` frame by frame and feeds the same photon kernel as the donor +channel. + +Two things this fixed, both silent before: the rate was a **single scalar** from +⟨R_DA⟩_E over the static clouds, making the FRET channel independent of the +diffusion; and a missing acceptor produced a donor-only result inside a bare +`except`. It now raises. + +`fret_efficiency` has **one** definition, `1 − QY_DA/QY_D`, taken from the two +simulated decays. `rda_mean_e()` remains available as a *diagnostic* distance — +what a FRET-efficiency measurement would report — but nothing in the simulation +consumes it. + +Both clouds hold dye *centres* and can overlap, where `(R0/r)^6` would diverge; +the distance is floored at the sum of the two dye radii, since the spheres +cannot interpenetrate. + +The kernel (`quest/core/av.py fret_rate_trace`) is general fluorescence machinery +and is slated to move into imp-tricks — +[specs/imp-tricks-dedup.md](/specs/imp-tricks-dedup.md), `DUP-03`. diff --git a/okf/subsystems/quenching-model.md b/okf/subsystems/quenching-model.md new file mode 100644 index 0000000..499e056 --- /dev/null +++ b/okf/subsystems/quenching-model.md @@ -0,0 +1,99 @@ +--- +type: Subsystem +title: Quenching model +description: Residue-type-specific PET quenching — contact radii, quenching centres, additive rates, multiplicative stickiness, and per-type attribution. +resource: quest/core/dye_diffusion.py +tags: [pet, quenching, amino-acids, physics] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: quest-core-dye-diffusion-py + resource: ../../quest/core/dye_diffusion.py + title: quest/core/dye_diffusion.py + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# Four numbers per residue type + +Quenching is resolved per residue *type*, through the +`amino_acid_interactions` table in the project (editable per dye in the web UI +under *Adv. Settings -> Amino-acid specific quenching*): + +| Field | Meaning | +| --- | --- | +| `kQ` | Quenching rate, 1/ns, applied while the dye is in contact | +| `quench_radius` | Contact radius, Å, from the **dye centre** to the residue's quenching centre; `null` inherits the project-wide `critical_distance` | +| `quench_atoms` | Atom names whose centroid defines the **quenching centre** | +| `slow_factor` | Diffusion scaling in [0, 1] — unspecific stickiness near the residue | + +Defaults live in `dye_diffusion.py` as `DEFAULT_QUENCHER_ATOMS`, +`REFERENCE_PET_QUENCHING` and `default_amino_acid_interactions()`. + +# The quenching centre is the redox-active moiety, not CB + +`DEFAULT_QUENCHER_ATOMS` puts the quencher on the group that actually mediates +electron transfer: the indole ring for TRP, the phenol ring for TYR, the +imidazole ring for HIS, SD for MET, SG for CYS. For tryptophan this moves the +centre ~3.3 Å away from CB — at contact distances of a few Å that is not a +detail. Residues with no known PET-active group fall back to a side-chain stub +so a user-supplied rate still has a well-defined centre. + +Stickiness and quenching therefore have **different centres**: stickiness stays +on the residue's slow centres, quenching sits on the moiety. `AV.calc_slow_av` +takes `quench_centers` separately from `slow_centers` for exactly this reason. + +# Contact distances are stored relative to the dye *surface* + +`REFERENCE_PET_QUENCHING` records `contact_distance` from the dye **surface** +(≈ van der Waals contact plus the offset from the moiety centroid to its outer +atoms). `default_amino_acid_interactions(dye_radius=…)` adds the dye radius to +get the centre-to-centre `quench_radius` the simulation uses. That is what makes +one reference table transferable across dyes of different size — a `kQ_scale` +handles how easily a given dye is reduced or oxidised. + +Reference ordering for a xanthene (Alexa488-like) dye: TRP > PRO ≈ TYR > MET > +HIS > CYS. + +# Composition rules + +- **Quenching rates add.** Where contact spheres overlap, the voxel's + `k_quench` is the sum of the contributing residues' rates. +- **Stickiness multiplies.** Overlapping slow centres multiply their factors, so + a dye in a crowded pocket slows down more than near a single residue. + +Both are baked into the grids in `AV.calc_slow_av` (`_additive_factor_grid` for +rates, `_slow_factor_grid` for stickiness), not recomputed per frame. + +# Attribution: who did the quenching + +`quest/core/simulation.py` walks the finished trajectory once and reports per residue type +(`aa_residence`, in `result.json` and `aa_residence.csv`): + +- residence — `frames_near`, `fraction_near`, `total_time_ns`, event count, + mean/max event duration, mean minimum distance; +- an **attributed** variant of the same statistics, where each frame is assigned + to a single residue type (`_attribute_frames_to_residue_type`) so overlapping + contacts are not double-counted; +- quenching — `mean_quench_rate`, `fraction_frames_quenched`, and + `quench_rate_fraction`, the share of the total quenching rate contributed by + that type. + +`top_quenchers(aa_residence, limit=3)` ranks by `quench_rate_fraction`; the CLI +scan and the web UI both surface the dominant quencher from it. + +Both the plain and attributed statistics exist on purpose. `frames_near` answers +"how much time did the dye spend near a TRP", counting a frame once per type; +the attributed variant answers "which residue type owned this frame", and the +attributed fractions sum to at most one. + +# Where the kernels are + +`_residue_type_contact_stats` and `_attribute_frames_to_residue_type` in +`quest/core/simulation.py` are numba kernels parallelised **over residue types**, so each +thread owns its accumulators and can still walk the trajectory sequentially — +which is what makes run-length (event) statistics possible in a parallel pass. + +See also: [references/pet-quenching-theory.md](/references/pet-quenching-theory.md), +[architecture/simulation-pipeline.md](/architecture/simulation-pipeline.md). diff --git a/okf/subsystems/rpc.md b/okf/subsystems/rpc.md new file mode 100644 index 0000000..65b7a77 --- /dev/null +++ b/okf/subsystems/rpc.md @@ -0,0 +1,96 @@ +--- +type: Subsystem +title: RPC service layer +description: quest/rpc/ — the named methods every surface shares, the result envelope, and how a host registers them. +resource: quest/rpc/services.py +tags: [rpc, service-layer, plugin, boundary] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: quest-rpc-services-py + resource: ../../quest/rpc/services.py + title: quest/rpc/services.py + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# One operation, one name + +`quest/rpc/` exposes QuEst's capabilities as named methods so the CLI, the +web backend, the GUI and a host application call the *same* operation with the +*same* result shape. It is the concrete first half of +[specs/plugin-integration.md](/specs/plugin-integration.md). + +```python +from quest.rpc import local_client + +client = local_client() +project = client.result("quest.template", {"with_fret": False})["project"] +response = client.call("quest.validate", {"project": project}) +``` + +# The envelope + +Every handler returns exactly one of: + +```python +{"ok": True, "result": } +{"ok": False, "error": ""} +``` + +Callers tell success from failure by `ok`, never by sniffing for a field. +`InProcessClient.call` returns the envelope; `.result` unwraps it and raises +`RemoteError` on failure. A handler that raises anyway is converted by +`ServiceDispatcher.dispatch`, so a caller never has to handle both styles. + +# The methods + +| Method | Returns | +|---|---| +| `quest.template` | `{"project": …}` — a minimal valid project | +| `quest.validate` | `{"valid": True, "project": …}`, or a failure naming what is wrong | +| `quest.simulate` | The full result payload (see below) | +| `quest.scan` | `{"results": {name: record}}` — one record per labeling site | +| `quest.parameter_catalog` | The shipped catalog | +| `quest.dyes.list` / `quest.dyes.save` | The dye presets | +| `quest.quenching_defaults` | Residue-type PET chemistry | +| `quest.structure.metadata` | Chains, residues and atoms of a structure file | +| `quest.jobs.list` / `quest.jobs.get` | Past runs: summaries, and one run's result | + +`METHODS` in `services.py` is the table with one-line summaries — the same table +a manifest declares. `tests/test_service_layer.py` asserts the registry matches +it. + +All eleven are registered, and the manifest declares the same eleven — the +surface is complete as of 2026-07-27. + +# `result_payload` is the boundary shape + +`result_payload(result)` converts a `DecaySimulationResult` to plain data — +arrays to lists, absent channels to `None`. Both `quest.simulate` and +`POST /api/simulate` return it, so there is one definition of what a simulation +result *is* on the wire. Add a field there, not in a route. + +# Registering with a host + +`register_services(dispatcher)` needs nothing but `register(name, handler)`, so +a host application's dispatcher works unchanged and QuEst never imports the +host: + +```python +from quest.rpc import register_services +register_services(host_dispatcher) # ChiSurf's ServiceDispatcher, say +``` + +Registering a name twice raises. That is deliberate: a silent overwrite would +make which implementation runs depend on import order. + +# Rules this layer keeps + +- Nothing here computes. A handler that grows logic means that logic belongs in + the domain, where the CLI and notebooks can reach it too. +- No Qt, no FastAPI, no host imports — pinned by a guardrail test. +- Long-running work (`quest.simulate`, `quest.scan`) is currently **blocking**; + a caller that needs progress or cancellation drives `quest.scan.scan_positions` + itself. Making that uniform is `LAY-07`. diff --git a/okf/subsystems/structure-io.md b/okf/subsystems/structure-io.md new file mode 100644 index 0000000..5b77fe9 --- /dev/null +++ b/okf/subsystems/structure-io.md @@ -0,0 +1,142 @@ +--- +type: Subsystem +title: Structure I/O +description: PDB/CIF/PQR parsing, the Structure object, coarse-graining, and PDB-ID fetching. +resource: quest/core/structure/ +tags: [pdb, cif, structure, io, rcsb] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-02-06 +sources: + - id: quest-core-structure + resource: ../../quest/core/structure/ + title: quest/core/structure/ + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# Four concerns, one package + +`quest/core/structure/` states its own layout, and the order is the direction of +travel: a caller says *what* it wants labelled, never *how to read it*. + +| Module | Owns | +|---|---| +| `fetch.py` | Where a structure comes from: a path, a PDB ID, bytes | +| `reader.py` | Turning that into QuEst's atom array -- **IMP does the parsing** | +| `model.py` | The `Structure` object and coarse-graining | +| `metadata.py` | What is in it: chains, residues, atoms, for a site picker | + +# Parsing: IMP is the parser + +`read(filename)` returns a NumPy structured array with the fields in +`reader.keys`. **QuEst no longer carries its own PDB or mmCIF parser** -- +`IMP.atom.read_pdb` / `read_mmcif` do it, and `read` raises `ImportError` +without IMP, which the accessible-volume stage needs anyway. The public surface +is small: `read`, `keys`, `formats`, plus `write` and `sequence`. + +The old hand-rolled entry points (`parse_string_pdb`, `parse_string_pqr`, +`parse_string_cif`, `assign_element_to_atom_name`) are **gone**; so is the +elements table they fed. + +**What counts as an obstacle changed with them, and it was measured rather than +assumed.** No selector is passed, so IMP's default applies: everything except +waters and hydrogens. Ligands, cofactors and modified residues are steric +obstacles because they physically are -- a dye cannot diffuse through a bound +sugar. QuEst used to strip every HETATM, which on 148L discarded 41 atoms +(1322 against 1363). Waters are deliberately *not* obstacles: adding them costs +**17 % of every accessible volume** on the 148l chain-E sites, and +crystallographic solvent is mobile on the timescale a tethered dye explores. +Full measurement: [specs/structure-io.md](/specs/structure-io.md). + +As a defensive guarantee added 2026-08-07, `_strip_waters` runs after the IMP +parse and removes every atom whose residue name identifies it as water (`HOH`, +`WAT`, `TIP3`, `SOL`, … — see `_WATER_RESIDUE_NAMES`). IMP's selector already +drops waters, but the explicit filter keeps QuEst correct regardless of which +selector a caller or a future parser passes. `tests/test_water_stripping.py` +covers it. + +**One residue table, three points of use**, because a water reaching *any* +surface is the same defect: + +| Where | What it does | +|---|---| +| `_strip_waters(atoms)` | filters the array after the IMP parse — the simulation path | +| `strip_water_pdb_text(text)` | filters raw PDB text by columns 18–20 — for anything that consumes text | +| `water_stripped_pdb_path(src)` | writes a cleaned copy to a temp file, reused per source — for a viewer that insists on a *file* | + +`structure_metadata` runs PDB text through `strip_water_pdb_text` and skips +water rows while parsing CIF, so the `pdb_text` it returns to the browser +viewer carries none either, and no site picker can offer a water as a labeling +site. The ChiMol 3D viewer loads with `keep_water=True`, which is why stripping +at the text level — rather than trusting the viewer's own selector — is the +thing that actually holds. Baselines moved with it: 148L `atom_count` +1525 → 1385, chain E residues 291 → 164. + +Residue names coming out of the structured array are byte-string valued and need +normalising before comparison -- hence `_normalize_residue_name` in both +`quest/core/simulation.py` and `quest/core/dye_diffusion.py` (it also unwraps +the `b'ALA'` repr that leaks through some paths). + +# `Structure` + +`model.py`'s `Structure` is now a **thin accessor over the atom array**, not the +geometry toolkit this concept used to describe. It exposes `xyz`, `vdw`, +`b_factors`, `atom_types`, `residue_names`, `residue_ids`, `residue_indices`, +`residue_dict`, `n_atoms`, `n_residues`, `radius_gyration`, and `to_coarse`; +module-level helpers add `move_center_of_mass`, `make_residue_lookup_table` and +`get_residue_sequence`. + +**The alignment and clustering methods are gone** -- `rmsd`, `super_impose`, +`average`, `find_best`, `find_representative`, `cluster`, `onRMSF`, +`calc_internal_coordinates`, `_internal_to_cartesian`. QuEst does not align or +cluster structures; that machinery belonged to the general-purpose library this +package replaced, and keeping a second copy of it is exactly what +[specs/imp-tricks-dedup.md](/specs/imp-tricks-dedup.md) argues against. + +`Structure(path, make_coarse=True)` still builds the coarse-grained +representation behind the project's `coarse_grained` flag +([dye-diffusion.md](dye-diffusion.md)); `tests/test_coarse_grained.py` covers it. + +# Structure sources: path or PDB ID + +`quest/core/structure/fetch.py` lets every surface accept a bare four-character RCSB +identifier wherever a file path is accepted: + +- `is_pdb_id(value)` — a 4-character alphanumeric string; +- `download_pdb_id(id, cache_dir=None)` — tries `.pdb` then `.cif` from + `files.rcsb.org`, caching under `QUEST_PDB_CACHE_DIR` (default: a + `quest-pdb-cache` folder in the system temp dir), and returns the cached path + if it already exists; +- `resolve_structure_path(source)` — the one call every surface uses. + +A 404 on `.pdb` falls through to `.cif` (large/modern entries have no PDB file); +other HTTP or network errors raise. `tests/test_pdb_id_support.py` covers this. + +Anything that takes a structure should call `resolve_structure_path`, not +`Path(...)` — that is how PDB-ID support stays uniform across CLI, API and web. + +# A path quirk that is gone — do not reintroduce it + +This section used to describe `quest/__init__.py` calling +`utils.set_search_paths()`, which inserted `quest/` itself onto +`sys.path` so that `import lib.fps` resolved. **Both are gone**: the injection +with `LAY-08` (2026-07-27), and `quest/utils.py` itself on 2026-07-28 — nothing +imported it, and the rest of it was Python-2.6 `unittest` monkey-patching plus a +`sitecustomize` coverage hook that wrote `.coverage.*` files into the working +directory. + +The rule it leaves behind outlived the package it was written about: every +internal import is spelled `quest.…`, absolutely. A bare `import lib…` was not a +legacy spelling to tolerate but a bug -- `lib.structure.Structure` and +`quest.lib.structure.Structure` were two different classes, so an `isinstance` +check across the boundary failed and a `Structure` got wrapped twice. `quest/lib` +itself is gone; the rule is why the replacement is a package under +`quest/core/`. + +Re-read against the tree on 2026-08-10, mechanically: every name above was +resolved with `hasattr`, and every name this concept claims is *gone* was +checked to be actually absent — a removal claim rots the same way a presence +claim does. `tests/test_coarse_grained.py` and `tests/test_pdb_id_support.py` +both exist. The only sentence that needed changing was the water paragraph, +which described one filter where there are now three. diff --git a/okf/subsystems/tasks.md b/okf/subsystems/tasks.md new file mode 100644 index 0000000..0e445d4 --- /dev/null +++ b/okf/subsystems/tasks.md @@ -0,0 +1,102 @@ +--- +type: Subsystem +title: Tasks +description: The one job mechanism every surface drives -- observable progress, cooperative cancellation, and a status vocabulary shaped to match the host. +resource: quest/tasks.py +tags: [jobs, cancellation, progress, threading, chisurf] +status: stable +generated: { by: claude-code/opus-5, at: 2026-08-06T09:10:00Z } +stale_after: 2027-02-06 +sources: + - id: quest-tasks-py + resource: ../../quest/tasks.py + title: quest/tasks.py + author: human:tpeulen + last_modified: 2026-07-28 + - id: quest-rpc-services + resource: ../../quest/rpc/services.py + title: quest/rpc/services.py -- the only caller today + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# Why it exists + +`LAY-07` recorded three unrelated ways of running long work -- a thread pool in +the web backend, a blocking call in the CLI, a `QProgressDialog` in the GUI -- +none of which could be observed or stopped from outside. `quest/tasks.py` is the +one they are meant to drive. + +It **mirrors ChiSurf's job contract without importing it**: the status +vocabulary, `progress`, the cooperative `should_cancel` and the `to_dict()` +shape match `chisurf/server/jobs.py` deliberately, so the host recognises what +QuEst reports -- but a plugin that needs its host in order to run standalone is +not a plugin. + +# The vocabulary + +``` +queued ──start──> running ──finish──> completed + │ │ └─fail──> failed + │ cancel + │ ↓ + └──cancel──> cancelling ──worker notices──> cancelled +``` + +`CANCELLING` is a distinct state from `CANCELLED` on purpose. Setting the flag +*asks*; the worker notices at its next checkpoint, and until then it may still +be touching shared state. A cancel button that implies more than it delivers is +worse than none. + +`JobStatus.is_terminal` is `completed | failed | cancelled` -- the states after +which nothing more may be written. + +# Cancellation is cooperative, and one simulation is nearly atomic + +A **scan** checks between sites, so it stops within one site. A single +`simulate` has essentially one checkpoint: `_simulate_traj` computes the whole +trajectory in a single `njit` call, and a jitted kernel cannot poll a Python +flag. Cancelling therefore means *"do not start the next stage"*, not *"stop +now"*. That limitation is stated rather than hidden. + +Two consequences worth knowing: + +- A job cancelled while still `QUEUED` goes straight to `CANCELLED` -- there is + no worker to notice anything. +- A worker that returns *after* observing cancellation is recorded as + `CANCELLED`, not `COMPLETED`, and its partial result is dropped. + +# The domain never learns about jobs + +`JobManager.canceller(job_id)` returns a zero-argument predicate and +`reporter(job_id)` returns a `(percent, message)` callback. The domain takes +those **callables**, not a `Job` or the manager, which is what keeps +[`quest/core/`](core-api.md) free of job bookkeeping and lets a caller with its +own cancellation source -- a host, a Qt dialog -- pass its own. + +This is the same rule as [surfaces.md](../architecture/surfaces.md), one level +down: bookkeeping lives at the edge, the domain stays plain. + +# `to_dict()` carries no result + +Deliberately JSON-only. `result` may be a `DecaySimulationResult` full of numpy, +and the dict crosses a transport; a caller fetches the result through the method +that produced it, where `to_payload` applies. + +# State, threading, history + +`JobManager` guards everything with an `RLock` and keeps insertion order so +`list()` can return newest-first, like every other listing in the codebase. +`_trim()` drops the oldest **terminal** jobs beyond `max_history` (default 100); +running jobs are never trimmed. `default_manager()` is a lazily-created +process-wide singleton the surfaces share -- a host may use its own. + +# Adoption is not finished + +`quest/rpc/services.py` is the only caller today. The web backend still uses its +own `ThreadPoolExecutor` ([webui.md](webui.md)), so cancellation and progress +stop at the RPC surface. Finishing that is also what the shared-server work with +FPSIMP needs -- this vocabulary is the strongest candidate for the common job +model, since FPSIMP's states carry no cancellation concept at all +([FPSIMP combined-stack](../../../fpsimp/okf/architecture/combined-stack.md), +OPEN-3). diff --git a/okf/subsystems/webui.md b/okf/subsystems/webui.md new file mode 100644 index 0000000..119f72c --- /dev/null +++ b/okf/subsystems/webui.md @@ -0,0 +1,263 @@ +--- +type: Subsystem +title: Web UI +description: The FastAPI backend, the Next.js frontend, and the Electron shell. +resource: webui/backend/app/main.py +tags: [fastapi, nextjs, electron, webui] +status: stable +generated: { by: process:okf-v0.1-import, at: 2026-07-26T00:00:00Z } +stale_after: 2027-01-26 +sources: + - id: webui-backend-app-main-py + resource: ../../webui/backend/app/main.py + title: webui/backend/app/main.py + author: human:tpeulen + last_modified: 2026-07-28 +--- + +# Three pieces + +| Piece | Path | Run | +|---|---|---| +| Backend | `webui/backend/app/main.py` | `python -m uvicorn webui.backend.app.main:app --port 8000` (needs `pip install -e ".[web]"`) | +| Frontend | `webui/frontend` (Next.js 16, React 19, Node ≥ 20.9) | `pixi run -e frontend dev` | +| Desktop | `webui/desktop` (Electron) | `npm --prefix webui/desktop run start` | + +The frontend needs Node ≥ 20.9; the pinned toolchain lives in the pixi +`frontend` environment so nothing has to be installed system-wide +([workflows/environment.md](/workflows/environment.md)). + +The Electron shell spawns the backend and the frontend's standalone server and +points a `BrowserWindow` at it; `QUEST_PYTHON` overrides the interpreter and +`webui/desktop/scripts/prepare-python-env.mjs` prepares a bundled one for +packaged builds. + +# Backend API + +``` +GET /health +GET /api/parameter-catalog # quest/settings/parameter_catalog.json +GET /api/autoform-spec # build_view_spec(locale) — the form the UI renders +GET /api/tour # quest.tour: the guided-tour steps +GET /api/demo-project # quest.tour: the 148L demo project +GET /api/i18n # locales_handler +GET /api/dyes # dye presets; POST /api/dyes appends one +GET /api/quenching-defaults # REFERENCE_PET_QUENCHING + DEFAULT_QUENCHER_ATOMS +GET /api/template +POST /api/validate +POST /api/structure/metadata # chains/residues parsed from an uploaded structure +POST /api/simulate +POST /api/scan +GET /api/jobs, /api/jobs/{id}, /api/jobs/{id}/download +``` + +**The backend goes through `quest.api`, not through the CLI.** It once imported +`quest.cli`'s private `_template_project` / `_validate_project` at four call +sites (`LAY-01`); since phase 8 it calls the facade and maps `error_code` onto +an HTTP status, so "a valid project" has one definition and the web is not +coupled to a terminal surface ([subsystems/core-api.md](/subsystems/core-api.md)). +`to_payload` is applied here because the transport is the boundary that +serialises — the same rule the [ZMQ server](/subsystems/rpc.md) follows. + +# Things that are easy to get wrong + +- **`SCAN_WORKERS` is small on purpose** — `max(1, min(4, cpus-1))`. LabelLib's + AV kernel holds the GIL, so extra workers add contention, not throughput. The + pool exists to keep the simulation off the event loop so the server stays + responsive and notices client disconnects during a long scan. +- **State lives on disk, not in the process.** Uploads and job directories go + under `QUEST_WEBUI_DATA_DIR` (default: a `quest-webui` folder in the system + temp dir). The server is restartable and holds no session state. +- **CORS origins** come from `QUEST_WEBUI_CORS_ORIGINS` (default: localhost + :3000/:3001). The frontend targets `QUEST_BACKEND_URL`. +- **Dye defaults are filled in server-side** (`_with_dye_stickiness_defaults`, + `_with_dye_library_defaults`) so a project posted from the browser is complete + before it reaches `quest.api`. + +# Frontend + +App-router pages: `/` , `/simulation`, `/labeling`, `/scan`, `/advanced`, with +shared state in `context/AppContext.tsx`. + +## The sidebar form is generated, not written (since 2026-08-09) + +`AppLayout` fetches `/api/autoform-spec?locale=…` and renders it through +`components/autoform/` (`AutoForm` → `AutoPanel` → `AutoSection` → +`AutoValue`/`AutoChoice`/`AutoToggle`). **No form is hand-written on this +surface any more**; the ~540-line legacy React block and its AutoForm/legacy +toggle are gone, and the only remaining switch is the JSON overlay +(`showJson`). The desktop renders the *same* spec through ChiSurf's AutoForm, +so a parameter added to the catalog reaches both +([specs/autoform-scheme.md](/specs/autoform-scheme.md)). + +Two consequences worth knowing before editing anything here: + +- **`lib/autoformPaths.ts` is load-bearing.** A spec `attr` is the flat + `ProjectFormModel` attribute (`attachment_chain`, `fret_enabled`, `fret_R0`), + not the nested project path (`attachment.chain`, `fret.enabled`, + `fret.R0_matrix[0][1]`). `AutoSection` resolves every `attr` through + `attrToPath` before reading or writing; without it the form silently produces + projects the backend rejects. `tests/test_autoform_blueprint.py` fails if the + catalog grows a parameter the map does not cover. +- **Two fields do not go through `setNested`.** `fret.enabled` routes through + `setFretEnabled` (which seeds the acceptor dye and the R0 matrix — a bare + toggle leaves a one-dye project) and `fret.R0_matrix.0.1` through + `setForsterRadius`, because a list cell is not a path `setNested` can index. + +The scan residue picker and the Calculate Scan button live in a **Scan +Settings** card on `app/scan/page.tsx` — they were in the deleted sidebar +block. `app/advanced/page.tsx` still uses the hand-written `Field.tsx` + +`HelpBadge.tsx` (labels and help from `lib/parameterCatalog.ts`) and +`QuenchingEditor.tsx`, the per-residue interaction table; those are the pieces +the view spec does not describe. + +## Click-to-select a labeling site + +`ProteinViewer.tsx` (NGL, vendored at `public/vendor/ngl.js` — no CDN) wires +NGL's picking proxy on `stage.signals.clicked` to the same `onResidueSelect` +callback the sequence bar uses, so clicking a residue in the 3D view sets the +attachment. The desktop has the same gesture through ChiSurf's `SequenceDock` +and `MolView` ([subsystems/chisurf-widgets.md](/subsystems/chisurf-widgets.md)); +a feature that reaches only one of the two surfaces is a bug, which is why they +land together. + +> **NGL is scheduled to be replaced by chimol here.** The two surfaces draw the +> same structure with two different engines — ChiSurf's chimol on the desktop, +> NGL in the browser — which is the same two-implementations shape the AutoForm +> migration removed from the forms. ChiSurf's `chimol → WebGPU` work exists to +> close it: one WGSL source, a desktop driver and a browser driver, so the web +> viewer becomes the *same* renderer rather than a lookalike. +> **Not yet actionable.** Upstream's desktop port is *done* — chimol draws with +> WGSL and the OpenGL renderer is deleted (`76df2fcfd`) — but its own handover +> says the browser half "has not been started". The status lives on ChiSurf's +> agent board (`~/dev/chisurf/okf/agent-board.md`) and in +> `~/dev/chisurf/okf/plugins/chimol-web.md` — check those, not this file, for +> whether it has landed. +> +> **What the swap will need from a browser driver**, i.e. what NGL does here +> today, so the first consumer's requirements are known before the driver is +> designed: load a structure from a string/blob (`loadFile`); three +> representations — `cartoon`, `licorice`, `surface` — added and removed per +> project change; a selection language, applied through +> `projectHelpers.selectionString`; `autoView` framing; a resize hook; and +> **atom picking**, which is what `stage.signals.clicked` feeds into +> `onResidueSelect`. Picking is the one that matters most and is the one +> upstream lists as still GL-only on the desktop side. + +## Guided tour (`components/tour/`) + +`Tour.tsx` is a **dependency-free, quest-agnostic onboarding overlay** — it +imports nothing from quest, knows no i18n, and takes `steps` + `labels` as +props. It is meant to be copy-pasted into FPSIMP unchanged (same React tree, no +React DOM). QuEst's shape lives in `tourSteps.ts`: `getTourSteps(t, navigate)` +returns `{ target, title, body, before }[]` spotting `[data-tour="…"]` hooks, +`getTourLabels(t)` builds the control labels, and both pull every string through +`t()` so the translation ratchet stays flat. + +How it works: opening locks `body` scroll; each step `scrollIntoView`s the +target, measures it with `getBoundingClientRect`, and draws a transparent +**spotlight** whose huge `box-shadow` (`0 0 0 9999px rgba(…,0.6)`) dims +everything but the target — the one-element cutout, no four-pane mask. The +tooltip card sits below (or above) the box, clamped into the viewport, and is +repositioned on resize/scroll. Keys: `Esc`/click-elsewhere close, `←→` step, +`Enter` advances. Labels (`next`, `prev`, `done`, `close`, +`stepIndicator(c,t)` are passed in already-translated. Spotlight targets live +on `data-tour` attributes, so steps are stable under refactors. The button that +opens it is **`data-testid="guide-btn"`** (it was `tour-btn` until 2026-08-08, +when the control was renamed "Guide" to match ChiSurf's chrome; `.tour-btn` is +still the CSS class on the tour's own next/prev buttons, which is a trap when +grepping). The step copy is the `web.tour.*` keys in all three locales. + +Since 2026-08-07 the tour is **exhaustive and cross-page** (24 steps, all three +locales). A step may carry a `before` hook that routes the app first (e.g. +`() => navigate("/simulation")`) — that is how the sidebar panels, which switch +with the active tab, get their own steps. Two consequences: + +- **Target measurement retries.** After `before` runs, the effect polls the + selector for ~3.5 s (`14 × 250 ms`) before falling back to a centred card, so + a target that only mounts after navigation (or a data round-trip) is caught. + `AppLayout` passes `navigate` as a guarded `router.push` that is a no-op when + already on that path (the step effect re-runs on `steps` identity changes). +- **`data-tour` hooks on every surface** — the topbar (language, theme, cite, + preset), the toolbar (PDB form, upload, download, tabs), the sidebar (runs, + JSON toggle, structure, labeling, FRET, AV, simulation-settings, + scan-settings, stickiness) and each page (labeling viewer, simulation + results, scan results, the two advanced cards). The first step is a centred + welcome card that routes to `/labeling` so the walk is identical whichever + page starts it; the last is a centred closing card. `TestTour` walks through + the `before` navigation and pins the titles via the browser suite. + +# Design language + +The visual layer lives entirely in `webui/frontend/src/app/globals.css` — no +inline styles, no per-component styling — so the look is changed by editing the +stylesheet and *nothing else*. Class names, ids and visible text are contract: +the browser suite pins them (`tests/test_webui_e2e.py`). + +## The CSS refresh + +A 2026-08-07 refresh made it denser and slightly more modern without touching +the DOM: + +- **Tokens** (`:root` + the three theme blocks): layered shadows + (`--shadow`, `--shadow-lift`), a shared focus ring `--focus` applied + `:focus-visible` on buttons/inputs/selects/links, a system font stack + `--font-ui`, and an accent-tinted hover wash `--accent-ink`. **Accent moved + from flat teal (`#00706b`) to a modern indigo (`#4f46e5` light / + `#818cf8` dark) with amber `--accent-2`; neutrals went from warm gray to cool + slate (`#f5f6fa` bg, `--ink #0f172a`).** +- **Density** (measured at 1440×900): app-shell padding 12→8 px, topbar + brand 38→30 px and title 22→18 px, control sidebar 320→296 px, panel + sections 7/9→5/8 px, uppercase section headings 12→10.5 px with + letter-spacing, tab buttons 4→3 px vertical, workflow/card chrome 8→6 px. + Body `scrollWidth == innerWidth` (1440) on all four tabs — no horizontal + overflow — and the panel-overflow guard stays green. +- **Primary action** gets a subtle vertical accent gradient + lift instead of + the flat fill; active tabs and cards use the shared shadow token. +- **Theme switch** — a sun/moon button in the topbar (`data-testid="theme-toggle"`) + flips `data-theme` on `` between `light` and `dark` and persists the + choice in `localStorage["quest-theme"]`. Default is **dark**; a saved choice + always wins over the OS `prefers-color-scheme` (the `:root[data-theme=…]` + blocks come after the media query, so they win). Label via the `web.theme_toggle` + key in all three locales. The `@media (prefers-color-scheme: dark)` rules that + flip `button.primary`'s label colour have `:root[data-theme=…]` twins so the + toggle path is styled too. + +**FRET is a sidebar section of the generated form, not a page panel.** It was +a hand-written panel on the labeling page until 2026-08-09; that page is now +just the `ProteinViewer`. Enabling FRET still seeds the acceptor on the *last +labelable* residue of the current chain — `lastLabelableResidue` skips the +waters and ions structures end with, which a dye cannot be tethered to — so +switching it on yields a project that validates. That seeding is why the +`fret.enabled` field is routed through `setFretEnabled` rather than written +straight into the project. + +# Tests + +`webui/backend/tests/test_backend_api.py` covers the API directly. +`tests/test_webui_e2e.py` drives a real browser and **skips unless both servers +are already running** — see [workflows/testing.md](/workflows/testing.md). + +Since the form became generated, the browser suite locates fields *by label* +through `_autoform_field` / `_autoform_input` / `_autoform_check` rather than by +the ids the hand-written inputs used to carry; `_use_legacy_form` is gone. Two +mechanical traps live here: `_server_is_up` waits **10 s** because a cold +Next.js dev server takes >3 s and a shorter timeout silently skipped the whole +suite, and a styled toggle's real checkbox is `display:none`, so a `.click()` on +the visible slider times out intermittently — drive it with `.check()` or +`evaluate()`. + +Two of its guards exist because a panel defect had no signal anywhere else: + +- **`TestLayoutAndAccessibility::test_no_inner_container_overflows_its_box`** + parametrises over all four tabs and fails if any element wider than its box + has `overflow-x: visible`. The page-level check missed this class: the + advanced card clips with `overflow: hidden`, so the document never scrolled + while the quenching table was cut off at the card's 560 px body. Fixed by + `min-width: 0` on `.quench-editor`, which lets the `quench-table-wrap` scroll + container govern its own width instead of the grid item forcing it wide. +- **`test_the_header_selects_have_accessible_names`** pins an `aria-label` on + the dye and run pickers, which are bare ` setPdbId(event.target.value)} +409: placeholder="PDB ID" +410: aria-label="PDB ID" +411: maxLength={4} +412: /> +413: +414: +415: +416: +419: +422:
+423: +424: +425:
+426:
+696: +697:
+698:

Accessible volume

+699: updateProject("av_parameter.linker_length", value)} +703: parameterId="av_parameter.linker_length" +704: catalog={catalog} +705: onSave={() => saveParameter("av_parameter.linker_length")} +706: isDirty={ +707: n(project.av_parameter?.linker_length, 21.5) !== +708: n(savedProject.av_parameter?.linker_length, 21.5) +709: } +710: /> + +(Showing lines 693-710 of 1075. Use offset=711 to continue.) + +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 4.6s) + +Now let me make all the edits. First, add `useRouter` and wire navigation: + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "oldString": "import { usePathname } from \"next/navigation\";", + "newString": "import { usePathname, useRouter } from \"next/navigation\";" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 5.0s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": " {\n if (window.location.pathname !== path) router.push(path);\n })}\n labels={getTourLabels(t)}\n onClose={() => setTourOpen(false)}\n />", + "oldString": " setTourOpen(false)}\n />" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 4.7s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": " const [tourOpen, setTourOpen] = React.useState(false);\n const router = useRouter();", + "oldString": " const [tourOpen, setTourOpen] = React.useState(false);" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 5.0s) + +Now the topbar and toolbar `data-tour` hooks: + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": "
\n {t(\"web.language\", \"Language\")}:", + "oldString": "
\n {t(\"web.language\", \"Language\")}:" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 5.3s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": " setTheme(theme === \"dark\" ? \"light\" : \"dark\")}\n aria-label={t(\"web.theme_toggle\", \"Toggle light/dark mode\")}\n title={t(\"web.theme_toggle\", \"Toggle light/dark mode\")}\n data-testid=\"theme-toggle\"\n data-tour=\"theme\"\n >", + "oldString": " setTheme(theme === \"dark\" ? \"light\" : \"dark\")}\n aria-label={t(\"web.theme_toggle\", \"Toggle light/dark mode\")}\n title={t(\"web.theme_toggle\", \"Toggle light/dark mode\")}\n data-testid=\"theme-toggle\"\n >" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 4.1s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": " \n 💾 Disk Preset\n ", + "oldString": " \n 💾 Disk Preset\n " +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 6.6s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": " setShowCitationModal(true)}\n className=\"cite-btn\"\n title=\"Show citation details\"\n data-tour=\"cite\"\n >", + "oldString": " setShowCitationModal(true)}\n className=\"cite-btn\"\n title=\"Show citation details\"\n >" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 3.2s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": " {\n event.preventDefault();\n void loadPdbId(pdbId);\n }}\n data-tour=\"pdb\"\n >", + "oldString": " {\n event.preventDefault();\n void loadPdbId(pdbId);\n }}\n >" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 3.4s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": "\n ", + "oldString": "\n " +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 3.0s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": "
\n

Configuration

", + "oldString": "
\n

Configuration

" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 4.8s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": " ", + "oldString": " " +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 4.3s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": "
", + "oldString": "
" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 4.6s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": "
\n

Accessible volume

", + "oldString": "
\n

Accessible volume

" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 4.7s) + +_Thinking:_ + +Now the page-level hooks. Let me check labeling/page.tsx viewer card, simulation page root, scan page root, advanced page quench-editor. + +Now page-level hooks. Let me find the viewer card in the labeling page and the advanced config card: + +**Tool: bash** + +**Input:** +```json +{ + "command": "cd /Users/tpeulen/dev/quest/webui/frontend && grep -n \"viewer-card\\|class=\\\"result-card\\|advanced-settings-card\\|sim-page\\|results-section\" src/app/labeling/page.tsx src/app/advanced/page.tsx | head" +} +``` + +**Output:** +``` +src/app/labeling/page.tsx:11:
+src/app/advanced/page.tsx:33:
+src/app/advanced/page.tsx:42:
+src/app/advanced/page.tsx:85:
+src/app/advanced/page.tsx:110:
+ +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 4.1s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/app/labeling/page.tsx", + "newString": "
", + "oldString": "
" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 5.3s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/app/simulation/page.tsx", + "newString": "
", + "oldString": "
" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 3.8s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/app/scan/page.tsx", + "newString": "
", + "oldString": "
" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 6.5s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/app/advanced/page.tsx", + "newString": "
", + "oldString": "
" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 4.1s) + +_Thinking:_ + +Now let me also add a "simulation settings" hook. The simulation settings panel in AppLayout's sidebar for the /simulation tab. Let me find it. + +**Tool: bash** + +**Input:** +```json +{ + "command": "cd /Users/tpeulen/dev/quest/webui/frontend && grep -n \"currentTab === \\\"/simulation\\\"\\|currentTab === \\\"/scan\\\"\\|currentTab === \\\"/advanced\\\"\" src/components/AppLayout.tsx" +} +``` + +**Output:** +``` +385: className={`tab-btn ${currentTab === "/simulation" ? "active" : ""}`} +391: className={`tab-btn ${currentTab === "/scan" ? "active" : ""}`} +397: className={`tab-btn ${currentTab === "/advanced" ? "active" : ""}`} +753: {currentTab === "/simulation" && ( +828: {currentTab === "/scan" && ( +973: {currentTab === "/advanced" && ( + +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 4.5s) + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "limit": 12, + "offset": 753 +} +``` + +**Output:** +``` +/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx +file + +753: {currentTab === "/simulation" && ( +754: <> +755:
+756:

{t("web.card.settings", "Simulation Settings")}

+757: updateProject("tau0", value)} +761: parameterId="tau0" +762: catalog={catalog} +763: onSave={() => saveParameter("tau0")} +764: isDirty={n(project.tau0, 4.2) !== n(savedProject.tau0, 4.2)} + +(Showing lines 753-764 of 1083. Use offset=765 to continue.) + +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 6.3s) + +**Tool: edit** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "newString": "
\n

{t(\"web.card.settings\", \"Simulation Settings\")}

", + "oldString": "
\n

{t(\"web.card.settings\", \"Simulation Settings\")}

" +} +``` + +**Output:** +``` +Edit applied successfully. +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 7.2s) + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "limit": 10, + "offset": 829 +} +``` + +**Output:** +``` +/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx +file + +829: <> +830:
+831:

Structure

+832:
+833: {structure?.filename || "No structure loaded"} +834: +835: {structure +836: ? `${structure.chains.length} chains, ${structure.atom_count} atoms` +837: : "Upload a structure file to start."} +838: + +(Showing lines 829-838 of 1083. Use offset=839 to continue.) + +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 7.1s) + +_Thinking:_ + +The scan tab sidebar section is just "Structure". Let me find "Scan residues" or similar in the scan section, plus the stickiness in advanced. Let me look around line 973 for advanced. + +**Tool: bash** + +**Input:** +```json +{ + "command": "cd /Users/tpeulen/dev/quest/webui/frontend && grep -n \"Scan residues\\|stickiness\\|Stickiness\\|Scan\\|Calculate Scan\" src/components/AppLayout.tsx | head" +} +``` + +**Output:** +``` +50: setScanAll, +51: selectedScanResidues, +52: setSelectedScanResidues, +55: isScanning, +70: runScan, +71: abortScan, +393: {t("web.tab.scan", "3 - Scan")} +843:

{t("web.card.scan_settings", "Scan Settings")}

+848: onChange={(e) => setScanAll(e.target.checked)} +851: Scan all residues ({allResidues.length}) + +``` + +--- + +## Assistant (Build · DeepSeek V4 Flash Free · 6.2s) + +**Tool: read** + +**Input:** +```json +{ + "filePath": "/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx", + "limit": 5, + "offset": 841 +} +``` + +**Output:** +``` +/Users/tpeulen/dev/quest/webui/frontend/src/components/AppLayout.tsx +file + +841: +842:
+843:

{t("web.card.scan_settings", "Scan Settings")}

+844:
+ ); +} diff --git a/webui/frontend/src/app/favicon.ico b/webui/frontend/src/app/favicon.ico new file mode 100644 index 0000000..59d6bf8 Binary files /dev/null and b/webui/frontend/src/app/favicon.ico differ diff --git a/webui/frontend/src/app/globals.css b/webui/frontend/src/app/globals.css new file mode 100644 index 0000000..94b3b56 --- /dev/null +++ b/webui/frontend/src/app/globals.css @@ -0,0 +1,2439 @@ +:root { + color-scheme: light; + --bg: #f5f6fa; + --surface: #ffffff; + --surface-2: #f1f3f8; + --surface-3: #e9ecf4; + --line: #e3e6ef; + --line-strong: #c6ccdb; + --ink: #0f172a; + --ink-2: #334155; + --muted: #64748b; + --accent: #4f46e5; + --accent-soft: #eef2ff; + --accent-2: #f59e0b; + --ok: #0f9d58; + --error: #d9304a; + --busy: #b45309; + --green: #0f9d58; + --red: #d9304a; + + --radius-sm: 6px; + --radius: 10px; + --radius-lg: 14px; + --shadow-sm: 0 1px 2px rgba(16, 24, 32, 0.05); + --shadow: 0 1px 2px rgba(16, 24, 32, 0.06), 0 12px 32px -16px rgba(16, 24, 32, 0.16); + --shadow-lift: 0 2px 4px rgba(16, 24, 32, 0.06), 0 16px 40px -20px rgba(16, 24, 32, 0.22); + --focus: 0 0 0 3px color-mix(in srgb, var(--accent) 26%, transparent); + --font-mono: ui-monospace, "SF Mono", "JetBrains Mono", Menlo, Consolas, monospace; + --font-ui: -apple-system, BlinkMacSystemFont, "SF Pro Text", "Inter", "Segoe UI", "Helvetica Neue", system-ui, sans-serif; + --speed: 160ms; + --accent-ink: color-mix(in srgb, var(--accent) 14%, transparent); +} + +@media (prefers-color-scheme: dark) { + :root { + color-scheme: dark; + --bg: #0b0f19; + --surface: #131a2b; + --surface-2: #1a2236; + --surface-3: #212b42; + --line: #2a3450; + --line-strong: #3f4a6e; + --ink: #eef1f8; + --ink-2: #c7cfe2; + --muted: #8b96b8; + --accent: #818cf8; + --accent-soft: #232b4a; + --accent-2: #fbbf24; + --ok: #34d399; + --error: #fb7185; + --busy: #fbbf24; + --green: #34d399; + --red: #fb7185; + --shadow-sm: 0 1px 2px rgba(0, 0, 0, 0.45); + --shadow: 0 1px 3px rgba(0, 0, 0, 0.5), 0 12px 32px -14px rgba(0, 0, 0, 0.7); + --shadow-lift: 0 2px 4px rgba(0, 0, 0, 0.5), 0 16px 40px -18px rgba(0, 0, 0, 0.75); + --accent-ink: color-mix(in srgb, var(--accent) 18%, transparent); + } +} + +/* The theme toggle stamps data-theme on the root; it must win either way. */ +:root[data-theme="light"] { + color-scheme: light; + --bg: #f5f6fa; + --surface: #ffffff; + --surface-2: #f1f3f8; + --surface-3: #e9ecf4; + --line: #e3e6ef; + --line-strong: #c6ccdb; + --ink: #0f172a; + --ink-2: #334155; + --muted: #64748b; + --accent: #4f46e5; + --accent-soft: #eef2ff; + --accent-2: #f59e0b; + --ok: #0f9d58; + --error: #d9304a; + --busy: #b45309; + --green: #0f9d58; + --red: #d9304a; + --shadow-lift: 0 2px 4px rgba(16, 24, 32, 0.06), 0 16px 40px -20px rgba(16, 24, 32, 0.22); + --accent-ink: color-mix(in srgb, var(--accent) 14%, transparent); +} + +:root[data-theme="dark"] { + color-scheme: dark; + --bg: #0b0f19; + --surface: #131a2b; + --surface-2: #1a2236; + --surface-3: #212b42; + --line: #2a3450; + --line-strong: #3f4a6e; + --ink: #eef1f8; + --ink-2: #c7cfe2; + --muted: #8b96b8; + --accent: #818cf8; + --accent-soft: #232b4a; + --accent-2: #fbbf24; + --ok: #34d399; + --error: #fb7185; + --busy: #fbbf24; + --green: #34d399; + --red: #fb7185; + --shadow-lift: 0 2px 4px rgba(0, 0, 0, 0.5), 0 16px 40px -18px rgba(0, 0, 0, 0.75); + --accent-ink: color-mix(in srgb, var(--accent) 18%, transparent); +} + +* { + box-sizing: border-box; +} + +html, +body { + margin: 0; + min-height: 100%; + background: var(--bg); + color: var(--ink); + font-family: "Aptos", "Segoe UI", "Helvetica Neue", sans-serif; + font-size: 14px; + letter-spacing: 0; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; +} + +button, +input, +select, +textarea { + font: inherit; +} + +button { + min-height: 24px; + border: 1px solid var(--line-strong); + border-radius: 6px; + background: var(--surface); + color: var(--ink); + padding: 0 8px; + cursor: pointer; + transition: border-color var(--speed) ease, background var(--speed) ease, + color var(--speed) ease, box-shadow var(--speed) ease; +} + +button:hover:not(:disabled) { + border-color: var(--accent); +} + +button:disabled { + cursor: not-allowed; + opacity: 0.5; +} + +button.primary { + background: linear-gradient(180deg, var(--accent), color-mix(in srgb, var(--accent) 88%, black)); + border-color: color-mix(in srgb, var(--accent) 80%, black); + color: white; + font-weight: 600; + box-shadow: 0 1px 2px rgba(16, 24, 32, 0.18); +} + +button.primary:hover:not(:disabled) { + filter: brightness(1.05); + box-shadow: var(--shadow); +} + +input, +select, +textarea { + width: 100%; + border: 1px solid var(--line); + border-radius: 6px; + background: white; + color: var(--ink); + min-height: 24px; + padding: 2px 6px; +} + +input:focus-visible, +select:focus-visible, +textarea:focus-visible, +button:focus-visible, +a:focus-visible { + outline: none; + box-shadow: var(--focus); +} + +textarea { + resize: vertical; +} + +.app-shell { + height: 100vh; + min-height: 0; + display: flex; + flex-direction: column; + overflow: hidden; + padding: 8px; +} + +.topbar { + display: flex; + justify-content: space-between; + gap: 12px; + align-items: center; + margin-bottom: 4px; +} + +.topbar-actions { + display: flex; + align-items: center; + gap: 8px; +} + +.cite-btn { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 30px; + border: 1px solid var(--line-strong); + border-radius: 6px; + background: var(--surface); + color: var(--ink); + padding: 0 10px; + cursor: pointer; + text-decoration: none; + font-size: 13px; + font-weight: 500; + transition: all 0.2s ease; +} + +.cite-btn:hover { + border-color: var(--accent); + color: var(--accent); + background: var(--accent-soft); +} + +.brand-container { + display: flex; + align-items: center; + gap: 12px; +} + +.brand-logo { + height: 30px; + width: auto; + object-fit: contain; +} + +.topbar h1 { + margin: 0; + font-size: 18px; + line-height: 1.1; +} + +.topbar p { + margin: 2px 0 0; + color: var(--muted); + font-size: 12px; +} + +.status { + min-width: 260px; + max-width: 520px; + border: 1px solid var(--line); + border-radius: 6px; + background: var(--surface); + padding: 5px 8px; + color: var(--muted); + font-size: 13px; +} + +.status.ok { + color: var(--ok); + border-color: #9ccbb8; +} + +.status.error { + color: var(--error); + border-color: #d69aaa; +} + +.status.busy { + color: var(--busy); + border-color: #d9c37d; +} + +.workflow { + display: flex; + gap: 8px; + flex-wrap: wrap; + align-items: center; + padding: 6px; + border: 1px solid var(--line); + border-radius: var(--radius); + background: var(--surface); + box-shadow: var(--shadow-sm); + margin-bottom: 8px; +} + +.main-grid { + display: grid; + grid-template-columns: 1fr; + gap: 10px; + align-items: start; + flex: 1; + min-height: 0; + overflow: hidden; +} + +.control-panel, +.viewer-card, +.result-card, +.metrics { + border: 1px solid var(--line); + border-radius: var(--radius); + background: var(--surface); + box-shadow: var(--shadow-sm); +} + +.control-panel { + overflow: auto; + min-height: 0; +} + +.panel-tabs { + display: grid; + grid-template-columns: 1fr 1fr; + border-bottom: 1px solid var(--line); +} + +.panel-tabs button { + border: 0; + border-radius: 0; + background: var(--surface-2); +} + +.panel-tabs button.active { + background: white; + color: var(--accent); + box-shadow: inset 0 -2px 0 var(--accent); +} + +.panel-section { + padding: 5px 8px; + border-bottom: 1px solid var(--line); +} + +.panel-section:last-child { + border-bottom: 0; +} + +.setup-columns { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: 14px; + padding: 4px 10px 10px; +} + +.setup-column { + display: flex; + flex-direction: column; + gap: 4px; +} + +.setup-column:not(:last-child) { + border-right: 1px solid var(--line); + padding-right: 14px; +} + +.setup-column .panel-section { + padding: 8px 0; +} + +.panel-section h2 { + margin: 0 0 3px; + font-size: 10.5px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--muted); +} + +.panel-section.compact { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 4px 6px; +} + +.panel-section.compact h2 { + grid-column: 1 / -1; + margin-bottom: 0; +} + +.field, +.wide-field { + display: grid; + gap: 2px; + margin-bottom: 4px; +} + +.field span, +.wide-field span, +.check-field { + color: var(--muted); + font-size: 11px; +} + +.structure-stats { + display: grid; + gap: 2px; + border: 1px solid var(--line); + border-radius: 6px; + background: var(--surface-2); + padding: 4px 6px; +} + +.structure-stats span { + color: var(--muted); + font-size: 11px; +} + +.pdb-id-form { + display: flex; + gap: 4px; + align-items: center; +} + +.pdb-id-form input { + width: 76px; + text-transform: uppercase; +} + +.check-field { + display: flex; + gap: 6px; + align-items: center; + margin-top: 4px; +} + +.check-field input { + width: auto; +} + +.json-panel { + padding: 8px; +} + +.json-panel textarea { + min-height: 320px; + font-family: "SFMono-Regular", Consolas, monospace; + font-size: 12px; + margin-bottom: 6px; +} + +.workbench { + display: grid; + gap: 12px; + min-height: 0; + overflow: auto; +} + +.card-header { + display: flex; + align-items: flex-start; + justify-content: space-between; + gap: 8px; + padding: 5px 12px; + border-bottom: 1px solid var(--line); +} + +.card-header h2 { + margin: 0; + font-size: 14px; + letter-spacing: -0.01em; +} + +.card-header p { + margin: 2px 0 0; + color: var(--muted); + font-size: 11px; +} + +.card-header > span { + color: var(--muted); + white-space: nowrap; + font-size: 12px; +} + +.protein-viewer-panel { + display: grid; + grid-template-rows: auto minmax(0, 1fr); + min-width: 0; + min-height: 0; + flex: 1; +} + +.protein-viewer { + position: relative; + min-height: 260px; + background: #f1f4f5; + overflow: hidden; +} + +.ngl-stage { + position: absolute; + inset: 0; + width: 100%; + height: 100%; +} + +.fallback-stage { + position: absolute; + inset: 0; + z-index: 1; + display: block; + width: 100%; + height: 100%; + background: #f8fafb; +} + +.viewer-placeholder { + position: absolute; + inset: 0; + z-index: 2; + display: grid; + place-items: center; + color: var(--muted); +} + +.viewer-badge { + position: absolute; + left: 12px; + bottom: 12px; + z-index: 2; + background: rgba(255, 255, 255, 0.88); + border: 1px solid var(--line); + border-radius: 6px; + padding: 6px 8px; + color: var(--muted); + font-size: 12px; +} + +.sequence-viewer { + display: flex; + gap: 12px; + min-width: 0; + overflow-x: auto; + overflow-y: hidden; + padding: 6px 10px; + border-bottom: 1px solid var(--line); + background: var(--surface); +} + +.sequence-chain { + display: grid; + grid-template-columns: auto minmax(0, max-content); + align-items: center; + gap: 5px; + min-width: max-content; +} + +.sequence-chain-label { + color: var(--muted); + font-size: 10px; + font-weight: 600; + white-space: nowrap; +} + +.sequence-residue-row { + display: flex; + gap: 0; + overflow: visible; + padding: 0; + font-family: "SFMono-Regular", Consolas, "Courier New", monospace; +} + +.sequence-residue { + position: relative; + display: grid; + width: 15px; + min-width: 15px; + height: 23px; + align-items: center; + justify-items: center; + padding: 5px 0 0; + border: 0; + border-radius: 0; + background: transparent; + color: var(--ink); + cursor: pointer; + font-family: inherit; +} + +.sequence-residue:hover { + color: var(--accent); + background: transparent; + text-decoration: underline; + text-underline-offset: 3px; +} + +.sequence-residue.selected { + color: #a71919; + background: transparent; + box-shadow: inset 0 -2px 0 #d62728; +} + +.sequence-residue-number { + position: absolute; + top: -1px; + left: 50%; + transform: translateX(-50%); + font-size: 10px; + line-height: 1; + color: var(--muted); + font-family: inherit; +} + +.sequence-residue-letter { + font-size: 13px; + line-height: 1; + font-weight: 700; + font-family: inherit; +} + +.result-row { + display: grid; + grid-template-columns: minmax(0, 1fr) 220px; + gap: 12px; +} + +.simulation-summary-row { + grid-template-columns: minmax(0, 1fr) minmax(220px, 300px); + align-items: stretch; +} + +.simulation-summary-row .result-card, +.simulation-summary-row .metrics { + overflow: hidden; +} + +.simulation-summary-row .plot-card { + min-height: 320px; +} + +.simulation-summary-row .decay-plot { + height: 320px; +} + +.simulation-page { + display: grid; + grid-template-columns: minmax(0, 1fr); + gap: 12px; + min-height: 0; + min-width: 0; +} + +.simulation-primary { + display: flex; + flex-direction: column; + gap: 12px; + min-height: 0; + min-width: 0; + overflow: visible; +} + +.simulation-chart-grid { + display: grid; + grid-template-columns: repeat(2, minmax(320px, 1fr)); + gap: 10px; + min-width: 0; +} + +.simulation-chart-grid .result-card { + display: flex; + flex-direction: column; + overflow: hidden; +} + +.aa-residence-card { + display: grid; + grid-template-rows: auto minmax(0, 1fr); + min-height: 0; + min-width: 0; + overflow: hidden; +} + +.aa-residence-table-scroll { + min-height: 0; + max-height: 520px; + overflow: auto; +} + +.aa-residence-table-scroll .scan-results-table { + min-width: 980px; +} + +.plot-card { + min-height: 260px; +} + +.empty-state { + min-height: 260px; + display: grid; + place-content: center; + gap: 6px; + text-align: center; + color: var(--muted); +} + +.decay-plot { + width: 100%; + height: 260px; + display: block; +} + +.decay-plot line { + stroke: #d7dee2; + stroke-dasharray: 2 3; +} + +.donor-line, +.fret-line { + fill: none; + stroke-width: 2; +} + +.donor-line { + stroke: var(--accent-2); +} + +.fret-line { + stroke: #1c68b3; +} + +.decay-plot text { + fill: var(--muted); + font-size: 12px; +} + +.axis-label { + transform: rotate(-90deg); + transform-origin: 14px 160px; +} + +.metrics { + padding: 8px 10px; + display: grid; + gap: 6px; + align-content: start; +} + +.metrics-title { + margin: -8px -10px 2px; + padding: 8px 10px; + border-bottom: 1px solid var(--line); + color: var(--ink); + font-size: 14px; + font-weight: 600; +} + +.metric { + display: grid; + gap: 1px; + border-bottom: 1px solid var(--line); + padding-bottom: 6px; +} + +.metric:last-child { + border-bottom: 0; + padding-bottom: 0; +} + +.metric span { + color: var(--muted); + font-size: 11px; +} + +.metric strong { + font-size: 16px; +} + +.advanced-settings-page { + display: grid; + gap: 12px; + min-width: 0; +} + +.advanced-settings-card { + overflow: hidden; +} + +.advanced-settings-body { + display: grid; + gap: 18px; + max-width: 560px; + padding: 16px; +} + +.structure-info-table { + width: min(100%, 720px); + border-collapse: collapse; + font-size: 13px; +} + +.structure-info-table tr { + border-bottom: 1px solid var(--line); +} + +.structure-info-table tr:last-child { + border-bottom: 0; +} + +.structure-info-table td { + padding: 8px 0; +} + +.structure-info-table td:first-child { + font-weight: 700; +} + +.structure-info-table td:last-child { + text-align: right; +} + +.monospace-cell { + font-family: "SFMono-Regular", Consolas, monospace; + overflow-wrap: anywhere; +} + +.advanced-empty-copy { + margin: 0; + color: var(--muted); + font-size: 13px; +} + +.advanced-empty-copy a { + color: var(--accent); +} + +@media (max-width: 1024px) { + .setup-columns { + grid-template-columns: repeat(2, 1fr); + gap: 16px; + } + .setup-column { + border-right: none !important; + padding-right: 0 !important; + } +} + +@media (max-width: 980px) { + .main-grid, + .result-row, + .simulation-page, + .simulation-chart-grid { + grid-template-columns: 1fr; + } + + .simulation-page { + height: auto; + } + + .simulation-primary, + .aa-residence-card { + overflow: visible; + } + + .aa-residence-table-scroll { + max-height: 520px; + } + + .app-shell { + height: auto; + min-height: 100vh; + overflow: auto; + } + + .main-grid { + flex: none; + min-height: auto; + overflow: visible; + } + + .control-panel { + overflow: visible; + } + + .viewer-card { + min-height: 0; + } + + .protein-viewer-panel { + min-height: 420px; + } + + .protein-viewer { + height: 360px; + min-height: 360px; + } + + .topbar { + display: grid; + } + + .status { + min-width: 0; + max-width: none; + } +} + +@media (max-width: 768px) { + .setup-columns { + grid-template-columns: 1fr; + } +} + +.result-tabs { + display: flex; + gap: 8px; + margin-bottom: 12px; + border-bottom: 1px solid var(--line); + padding-bottom: 8px; +} + +.result-tabs button { + border: 1px solid transparent; + background: transparent; + padding: 6px 12px; + font-weight: 500; + color: var(--muted); + border-radius: 4px; +} + +.result-tabs button:hover:not(:disabled) { + border-color: var(--line); +} + +.result-tabs button.active { + background: var(--surface-2); + color: var(--accent); + border-color: var(--line); + box-shadow: inset 0 -2px 0 var(--accent); +} + +.result-trajectory-row { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 12px; +} + +.trajectory-line { + fill: none; + stroke: #8b5cf6; /* Violet */ + stroke-width: 1.5; +} + +.autocorr-line { + fill: none; + stroke: #10b981; /* Emerald/Green */ + stroke-width: 2; +} + +@media (max-width: 980px) { + .result-trajectory-row { + grid-template-columns: 1fr; + } +} + +/* HelpBadge and Tooltip styles */ +.help-badge-container { + display: inline-flex; + position: relative; + align-items: center; +} + +.help-badge { + display: inline-flex; + width: 14px; + height: 14px; + align-items: center; + justify-content: center; + border-radius: 50%; + border: 1px solid var(--line-strong); + background: var(--surface); + color: var(--muted); + font-size: 10px; + font-weight: bold; + cursor: help; + margin-left: 6px; + transition: all 0.2s ease; + user-select: none; +} + +.help-badge:hover, +.help-badge:focus { + border-color: var(--accent); + background: #f0f7f7; + color: var(--accent); + outline: none; +} + +.help-tooltip { + position: fixed; + z-index: 10000; + width: 280px; + padding: 10px 12px; + background: var(--surface); + border: 1px solid var(--line); + border-radius: 8px; + box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.1), 0 8px 10px -6px rgba(0, 0, 0, 0.1); + font-size: 12px; + line-height: 1.4; + color: var(--ink); + pointer-events: none; + text-align: left; +} + +.help-tooltip-title { + font-size: 10px; + font-weight: 800; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--accent); + margin-bottom: 4px; +} + +.help-tooltip-unit { + font-size: 10px; + font-weight: bold; + text-transform: uppercase; + color: var(--muted); + margin-top: 6px; +} + +.footer-citation { + margin-top: 16px; + padding: 12px 10px 8px; + border-top: 1px solid var(--line); + text-align: center; + color: var(--muted); + font-size: 12px; + line-height: 1.5; +} + +.footer-citation p { + margin: 0; +} + +.footer-citation a { + color: var(--accent); + text-decoration: none; + font-weight: 500; + transition: color 0.2s ease; +} + +.footer-citation a:hover { + color: var(--accent-2); + text-decoration: underline; +} + +/* Amino-acid interaction table */ +.interaction-table-container { + margin-top: 6px; + border: 1px solid var(--line); + border-radius: 6px; + overflow: hidden; + background: white; +} + +.interaction-table { + width: 100%; + border-collapse: collapse; + font-size: 12px; +} + +.interaction-table th { + background: var(--surface-2); + color: var(--muted); + font-weight: 500; + text-align: left; + padding: 4px 6px; + border-bottom: 1px solid var(--line); +} + +.interaction-table td { + padding: 3px 5px; + border-bottom: 1px solid var(--line); +} + +.interaction-table tr:last-child td { + border-bottom: none; +} + +.interaction-table input { + border: none; + background: transparent; + padding: 2px 4px; + font-size: 11px; + border-radius: 4px; + width: 100%; +} + +.interaction-table input:focus { + background: var(--surface-2); + outline: 1px solid var(--accent); +} + +/* Sidebar Toggle Switch Header */ +.sidebar-header-toggle { + display: flex; + justify-content: space-between; + align-items: center; + padding: 8px 12px; + border-bottom: 1px solid var(--line); + background: var(--surface-2); +} + +.sidebar-header-toggle h2 { + margin: 0; + font-size: 12px; + text-transform: uppercase; + letter-spacing: 0.05em; + color: var(--muted); +} + +/* Toggle Switch Styling */ +.toggle-switch { + display: inline-flex; + align-items: center; + gap: 8px; + cursor: pointer; + user-select: none; +} + +.toggle-label { + font-size: 12px; + font-weight: 500; + color: var(--muted); +} + +.switch { + position: relative; + display: inline-block; + width: 36px; + height: 20px; +} + +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: var(--line-strong); + transition: 0.2s; + border-radius: 20px; +} + +.slider:before { + position: absolute; + content: ""; + height: 14px; + width: 14px; + left: 3px; + bottom: 3px; + background-color: white; + transition: 0.2s; + border-radius: 50%; +} + +input:checked + .slider { + background-color: var(--accent); +} + +input:checked + .slider:before { + transform: translateX(16px); +} + +/* JSON Mode Panel */ +.json-panel { + padding: 10px; + display: flex; + flex-direction: column; + gap: 8px; +} + +.json-panel textarea { + min-height: 360px; + font-family: "SFMono-Regular", Consolas, monospace; + font-size: 12px; + border: 1px solid var(--line); + border-radius: 6px; + padding: 8px; + resize: vertical; + width: 100%; + line-height: 1.4; +} + +.json-panel button { + align-self: flex-end; + background: var(--accent); + color: white; + border: none; + font-weight: 500; +} + +.json-panel button:hover { + background: #005652; +} + +/* Simulation Results Section (below 3D viewer) */ +.results-section { + margin-top: 10px; + border: 1px solid var(--line); + border-radius: 8px; + background: var(--surface); + overflow: hidden; +} + +.results-header { + padding: 8px 12px; + border-bottom: 1px solid var(--line); + background: var(--surface-2); +} + +.results-header h2 { + margin: 0; + font-size: 14px; + font-weight: 600; + color: var(--ink); +} + +.results-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(320px, 1fr)); + gap: 10px; + padding: 10px; +} + +.results-grid .result-card { + display: flex; + flex-direction: column; + border: 1px solid var(--line); + border-radius: 8px; + background: var(--surface); + overflow: hidden; +} + +.results-layout { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 12px; + padding: 12px; +} + +.results-left, +.results-right { + display: flex; + flex-direction: column; + gap: 12px; +} + +.results-left .result-card { + flex: 1; + display: flex; + flex-direction: column; + border: 1px solid var(--line); + border-radius: 8px; + background: var(--surface); + overflow: hidden; +} + +.results-left .decay-plot { + height: 420px; +} + +.results-right .result-card { + display: flex; + flex-direction: column; + border: 1px solid var(--line); + border-radius: 8px; + background: var(--surface); + overflow: hidden; +} + +@media (max-width: 980px) { + .results-layout { + grid-template-columns: 1fr; + } +} + +.empty-results-state { + padding: 48px 16px; + text-align: center; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + gap: 8px; + color: var(--muted); + background: var(--surface-2); +} + +.empty-results-state strong { + font-size: 14px; + color: var(--ink); +} + +.empty-results-state span { + font-size: 12px; +} + +/* Workflow & Tab Container styling */ +.workflow-tab-container { + display: flex; + justify-content: space-between; + align-items: center; + flex-wrap: wrap; + gap: 8px; + padding: 4px 10px; + border: 1px solid var(--line); + border-radius: var(--radius); + background: var(--surface); + box-shadow: var(--shadow-sm); + margin-bottom: 6px; +} + +.app-tabs { + display: flex; + gap: 4px; + background: var(--surface-2); + padding: 3px; + border-radius: 6px; + border: 1px solid var(--line); +} + +.tab-btn { + padding: 3px 10px; + font-size: 12px; + font-weight: 600; + border: 1px solid transparent; + background: transparent; + border-radius: 4px; + color: var(--muted); + cursor: pointer; + transition: all 0.15s ease; +} + +.tab-btn:hover { + color: var(--ink); +} + +.tab-btn.active { + background: var(--surface); + color: var(--accent); + box-shadow: var(--shadow-sm); + border: 1px solid var(--line); +} + +.global-actions { + display: flex; + gap: 8px; +} + +.clear-btn { + background: var(--surface); + border: 1px solid var(--line-strong); + color: var(--muted); + transition: all 0.2s ease; +} + +.clear-btn:hover:not(:disabled) { + border-color: var(--accent-2); + color: var(--accent-2); + background: color-mix(in srgb, var(--accent-2) 10%, var(--surface)); +} + + +/* Vertical Stack Setup */ +.setup-vertical-stack { + display: flex; + flex-direction: column; +} + +.setup-vertical-stack .panel-section { + padding: 5px 8px; + border-bottom: 1px solid var(--line); +} + +.setup-vertical-stack .panel-section:last-child { + border-bottom: none; +} + +/* Desktop Split Layout overrides */ +@media (min-width: 1024px) { + .main-grid { + grid-template-columns: 296px 1fr !important; + gap: 10px !important; + align-items: stretch !important; + } + + .workbench > div { + height: 100%; + } + + .viewer-card { + height: 100%; + display: flex; + flex-direction: column; + min-height: 0; + } + + .protein-viewer { + height: auto !important; + flex: 1; + min-height: 0; + } +} + +@media (min-width: 1024px) and (max-width: 1499px) { + .workbench > .simulation-page { + height: auto; + } +} + +@media (min-width: 1500px) { + .workbench > .simulation-page { + grid-template-columns: minmax(0, 1fr) minmax(360px, 520px); + height: 100%; + } + + .simulation-primary { + overflow: auto; + } + + .aa-residence-table-scroll { + max-height: none; + } +} + +/* Header Dye Selector & Control Styling */ +/* Guided user tour. The overlay itself is transparent; a huge box-shadow on + the spotlight cuts the dim masking out over the target so it stays bright. */ +.tour-overlay { + position: fixed; + inset: 0; + z-index: 2000; + cursor: pointer; +} + +.tour-highlight { + position: fixed; + z-index: 2001; + border: 2px solid var(--accent); + border-radius: 8px; + box-shadow: 0 0 0 9999px rgba(6, 10, 18, 0.6); + pointer-events: none; + transition: all 0.18s ease; +} + +.tour-card { + position: fixed; + z-index: 2002; + width: min(360px, calc(100vw - 24px)); + background: var(--surface); + border: 1px solid var(--line-strong); + border-radius: 12px; + box-shadow: var(--shadow-lift); + color: var(--ink); + cursor: default; + padding: 14px 16px; +} + +.tour-card-header { + display: flex; + align-items: center; + justify-content: space-between; + gap: 8px; +} + +.tour-step { + font-size: 11px; + font-weight: 700; + text-transform: uppercase; + letter-spacing: 0.06em; + color: var(--accent); +} + +.tour-close { + width: 22px; + min-height: 22px; + padding: 0; + border: none; + background: transparent; + color: var(--muted); + font-size: 18px; + line-height: 1; +} + +.tour-close:hover { + color: var(--ink); +} + +.tour-card-title { + margin: 8px 0 4px; + font-size: 15px; + letter-spacing: -0.01em; +} + +.tour-card-body { + margin: 0 0 12px; + font-size: 13px; + line-height: 1.5; + color: var(--ink-2); +} + +.tour-card-footer { + display: flex; + justify-content: flex-end; + gap: 8px; +} + +.tour-btn { + min-height: 26px; +} + +.theme-toggle { + display: inline-flex; + align-items: center; + justify-content: center; + width: 30px; + min-height: 24px; + padding: 0; + border: 1px solid var(--line-strong); + border-radius: 6px; + background: var(--surface); + color: var(--ink-2); + box-shadow: var(--shadow-sm); +} + +.theme-toggle:hover { + border-color: var(--accent); + color: var(--accent); +} + +.header-select-group { + display: flex; + align-items: center; + gap: 6px; + background: var(--surface); + border: 1px solid var(--line); + border-radius: 6px; + padding: 2px 8px; + min-height: 30px; +} + +.header-label { + font-size: 12px; + font-weight: 600; + color: var(--muted); + white-space: nowrap; +} + +.header-select { + border: none; + background: transparent; + padding: 0; + font-size: 13px; + font-weight: 500; + width: auto; + min-width: 100px; + cursor: pointer; + outline: none; + color: var(--ink); +} + +.header-select:focus { + outline: none; +} + +/* Citation Modal Styles */ +.citation-modal-overlay { + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.4); + backdrop-filter: blur(2px); + display: grid; + place-items: center; + z-index: 20000; + animation: fadeIn 0.18s ease-out; +} + +.citation-modal { + background: var(--surface); + border: 1px solid var(--line); + border-radius: 8px; + width: 90%; + max-width: 500px; + box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.15), 0 10px 10px -5px rgba(0, 0, 0, 0.1); + animation: scaleUp 0.18s cubic-bezier(0.16, 1, 0.3, 1); + overflow: hidden; +} + +.citation-modal-header { + display: flex; + justify-content: space-between; + align-items: center; + padding: 10px 14px; + border-bottom: 1px solid var(--line); + background: var(--surface-2); +} + +.citation-modal-header h2 { + margin: 0; + font-size: 14px; + font-weight: 600; + color: var(--ink); +} + +.citation-modal-header .close-btn { + background: transparent; + border: none; + font-size: 20px; + padding: 0 4px; + min-height: auto; + color: var(--muted); + cursor: pointer; +} + +.citation-modal-header .close-btn:hover { + color: var(--ink); +} + +.citation-modal-body { + padding: 14px; +} + +.citation-modal-body p { + margin: 0 0 8px; + color: var(--ink); +} + +.citation-text { + margin: 0 0 12px; + padding: 8px 10px; + background: var(--surface-2); + border-left: 3px solid var(--accent); + font-size: 13px; + line-height: 1.45; + color: var(--ink); + font-style: normal; +} + +.citation-modal-actions { + display: flex; + gap: 8px; + justify-content: flex-end; +} + +.primary-btn-link { + display: inline-flex; + align-items: center; + justify-content: center; + min-height: 30px; + border: 1px solid var(--accent); + background: var(--accent); + color: white; + border-radius: 6px; + padding: 0 12px; + font-size: 13px; + font-weight: 500; + text-decoration: none; + cursor: pointer; + transition: opacity 0.2s; +} + +.primary-btn-link:hover { + opacity: 0.9; +} + +@keyframes fadeIn { + from { opacity: 0; } + to { opacity: 1; } +} + +@keyframes scaleUp { + from { transform: scale(0.96); opacity: 0; } + to { transform: scale(1); opacity: 1; } +} + +/* Scan tab CSS */ +.scan-residues-selection { + display: flex; + flex-direction: column; + gap: 8px; + margin-top: 10px; +} + +.scan-selection-actions { + display: flex; + gap: 8px; +} + +.scan-selection-actions button { + flex: 1; + padding: 4px 8px; + font-size: 11px; + min-height: 24px; + background: var(--surface-2); + border: 1px solid var(--line); + color: var(--ink); + cursor: pointer; + border-radius: 4px; + transition: background 0.15s; +} + +.scan-selection-actions button:hover { + background: var(--line); +} + +.scan-residues-list { + max-height: 200px; + overflow-y: auto; + border: 1px solid var(--line); + border-radius: 6px; + background: var(--surface-2); + padding: 6px; + display: flex; + flex-direction: column; + gap: 4px; +} + +.scan-residue-item { + display: flex; + align-items: center; + gap: 8px; + padding: 4px 6px; + border-radius: 4px; + cursor: pointer; + font-size: 12px; + color: var(--ink); +} + +.scan-residue-item:hover { + background: var(--line); +} + +.scan-residue-item input[type="checkbox"] { + width: 14px; + height: 14px; + cursor: pointer; +} + +.scan-table-container { + overflow-x: auto; + border: 1px solid var(--line); + border-radius: 8px; + background: var(--surface); +} + +.scan-results-table { + width: 100%; + border-collapse: collapse; + font-size: 13px; + text-align: left; +} + +.scan-results-table th, +.scan-results-table td { + padding: 5px 6px; + border-bottom: 1px solid var(--line); + font-size: 11.5px; +} + +.scan-results-table th { + background: var(--surface-2); + font-weight: 600; + color: var(--muted); + font-size: 10.5px; + text-transform: uppercase; + letter-spacing: 0.05em; + user-select: none; +} + +.scan-results-table th.sortable { + cursor: pointer; +} + +.scan-results-table th.sortable:hover { + background: var(--surface-3); + color: var(--text); +} + +.sort-icon { + margin-left: 4px; + font-size: 10px; + display: inline-block; + vertical-align: middle; +} + +.scan-results-table tr:hover { + background: var(--surface-2); +} + +.status-badge { + display: inline-flex; + align-items: center; + padding: 1px 5px; + border-radius: 10px; + font-size: 10px; + font-weight: 500; +} + +.status-badge.success { + background: rgba(16, 185, 129, 0.15); + color: #10b981; + border: 1px solid rgba(16, 185, 129, 0.2); +} + +.status-badge.failed { + background: rgba(239, 68, 68, 0.15); + color: #ef4444; + border: 1px solid rgba(239, 68, 68, 0.2); +} + +.column-filter-input, +.column-filter-select { + width: 100%; + padding: 2px 4px; + font-size: 10px; + border: 1px solid var(--line); + border-radius: 4px; + background: var(--surface-3); + color: var(--text); + box-sizing: border-box; +} + + + +.filter-row th { + padding: 4px 6px; + background: var(--surface-2); +} + +/* ========================================================================== + Modernization layer + Loaded last so it refines the base rules above without rewriting them. + ========================================================================== */ + +html, +body { + font-family: "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", "Helvetica Neue", sans-serif; + -webkit-font-smoothing: antialiased; + text-rendering: optimizeLegibility; + overflow-x: hidden; +} + +/* --- controls ------------------------------------------------------------ */ + +button { + border-radius: var(--radius-sm); + font-weight: 500; + transition: background-color 0.15s ease, border-color 0.15s ease, color 0.15s ease; +} + +button:hover:not(:disabled) { + background: var(--surface-2); + border-color: var(--accent); +} + +button.primary { + box-shadow: var(--shadow-sm); +} + +button.primary:hover:not(:disabled) { + background: color-mix(in srgb, var(--accent) 88%, black); + border-color: color-mix(in srgb, var(--accent) 88%, black); + color: #fff; +} + +input, +select, +textarea { + background: var(--surface); + color: var(--ink); + border-radius: var(--radius-sm); + transition: border-color 0.15s ease, box-shadow 0.15s ease; +} + +input:focus-visible, +select:focus-visible, +textarea:focus-visible, +button:focus-visible, +a:focus-visible { + outline: none; + border-color: var(--accent); + box-shadow: var(--focus); +} + +input[type="number"] { + font-variant-numeric: tabular-nums; +} + +/* --- surfaces ------------------------------------------------------------ */ + +.control-panel, +.viewer-card, +.result-card, +.metrics { + border-radius: var(--radius); + box-shadow: var(--shadow-sm); + border-color: var(--line); +} + +.topbar { + background: var(--surface); + border-bottom: 1px solid var(--line); +} + +.card-header { + align-items: baseline; + gap: 10px; +} + +.card-subtitle { + color: var(--muted); + font-size: 12px; +} + +.panel-note { + margin: 0 0 8px; + color: var(--muted); + font-size: 12px; + line-height: 1.45; +} + +.pill { + display: inline-flex; + align-items: center; + gap: 4px; + padding: 2px 8px; + border-radius: 999px; + background: var(--surface-3); + color: var(--ink-2); + font-size: 11px; + font-weight: 500; + white-space: nowrap; +} + +.pill-accent { + background: var(--accent-soft); + color: var(--accent); +} + +.pill-warn { + background: color-mix(in srgb, var(--accent-2) 16%, transparent); + color: var(--accent-2); +} + +.muted { + color: var(--muted); +} + +.hint { + display: block; + color: var(--muted); + font-size: 11px; + line-height: 1.4; +} + +/* --- charts -------------------------------------------------------------- */ + +.chart { + width: 100%; + height: auto; + display: block; +} + +.chart-grid line { + stroke: var(--line); + stroke-width: 1; + stroke-dasharray: 2 4; +} + +.chart-axis line { + stroke: var(--line-strong); + stroke-width: 1; +} + +.chart-ticks text { + fill: var(--muted); + font-size: 11px; + font-variant-numeric: tabular-nums; +} + +.chart-axis-label { + fill: var(--ink-2); + font-size: 12px; + font-weight: 500; +} + +.donor-line, +.fret-line, +.trajectory-line, +.autocorr-line { + fill: none; + stroke-width: 1.6; + stroke-linejoin: round; + stroke-linecap: round; + vector-effect: non-scaling-stroke; +} + +.donor-line { + stroke: var(--accent); +} + +.fret-line { + stroke: var(--green); +} + +.trajectory-line { + stroke: var(--accent-2); + stroke-width: 1.2; +} + +.autocorr-line { + stroke: var(--accent); +} + +/* --- quenching breakdown ------------------------------------------------- */ + +.quench-breakdown { + display: flex; + flex-direction: column; + gap: 8px; + padding: 14px 16px 16px; +} + +.quench-bar-row { + display: grid; + grid-template-columns: 46px minmax(80px, 1fr) 52px auto; + align-items: center; + gap: 10px; +} + +.quench-bar-track { + height: 10px; + border-radius: 999px; + background: var(--surface-3); + overflow: hidden; +} + +.quench-bar-fill { + height: 100%; + border-radius: 999px; + background: linear-gradient(90deg, var(--accent), color-mix(in srgb, var(--accent) 55%, var(--accent-2))); + transition: width 0.25s ease; +} + +.quench-bar-value { + text-align: right; + font-variant-numeric: tabular-nums; + font-weight: 600; + font-size: 12px; +} + +.quench-bar-detail { + color: var(--muted); + font-size: 11px; + font-variant-numeric: tabular-nums; + white-space: nowrap; +} + +.residue-code { + display: inline-block; + font-family: var(--font-mono); + font-size: 12px; + font-weight: 600; + letter-spacing: 0.02em; +} + +/* --- quenching editor ---------------------------------------------------- */ + +.quench-editor-card .advanced-settings-body { + padding: 0; +} + +.quench-editor { + /* Let the grid item shrink below its content's intrinsic width, so the + `quench-table-wrap` scroll container below governs its own horizontal + extent instead of forcing the 560px card wide. Without this the flex/item + default `min-width: auto` makes the quenching table spill past the card. */ + min-width: 0; + display: flex; + flex-direction: column; + gap: 14px; + padding: 14px 16px 18px; +} + +.quench-editor-intro p { + margin: 0 0 10px; + color: var(--ink-2); + font-size: 13px; + line-height: 1.55; + max-width: 70ch; +} + +.quench-editor-stats { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.quench-editor-toolbar { + display: flex; + flex-wrap: wrap; + gap: 10px; + align-items: center; + justify-content: space-between; +} + +.quench-editor-actions { + display: flex; + flex-wrap: wrap; + gap: 6px; +} + +.segmented { + display: inline-flex; + padding: 2px; + border: 1px solid var(--line); + border-radius: 999px; + background: var(--surface-2); +} + +.segmented button { + border: none; + background: transparent; + border-radius: 999px; + padding: 2px 12px; + min-height: 24px; + color: var(--muted); + font-size: 12px; +} + +.segmented button.active { + background: var(--surface); + color: var(--ink); + box-shadow: var(--shadow-sm); +} + +.quench-table-wrap { + overflow-x: auto; + border: 1px solid var(--line); + border-radius: var(--radius); +} + +.quench-table { + width: 100%; + min-width: 640px; + border-collapse: collapse; + font-size: 13px; +} + +.quench-table thead th { + position: sticky; + top: 0; + z-index: 1; + background: var(--surface-2); + border-bottom: 1px solid var(--line); + padding: 8px 10px; + text-align: left; + font-size: 11px; + font-weight: 600; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--muted); + white-space: nowrap; +} + +.quench-table .unit { + font-weight: 400; + text-transform: none; + letter-spacing: 0; +} + +.quench-table tbody th, +.quench-table tbody td { + padding: 6px 10px; + border-bottom: 1px solid var(--line); + vertical-align: middle; + text-align: left; +} + +.quench-table tbody tr:last-child th, +.quench-table tbody tr:last-child td { + border-bottom: none; +} + +.quench-table tbody tr.is-quenching { + background: color-mix(in srgb, var(--accent-soft) 55%, transparent); +} + +.quench-table tbody tr.is-dirty th::after { + content: "•"; + margin-left: 6px; + color: var(--accent-2); +} + +.quench-table tbody th { + font-weight: 500; + white-space: nowrap; +} + +.residue-name { + display: block; + color: var(--muted); + font-size: 11px; +} + +.quench-table input[type="number"] { + width: 100%; + max-width: 110px; +} + +.atom-summary { + display: inline-flex; + align-items: center; + gap: 6px; + min-height: 24px; + padding: 2px 8px; + border: 1px dashed var(--line-strong); + background: transparent; + font-size: 12px; + color: var(--ink-2); + text-align: left; +} + +.atom-moiety { + font-style: italic; +} + +.atom-count { + color: var(--muted); + font-size: 11px; + white-space: nowrap; +} + +.quench-atom-row td { + background: var(--surface-2); +} + +.quench-atom-editor { + display: flex; + flex-direction: column; + gap: 4px; + font-size: 12px; + color: var(--ink-2); +} + +.quench-atom-editor input { + font-family: var(--font-mono); + text-transform: uppercase; +} + +.quench-atom-footer { + display: flex; + align-items: center; + justify-content: space-between; + gap: 10px; + margin-top: 6px; +} + +.quench-fallback { + max-width: 460px; +} + +.quench-summary-list { + list-style: none; + margin: 0; + padding: 0; + display: flex; + flex-direction: column; + gap: 4px; +} + +.quench-summary-list li { + display: grid; + grid-template-columns: 44px 1fr auto; + align-items: center; + gap: 8px; + padding: 4px 8px; + border-radius: var(--radius-sm); + background: var(--surface-3); + font-size: 12px; + font-variant-numeric: tabular-nums; +} + +/* --- tables -------------------------------------------------------------- */ + +.scan-results-table th, +.scan-results-table td { + font-variant-numeric: tabular-nums; +} + +.scan-results-table thead th { + position: sticky; + top: 0; + z-index: 1; + background: var(--surface-2); + white-space: nowrap; +} + +.scan-results-table tbody tr.is-quenching { + background: color-mix(in srgb, var(--accent-soft) 45%, transparent); +} + +/* --- responsive ---------------------------------------------------------- */ + +@media (max-width: 1100px) { + .quench-editor-toolbar { + align-items: flex-start; + flex-direction: column; + } +} + +@media (max-width: 760px) { + .quench-bar-row { + grid-template-columns: 42px 1fr 48px; + } + + .quench-bar-detail { + grid-column: 1 / -1; + white-space: normal; + } + + .topbar, + .workflow-tab-container { + flex-direction: column; + align-items: stretch; + gap: 10px; + } +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + animation-duration: 0.01ms !important; + transition-duration: 0.01ms !important; + } +} + +/* Primary buttons use a light accent in dark mode, so the label must go dark. */ +@media (prefers-color-scheme: dark) { + button.primary, + button.primary:hover:not(:disabled) { + color: #0e1417; + } +} + +:root[data-theme="dark"] button.primary, +:root[data-theme="dark"] button.primary:hover:not(:disabled) { + color: #0e1417; +} + +:root[data-theme="light"] button.primary, +:root[data-theme="light"] button.primary:hover:not(:disabled) { + color: #ffffff; +} + +/* Let charts use the full height of their card instead of leaving dead space. */ +.plot-card { + display: flex; + flex-direction: column; + min-height: 0; +} + +.plot-card .chart { + flex: 1; + min-height: 200px; + height: 100%; +} + +.simulation-chart-grid .plot-card .chart { + min-height: 220px; +} + +.quencher-cell { + display: inline-flex; + align-items: center; + gap: 6px; + white-space: nowrap; +} + +/* Viewer legend: names the colours the 3D view uses, which were previously + unexplained (magenta spheres in particular). */ +.viewer-legend { + position: absolute; + left: 12px; + bottom: 12px; + margin: 0; + padding: 6px 10px; + list-style: none; + display: flex; + flex-direction: column; + gap: 4px; + font-size: 11px; + line-height: 1.4; + color: var(--muted, #555); + background: rgba(255, 255, 255, 0.86); + border: 1px solid rgba(0, 0, 0, 0.08); + border-radius: 6px; + pointer-events: none; +} + +.viewer-legend li { + display: flex; + align-items: center; + gap: 6px; +} + +.legend-swatch { + width: 10px; + height: 10px; + border-radius: 50%; + flex: 0 0 auto; +} + +.legend-quencher { background: magenta; } +.legend-site { background: #ffd400; } +.legend-surface { background: rgba(140, 140, 140, 0.55); } diff --git a/webui/frontend/src/app/icon.png b/webui/frontend/src/app/icon.png new file mode 100644 index 0000000..585d65d Binary files /dev/null and b/webui/frontend/src/app/icon.png differ diff --git a/webui/frontend/src/app/labeling/page.tsx b/webui/frontend/src/app/labeling/page.tsx new file mode 100644 index 0000000..9108678 --- /dev/null +++ b/webui/frontend/src/app/labeling/page.tsx @@ -0,0 +1,26 @@ +"use client"; + +import React from "react"; +import { useAppContext } from "../../context/AppContext"; +import ProteinViewer from "../../components/ProteinViewer"; + +export default function LabelingPage() { + const { structure, project, result, surfaceRendering, renderSparsity, onSequenceResidueSelect } = useAppContext(); + + return ( +
+
+

Protein Viewer

+
+ +
+ ); +} diff --git a/webui/frontend/src/app/layout.tsx b/webui/frontend/src/app/layout.tsx new file mode 100644 index 0000000..4971231 --- /dev/null +++ b/webui/frontend/src/app/layout.tsx @@ -0,0 +1,26 @@ +import "./globals.css"; +import type { ReactNode } from "react"; +import Script from "next/script"; +import { AppProvider } from "../context/AppContext"; +import { AppLayout } from "../components/AppLayout"; + +export const metadata = { + title: "Quenching Estimator", + description: "QuEst protein quenching simulation workbench", +}; + +export default function RootLayout({ children }: { children: ReactNode }) { + return ( + + + + {children} + +