Spaces:
Running
Running
| # Compute Integration β live CRC features β 4 HF datasets β dashboard | |
| This document is the **contract** for replacing the dashboard's single frozen feature | |
| table (`SupraBench/physics_feature/test_features_table.csv`) with features that we | |
| compute ourselves from the `SupraEngineering` pipeline on **CRC**, served through | |
| **four** Hugging Face datasets. | |
| It is the spec implementation works against. Code is written by Codex; this doc is | |
| owned by the planning side and kept in sync as decisions change. | |
| --- | |
| ## 1. Goal | |
| - Stop reading a hand-authored, third-party feature table. | |
| - Compute every feature ourselves (`SupraEngineering`, GLIDE docking on CRC). | |
| - Serve features to the dashboard via four private datasets under the `SupraBench` org. | |
| - Keep `app.py` / `prompts/builder.py` essentially untouched by preserving the | |
| `load_features()` / `guest_choices()` / `get_record()` API. | |
| A convenient invariant: the dashboard's feature **column names already equal** the | |
| pipeline's `constants.POSE_FEATURES` and `constants.SCORE_NAMES`. So as long as the | |
| datasets use those exact names, only the *loader* underneath the app changes. | |
| --- | |
| ## 2. The four datasets (private, `SupraBench` org) | |
| | Dataset | Holds | Rows | Needs docking? | Producer | | |
| |---|---|---|---|---| | |
| | `SupraBench/SupraDB-GEOM` | guest pool: `inchikey, name, smiles[, logka]` | whole pool | no | Phase 0 pool builder | | |
| | `SupraBench/SupraDB-LigandScore` | 9 ligand-only mechanism scores | whole pool | no (rdkit) | `score_nodock` | | |
| | `SupraBench/SupraDB-PoseFeat` | 24 pose features | docked subset | **yes** (GLIDE) | `compute_all_features` | | |
| | `SupraBench/SupraDB-CavityScore` | 4 cavity scores | docked subset | **yes** (GLIDE) | `compute_all_features` | | |
| - **Primary / join key:** `inchikey` for all four. | |
| - **Storage format:** one CSV per dataset (`*.csv`) + a generated `README.md` dataset card. | |
| - **Fixed pool** β fixed row counts. `SupraDB-GEOM` and `SupraDB-LigandScore` cover the | |
| *entire* pool (Group 1 is cheap, precomputed for everything). `PoseFeat` / `CavityScore` | |
| cover only the **docked subset** (default: the 63 labeled guests). | |
| ### 2.1 Column contracts | |
| `SupraDB-GEOM`: | |
| ``` | |
| inchikey, name, smiles, logka # logka may be empty for unlabeled (GEOM-only) guests | |
| ``` | |
| `SupraDB-LigandScore` (9 β produced by `score_nodock`, ligand-intrinsic, `charge_access=0`): | |
| ``` | |
| inchikey, | |
| S_charge, S_hydrophobic, S_rigidity, S_desolvation, S_packing, | |
| S_shape, S_conformer_diversity, S_boltzmann_concentration, S_bad | |
| ``` | |
| `SupraDB-CavityScore` (4 β cavity terms from the best docked pose): | |
| ``` | |
| inchikey, S_occupancy, S_portal, S_accessibility, S_orientation | |
| ``` | |
| `SupraDB-PoseFeat` (24 pose features, `constants.POSE_FEATURES` order, + provenance): | |
| ``` | |
| inchikey, | |
| DockingScore, Pose_Energy, Distance_to_Cavity_Center, Distance_to_Portal, | |
| Insertion_Depth, Packing_Coefficient, Occupancy, Hydrophobic_Occupancy, | |
| Shape_Complementarity, Steric_Clash, Guest_CB7_Min_Distance, Pose_RMSD_to_Template, | |
| Portal_Compatibility, Positive_Center_to_Portal_Distance, Positive_Center_Orientation, | |
| Charge_Accessibility, Portal_Facing_Accessibility, HBond_Count, HBond_Geometry, | |
| Carbonyl_Oxygen_Contact_Count, Hydrophobic_Contact, Polar_Contact_Penalty, | |
| Bad_Group_Portal_Exposure, Desolvation_Penalty, | |
| boltzmann_weight, delta_e # provenance of the kept (collapsed) pose | |
| ``` | |
| > Why `S_charge` lives in `LigandScore`: it is computed by `score_nodock` with the | |
| > cavity-dependent `charge_access` term set to 0, so it is reproducible from SMILES for | |
| > the whole pool. The pose-enhanced `charge_access` from the full run is reflected | |
| > separately in `CavityScore` (`S_accessibility`); we do **not** overwrite the | |
| > ligand-score `S_charge` per-pose. This keeps each dataset's provenance clean. | |
| ### 2.2 Pose collapse | |
| `pose_feats.pkl` stores up to *P* poses/guest as `float32[P, 24]` with per-pose | |
| `delta_e` and `boltz`. The dashboard shows one row/guest, so `publish.py` **collapses** | |
| to the single pose with the **highest `boltzmann_weight`** (the dominant, lowest-energy | |
| geometry β a real pose, not an average). `boltzmann_weight` + `delta_e` of that pose are | |
| carried into the CSV for transparency. (Alternative rules β weighted average, lowest | |
| GlideScore β are documented but not the default.) | |
| --- | |
| ## 3. Identifiers β SMILES & InChIKey | |
| The pipeline and dashboard both **assume** `inchikey`/`smiles` are given; neither derives | |
| them. We make that explicit in Phase 0: | |
| 1. **SMILES** is the source of truth (from GEOM, or the seed `guests.csv`). | |
| 2. **Canonicalize + desalt once** (RDKit, largest fragment) β matches what the pipeline | |
| does internally (`ligand_descriptors`, `smiles_to_xyz`), so the stored InChIKey is the | |
| same key the pipeline computes under. | |
| 3. **InChIKey = `Chem.MolToInchiKey(Chem.MolFromSmiles(canonical_smiles))`** β a canonical | |
| hash; identical molecules β identical key. This is the join key across all four | |
| datasets, the SQLite cache, and the 2D/3D structure fetch. | |
| 4. `name`: keep any name GEOM/seed provides; else fall back to a short InChIKey label. | |
| Generated in exactly one place (the pool builder) so every downstream piece keys off the | |
| same value. | |
| --- | |
| ## 4. Feature selection (compute + inference) | |
| All **37** features are stored. Selection is a *choice*, defaulting to a recommendation. | |
| - **At inference (drives the LLM prompt):** a UI selector with presets β | |
| `Recommended` (default, the curated ~22: strongest pose features + meaningful scores, | |
| dropping redundant pairs like `Occupancy`/`S_occupancy`), `All 37`, `Physics`, | |
| `Chemistry`, `Custom` (per-feature). The existing physics/chemistry/combined | |
| trajectories become presets of this same control. The selected set drives | |
| `prompts/builder.py:_feature_lines()` instead of the fixed `FEATURES` constant. The | |
| choice is recorded with each sample and **folded into the cache key** so different | |
| feature sets don't collide. | |
| - **At compute:** the meaningful choice is *which of the three groups to (re)compute* | |
| (docking is the expensive step; once docked, all pose features are free). Default: all. | |
| The `Recommended` preset = the current 22-feature `FEATURES` list in `data/loader.py`. | |
| --- | |
| ## 5. Dataset cards (README.md per dataset) | |
| Every `SupraDB-*` dataset ships a generated HF dataset card: | |
| - YAML frontmatter: `license`, `pretty_name`, `tags`, `configs` (point at the CSV). | |
| - Body: what it is + pipeline position; full **schema** (column, dtype, units, meaning | |
| from `DEFINITIONS.md` / `features_lib`); the `inchikey` join-key note; **provenance** | |
| (CRC; GLIDE 2025u2 / aISS fallback; pose-collapse rule; row count); and the exact | |
| `refresh`/`publish.py` command + `SupraEngineering` commit that produced it. | |
| Cards are **generated by the scripts** (Phase 0 writes the GEOM card; `publish.py` writes | |
| the three feature cards) so they never drift from the data. | |
| --- | |
| ## 6. Pipeline (Phases) | |
| ``` | |
| GEOM SMILES (or seed guests.csv) | |
| β Phase 0: pool_builder.py (RDKit canonicalize+desalt β InChIKey) | |
| βΌ | |
| SupraDB-GEOM βββ source of truth (guest list, names, SMILES, logka) | |
| β | |
| ββ Group 1: score_nodock (rdkit, whole pool) ββββββΊ SupraDB-LigandScore | |
| ββ Groups 2+3: dock_glide β compute_all_features ββΊ SupraDB-PoseFeat + SupraDB-CavityScore | |
| (CRC, GLIDE 2025u2; docked subset) β | |
| all four joined on inchikey | |
| βΌ | |
| data/loader.py β app.py (unchanged) | |
| ``` | |
| - **Phase 0 β Pool builder** (`SupraEngineering/src/pool_builder.py`): SMILES source β | |
| canonical `guests.csv` + `SupraDB-GEOM` card; `--push` uploads. Seed source = the | |
| existing 63-guest `SupraEngineering/data/guests.csv`; pluggable for a GEOM list. | |
| - **Phase 1 β CRC compute** (two run dirs, because `score_nodock` and | |
| `compute_all_features` both write `features/scores.pkl` and would clobber each other); | |
| one SGE wrapper `SupraEngineering/scripts/crc_compute.sge` runs both: | |
| - **whole-pool no-dock run:** `scripts/score_nodock.sh <pool_dir>` β `<pool_dir>/features/scores.pkl` | |
| (13-d, cavity terms = 0). Source of **LigandScore** (the 9 ligand cols). | |
| - **docked-subset run:** `scripts/dock_glide.sh <dock_dir>` then `scripts/compute_all_features.sh <dock_dir>` | |
| β `<dock_dir>/features/scores.pkl` (full 13-d) + `pose_feats.pkl`. Source of | |
| **CavityScore** (the 4 cavity cols) and **PoseFeat** (24-d). | |
| - GLIDE confirmed at `/opt/crc/s/schrodinger/2025u2` (module `schrodinger/2025u2`). | |
| aISS/xtb fallback on GLIDE failure β **xtb is not yet on CRC** | |
| (`conda install -c conda-forge xtb` first). | |
| - **Phase 2 β Publish** (`SupraEngineering/src/publish.py`, runs on CRC, HF_TOKEN present): | |
| inputs `--pool-scores <pool_dir>/features/scores.pkl`, | |
| `--dock-scores <dock_dir>/features/scores.pkl`, `--pose-feats <dock_dir>/features/pose_feats.pkl`. | |
| Splits into 3 feature CSVs (`features.csv` each, full named columns) + cards, collapses | |
| poses by Boltzmann weight, uploads to the three feature repos. | |
| - **Phase 3 β Loader** (`src/data/loader.py`): read the 4 datasets, LEFT-join on | |
| `inchikey`, return the same `rec` dict. Env: 4 repo ids + `HF_TOKEN`; `LOCAL_*` CSV | |
| fallbacks for offline dev; `lru_cache`. Report which datasets loaded (health strip). | |
| - **Phase 4 β UI + automation**: feature-selection control; one-command `refresh` | |
| (ssh CRC β qsub β wait β publish); finalize this runbook. | |
| --- | |
| ## 7. CRC connection (runbook) | |
| - Host `crc` β `crcfe01.crc.nd.edu` (fallback `crcfe02`), user `tma2`, **password-only** | |
| (no SSH keys). From a Mac session: | |
| `sshpass -p "$(op read 'op://openclaw/CRC/password')" ssh crc '<cmd>'` | |
| (`op` unlocked via Touch ID; `sshpass`/`op` via Homebrew). | |
| - Scheduler: **SGE** (`qsub`/`qstat`/`qdel`); never run docking interactively on a login | |
| node for the full pool. | |
| - GLIDE: `module load schrodinger/2025u2`; `$SCHRODINGER=/opt/crc/s/schrodinger/2025u2`. | |
| - Env: a Python env with `rdkit, numpy, pandas, scipy` (the project's `GPM` conda env); | |
| `huggingface_hub` + `HF_TOKEN` on CRC for the publish step. | |
| --- | |
| ## 8. Decision ledger | |
| | Decision | Status | | |
| |---|---| | |
| | 4 datasets `SupraDB-GEOM/-LigandScore/-PoseFeat/-CavityScore` | locked | | |
| | `inchikey` = sole join key, derived once in Phase 0 from SMILES | locked | | |
| | Store all 37 features; inference set selectable; `Recommended` default | locked | | |
| | Each dataset ships a generated `README.md` card | locked | | |
| | `publish.py` runs on CRC (HF_TOKEN already there) | locked | | |
| | GLIDE 2025u2 default (confirmed on CRC); aISS/xtb fallback (xtb needs install) | locked | | |
| | Pose collapse = highest Boltzmann weight | default (flag to change) | | |
| | GEOM Group-1 scope = CB[7]-plausible subset (not all ~430k) | default (flag to change) | | |
| | Docking subset = 63 labeled guests; GEOM-only guests prediction-only | default (flag to change) | | |