From f84c08cbb30db342e9dd5fff792354eb77a0c727 Mon Sep 17 00:00:00 2001 From: David Meijer Date: Thu, 27 Aug 2026 13:13:37 -0400 Subject: [PATCH 1/4] WIP: on-the-fly training of PARAS model for substrate specificity prediction --- .env.example | 10 + database/Snakemake | 11 +- database/config.yaml | 23 +- database/envs/retromol.yaml | 34 - database/profiles/slurm/config.yaml | 2 +- database/scripts/parse_gbks.py | 123 +- docker-compose.yml | 11 + environment.yml | 75 + .../components/workspace/AnnotatedArrow.tsx | 45 + .../workspace/ClusterReadoutDiagram.tsx | 377 ++ .../components/workspace/DialogViewItem.tsx | 119 +- .../workspace/WorkspaceDiscovery.tsx | 4 +- gui/src/client/src/features/clusters/api.ts | 48 + gui/src/client/src/features/clusters/types.ts | 30 +- gui/src/client/src/features/session/types.ts | 6 + gui/src/server/routes/jobs.py | 64 +- pyproject.toml | 8 +- scripts/predict_bgc.py | 207 + scripts/train_paras.py | 55 + src/retromol/data/pmp.yml | 252 ++ src/retromol_antismash/inference/factory.py | 67 + .../inference/model_paras_cli.py | 87 + src/retromol_antismash/modules.py | 190 +- src/retromol_antismash/predictions.py | 230 ++ src/retromol_database/duckdb.py | 35 + src/retromol_paras/__init__.py | 24 + src/retromol_paras/constants.py | 55 + src/retromol_paras/data/AMP-binding_full.hmm | 1559 +++++++ .../data/AMP-binding_hmmer2.hmm | 688 ++++ src/retromol_paras/data/__init__.py | 0 src/retromol_paras/data/active_site.txt | 1 + src/retromol_paras/data/active_site_hmm2.txt | 1 + .../data/database_files/parasect_dataset.txt | 3654 +++++++++++++++++ .../data/database_files/smiles.tsv | 311 ++ .../data/included_substrates.txt | 38 + .../data/included_substrates_bacterial.txt | 30 + .../data/physicochemical_properties.txt | 22 + src/retromol_paras/data/stachelhaus.txt | 1 + src/retromol_paras/data/stachelhaus_hmm2.txt | 1 + .../data/structure_alignment.fasta | 1846 +++++++++ src/retromol_paras/domain.py | 162 + src/retromol_paras/fasta.py | 37 + src/retromol_paras/featurisation.py | 224 + src/retromol_paras/hmmer.py | 90 + src/retromol_paras/muscle.py | 25 + src/retromol_paras/predict.py | 105 + src/retromol_paras/tabular.py | 35 + src/retromol_paras/train.py | 134 + 48 files changed, 10939 insertions(+), 217 deletions(-) delete mode 100644 database/envs/retromol.yaml create mode 100644 environment.yml create mode 100644 gui/src/client/src/components/workspace/AnnotatedArrow.tsx create mode 100644 gui/src/client/src/components/workspace/ClusterReadoutDiagram.tsx create mode 100755 scripts/predict_bgc.py create mode 100755 scripts/train_paras.py create mode 100644 src/retromol/data/pmp.yml create mode 100644 src/retromol_antismash/inference/factory.py create mode 100644 src/retromol_antismash/inference/model_paras_cli.py create mode 100644 src/retromol_antismash/predictions.py create mode 100644 src/retromol_paras/__init__.py create mode 100644 src/retromol_paras/constants.py create mode 100644 src/retromol_paras/data/AMP-binding_full.hmm create mode 100644 src/retromol_paras/data/AMP-binding_hmmer2.hmm create mode 100644 src/retromol_paras/data/__init__.py create mode 100644 src/retromol_paras/data/active_site.txt create mode 100644 src/retromol_paras/data/active_site_hmm2.txt create mode 100644 src/retromol_paras/data/database_files/parasect_dataset.txt create mode 100644 src/retromol_paras/data/database_files/smiles.tsv create mode 100644 src/retromol_paras/data/included_substrates.txt create mode 100644 src/retromol_paras/data/included_substrates_bacterial.txt create mode 100644 src/retromol_paras/data/physicochemical_properties.txt create mode 100644 src/retromol_paras/data/stachelhaus.txt create mode 100644 src/retromol_paras/data/stachelhaus_hmm2.txt create mode 100644 src/retromol_paras/data/structure_alignment.fasta create mode 100644 src/retromol_paras/domain.py create mode 100644 src/retromol_paras/fasta.py create mode 100644 src/retromol_paras/featurisation.py create mode 100644 src/retromol_paras/hmmer.py create mode 100644 src/retromol_paras/muscle.py create mode 100644 src/retromol_paras/predict.py create mode 100644 src/retromol_paras/tabular.py create mode 100644 src/retromol_paras/train.py diff --git a/.env.example b/.env.example index 02c3049..ce5eec6 100644 --- a/.env.example +++ b/.env.example @@ -7,6 +7,16 @@ REDIS_PASSWORD=supersecretpassword PARAS_MODEL_PATH=/app/models/all_substrates_model.paras.gz PARAS_MODEL_HOST_PATH=/srv/models/all_substrates_model.paras.gz +# Cache dir for whichever NRPS model pmp.yml's predictors.nrps.a_domain currently +# selects (see src/retromol/data/pmp.yml) -- a download cache for "paras", or a +# trained-model cache for "paras_cli" (src/retromol_paras/). Populate +# PARAS_CACHE_HOST_PATH by running `python scripts/train_paras.py --cache-dir +# ` once (needs environment.yml's hmmer2/hmmer/muscle tools -- see that +# script's own docstring), so containers mount an already-trained model instead of +# each one training its own on first request. +PARAS_CACHE_DIR=/app/models/paras_cache +PARAS_CACHE_HOST_PATH=/srv/models/paras_cache + PFAM_HMM_DIR_PATH=/app/hmms/ PFAM_HMM_DIR_HOST_PATH=/srv/hmms/ diff --git a/database/Snakemake b/database/Snakemake index a6cd5d0..5885b55 100644 --- a/database/Snakemake +++ b/database/Snakemake @@ -34,9 +34,14 @@ MARKERS = WORKDIR / "markers" RXN_RULES = config["paths"].get("reaction_rules") MXN_RULES = config["paths"].get("matching_rules") +# null -> pmp.yml's packaged default. See that file's "predictors.nrps.a_domain" for +# which model (if any) this actually selects -- the same file the GUI backend and +# scripts/predict_bgc.py read, so all three resolve GenBank substrates identically. +PMP_PATH = config["paras"].get("pmp_path") PARAS_THRESHOLD = config["paras"]["threshold"] PARAS_KEEP_TOP = config["paras"]["keep_top"] -PARAS_TRAINING_DATA_PATH = config["paras"].get("training_data_path") +PARAS_CACHE_DIR = config["paras"].get("cache_dir") or str(WORKDIR / "paras_cache") +PARAS_FORCE_RETRAIN = config["paras"].get("force_retrain") or False PARSE_COMPOUNDS_WORKERS = config["compute"]["parse_compounds_workers"] PARSE_GBKS_WORKERS = config["compute"]["parse_gbks_workers"] @@ -282,9 +287,11 @@ rule parse_mibig_gbks: parse_gbks.run( gbk_dir=input.gbk_dir, readouts_output_path=output.readouts, + pmp_path=PMP_PATH, paras_threshold=PARAS_THRESHOLD, paras_keep_top=PARAS_KEEP_TOP, - paras_training_data_path=PARAS_TRAINING_DATA_PATH, + paras_cache_dir=PARAS_CACHE_DIR, + force_retrain=PARAS_FORCE_RETRAIN, workers=threads, ) diff --git a/database/config.yaml b/database/config.yaml index b53e44f..29ab4ae 100644 --- a/database/config.yaml +++ b/database/config.yaml @@ -52,12 +52,23 @@ paras: threshold: 0.1 keep_top: 3 - # Path to a training data file to retrain PARAS on the fly before parsing GBKs. - # NOT YET IMPLEMENTED -- setting this raises NotImplementedError right now. - # null (the default) skips PARAS inference entirely: every NRPS A-domain module - # gets an explicit "unknown" substrate instead of a predicted one, rather than - # running the bundled pretrained model. - training_data_path: null + # Path to a pmp.yml prediction-mapping file (see src/retromol/data/pmp.yml). + # null -> the packaged default. Its "predictors.nrps.a_domain" selects which + # model (if any) actually runs here -- "paras" (pyhmmer, a pretrained model + # file), "paras_cli" (src/retromol_paras/, retrained/cached locally from + # command-line HMMER2/HMMER3/MUSCLE3 -- see envs/retromol_paras.yaml -- or + # rather environment.yml at repo root), or a source: qualifier method that + # reads antiSMASH's own NRPS substrate call and runs no model at all. Same + # file the GUI backend and scripts/predict_bgc.py read, so switching + # predictors here changes every entry point at once. + pmp_path: null + + # Cache directory for whichever model pmp_path selects (a download cache for + # "paras", a training-signature + fitted-model cache for "paras_cli"). + cache_dir: null + + # "paras_cli"-only: retrain from scratch even if a cached model is present. + force_retrain: false compute: # Both are embarrassingly parallel over independent compounds/files. diff --git a/database/envs/retromol.yaml b/database/envs/retromol.yaml deleted file mode 100644 index 79db115..0000000 --- a/database/envs/retromol.yaml +++ /dev/null @@ -1,34 +0,0 @@ -# Conda env for running database/Snakemake (the database-construction pipeline only -- -# this has no bearing on the GUI/webapp). -# -# Every rule in that Snakefile uses Snakemake's `run:` directive (inline Python that -# imports and calls database/scripts/*.py functions directly), not `shell:`. Snakemake -# executes `run:` blocks in its own process rather than a subprocess, so a per-rule -# `conda:` env (the --use-conda mechanism) would NOT actually reach any of this -# pipeline's own code -- only `shell()` calls made from *within* a `run:` block, which -# this pipeline never makes. There is deliberately no per-rule conda: directive in -# database/Snakemake, and no --use-conda flag in the invocation below, because of this. -# -# This env is instead the one Snakemake itself runs in, so it needs both Snakemake and -# every runtime dependency database/scripts/*.py imports (rdkit, duckdb, etc. -- all -# already listed in the repo's own pyproject.toml, pulled in by the editable install -# below rather than duplicated here). -# -# Usage: -# -# conda env create -f database/envs/retromol.yaml -# conda activate retromol -# pip install -e . -# snakemake -p -s database/Snakemake --configfile database/config.yaml \ -# --workflow-profile database/profiles/slurm -name: retromol - -channels: - - conda-forge - -dependencies: - - python=3.11 - - pip - - snakemake - - snakemake-executor-plugin-slurm - - mamba diff --git a/database/profiles/slurm/config.yaml b/database/profiles/slurm/config.yaml index 13a1265..796187c 100644 --- a/database/profiles/slurm/config.yaml +++ b/database/profiles/slurm/config.yaml @@ -1,6 +1,6 @@ # Snakemake workflow profile for running database/Snakemake on a Slurm cluster. # -# Usage (from the repo root, with database/envs/retromol.yaml's env active -- see that +# Usage (from the repo root, with environment.yml's env active -- see that # file's own comment for why there's no --use-conda here): # # conda activate retromol diff --git a/database/scripts/parse_gbks.py b/database/scripts/parse_gbks.py index cb33997..709312e 100644 --- a/database/scripts/parse_gbks.py +++ b/database/scripts/parse_gbks.py @@ -1,17 +1,20 @@ """Step 7: parse antiSMASH GenBank files into linear module readouts. -For each region: PARAS predicts NRPS A-domain substrate specificities -(retromol_antismash.inference.registry.annotate_region), then +For each region: whichever model pmp.yml's "predictors.nrps.a_domain" currently +selects predicts NRPS A-domain substrate specificities +(retromol_antismash.inference.factory.build_nrps_a_domain_model + +retromol_antismash.inference.registry.annotate_region), then retromol_antismash.modules.linear_readout collects PKS/NRPS modules in -biosynthetic order. One file per worker process (PARAS model loading is the -expensive per-process setup cost, so it's paid once per worker, not once per file). +biosynthetic order -- using the SAME factory + pmp.yml the GUI backend +(gui/src/server/routes/jobs.py) and the CLI test script (scripts/predict_bgc.py) +use, so all three ways of parsing a GenBank file resolve substrates identically. +One file per worker process (model loading is the expensive per-process setup +cost, so it's paid once per worker, not once per file). -PARAS is optional, gated by `paras_training_data_path`: -- None (default): PARAS is skipped entirely -- no model is loaded, annotate_region - is never called -- and every NRPS module's substrate is set to an explicit - "unknown" (see _mark_nrps_unknown) instead of a predicted one. -- set: raises NotImplementedError. On-the-fly retraining from a training data file - isn't built yet; this exists so config can already carry the path for later. +If pmp.yml's selected method is `source: qualifier` instead of `source: model` +(e.g. reading antiSMASH's own NRPS substrate call straight from the GenBank +record), no model is built or run at all -- collect_nrps_modules reads the +qualifier directly, same as everywhere else this config is used. Emits one output: readouts JSONL, one line per antiSMASH region, with its LinearReadout, the raw GenBank text of its source file, and the MIBiG accession @@ -40,46 +43,47 @@ from tqdm import tqdm from common import split_accession_version -from retromol_antismash.inference.model_paras import ParasModel +from retromol_antismash.inference.base import DomainInferenceModel +from retromol_antismash.inference.factory import build_nrps_a_domain_model from retromol_antismash.inference.registry import annotate_region from retromol_antismash.io import AntiSmashOptions, parse_antismash_gbk -from retromol_antismash.modules import LinearReadout, ModuleType, NRPSSubstrate, linear_readout +from retromol_antismash.modules import linear_readout +from retromol_antismash.predictions import PredictionConfig log = logging.getLogger(__name__) GBK_GLOBS = ("*.gbk", "*.gb", "*.gbff") -UNKNOWN_NRPS_SUBSTRATE = NRPSSubstrate(name="unknown", smiles=None, score=0.0) - -_G_PARAS_MODEL: ParasModel | None = None - - -def _mark_nrps_unknown(readout: LinearReadout) -> None: - """Set every NRPS module's substrate to an explicit "unknown" -- used when PARAS is skipped - so a module with no substrate call is visibly "not predicted", not indistinguishable from one - PARAS looked at and genuinely couldn't call (module.predicted_substrate is mutable, not frozen).""" - for module in readout.modules: - if module.type == ModuleType.NRPS: - module.predicted_substrate = UNKNOWN_NRPS_SUBSTRATE +_G_CONFIG: PredictionConfig | None = None +_G_NRPS_MODEL: DomainInferenceModel | None = None def _init_worker( - use_paras: bool, paras_threshold: float, paras_keep_top: int, paras_model_path: str | None, paras_cache_dir: str + pmp_path: str | None, + threshold: float, + keep_top: int, + model_path: str | None, + cache_dir: str, + force_retrain: bool, ) -> None: - global _G_PARAS_MODEL + global _G_CONFIG, _G_NRPS_MODEL # Belt-and-braces: importing this module (to resolve _init_worker as this pool's # initializer) already re-runs common.py's own RDLogger.DisableLog at the top of # this file's import chain, but this initializer is what the pool guarantees runs # once per worker no matter what -- see common.run_retromol_stream_quiet's # docstring for why that guarantee matters more than it might seem. RDLogger.DisableLog("rdApp.*") - if use_paras: - _G_PARAS_MODEL = ParasModel( - threshold=paras_threshold, - keep_top=paras_keep_top, - model_path=paras_model_path, - cache_dir=paras_cache_dir, - ) + _G_CONFIG = PredictionConfig.load_from_file(pmp_path) if pmp_path else PredictionConfig.load_default() + # None when pmp.yml's predictors.nrps.a_domain is source: qualifier -- nothing to + # build or register, collect_nrps_modules reads the qualifier directly. + _G_NRPS_MODEL = build_nrps_a_domain_model( + _G_CONFIG, + threshold=threshold, + keep_top=keep_top, + cache_dir=cache_dir, + model_path=model_path, + force_retrain=force_retrain, + ) def _process_file(path_str: str) -> tuple[list[dict], str | None]: @@ -93,13 +97,10 @@ def _process_file(path_str: str) -> tuple[list[dict], str | None]: entries: list[dict] = [] for region in regions: - if _G_PARAS_MODEL is not None: - annotate_region(region, domain_models=[_G_PARAS_MODEL]) + if _G_NRPS_MODEL is not None: + annotate_region(region, domain_models=[_G_NRPS_MODEL]) - readout = linear_readout(region) - - if _G_PARAS_MODEL is None: - _mark_nrps_unknown(readout) + readout = linear_readout(region, config=_G_CONFIG) accession, _version = split_accession_version(region.id) @@ -119,21 +120,28 @@ def _process_file(path_str: str) -> tuple[list[dict], str | None]: def run( gbk_dir: str | Path, readouts_output_path: str | Path, + pmp_path: str | Path | None = None, paras_threshold: float = 0.1, paras_keep_top: int = 3, paras_model_path: str | Path | None = None, paras_cache_dir: str | Path = "paras_cache", - paras_training_data_path: str | Path | None = None, + force_retrain: bool = False, workers: int = 1, ) -> None: - if paras_training_data_path is not None: - raise NotImplementedError( - "retraining PARAS on the fly from a training data file is not implemented yet " - f"(got paras_training_data_path={paras_training_data_path!r}); " - "set paras.training_data_path back to null in config.yaml to skip PARAS " - "and label every NRPS module 'unknown' instead" - ) - + """ + :param gbk_dir: directory of antiSMASH GenBank files to parse (searched recursively). + :param readouts_output_path: where to write the readouts JSONL. + :param pmp_path: path to a pmp.yml prediction-mapping file, or None to use the packaged + default -- see retromol_antismash.inference.factory.build_nrps_a_domain_model for + how this selects (or skips) an NRPS substrate-prediction model. + :param paras_threshold: minimum predicted probability for a substrate call to be kept. + :param paras_keep_top: number of top-scoring substrate predictions to keep per domain. + :param paras_model_path: "paras"-only: path to a custom PARAS model file. + :param paras_cache_dir: model/training cache directory (meaning is model-specific -- + see build_nrps_a_domain_model). + :param force_retrain: "paras_cli"-only: retrain from scratch even if a cached model exists. + :param workers: number of worker processes. + """ gbk_dir = Path(gbk_dir) readouts_output_path = Path(readouts_output_path) readouts_output_path.parent.mkdir(parents=True, exist_ok=True) @@ -144,16 +152,13 @@ def run( n_entries = 0 n_errors = 0 - # PARAS is always disabled for now -- paras_training_data_path is the only way - # to opt in once retraining exists, and that path always raises above. - use_paras = False - init_args = ( - use_paras, + str(pmp_path) if pmp_path else None, paras_threshold, paras_keep_top, str(paras_model_path) if paras_model_path else None, str(paras_cache_dir), + force_retrain, ) # Bounded sliding window rather than submitting every file as a future up front -- @@ -202,26 +207,24 @@ def main() -> None: ap = argparse.ArgumentParser(description=__doc__) ap.add_argument("--gbk-dir", required=True) ap.add_argument("--readouts-output", required=True) + ap.add_argument("--pmp", default=None, help="path to a pmp.yml prediction-mapping file (default: packaged pmp.yml)") ap.add_argument("--paras-threshold", type=float, default=0.1) ap.add_argument("--paras-keep-top", type=int, default=3) - ap.add_argument("--paras-model-path", default=None) + ap.add_argument("--paras-model-path", default=None, help="'paras'-only: path to a custom PARAS model file") ap.add_argument("--paras-cache-dir", default="paras_cache") - ap.add_argument( - "--paras-training-data-path", - default=None, - help="retrain PARAS on the fly from this file before parsing (NOT YET IMPLEMENTED -- raises if set)", - ) + ap.add_argument("--force-retrain", action="store_true", help="'paras_cli'-only: retrain from scratch even if a cached model exists") ap.add_argument("--workers", type=int, default=1) args = ap.parse_args() run( gbk_dir=args.gbk_dir, readouts_output_path=args.readouts_output, + pmp_path=args.pmp, paras_threshold=args.paras_threshold, paras_keep_top=args.paras_keep_top, paras_model_path=args.paras_model_path, paras_cache_dir=args.paras_cache_dir, - paras_training_data_path=args.paras_training_data_path, + force_retrain=args.force_retrain, workers=args.workers, ) diff --git a/docker-compose.yml b/docker-compose.yml index 2725a97..fffcc43 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -2,14 +2,25 @@ # and need the same Redis/DuckDB/PARAS access, now that discovery_query and # reconstruct_gene_cluster (among others) run as RQ jobs on worker too, not just on # backend. Kept in one place so the two services can't drift out of sync. +# +# PARAS_MODEL_PATH is "paras"-only (a pretrained model *file*). PARAS_CACHE_DIR is +# read by whichever NRPS model pmp.yml's predictors.nrps.a_domain actually selects +# (see retromol_antismash.inference.factory.build_nrps_a_domain_model) -- a download +# cache for "paras", or a trained-model + extracted-training-signatures cache for +# "paras_cli" (src/retromol_paras/). Mounted read-only here so containers pick up an +# already-trained model instead of each one training its own on first use -- run +# scripts/train_paras.py once (locally, or via `docker compose run backend ...`) to +# populate PARAS_CACHE_HOST_PATH, then restart backend/worker to pick it up. x-backend-env: &backend-common env_file: - gui/docker/backend.env environment: PARAS_MODEL_PATH: ${PARAS_MODEL_PATH} + PARAS_CACHE_DIR: ${PARAS_CACHE_DIR} RETROMOL_DUCKDB_PATH: /data/retromol.duckdb volumes: - ${PARAS_MODEL_HOST_PATH}:${PARAS_MODEL_PATH}:ro + - ${PARAS_CACHE_HOST_PATH}:${PARAS_CACHE_DIR}:ro - ${RETROMOL_DUCKDB_HOST_PATH}:/data/retromol.duckdb:ro services: diff --git a/environment.yml b/environment.yml new file mode 100644 index 0000000..9ed9754 --- /dev/null +++ b/environment.yml @@ -0,0 +1,75 @@ +# Single conda env for this repo: everything needed to run the database-construction +# Snakemake pipeline (database/Snakemake) AND retromol_paras (src/retromol_paras/, the +# self-contained PARAS reimplementation used by retromol_antismash's "paras_cli" +# DomainInferenceModel and selected via pmp.yml's predictors.nrps.a_domain: paras_cli). +# These two used to be separate env files (database/envs/retromol.yaml, +# envs/retromol_paras.yaml) -- consolidated here since there's no reason to keep two +# conda envs around for one repo. +# +# Snakemake / database pipeline: +# Every rule in database/Snakemake uses Snakemake's `run:` directive (inline Python +# that imports and calls database/scripts/*.py functions directly), not `shell:`. +# Snakemake executes `run:` blocks in its own process rather than a subprocess, so a +# per-rule `conda:` env (the --use-conda mechanism) would NOT actually reach any of +# this pipeline's own code -- only `shell()` calls made from *within* a `run:` block, +# which this pipeline never makes. There is deliberately no per-rule conda: directive +# in database/Snakemake, and no --use-conda flag in the invocation below, because of +# this. This env is instead the one Snakemake itself runs in, so it needs both +# Snakemake and every runtime dependency database/scripts/*.py imports (rdkit, +# duckdb, etc. -- all already listed in the repo's own pyproject.toml, pulled in by +# the editable install below rather than duplicated here). +# +# retromol_paras / PARAS CLI tools: +# None of these are pip-installable -- they're the command-line binaries +# retromol_paras shells out to instead of pyhmmer: +# - hmmpfam2 (legacy HMMER2) -> bioconda "hmmer2" +# - hmmscan, hmmpress (HMMER3) -> bioconda "hmmer" +# - muscle, MUSCLE v3 CLI syntax -> bioconda "muscle=3.8.1551" (pinned: bioconda's +# unpinned "muscle" resolves to MUSCLE v5 today, whose CLI is incompatible -- +# `-in1/-in2/-profile` is v3-only) +# +# Usage: +# +# conda env create -f environment.yml +# conda activate retromol +# pip install -e . +# snakemake -p -s database/Snakemake --configfile database/config.yaml \ +# --workflow-profile database/profiles/slurm +# +# --------------------------------------------------------------------------- +# Apple Silicon (arm64) note +# --------------------------------------------------------------------------- +# hmmer2 and muscle=3.8.1551 are old, low-traffic bioconda packages -- osx-arm64 +# builds may not exist for every build number, or may exist but not solve +# together with the rest of this environment's dependencies. If `conda env +# create` fails to solve, or the env solves but a binary immediately fails at +# runtime (segfault / "bad CPU type in executable"), force the whole +# environment onto the osx-64 (Intel) package set instead, which conda then +# runs through Rosetta 2 automatically: +# +# softwareupdate --install-rosetta # one-time, if not already installed +# CONDA_SUBDIR=osx-64 conda env create -f environment.yml -n retromol +# conda activate retromol +# conda config --env --set subdir osx-64 # pin osx-64 for this env so future +# # `conda install`/`conda update` in it +# # don't drift back to arm64 packages +# pip install -e . +# +# This makes the whole env (Python included) run under Rosetta, which is fine -- +# it's only these binaries retromol_paras invokes as subprocesses that need it, +# and there's no measurable performance concern for occasional HMMER/MUSCLE runs. +name: retromol + +channels: + - bioconda + - conda-forge + +dependencies: + - python=3.11 + - pip + - snakemake + - snakemake-executor-plugin-slurm + - mamba + - hmmer2 + - hmmer + - muscle=3.8.1551 diff --git a/gui/src/client/src/components/workspace/AnnotatedArrow.tsx b/gui/src/client/src/components/workspace/AnnotatedArrow.tsx new file mode 100644 index 0000000..012b3d7 --- /dev/null +++ b/gui/src/client/src/components/workspace/AnnotatedArrow.tsx @@ -0,0 +1,45 @@ +import React from "react"; +import Box from "@mui/material/Box"; +import Typography from "@mui/material/Typography"; + +// A labeled "->" used between stages of a structure/readout diagram (e.g. +// "structure -> Linearization -> primary sequence" for a compound, or +// "genes/domains -> Readout -> primary sequence" for a gene cluster). +export function AnnotatedArrow({ annotation }: { annotation: string }) { + return ( + + + {annotation} + + + {/* horizontal line */} + + {/* arrow head */} + + + + ); +} diff --git a/gui/src/client/src/components/workspace/ClusterReadoutDiagram.tsx b/gui/src/client/src/components/workspace/ClusterReadoutDiagram.tsx new file mode 100644 index 0000000..d477d21 --- /dev/null +++ b/gui/src/client/src/components/workspace/ClusterReadoutDiagram.tsx @@ -0,0 +1,377 @@ +import React from "react"; +import Box from "@mui/material/Box"; +import CircularProgress from "@mui/material/CircularProgress"; +import Chip from "@mui/material/Chip"; +import Stack from "@mui/material/Stack"; +import Tooltip from "@mui/material/Tooltip"; +import Typography from "@mui/material/Typography"; +import RestartAltIcon from "@mui/icons-material/RestartAlt"; +import { ClusterItem, Session, SessionItem } from "../../features/session/types"; +import type { ClusterModule, ClusterPrimarySequence } from "../../features/clusters/types"; +import { saveEditedClusterPrimarySequence, revertEditedClusterPrimarySequence } from "../../features/clusters/api"; +import type { PrimarySequenceItem } from "../../features/reconstruction/types"; +import { blocksFromSequence, sequenceFromBlocks, PrimarySequenceChips } from "./PrimarySequenceEditor"; +import { SequenceEditor, type SequenceBlock } from "./SequenceEditor"; +import { AnnotatedArrow } from "./AnnotatedArrow"; +import { MinimalIconButton } from "../MinimalIconButton"; +import { useNotifications } from "../NotificationProvider"; +import { horizontalScrollSx } from "../../theme/scrollbarSx"; + +// Mirrors the PKS extender-unit classification in retromol_antismash/modules.py +// (PKSModule.substrate) for the tooltip only -- the chip's own label comes from +// the region's resolved primary sequence (see ClusterReadoutDiagram), which +// already accounts for the specific extender digit/stereo suffix a module may +// have resolved (pmp.yml's "pks.extender"/"pks.kr_stereochemistry" axes), not +// just the reduction letter these anatomy flags alone can tell you. +function pksReductionLetter(anatomy: Extract["anatomy"]): string { + const KR = anatomy.has_active_KR; + const DH = anatomy.has_active_DH; + const ER = anatomy.has_active_ER; + const effDH = DH && KR; + const effER = ER && KR && DH; + + if (!KR) return "A"; + if (!effDH) return "B"; + if (!effER) return "C"; + return "D"; +} + +// A single gene/domain module box in the "genes & domains" row -- selectable the +// same way a SequenceEditor block or PrimarySequenceChips entry is, so clicking a +// readout token can highlight the module(s) it came from and vice versa. +function ModuleBox({ + module, + selected, + onClick, +}: { + module: ClusterModule; + selected: boolean; + onClick?: () => void; +}) { + const isNRPS = module.type === "NRPS"; + const substrateName = isNRPS ? module.predicted_substrate?.name ?? null : null; + const hasConfidentSubstrate = isNRPS && !!substrateName && substrateName !== "unknown"; + + const tooltipLines = [ + `${module.type} module ${module.module_index_in_gene + 1} in ${module.gene_id} (${module.gene_strand} strand)`, + `domains: ${module.present_domains.join(", ") || "none"}`, + !isNRPS ? `reduction level: PKS_${pksReductionLetter(module.anatomy)}` : null, + isNRPS && module.predicted_substrate?.score != null + ? `prediction confidence: ${(module.predicted_substrate.score * 100).toFixed(1)}%` + : null, + onClick ? "Click to highlight the matching readout token" : null, + ].filter(Boolean).join("\n"); + + return ( + {tooltipLines}} arrow> + + + {module.type} · {module.gene_id} + + + {isNRPS ? (hasConfidentSubstrate ? substrateName : "unknown") : `PKS_${pksReductionLetter(module.anatomy)}`} + + + + ); +} + +// The "genes & domains" row -- one selectable box per module, in the same +// biosynthetic order as the readout row below it (see ClusterPrimarySequence's +// index alignment, features/clusters/types.ts). +function ModulesRow({ + modules, + selectedIndices, + onToggleModule, +}: { + modules: ClusterModule[]; + selectedIndices: number[]; + onToggleModule?: (index: number) => void; +}) { + return ( + + {modules.map((module, idx) => ( + onToggleModule(idx) : undefined} + /> + ))} + + ); +} + +// Shared editing state machine for a gene cluster's per-region primary sequence -- +// mirrors PrimarySequenceEditor.tsx's usePrimarySequenceEditor, but keyed by +// region index against ClusterItem.editedPrimarySequences instead of +// CompoundItem.editedPrimarySequences. +export function useClusterPrimarySequenceEditor( + session: Session, + setSession: React.Dispatch>, + item: SessionItem, + data: ClusterPrimarySequence[] | null | undefined, + resetSignal?: unknown, +) { + const { pushNotification } = useNotifications(); + const [editing, setEditing] = React.useState(false); + const [drafts, setDrafts] = React.useState>({}); + const [saving, setSaving] = React.useState(false); + const [revertingIdx, setRevertingIdx] = React.useState(null); + + const savedSequenceFor = (idx: number, original: PrimarySequenceItem[]): PrimarySequenceItem[] => { + if (item.kind !== "cluster") return original; + return (item as ClusterItem).editedPrimarySequences?.[String(idx)] ?? original; + }; + + React.useEffect(() => { + if (!data) return; + const initial: Record = {}; + data.forEach((region, idx) => { + initial[idx] = blocksFromSequence(savedSequenceFor(idx, region.primary_sequence)); + }); + setDrafts(initial); + setEditing(false); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [data, item.id, resetSignal]); + + const isRowDirty = (idx: number, original: PrimarySequenceItem[]): boolean => { + const draft = drafts[idx]; + if (!draft) return false; + return JSON.stringify(sequenceFromBlocks(draft)) !== JSON.stringify(savedSequenceFor(idx, original)); + }; + + const anyDirty = (data ?? []).some((region, idx) => isRowDirty(idx, region.primary_sequence)); + + const handleCancelEdit = () => { + if (data) { + const initial: Record = {}; + data.forEach((region, idx) => { + initial[idx] = blocksFromSequence(savedSequenceFor(idx, region.primary_sequence)); + }); + setDrafts(initial); + } + setEditing(false); + }; + + const handleSaveAll = async () => { + if (item.kind !== "cluster" || !data) return; + + const dirtyIndices = data + .map((region, idx) => idx) + .filter((idx) => isRowDirty(idx, data[idx].primary_sequence)); + if (dirtyIndices.length === 0) return; + + setSaving(true); + try { + let nextSession = session; + for (const idx of dirtyIndices) { + nextSession = await saveEditedClusterPrimarySequence(nextSession, item.id, idx, sequenceFromBlocks(drafts[idx] ?? [])); + } + setSession(() => nextSession); + pushNotification("Saved edited primary sequence(s).", "success"); + setEditing(false); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + pushNotification(`Failed to save edited sequence(s): ${msg}`, "error"); + } finally { + setSaving(false); + } + }; + + const handleRevertRow = async (idx: number, original: PrimarySequenceItem[]) => { + setDrafts((prev) => ({ ...prev, [idx]: blocksFromSequence(original) })); + + if (item.kind !== "cluster" || !(item as ClusterItem).editedPrimarySequences?.[String(idx)]) return; + + setRevertingIdx(idx); + try { + const nextSession = await revertEditedClusterPrimarySequence(session, item.id, idx); + setSession(() => nextSession); + pushNotification("Reverted to the algorithm-parsed sequence.", "success"); + } catch (err) { + const msg = err instanceof Error ? err.message : String(err); + pushNotification(`Failed to revert sequence: ${msg}`, "error"); + } finally { + setRevertingIdx(null); + } + }; + + return { + editing, + setEditing, + drafts, + setDrafts, + saving, + revertingIdx, + anyDirty, + isRowDirty, + savedSequenceFor, + handleCancelEdit, + handleSaveAll, + handleRevertRow, + }; +} + +export type ClusterPrimarySequenceEditorState = ReturnType; + +// One region: a "genes & domains" row, an arrow, and the readout (primary +// sequence) row -- either read-only chips or, while editing, a live +// SequenceEditor. Clicking a chip on either row highlights its counterpart on +// the other, via `selectedIndices`/`onToggleIndex` (shared with the sibling row). +function RegionDiagram({ + item, + region, + regionIndex, + state, + selectedIndices, + onToggleIndex, +}: { + item: SessionItem; + region: ClusterPrimarySequence; + regionIndex: number; + state: ClusterPrimarySequenceEditorState; + selectedIndices: number[]; + onToggleIndex: (index: number) => void; +}) { + const { editing, drafts, setDrafts, revertingIdx, isRowDirty, savedSequenceFor, handleRevertRow } = state; + + const override = item.kind === "cluster" ? (item as ClusterItem).editedPrimarySequences?.[String(regionIndex)] : undefined; + const draftBlocks = drafts[regionIndex] ?? blocksFromSequence(override ?? region.primary_sequence); + const dirty = isRowDirty(regionIndex, region.primary_sequence); + + const onToggleMotif = (tags: number[]) => onToggleIndex(tags[0]); + + return ( + + + + {region.id} ({region.modules.length} module{region.modules.length === 1 ? "" : "s"}) + + {override && !editing && ( + + )} + + + {region.modules.length === 0 ? ( + + No NRPS/PKS modules were detected in this region. + + ) : ( + + + + + + + + + {editing ? ( + <> + + setDrafts((prev) => ({ ...prev, [regionIndex]: blocks }))} + showProvenance + selectedTags={selectedIndices} + onBlockClick={onToggleMotif} + /> + + + + handleRevertRow(regionIndex, region.primary_sequence)} + > + {revertingIdx === regionIndex ? : } + + + + + ) : ( + + + + )} + + + )} + + ); +} + +// Full "genes/domains -> readout" diagram for every region in a gene cluster, +// with click-to-highlight linking a readout token to the module(s) it came +// from. Wrap this in a ref and pass that ref to ExportImageButton to let a user +// download it as a PNG (see DialogViewItem.tsx for the pattern used for a +// compound's own structure/backbone/sequence diagram). +export function ClusterReadoutDiagram({ + item, + data, + state, +}: { + item: SessionItem; + data: ClusterPrimarySequence[]; + state: ClusterPrimarySequenceEditorState; +}) { + const [selectedIndices, setSelectedIndices] = React.useState([]); + + // Selection is per-region in spirit (a module index only makes sense within its + // own region), but since only one region's chips are ever clicked at a time in + // practice, a single shared selection list keeps the state simple; toggling + // clears cleanly per click regardless of which region it came from. + const handleToggleIndex = (index: number) => { + setSelectedIndices((prev) => (prev.includes(index) ? prev.filter((i) => i !== index) : [...prev, index])); + }; + + if (data.length === 0) { + return ( + + No antiSMASH regions were found in this file. + + ); + } + + return ( + + {data.map((region, idx) => ( + + ))} + + ); +} diff --git a/gui/src/client/src/components/workspace/DialogViewItem.tsx b/gui/src/client/src/components/workspace/DialogViewItem.tsx index b02a571..0954696 100644 --- a/gui/src/client/src/components/workspace/DialogViewItem.tsx +++ b/gui/src/client/src/components/workspace/DialogViewItem.tsx @@ -9,14 +9,15 @@ import InfoOutlinedIcon from "@mui/icons-material/InfoOutlined"; import { useQuery } from "@tanstack/react-query"; import { Session, SessionItem } from "../../features/session/types"; import { reconstructCompound } from "../../features/reconstruction/api"; -import { getClusterReadout } from "../../features/clusters/api"; +import { reconstructGeneCluster } from "../../features/clusters/api"; import { DialogWindow } from "../DialogWindow"; import { ErrorBoundary } from "../ErrorBoundary"; import { ExportImageButton } from "../ExportImageButton"; import SmilesDrawerContainer from "../SmilesDrawerContainer.js"; import { DrawingAttribution } from "../DrawingAttribution"; import { PrimarySequenceOverview, PrimarySequenceRows, usePrimarySequenceEditor } from "./PrimarySequenceEditor"; -import { ClusterReadoutRows } from "./ClusterReadoutRows"; +import { AnnotatedArrow } from "./AnnotatedArrow"; +import { ClusterReadoutDiagram, useClusterPrimarySequenceEditor } from "./ClusterReadoutDiagram"; type HighlightAtom = [number, string]; @@ -28,45 +29,6 @@ type DialogViewItemProps = { onClose: () => void; }; -function AnnotatedArrow({ annotation }: { annotation: string }) { - return ( - - - {annotation} - - - {/* horizontal line */} - - {/* arrow head */} - - - - ); -}; - function DescriptionBox({ title, description }: { title: string; description: string }) { return ( @@ -147,24 +109,36 @@ export const DialogViewItem: React.FC = ({ const allHaveBackbone = hasReconstructions && !isUnordered && (data ?? []).every((r) => !!r.tagged_backbone_smiles); const backboneWarning = (data ?? []).find((r) => r.backbone_warning)?.backbone_warning ?? null; - const clusterReadoutQuery = useQuery({ - queryKey: ["getClusterReadout", sessionId, item.id], - queryFn: ({ signal }) => getClusterReadout(sessionId, item.id, signal), + const clusterReconstructionQuery = useQuery({ + queryKey: ["reconstructGeneCluster", sessionId, item.id], + queryFn: ({ signal }) => reconstructGeneCluster(sessionId, item.id, signal), enabled: open && !isCompound && item.status === "done", }); + const clusterData = clusterReconstructionQuery.data ?? null; // resetSignal is `open` -- re-seeding on every open (even for the same item) // matches the dialog's existing "fresh state each time" behavior for selectedTags. const editor = usePrimarySequenceEditor(session, setSession, item, data, open); const { editing, setEditing, anyDirty, saving, handleCancelEdit, handleSaveAll } = editor; + const clusterEditor = useClusterPrimarySequenceEditor(session, setSession, item, clusterData, open); + const { + editing: clusterEditing, + setEditing: setClusterEditing, + anyDirty: clusterAnyDirty, + saving: clusterSaving, + handleCancelEdit: handleClusterCancelEdit, + handleSaveAll: handleClusterSaveAll, + } = clusterEditor; + const clusterDiagramRef = React.useRef(null); + return ( = ({ }, ] : []), + ...(item.kind === "cluster" && clusterEditing + ? [ + { key: "cancel-cluster-edit", label: "Cancel", variant: "text" as const, color: "inherit" as const, onClick: handleClusterCancelEdit }, + { + key: "save-cluster", + label: clusterSaving ? "Saving..." : "Save changes", + variant: "contained" as const, + color: "primary" as const, + onClick: handleClusterSaveAll, + disabled: !clusterAnyDirty || clusterSaving, + startIcon: clusterSaving ? : undefined, + }, + ] + : []), + ...(item.kind === "cluster" && !clusterEditing + ? [ + { + key: "edit-cluster", + label: "Edit sequences", + variant: "contained" as const, + color: "primary" as const, + onClick: () => setClusterEditing(true), + disabled: clusterReconstructionQuery.isLoading || !clusterData || clusterData.length === 0, + }, + ] + : []), { key: "close", label: "Close", variant: "text" as const, color: "inherit" as const, onClick: onClose }, ]} maxWidth={"lg"} > {!isCompound && item.kind === "cluster" && ( - <> + {item.status === "queued" && ( Waiting to be parsed... @@ -212,18 +212,33 @@ export const DialogViewItem: React.FC = ({ )} - {item.status === "done" && clusterReadoutQuery.isLoading && } + {item.status === "done" && clusterReconstructionQuery.isLoading && } - {item.status === "done" && clusterReadoutQuery.error && ( + {item.status === "done" && clusterReconstructionQuery.error && ( - {(clusterReadoutQuery.error as Error).message || "Failed to load parsed gene cluster."} + {(clusterReconstructionQuery.error as Error).message || "Failed to load parsed gene cluster."} )} - {item.status === "done" && clusterReadoutQuery.data && ( - + {item.status === "done" && clusterData && ( + <> + + + + + + + + )} - + )} {loading && ( diff --git a/gui/src/client/src/components/workspace/WorkspaceDiscovery.tsx b/gui/src/client/src/components/workspace/WorkspaceDiscovery.tsx index 1288e21..8a160b0 100644 --- a/gui/src/client/src/components/workspace/WorkspaceDiscovery.tsx +++ b/gui/src/client/src/components/workspace/WorkspaceDiscovery.tsx @@ -704,12 +704,12 @@ export const WorkspaceDiscovery: React.FC = ({ session, {region.id} - + name)} /> + + + ) : ( + + )} + + )} + )} diff --git a/gui/src/server/app.py b/gui/src/server/app.py index bcaa7ed..cb6380c 100644 --- a/gui/src/server/app.py +++ b/gui/src/server/app.py @@ -26,6 +26,7 @@ blp_submit_gene_cluster, blp_get_cluster_readout, blp_reconstruct_gene_cluster, + check_paras_model_cache, ) from routes.events import blp_events, blp_sse_ticket from routes.discovery import ( @@ -274,3 +275,11 @@ def ready() -> tuple[dict[str, str], int]: app.logger.info("Discovery context warmed successfully") except Exception: app.logger.exception("Failed to warm discovery context at startup; will build lazily on first request") + +# Surface whether the PARAS substrate model has a pretrained cache to load, since a +# missing one is otherwise a silent 10+ minute delay (and likely a job timeout) on +# the first cluster upload rather than an obvious startup error. +try: + check_paras_model_cache() +except Exception: + app.logger.exception("Failed to check PARAS model cache at startup") diff --git a/gui/src/server/routes/jobs.py b/gui/src/server/routes/jobs.py index 94bfd9c..6b7805f 100644 --- a/gui/src/server/routes/jobs.py +++ b/gui/src/server/routes/jobs.py @@ -47,7 +47,7 @@ DEFAULT_LIMIT = 10 MAX_LIMIT = 50 -# PARAS' own default (retromol_antismash.inference.model_paras.ParasModel.threshold) -- +# PARAS' own default (retromol_antismash.inference.model_paras_cli.ParasCliModel.threshold) -- # repeated here since submit_gene_cluster now builds the NRPS model explicitly (see # _build_nrps_model) rather than relying on the model's own constructor default. PARAS_THRESHOLD_DEFAULT = 0.1 @@ -76,11 +76,43 @@ def _build_nrps_model(threshold: float): return build_nrps_a_domain_model( PredictionConfig.load_from_file(os.getenv("PMP_PATH")) if os.getenv("PMP_PATH") else PredictionConfig.load_default(), threshold=threshold, - model_path=os.getenv("PARAS_MODEL_PATH"), cache_dir=os.getenv("PARAS_CACHE_DIR", "paras_cache"), ) +def check_paras_model_cache() -> None: + """ + Log, at startup, whether a pretrained "paras_cli" model is already cached at + PARAS_CACHE_DIR -- otherwise the first cluster upload silently pays the full + from-scratch training cost (HMMER2/HMMER3/MUSCLE3 extraction over the whole + PARASECT dataset + a RandomForestClassifier fit -- see + retromol_paras.train.train_model), which is slow enough to blow past the RQ job + timeout. Doesn't build or train anything itself. + """ + from retromol_paras.train import MODEL_FILE + + model = _build_nrps_model(PARAS_THRESHOLD_DEFAULT) + if model is None: + logger.info("PARAS model cache check: skipped (pmp.yml's nrps.a_domain reads antiSMASH's own qualifier, no model needed)") + return + + cache_dir = getattr(model, "cache_dir", None) + if cache_dir is None: + logger.info("PARAS model cache check: skipped (selected model has no cache_dir)") + return + + model_file = Path(cache_dir) / MODEL_FILE + if model_file.exists(): + logger.info("PARAS model cache: found trained model at %s -- cluster uploads will use it directly", model_file) + else: + logger.warning( + "PARAS model cache: NO trained model found at %s -- the first cluster " + "upload will train one from scratch (slow, likely to exceed the job " + "timeout). Run scripts/train_paras.py --cache-dir %s once to pre-populate it.", + model_file, cache_dir, + ) + + @blp_search_compound.get("/api/searchCompound") def search_compound_by_name(): """ diff --git a/pyproject.toml b/pyproject.toml index 4632a35..0a661aa 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -74,7 +74,6 @@ include = [ "src/retromol/data/mxn.yml", "src/retromol/data/rxn.yml", "src/retromol/data/pmp.yml", - "src/retromol_antismash/data/AMP-binding_converted.hmm", "src/retromol_paras/data/*.hmm", "src/retromol_paras/data/*.txt", "src/retromol_paras/data/*.fasta", diff --git a/scripts/predict_bgc.py b/scripts/predict_bgc.py index 5590be8..58c1368 100755 --- a/scripts/predict_bgc.py +++ b/scripts/predict_bgc.py @@ -15,9 +15,9 @@ # antiSMASH's own qualifier fallback without downloading/running/training a model): python scripts/predict_bgc.py path/to/cluster.gbk --no-nrps-model - # Point at a custom PARAS model file instead of the packaged default: + # Point at an already-trained model cache instead of training fresh: python scripts/predict_bgc.py path/to/cluster.gbk \\ - --paras-model-path /path/to/all_substrates_model.paras + --paras-cache-dir /path/to/paras_cache # Try edits to pmp.yml/mxn.yml before committing them: python scripts/predict_bgc.py path/to/cluster.gbk \\ @@ -74,8 +74,7 @@ def build_arg_parser() -> argparse.ArgumentParser: nrps = parser.add_argument_group("NRPS model (used when pmp.yml selects a source: model method for nrps.a_domain, e.g. paras/paras_cli)") nrps.add_argument("--no-nrps-model", "--no-paras", dest="no_nrps_model", action="store_true", help="don't register/run any NRPS model, even if pmp.yml selects one") - nrps.add_argument("--paras-model-path", type=Path, default=None, help="'paras'-only: path to a custom PARAS model file (default: download/cache the packaged model)") - nrps.add_argument("--paras-cache-dir", type=Path, default=None, help="cache directory for whichever model pmp.yml selects (download cache for 'paras', training+model cache for 'paras_cli')") + nrps.add_argument("--paras-cache-dir", type=Path, default=None, help="training-signature + fitted-model cache directory for 'paras_cli' (see retromol_paras.train.train_model)") nrps.add_argument("--paras-threshold", type=float, default=0.1, help="probability threshold (default: 0.1)") nrps.add_argument("--paras-keep-top", type=int, default=3, help="number of top predictions to keep per domain (default: 3)") nrps.add_argument("--force-retrain", action="store_true", help="'paras_cli'-only: retrain from scratch even if a cached model exists") @@ -103,7 +102,6 @@ def _maybe_register_nrps_model(config: PredictionConfig, args: argparse.Namespac threshold=args.paras_threshold, keep_top=args.paras_keep_top, cache_dir=args.paras_cache_dir, - model_path=args.paras_model_path, force_retrain=args.force_retrain, ) if model is None: diff --git a/src/retromol/data/pmp.yml b/src/retromol/data/pmp.yml index a9d71b1..c829588 100644 --- a/src/retromol/data/pmp.yml +++ b/src/retromol/data/pmp.yml @@ -24,7 +24,7 @@ predictors: starter: antismash kr_stereochemistry: antismash nrps: - a_domain: paras + a_domain: paras_cli # --------------------------------------------------------------------------- # methods: every prediction method available for each axis, keyed by name. @@ -212,27 +212,17 @@ methods: combine_with: null mapping: {} - # RetroMol's own model: PARAS (retromol_antismash/inference/ - # model_paras.py) runs ML inference on the A domain's sequence to - # predict a substrate class label. By default (empty mapping) an - # unmapped label falls back to PARAS' own label->SMILES table plus - # structural matching against mxn.yml -- add an entry here only to - # force a specific label onto a specific mxn.yml name, e.g. after - # renaming something in mxn.yml. - paras: - source: model - model: paras - combine_with: null - mapping: {} - - # Self-contained reimplementation of PARAS (retromol_paras/, see its - # module docstring): same idea as "paras" above (predicted label -> - # PARAS' own label->SMILES table -> structural match against mxn.yml), - # but domain extraction runs via command-line HMMER2/HMMER3/MUSCLE3 - # instead of pyhmmer, and the RandomForestClassifier is trained (and - # cached) locally against this repo's pinned scikit-learn version - # instead of unpickling a model file built under someone else's - # sklearn. Requires hmmpfam2/hmmscan/hmmpress/muscle(v3) on PATH. + # RetroMol's own model: PARAS, reimplemented from scratch in + # retromol_paras/ (see its module docstring) -- domain extraction runs + # via command-line HMMER2/HMMER3/MUSCLE3 (no pyhmmer, no pretrained + # model file to unpickle), and the RandomForestClassifier is trained + # and cached locally, against this repo's own pinned scikit-learn + # version. Requires hmmpfam2/hmmscan/hmmpress/muscle(v3) on PATH -- + # see environment.yml (repo root). By default (empty mapping) an + # unmapped predicted label falls back to PARAS' own label->SMILES + # table plus structural matching against mxn.yml -- add an entry here + # only to force a specific label onto a specific mxn.yml name, e.g. + # after renaming something in mxn.yml. paras_cli: source: model model: paras_cli diff --git a/src/retromol_antismash/data/AMP-binding_converted.hmm b/src/retromol_antismash/data/AMP-binding_converted.hmm deleted file mode 100644 index d3b5e7a..0000000 --- a/src/retromol_antismash/data/AMP-binding_converted.hmm +++ /dev/null @@ -1,690 +0,0 @@ -HMMER3/f [3.4 | Aug 2023] -NAME AMP-binding -LENG 166 -ALPH amino -RF no -MM no -CONS yes -CS no -MAP yes -DATE Mon Feb 23 10:56:16 2004 -COM [1] hmmbuild aa-activating-core.198-334.hmm aa-activating-core.198-334.aln -COM [2] hmmcalibrate aa-activating-core.198-334.hmm -NSEQ 201 -STATS LOCAL MSV -9.0550 0.70049 -STATS LOCAL VITERBI -9.8471 0.70049 -STATS LOCAL FORWARD -6.0470 0.70049 -HMM A C D E F G H I K L M N P Q R S T V W Y - m->m m->i m->d i->m i->i d->m d->d - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01026 * 4.58503 0.00000 * 0.00000 * - 1 9.62963 10.04414 9.51457 9.52705 10.17930 8.61279 10.03027 10.56885 0.00113 9.59220 10.93899 9.87778 9.23385 9.85699 9.15067 10.02889 9.95957 10.24515 10.42606 10.37962 1 K - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 2 2.49805 4.65097 8.61924 8.68647 8.81401 0.18502 8.98037 8.34891 8.48130 2.65956 8.75163 7.63012 7.52268 8.47160 8.33643 6.13708 6.52039 7.31889 10.15317 9.21465 2 G - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 3 3.65808 7.86410 8.92253 8.57804 7.58892 8.22384 9.73074 2.16574 8.61478 5.90596 7.22155 3.71076 8.58844 8.96690 8.85461 7.74141 3.98871 0.21037 9.98444 8.67092 3 V - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 4 2.84536 6.78312 7.37022 3.13301 4.26145 4.83746 6.91066 2.82248 4.98510 2.11963 1.06327 6.73876 2.43293 2.41352 6.54884 5.88827 5.00451 1.93317 7.40488 4.94143 4 m - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 5 3.92938 6.78238 7.38472 6.76851 4.35151 3.34229 6.91477 1.22056 3.59321 2.84322 3.01304 4.30299 6.94388 6.67979 2.68172 5.89168 3.07473 1.01470 7.40482 6.22855 5 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 6 3.58555 7.73681 3.98965 0.97932 7.08317 4.00698 6.18139 6.57024 4.91708 6.04276 6.77818 4.42010 2.50147 4.03055 2.73506 2.19510 1.40421 6.12871 8.16864 4.77776 6 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 7 4.90653 9.71420 5.00703 5.68285 8.80825 3.71293 0.16263 8.72508 6.89794 8.10679 9.11740 4.52322 7.58208 2.66212 7.68882 6.69138 7.26739 8.18581 10.09820 3.79333 7 H - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 8 2.27964 7.72154 2.42936 4.40552 4.48731 2.79465 3.28332 4.96489 2.70662 4.40413 6.76222 3.24727 6.37544 2.36212 0.97236 3.64791 3.70128 4.12341 8.15337 3.92656 8 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 9 1.99069 5.11955 2.61313 4.08884 7.38545 1.52697 6.45247 6.88153 5.22976 6.35266 7.09779 1.34883 4.04656 3.35480 5.73784 1.55054 4.70713 6.42821 8.47993 7.05343 9 n - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 10 2.55004 6.83577 7.44643 6.83092 3.84831 6.64100 6.97440 1.48398 6.61258 1.42853 3.98763 6.80805 6.99936 4.71544 6.61397 5.95340 5.69762 1.23029 4.64404 2.41627 10 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 11 1.62044 3.64304 4.27519 6.75111 3.66730 4.75554 4.27866 2.39260 6.53693 2.36765 3.70127 4.27450 6.94034 4.28212 4.68969 2.61372 2.72185 1.15880 7.40475 4.57394 11 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 12 2.73589 7.71199 5.46273 3.38190 4.85831 4.24071 3.08108 6.53641 4.90891 4.12149 6.75406 0.89142 6.37907 4.13397 1.84312 2.21048 3.56697 6.10112 8.14660 2.58132 12 n - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 13 3.10874 3.91001 7.35634 6.74221 2.25894 3.95784 4.77714 5.21590 6.53011 0.97176 4.13390 3.62582 6.93907 4.84992 3.15518 2.64571 2.37816 2.99298 7.40625 2.22844 13 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 14 2.34429 3.31955 7.38763 6.77142 2.67839 4.75644 3.91150 2.47322 4.94082 1.50905 4.14023 6.74647 6.94332 3.69038 3.75138 3.38470 2.93970 1.25674 4.62474 4.75298 14 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 15 2.56467 5.35251 2.60765 3.23772 3.60232 4.31210 3.43873 3.53785 1.96787 2.32277 4.43063 2.65686 4.28645 2.73034 2.73588 2.89323 2.34495 3.12751 4.91028 3.28485 15 k - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 16 1.76057 4.11380 2.11130 3.07478 3.35827 3.14409 3.49274 6.55507 3.87051 6.02758 6.76232 2.51957 4.19074 3.44769 4.04796 2.62284 3.91556 3.55235 1.41469 6.74222 16 w - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 17 2.88288 4.60397 4.42444 4.30591 2.60216 6.31535 2.44065 3.05755 4.62199 1.90832 2.33322 3.61900 3.72644 3.26619 3.13449 2.11349 2.10170 3.93300 3.27728 4.56307 17 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.06801 8.15565 2.72623 0.61948 0.77267 0.48579 0.95505 - 18 2.02815 3.73260 3.57318 2.86547 3.92044 2.61247 4.81114 2.58614 2.84607 3.57526 4.73351 1.97755 6.31596 2.47038 2.09261 2.84260 3.51773 3.10045 8.08002 5.02879 18 n - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.04815 8.08865 3.06403 0.61948 0.77267 2.15850 0.12273 - 19 2.88202 5.06474 2.23462 1.54771 5.08484 3.42684 3.40881 6.44757 2.32750 4.42150 5.06266 3.06085 4.10057 2.55486 2.10431 3.14264 3.91966 3.92729 8.04597 2.49386 19 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 1.23585 8.04048 0.34377 0.61948 0.77267 2.59059 0.07794 - 20 2.16806 6.14603 2.76763 2.29214 5.35585 3.69922 3.49059 3.18768 3.95222 2.46819 3.32908 4.46862 5.29623 4.29602 1.27252 4.11719 2.57147 2.66366 6.66867 5.35792 20 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.34135 6.80633 1.24452 0.61948 0.77267 2.77981 0.06406 - 21 3.13720 5.41350 6.01376 5.39755 2.43227 5.21110 5.54450 2.03995 5.17991 3.03947 4.53251 5.37607 3.28969 3.56834 5.18476 4.52211 2.99372 2.44336 2.78716 0.99815 21 y - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00192 6.65197 7.37493 0.61948 0.77267 0.96446 0.47995 - 22 2.42942 4.28220 3.09137 3.29446 1.92481 2.70598 3.17663 2.52438 4.19209 3.09137 4.18585 2.31505 5.98873 3.68817 4.07426 3.54053 3.75610 3.35546 2.72331 2.21593 22 f - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00083 7.49306 8.21531 0.61948 0.77267 0.02287 3.78943 - 23 2.28104 7.69729 2.48067 2.36283 3.71447 2.72535 3.25214 2.80714 3.80735 2.12300 4.28701 4.05688 3.48989 2.83902 2.25470 3.24244 3.56960 2.45225 8.13536 4.59338 23 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.05512 8.14970 2.93099 0.61948 0.77267 0.33173 1.26471 - 24 3.60168 2.51621 3.34730 4.72666 1.40025 4.23314 3.56564 2.72347 4.82925 2.41779 2.86972 4.01411 3.45820 3.79715 4.95817 3.26412 3.34522 2.87734 4.58457 2.11904 24 f - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00045 8.10126 8.82352 0.61948 0.77267 0.08938 2.45925 - 25 2.28873 4.65791 3.02000 3.13784 7.06798 1.56716 4.57126 6.55505 3.59809 4.01675 3.97446 2.99089 2.35943 3.21200 2.56044 2.14178 2.44954 3.23696 5.29768 6.74220 25 g - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.34333 8.15580 1.23680 0.61948 0.77267 0.48579 0.95505 - 26 2.71022 4.25594 3.26751 2.10302 2.72755 2.60694 3.32851 2.66239 2.93272 2.11134 3.90382 3.97383 2.46208 4.27327 3.23008 3.44426 2.54387 3.00134 7.78337 6.39153 26 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.10235 7.81292 2.33428 0.61948 0.77267 3.49180 0.03092 - 27 2.50207 7.30904 2.03211 2.01063 3.73240 2.51454 3.37405 4.60785 3.87935 3.07807 4.51081 2.46949 3.75805 2.42582 3.45445 2.48959 2.21441 5.70094 7.74087 6.32893 27 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00067 7.71123 8.43349 0.61948 0.77267 3.69469 0.02517 - 28 2.81335 7.30910 1.46171 3.00535 3.33529 2.79394 3.69434 6.14254 3.60631 5.61505 6.34979 3.76851 1.76878 2.30943 2.71631 2.40093 3.25766 4.48869 7.74094 6.32899 28 d - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 1.70184 7.71142 0.20187 0.61948 0.77267 3.69469 0.02517 - 29 1.91507 5.89997 1.76951 3.13154 5.23109 4.20384 2.40859 4.70707 2.40166 2.67684 4.94482 3.67636 4.59686 3.49337 2.76140 2.68308 2.29561 4.28355 6.34151 3.30968 29 d - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 1.61022 6.01309 0.22601 0.61948 0.77267 1.18301 0.36579 - 30 2.79058 5.64149 3.69514 5.60060 2.91951 3.67989 3.57037 2.89871 3.65494 0.98770 2.92505 5.59020 5.79607 5.52158 5.40097 3.69444 3.40887 1.68154 6.26255 3.47610 30 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 2.95139 6.91619 0.05473 0.61948 0.77267 3.16174 0.04327 - 31 2.87170 4.79934 3.47682 2.95557 3.98698 3.73883 2.25272 3.40958 2.91190 1.83059 3.94539 3.41236 2.47661 3.26610 3.30838 1.98655 3.12331 3.14203 5.37050 4.07916 31 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01160 4.85877 5.58103 0.61948 0.77267 1.13451 0.38799 - 32 2.67681 6.75390 1.96702 3.10656 6.10026 1.59619 5.20056 3.84615 3.03516 5.05985 5.79458 2.58878 2.92149 3.49611 3.09478 2.06822 2.15833 5.14580 7.18573 5.77379 32 g - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00125 7.08313 7.80539 0.61948 0.77267 2.17385 0.12074 - 33 1.92122 6.90772 2.92005 1.53306 6.25478 2.80498 3.20562 5.74115 3.20424 5.21436 5.94910 3.85579 2.78488 2.29968 3.09472 2.66497 2.36483 3.42327 7.34024 5.92830 33 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00104 7.26245 7.98471 0.61948 0.77267 0.71487 0.67189 - 34 2.28816 4.33849 2.40392 2.55987 6.73193 2.27984 3.06587 6.21900 3.46998 5.69151 6.42625 2.67494 2.44135 2.27846 2.56265 2.14329 2.63543 5.77746 7.81740 6.40546 34 s - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01438 7.79357 4.27862 0.61948 0.77267 0.87005 0.54288 - 35 2.85298 7.50885 1.12705 2.55354 4.30166 4.26493 3.83795 4.55605 4.11243 2.27906 6.55162 3.94469 3.34443 3.66397 5.20761 2.25618 2.36432 2.60553 7.94623 6.53914 35 d - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00053 7.94607 8.66833 0.61948 0.77267 0.07814 2.58803 - 36 2.37129 5.15844 3.55588 4.89851 7.04241 4.32874 4.37588 3.39022 2.54042 6.00477 5.12933 2.94661 3.63768 3.33269 0.92331 4.43202 2.61320 2.12939 8.13689 6.72842 36 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14560 8.86856 0.61948 0.77267 0.97393 0.47417 - 37 3.06217 6.77189 7.37909 6.76288 2.56449 4.86920 4.62591 1.95729 6.54384 2.29208 2.44249 6.73793 6.93409 6.67138 6.54592 2.77035 3.03028 1.20107 2.79808 3.04553 37 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14560 8.86856 0.61948 0.77267 0.26948 1.44298 - 38 1.64327 6.78296 7.39016 6.77395 4.59539 3.94175 6.91674 3.18969 6.55492 0.59870 3.04066 6.74900 4.80888 6.68315 6.55769 3.49536 2.80915 3.57022 7.40541 6.22983 38 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 39 2.27216 3.82828 7.10686 6.50798 2.93065 3.77144 2.26523 4.06741 4.33912 1.87291 2.55982 3.11017 4.97405 1.27819 6.44213 2.85440 4.67461 3.49279 7.43264 6.25013 39 q - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 40 3.43103 6.78517 7.35009 6.73665 1.48190 4.94279 2.95831 3.25220 2.67273 1.72797 3.40954 4.56710 6.93836 2.73858 6.54118 3.69997 2.90701 1.86313 7.40623 3.04980 40 f - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 41 1.32527 6.78519 7.34872 6.73459 3.30213 3.25014 3.16350 3.94190 6.52457 2.55076 5.90490 3.92319 3.23281 6.65973 6.54051 1.20328 2.28043 3.33193 4.63159 6.23068 41 s - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 42 2.36358 7.86994 7.21699 4.65582 8.57210 3.03801 8.21929 8.09591 7.30849 4.89564 8.45010 1.81391 1.56438 7.48178 7.61555 0.96481 2.48973 7.21353 9.84125 8.67538 42 s - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 4.80339 2.61166 0.08514 0.01822 4.01422 0.48579 0.95505 - 43 0.38524 5.76960 3.99307 2.35724 6.12935 2.34892 5.51106 5.63375 4.62591 5.23727 6.05172 4.35628 5.04527 4.74929 5.07022 3.83018 4.22181 4.92466 7.38464 6.08915 44 A - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00523 5.65092 6.37318 0.61948 0.77267 0.01609 4.13754 - 44 3.79924 3.57674 7.38073 6.76452 1.68306 6.57252 2.37343 1.78634 6.54479 1.82931 4.13611 6.73957 3.26274 6.67302 6.54756 5.88353 4.59358 3.67516 7.39528 1.42313 45 y - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14630 8.86856 0.61948 0.77267 0.27476 1.42608 - 45 1.37864 4.05835 4.75496 4.56296 3.89130 2.64294 3.85179 4.03201 6.10244 5.06341 4.46315 2.45926 6.84480 6.32840 6.29583 1.17901 3.01516 2.27211 4.67248 6.28335 46 s - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 46 8.41995 4.72409 9.02369 9.09924 0.07446 8.68820 4.06907 7.92089 8.85248 5.35832 8.39361 8.13299 8.91486 8.34995 8.54888 8.11358 8.58700 7.90009 4.82599 3.50693 47 F - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 47 4.62462 9.30128 0.14203 3.50241 9.04135 4.59481 7.65852 4.64610 7.00835 8.11946 9.08224 6.33738 3.13227 6.87041 7.83666 4.84781 4.16229 8.05916 10.26891 8.59219 48 D - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 48 1.26834 5.34890 4.63149 6.77124 2.46541 2.96170 3.88636 2.84386 6.55220 1.61076 2.73504 6.74698 3.02616 6.68043 6.55497 4.54208 3.71376 2.12438 7.40269 4.26343 49 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 49 2.58206 3.14212 7.38765 6.77144 1.98110 3.07489 4.78488 3.33482 6.55310 4.45078 4.11807 6.74718 6.94403 6.68133 6.55656 0.57262 3.60722 3.75486 7.40498 6.22940 50 S - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 50 2.97135 3.61528 7.38808 6.77187 5.87286 4.50736 6.91397 2.09590 6.55284 2.67745 3.96047 6.74692 6.94308 3.75183 6.55561 2.45426 2.28513 0.88082 3.77055 3.19731 51 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 51 3.05469 7.59272 5.53546 2.36708 2.14320 3.23698 6.21682 6.33189 3.39294 2.70257 3.04983 4.43266 2.66791 2.60761 3.09142 3.93013 2.63187 4.84716 1.62680 2.99785 52 w - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00413 8.15554 5.56455 0.61948 0.77267 0.48579 0.95505 - 52 3.50838 5.06103 1.61262 0.81135 7.10374 2.59897 6.19987 6.59150 4.53355 6.06402 6.80014 5.46999 4.53840 2.22606 5.43395 2.62531 4.57098 6.14997 8.19059 4.20361 53 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01011 8.15181 4.62855 0.61948 0.77267 0.37006 1.17342 - 53 3.89206 6.80328 7.41394 6.79843 2.57161 6.60781 6.94329 1.03491 6.58078 1.45565 1.99492 6.77486 6.96894 6.70762 6.58286 4.27745 3.38329 2.27287 4.22130 6.25430 54 i - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14560 8.86786 0.61948 0.77267 0.26834 1.44669 - 54 2.83515 3.88042 7.38844 6.77223 0.78690 6.58023 6.91432 3.53662 6.55319 2.07130 3.98231 4.77735 6.94344 6.68143 5.30622 5.89193 3.29055 3.66346 2.52670 2.08031 55 f - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 55 2.31866 6.79985 3.90042 6.61755 5.89460 1.42242 6.88095 4.01548 6.43248 2.48986 3.17261 6.66885 2.18557 6.59052 3.24539 2.57373 1.80157 3.33065 2.87317 6.23979 56 g - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.02411 8.15542 3.74909 0.61948 0.77267 0.48579 0.95505 - 56 1.16810 4.03288 7.35860 6.74239 5.85101 3.99337 6.89003 3.83187 6.52474 3.86791 4.58463 6.72090 1.48279 4.53818 6.53029 2.32774 1.80510 2.88434 3.91089 4.22142 57 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00044 8.13175 8.85401 0.61948 0.77267 0.16372 1.89035 - 57 5.04485 6.88031 7.49374 6.87753 3.13315 6.68969 7.02309 2.85936 6.66058 0.24827 4.13128 6.85743 4.56034 6.77911 6.66058 5.32142 4.12297 3.31060 4.06613 6.32856 58 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 58 2.18406 4.95457 7.38821 6.77200 3.13159 4.72167 4.50194 2.53756 6.55297 0.68686 4.86377 6.74705 6.94321 4.89981 4.61701 3.11426 3.07475 2.71016 5.14172 3.19051 59 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 59 1.77028 3.69307 4.45899 4.50821 4.00360 3.06438 3.08379 4.71546 4.27878 2.82733 4.21015 1.56372 6.60844 4.61634 5.79469 1.59768 2.74138 3.03596 7.72441 3.33194 60 n - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 60 4.28938 8.17031 6.66271 5.29236 8.90435 0.05286 8.15229 8.43162 5.39425 7.98801 8.79275 6.97532 7.54509 7.41062 5.44208 4.06410 6.71539 7.53123 10.05775 8.86761 61 G - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01313 8.15553 4.36193 0.61948 0.77267 0.48579 0.95505 - 61 1.05269 4.74231 6.54727 6.21109 8.17062 0.86346 2.70238 7.66462 4.29246 7.19536 7.94812 3.19174 7.18358 3.03024 6.60896 3.22363 6.26169 6.99296 9.30669 8.01674 62 g - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14283 8.86509 0.61948 0.77267 0.23521 1.56258 - 62 2.65207 2.90784 5.46971 2.87665 7.07712 4.66012 6.17811 6.56281 2.23688 4.56100 6.77144 5.46070 6.38605 2.47878 2.08716 2.38521 0.98713 6.12266 8.16120 6.75204 63 t - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.04496 8.15548 3.13085 0.61948 0.77267 0.48579 0.95505 - 63 3.69422 5.08121 7.79350 7.20571 6.25956 7.03381 7.42405 3.00316 7.01371 0.43227 3.98049 7.20502 7.37276 7.15511 7.03450 4.16071 4.10387 1.56349 7.88707 6.70803 64 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00045 8.11096 8.83322 0.61948 0.77267 0.10446 2.31075 - 64 3.08442 3.12254 7.38817 6.77196 3.47189 6.57996 2.19511 2.59228 5.03077 3.19047 5.90067 4.49428 6.94317 6.68116 6.55570 5.06682 4.77500 0.67989 7.40342 2.27759 65 V - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 65 3.68893 2.56326 7.39103 6.77482 4.11175 6.58282 5.39753 1.26915 6.55578 1.40362 3.09421 6.75056 3.42900 6.68402 6.55856 4.65171 4.94006 1.40709 7.40628 6.23070 66 i - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 66 1.88876 3.11216 7.38888 6.77267 5.87297 3.54815 6.91477 1.83400 6.55364 1.99135 4.71541 6.74772 1.72587 6.68187 6.55641 3.05186 3.78452 1.63784 7.40413 4.11307 67 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.14946 8.15531 1.97660 0.61948 0.77267 0.48579 0.95505 - 67 2.64084 7.58229 1.53874 2.58886 6.92934 4.32588 4.94070 6.41572 3.13852 4.09507 6.62367 3.31666 1.35852 3.47678 2.49805 2.69976 2.70045 4.45966 8.01481 6.60287 68 p - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00050 8.00634 8.72930 0.61948 0.77267 2.80388 0.06249 - 68 3.14618 7.58301 1.80840 2.09259 6.92937 3.58078 3.75684 6.41575 1.64551 4.33007 6.62370 3.65079 2.21459 2.69009 2.74484 3.00200 5.29978 5.97491 8.01484 2.48769 69 k - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.43773 8.00620 1.03799 0.61948 0.77267 2.80388 0.06249 - 69 2.33298 7.17947 2.23040 1.30158 6.52583 2.12157 3.52173 3.96396 3.36646 3.44132 6.22084 3.50301 2.53746 3.81632 4.85465 2.71491 3.42677 3.12178 7.61199 6.20074 70 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 2.98050 7.56983 0.05264 0.61948 0.77267 3.89796 0.02049 - 70 2.99871 4.70316 4.19855 3.85128 1.24782 3.79652 4.25608 3.47421 3.82009 3.07495 4.12854 3.96426 4.40094 4.04813 4.04605 1.28594 3.38410 3.23368 4.77316 3.18239 71 f - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 1.25250 1.00643 1.05357 0.68349 0.70290 1.89918 0.16216 - 71 3.66201 6.17606 2.40464 2.48921 5.52242 4.42239 4.61647 5.00880 2.55297 4.48131 5.21813 3.88867 1.68446 3.71400 1.96796 1.55831 2.60496 4.56795 6.60719 5.19456 74 s - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 2.95326 0.05452 7.02758 0.00911 4.70241 1.08801 0.41081 - 72 2.39831 6.96337 1.82854 1.32670 2.89183 5.22496 3.18503 5.79542 3.35970 3.06581 6.00406 4.69193 2.94381 2.74003 3.37426 2.82251 3.13789 5.35527 4.37793 4.39596 76 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00098 7.32824 8.05049 0.61948 0.77267 0.21137 1.65797 - 73 3.13920 4.70572 2.55557 2.35040 4.29468 2.22702 4.94485 2.69282 5.75098 2.86194 3.34437 4.59343 6.67009 3.27853 3.49548 5.56106 1.40218 1.96293 4.50956 6.22371 77 t - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00956 8.04521 4.68969 0.61948 0.77267 1.25181 0.33685 - 74 2.10996 7.54284 3.33891 2.95421 4.52627 4.45349 3.32366 2.57922 2.93549 2.13768 3.35277 4.63301 6.31667 3.77489 1.59495 3.20305 2.62912 2.55634 8.00032 3.80747 78 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00047 8.06385 8.78611 0.61948 0.77267 2.40172 0.09493 - 75 3.20297 7.35353 3.29793 5.00792 3.88433 3.64104 3.33744 3.93424 2.45575 1.41187 2.58676 3.04077 4.06178 3.70827 1.72518 3.49617 2.80579 3.47884 4.72442 4.57748 79 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00047 8.06385 8.78611 0.61948 0.77267 0.16247 1.89741 - 76 4.54482 7.90173 0.61676 2.49103 7.24394 3.86068 3.91960 6.73586 3.51758 6.20629 6.94727 2.40438 3.05178 4.50947 5.58108 2.23110 3.56956 6.29224 8.33287 6.90984 80 D - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.03067 8.14603 3.50957 0.61948 0.77267 0.97695 0.47234 - 77 1.96010 4.23916 6.29643 4.53791 2.93951 2.57908 6.57576 2.47511 3.87249 5.16382 3.57721 3.25004 1.03475 4.86230 4.61000 2.92565 3.77406 2.62067 7.54825 6.32554 81 p - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.03954 8.11609 3.25782 0.61948 0.77267 0.11354 2.23180 - 78 2.14593 7.68695 2.17296 1.86728 4.73414 2.78570 3.32982 4.18378 2.20207 3.18218 4.68493 3.65699 2.77461 2.64014 2.85363 3.52806 3.29170 3.07613 8.11878 6.70684 82 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00990 8.11834 4.65052 0.61948 0.77267 1.72070 0.19716 - 79 1.34242 7.67640 3.49672 2.32253 6.13207 3.90568 3.81418 4.56209 2.88398 2.78486 4.38118 4.44148 3.88904 2.62682 2.00992 2.75436 3.02053 3.41701 8.10892 3.19520 83 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00045 8.10819 8.83114 0.61948 0.77267 0.10008 2.35142 - 80 3.11433 3.54547 7.41877 6.80257 1.99975 6.61195 6.94605 2.65824 6.58422 0.53305 3.72776 6.77900 6.97239 6.70968 6.58630 5.92366 4.32526 3.30980 3.23078 4.77858 84 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 81 1.75916 4.36262 5.72050 3.11565 2.11405 3.61194 4.35153 3.31458 2.85641 2.67897 4.83188 3.13852 4.26419 3.17041 2.75105 3.21616 2.67550 2.83007 7.88866 2.25615 85 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 82 1.74378 7.72217 2.18739 1.82003 5.44103 3.24098 3.34287 5.06257 2.51595 3.89184 5.05494 4.09701 3.09680 2.42722 1.94202 3.32831 3.69984 6.11407 8.15401 6.74206 86 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 83 2.16268 6.78250 5.33521 4.28440 2.20149 6.57803 4.53116 3.30429 4.64553 1.43765 3.21002 6.74161 6.94193 5.21045 4.23935 5.88904 2.41083 2.37340 2.80869 1.89512 87 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 84 3.23001 4.23854 7.39929 6.78378 2.23465 4.92337 6.92726 0.88717 6.56474 1.46942 2.84185 6.75952 6.95499 6.69298 6.56821 5.90417 4.37856 2.47656 7.41523 3.78453 88 i - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 85 1.93379 4.43466 2.93885 1.62534 4.65300 4.01877 3.20294 5.16593 2.36146 4.01392 6.76294 2.36285 4.01254 3.04698 2.06757 2.75101 3.46079 3.75330 8.15409 6.74215 89 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 86 2.54237 7.72226 2.12510 1.82566 7.06862 4.36812 4.53864 4.57537 1.69188 6.02821 6.76294 3.85311 6.37548 2.48484 1.58028 3.30206 2.72675 6.11416 8.15478 6.74284 90 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.02389 8.15589 3.75856 0.61948 0.77267 0.48579 0.95505 - 87 2.97224 7.68841 5.44123 1.45702 3.60855 4.70095 1.57901 6.51214 3.95859 3.61964 6.73048 2.26731 6.35687 2.13838 4.44517 3.54616 3.15176 4.49647 4.28229 2.42257 91 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00044 8.13175 8.85470 0.61948 0.77267 0.16477 1.88447 - 88 3.24937 4.89698 3.25561 2.93746 7.06861 1.42224 2.96865 6.55568 2.12231 6.02820 6.76294 2.48552 3.36513 2.12925 1.87070 3.31938 5.00234 4.72300 8.15408 6.74283 92 g - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 89 3.49553 3.97727 7.42568 6.81085 5.12651 6.62024 6.95849 0.88167 6.59390 2.74139 5.93402 6.78798 4.63160 6.72352 6.59806 4.43544 3.88161 0.91564 4.56852 6.27020 93 i - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 90 4.72459 7.75295 3.12550 3.51505 7.09862 3.44365 3.57535 4.56239 4.93323 6.05890 6.79502 1.89447 6.39993 4.07095 3.42217 2.34501 0.62740 6.14485 8.18547 6.77145 94 T - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 91 2.16465 6.79210 4.96635 3.77968 2.92157 4.06110 2.65886 2.01077 6.47672 2.78294 3.39360 4.69741 6.92865 4.56155 3.94326 4.67176 2.36774 1.51517 4.01189 2.28803 95 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 92 2.18271 6.78105 7.38825 6.77204 3.75061 4.59694 6.91414 2.35600 6.55301 1.36965 1.97893 6.74709 6.94325 6.68124 6.55578 3.79775 2.20351 2.12934 2.38165 4.40772 96 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 93 2.79965 4.97682 2.85857 3.38952 2.33524 4.53390 2.39624 3.32575 2.89946 2.80242 3.57459 2.14047 6.53502 3.54963 5.66235 2.38515 2.56467 2.82114 3.33614 3.04641 97 n - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 94 2.01694 4.54762 7.38814 6.77193 2.10220 2.38639 6.91402 2.96309 6.55289 1.09991 4.01459 6.74698 6.94314 3.15717 6.55567 2.00932 4.36740 3.22024 7.40339 6.22781 98 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 95 3.50119 7.02168 7.60739 4.53259 6.23149 6.65500 7.24765 3.88657 6.84701 5.30475 4.06679 6.96484 1.88892 6.97940 6.86087 3.31473 0.70018 1.50839 7.77028 6.59678 99 t - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 96 3.08034 7.30715 7.42568 6.93354 6.77065 4.71478 7.48529 6.12949 6.80670 4.07431 6.77273 4.02787 0.34379 7.01603 5.05095 3.04221 2.20212 4.12630 4.58100 7.08326 100 P - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 97 1.26235 7.45700 7.13608 6.64810 7.08270 3.07423 4.54994 6.46026 6.58572 3.55389 7.05151 6.79158 2.66250 4.37181 6.86575 0.89636 2.17522 4.06128 8.52237 7.32600 101 s - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 98 2.45300 6.78101 7.38752 6.77131 2.36012 6.58000 3.09416 3.54748 5.06478 0.93709 2.38507 5.10568 6.94321 3.46777 6.55505 4.24617 5.64079 1.94908 4.70296 3.16972 102 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 99 2.26730 4.30377 7.38827 6.77206 1.49375 3.36732 6.91416 2.78300 6.55303 1.02864 3.37287 6.74711 6.94327 4.50686 6.55580 3.89342 5.64085 2.49188 3.99739 3.63349 103 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 100 2.81141 7.72236 2.39136 2.47801 7.06872 3.20651 2.82874 3.47475 2.11203 3.73468 3.85252 2.02677 4.00155 2.13213 2.16263 3.09630 4.60874 4.36753 8.15419 4.21919 104 n - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01708 8.15532 4.09556 0.61948 0.77267 0.48579 0.95505 - 101 2.07594 6.93213 6.46010 3.46986 3.71246 4.07706 2.98674 3.13784 4.82427 1.66075 2.12932 4.60732 3.17250 1.83958 4.76674 3.89337 2.73998 2.58333 7.53032 4.77090 105 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.13867 8.86093 0.61948 0.77267 1.22425 0.34811 - 102 3.31042 2.30536 7.37434 4.76880 2.14039 6.56544 6.90023 2.25406 6.53841 0.84698 4.44649 6.73318 6.92865 6.66664 6.54118 5.87714 4.46659 3.01722 2.67758 2.97702 106 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.02344 8.13881 3.77753 0.61948 0.77267 1.22425 0.34811 - 103 1.85415 7.11444 2.18686 3.22519 3.23559 6.19463 4.50890 3.50314 4.41810 1.18526 2.51333 3.87259 4.74596 3.84486 5.77043 3.51354 2.98606 2.61730 7.67797 6.41852 107 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.04038 8.11624 3.23717 0.61948 0.77267 0.53365 0.88300 - 104 2.19786 7.66056 1.61215 1.66830 3.70130 3.62921 3.93281 4.70220 3.67843 2.36907 4.36880 3.06776 3.04836 2.58880 5.34752 3.38869 3.33948 3.65001 8.09516 3.92519 108 d - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.26880 8.09998 1.44646 0.61948 0.77267 2.00743 0.14425 - 105 1.41738 3.73110 2.56939 2.13548 6.74491 2.87160 3.18282 3.69506 3.67981 3.44414 3.99242 3.17035 4.54417 2.90626 4.14145 2.71634 3.44345 2.71703 4.42287 3.22233 109 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.16696 7.83179 1.87488 0.61948 0.77267 1.96140 0.15159 - 106 1.65033 7.23710 2.35318 4.07288 6.54880 2.39269 4.64473 2.69768 4.53590 3.00266 3.63204 3.14337 4.32865 2.67203 2.51053 2.27693 3.53500 2.76144 7.68972 3.31042 110 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 1.09168 7.71609 0.40962 0.61948 0.77267 3.68590 0.02539 - 107 1.72035 3.00406 2.19446 1.56924 5.72328 4.63989 4.82704 4.66969 3.05605 4.68356 5.41898 4.10686 3.40539 3.01168 2.41003 2.86543 3.88574 4.76881 6.81013 2.46548 111 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.33778 6.62671 1.25412 0.61948 0.77267 2.29764 0.10591 - 108 3.28822 6.40877 3.41576 1.30236 3.03800 4.27734 2.76975 5.23943 2.98809 2.17018 5.45015 4.14010 2.98740 2.35594 2.94304 2.58191 4.13040 4.79998 6.84199 3.15098 112 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.51320 6.66834 0.91591 0.61948 0.77267 4.44175 0.01185 - 109 2.06828 5.18051 4.79720 4.22119 2.78569 3.30139 3.00819 2.92917 4.14079 2.16809 4.29189 2.32682 5.03703 3.04631 2.22354 3.93077 2.64151 2.16047 3.75540 4.57470 113 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.43878 6.15793 1.04112 0.61948 0.77267 2.12547 0.12713 - 110 2.14802 6.22303 2.09257 2.36359 5.55553 4.52066 4.70920 5.03359 2.62074 2.07524 3.29795 3.99179 2.62005 3.80880 3.93911 2.14455 2.02602 4.60730 6.66318 5.25955 114 t - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.10284 6.46108 2.34170 0.61948 0.77267 3.33696 0.03619 - 111 2.41835 6.25492 2.36844 2.06415 5.59574 2.63738 4.71683 3.07684 3.45322 4.55879 5.29768 2.92781 1.67530 3.81435 3.94535 2.19169 2.51400 4.64405 6.69022 3.67572 115 p - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.04315 6.47555 3.20182 0.61948 0.77267 3.50121 0.03062 - 112 2.77112 3.45249 2.09530 2.66715 2.48762 2.89312 4.74382 5.12574 2.96104 3.11354 5.33507 2.14729 3.64033 2.62071 2.85430 2.15075 3.24038 4.68559 6.72691 3.92660 116 d - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.04342 6.51880 3.19378 0.61948 0.77267 1.92103 0.15836 - 113 2.72953 6.61809 2.68725 2.30256 1.89083 2.35315 5.08831 5.43766 3.29445 2.76003 5.66085 4.37021 2.73161 2.79538 3.17453 2.23047 3.17592 3.46219 3.21474 5.64838 117 f - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00143 6.94400 7.66626 0.61948 0.77267 1.29272 0.32093 - 114 1.84857 4.89980 3.41508 2.89591 4.33558 2.64984 2.93265 4.09714 3.23833 2.29079 4.33281 2.21663 3.57312 3.03454 2.68935 2.69836 2.36496 3.79007 7.48593 6.07538 118 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01083 7.43235 4.58768 0.61948 0.77267 0.45739 1.00221 - 115 2.55346 7.52056 2.96519 2.21798 4.73480 2.76280 3.72211 4.77500 3.46218 3.03104 6.56124 2.93608 1.43542 2.36701 3.24384 2.77804 2.87231 4.01046 4.30158 6.54114 119 p - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00053 7.94053 8.66279 0.61948 0.77267 0.38621 1.13827 - 116 2.03351 7.66256 2.20887 1.67584 5.10831 3.33108 3.43990 3.95838 2.94222 2.88053 6.70324 4.67648 3.36782 3.55774 2.07995 2.43345 2.85073 3.97085 8.09439 5.00226 120 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.02912 8.09251 3.56140 0.61948 0.77267 1.51468 0.24830 - 117 2.53821 2.80161 1.65792 3.23067 3.33187 4.17543 3.70755 3.45248 3.25770 2.47237 3.17591 3.51209 3.70825 2.78151 2.89449 2.66783 2.68170 3.39079 4.28009 6.64788 121 d - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00594 8.07209 5.18375 0.61948 0.77267 0.11817 2.19414 - 118 3.01941 3.43599 4.36134 3.84980 2.09752 3.55660 4.39184 2.62293 3.63562 1.27129 3.59056 3.45540 2.39142 4.32599 3.92535 3.56769 3.47550 2.72551 4.71207 3.70701 122 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01839 8.14554 4.02131 0.61948 0.77267 0.26557 1.45571 - 119 2.01014 7.70573 2.90360 3.44218 4.73836 3.43247 2.78230 6.53847 2.70328 2.77953 6.74641 3.96135 1.80081 3.44010 2.81488 1.69891 2.92578 3.87470 8.13756 4.56646 123 s - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.07117 8.13802 2.68226 0.61948 0.77267 1.25825 0.33429 - 120 2.64569 4.24270 2.64015 4.02644 3.92940 2.18198 2.83076 6.47256 3.19189 5.94507 4.84089 2.77739 3.64244 2.85988 2.87859 1.28227 2.43290 4.40421 8.07096 6.65902 124 s - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00047 8.06731 8.78957 0.61948 0.77267 0.15004 1.97094 - 121 4.53310 6.77336 7.37986 6.76365 4.74451 3.73598 6.90644 2.65883 6.54462 0.36313 3.71519 6.73870 3.36515 4.52825 4.49637 4.41873 4.57747 2.54031 7.39580 6.22022 125 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14768 8.86994 0.61948 0.77267 0.28854 1.38372 - 122 4.50816 7.72228 3.00888 2.89451 7.06865 4.46033 3.14197 4.54351 1.73765 3.94394 4.56084 3.58974 4.21427 2.52645 1.02440 3.36516 2.82658 3.34437 8.15411 6.74217 126 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00583 8.15586 5.19751 0.61948 0.77267 0.48579 0.95505 - 123 2.78017 3.27993 3.11150 2.73442 3.49619 6.05044 2.15565 3.03733 3.28270 2.24714 4.18518 4.78753 4.80485 3.74087 1.92691 3.32637 2.32547 2.47241 7.98709 3.45044 127 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14976 8.87271 0.61948 0.77267 0.33350 1.26024 - 124 3.25625 6.88418 7.50247 6.88903 2.61578 6.70188 7.03945 1.93442 6.67346 1.13383 3.44825 6.86963 5.03140 6.79615 6.67554 6.01567 4.55729 1.04996 4.63561 6.34491 128 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 125 3.75429 3.68567 3.90540 6.77087 2.49276 4.12651 4.82659 1.57018 6.55253 1.49532 3.32593 4.51467 4.67063 2.68407 6.55530 5.89126 2.69655 2.29106 3.57269 2.74299 129 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 126 2.48910 2.81626 7.38826 6.77205 1.85210 6.58005 6.91415 2.80725 6.55302 1.64069 4.59211 4.89570 5.01909 3.72221 6.55579 3.50109 2.11896 1.47225 4.71479 6.22724 130 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 127 1.76511 3.19369 4.22647 7.04135 6.20680 0.62835 7.21325 3.52778 6.82924 3.58739 6.22967 6.93114 7.08432 6.95470 6.83271 2.69393 3.48550 2.63016 7.73449 6.56377 131 G - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 128 4.80112 7.83433 8.52401 8.59610 8.85049 0.05791 8.97248 8.39786 8.47064 8.08595 8.78810 7.62084 7.52727 8.45747 8.33964 3.16113 6.52844 7.33943 10.16747 9.23449 132 G - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 129 2.86303 9.71340 1.28127 0.52435 9.09511 3.71837 7.60623 8.76448 6.96715 8.16006 9.16304 6.27816 7.57435 6.81466 7.84398 3.17564 7.26174 8.20165 10.31367 8.57317 133 E - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 130 1.15472 7.72021 3.85731 2.48695 7.06519 4.09783 6.16964 3.34299 2.38575 4.65512 4.02158 3.70828 3.30625 2.81758 1.96293 3.52321 4.45549 2.88343 3.07544 6.74149 134 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01942 8.15558 3.96620 0.61948 0.77267 0.48579 0.95505 - 131 2.63280 3.18662 7.37392 6.75771 2.34167 6.56641 6.90050 2.62725 6.53868 0.65109 3.87214 6.73345 6.92892 6.66691 6.54145 3.48121 3.73559 2.30840 4.65748 6.21359 135 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.13660 8.85886 0.61948 0.77267 1.29423 0.32036 - 132 2.94942 7.70372 2.33876 3.74100 7.05008 3.24332 3.47968 4.15342 3.37848 3.89141 5.07946 3.35353 1.90277 3.70149 3.57187 1.51738 1.81613 2.82188 8.13624 6.72430 136 s - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.13660 8.85886 0.61948 0.77267 1.29423 0.32036 - 133 1.66132 7.66189 4.55313 2.57558 4.11506 3.25417 4.06099 3.72828 3.31239 2.71421 4.12823 4.66611 1.50813 4.06030 3.16475 3.03028 2.82165 2.22138 8.10551 6.70604 137 p - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.13660 8.85886 0.61948 0.77267 1.29423 0.32036 - 134 1.98509 7.70425 2.26443 2.15838 4.91156 2.95619 2.81271 6.53768 2.40444 6.01019 6.74493 4.45477 3.02481 2.71012 2.65675 1.93726 2.72329 3.92105 8.13677 6.72483 138 s - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.04839 8.13673 3.05873 0.61948 0.77267 0.18805 1.76358 - 135 2.51125 7.65510 1.91930 3.84972 6.99106 3.56414 2.47798 4.04103 4.03271 1.27121 5.18333 4.43265 4.93934 3.31738 3.24807 2.84188 2.48422 2.67830 8.09386 4.51237 139 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00045 8.10819 8.83114 0.61948 0.77267 1.88212 0.16519 - 136 1.21791 3.59887 7.33146 4.21369 2.44408 6.53365 6.86706 2.89879 3.95168 2.13147 4.90476 4.79455 3.40132 4.67255 3.91217 5.84466 3.66957 1.45635 4.58036 3.54064 140 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00045 8.10819 8.83114 0.61948 0.77267 1.88212 0.16519 - 137 2.08137 7.67646 2.70382 2.20614 4.30429 3.65897 4.45956 4.38678 2.18534 2.68510 4.83386 2.77868 4.68067 2.78353 1.77361 3.34221 3.75116 2.82304 3.75602 6.69773 141 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00045 8.10819 8.83114 0.61948 0.77267 0.10008 2.35142 - 138 2.57652 7.72175 3.64258 3.00211 4.89648 4.57833 4.81816 4.96441 1.68998 3.04370 5.12869 3.49147 3.69942 2.34431 1.13131 4.10976 2.83784 3.94687 4.88470 6.74233 142 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 139 2.30883 4.29955 4.13804 3.98971 2.44261 6.57654 4.72306 2.15772 4.27321 1.38902 3.37350 4.27113 6.93975 6.66734 4.17894 4.18310 3.74295 1.94285 2.12653 4.68217 143 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 140 3.39573 4.53318 3.46643 3.23215 3.03737 3.87747 4.10690 3.28275 2.17371 2.14321 4.38139 4.38139 3.81647 2.65129 1.45700 3.18987 3.48584 3.08104 4.76470 2.90775 144 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 141 1.98712 4.42699 2.84246 1.84502 7.06858 3.40876 4.25925 5.21372 2.45014 3.68463 6.76290 3.05595 2.80711 2.43627 2.22209 2.56381 2.92148 3.41292 8.15405 6.74210 145 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.07531 8.15533 2.62748 0.61948 0.77267 0.48579 0.95505 - 142 1.96443 4.58383 3.64600 3.02009 6.91696 3.20655 3.10535 3.65432 2.93622 1.91591 4.25597 3.96901 6.32086 3.17327 1.59498 4.48818 2.60143 3.18575 3.06168 4.71137 146 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01553 8.08099 4.19313 0.61948 0.77267 0.68900 0.69731 - 143 2.41081 2.30338 7.13323 4.70444 1.39605 4.69266 2.96533 3.49906 4.95605 2.39210 4.12497 3.77770 4.53670 3.35696 2.88631 3.25853 3.32092 2.39071 4.66632 3.04504 147 f - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.30998 8.10304 1.32336 0.61948 0.77267 1.96855 0.15043 - 144 3.02288 3.71325 4.20747 3.12269 4.35927 1.78007 3.00971 6.21413 2.44549 3.37985 6.42346 3.89555 1.12920 3.81792 2.95010 3.76871 3.18854 3.55314 7.81530 6.40405 148 p - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.17260 7.79375 1.84447 0.61948 0.77267 3.11334 0.04547 - 145 3.45184 2.57362 1.94147 2.53481 6.58140 1.96227 3.26954 4.07221 3.32985 4.31273 6.27572 2.02326 4.26837 2.48490 3.78039 2.22705 3.36797 3.72355 7.66687 6.25493 149 d - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 3.50721 3.76368 0.05464 0.43056 1.05023 2.90710 0.05618 - 146 2.97219 5.44742 3.16905 1.96852 4.79101 2.37193 2.39341 4.26560 2.63532 3.74921 4.50058 3.19400 4.12559 3.02002 1.94564 2.08358 3.20370 3.84071 5.88202 4.48533 152 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00944 5.06386 5.78612 0.61948 0.77267 0.43397 1.04394 - 147 1.52207 4.81521 4.34803 3.89402 6.66384 2.34553 4.54835 4.08394 2.59922 3.27573 4.54073 3.61329 1.71130 3.39495 2.99085 3.26811 2.55209 2.48277 7.76178 6.35469 153 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.56752 7.74714 0.83785 0.61948 0.77267 0.91922 0.50888 - 148 3.04978 4.22466 2.48071 3.21128 6.44481 1.86103 2.47169 3.57796 2.32267 5.40440 6.13914 3.26951 3.03037 3.35684 2.60339 1.99620 2.56458 3.53568 7.53028 6.11834 154 g - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.30822 7.47744 1.32923 0.61948 0.77267 2.62848 0.07493 - 149 3.34705 3.85374 3.22229 5.89645 5.02100 3.12455 6.05518 3.24100 5.68227 1.65647 2.37803 5.88259 2.46884 5.81466 2.75996 3.81008 2.57905 1.57884 4.07139 3.05732 155 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00107 7.24099 7.96325 0.61948 0.77267 0.05554 2.91824 - 150 3.26611 5.38368 3.89133 2.49187 4.42991 3.24532 3.75409 6.52876 2.62911 3.12194 4.86243 3.16145 3.19611 2.31928 1.32392 2.86548 2.44474 3.10669 8.12785 4.02234 156 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00044 8.12759 8.84985 0.61948 0.77267 0.84966 0.55785 - 151 3.57939 7.00978 7.64539 7.03612 3.05398 4.22055 7.19900 1.41192 6.82609 0.89206 3.32431 7.02433 7.19762 6.94046 6.82748 6.17453 5.88826 1.67324 7.65371 3.91141 157 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.13660 8.85886 0.61948 0.77267 0.18984 1.75497 - 152 3.14133 6.78173 7.38131 6.76510 2.60344 6.57864 2.33312 1.61571 4.83191 3.07548 4.12559 4.05767 6.94254 2.68385 3.74436 5.89035 2.71851 1.84445 3.51770 1.92624 158 i - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 153 3.98657 8.64521 4.08638 5.54338 8.21408 4.59931 2.95725 7.74967 6.12216 7.21802 8.01999 0.30041 7.18267 2.24123 6.70232 3.85418 4.15570 4.77884 9.35430 7.86404 159 N - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 154 1.83950 4.09778 7.31537 2.38917 4.49218 2.18469 2.71703 3.84616 6.50022 2.10498 2.28589 3.95083 5.26850 6.64163 6.52795 2.67821 2.83486 1.97467 7.40963 6.23267 160 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 155 8.40499 9.15082 9.02258 9.09744 2.69554 3.02547 7.15802 7.91424 8.85276 3.93350 8.38558 8.13535 8.91099 8.35231 8.54986 8.10832 8.57828 7.89622 7.21763 0.15099 161 Y - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 156 4.19423 8.17913 8.63384 8.66156 8.91387 0.03119 9.08854 8.70870 8.38846 8.32677 9.09409 7.92198 7.83048 8.61096 5.38298 6.52598 6.90374 7.69809 5.21524 9.15508 162 G - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 157 3.05869 6.78159 7.37908 6.76356 3.54459 6.57849 4.82622 2.85352 6.54592 4.26754 2.66290 6.74277 0.41988 4.60926 5.18457 4.07069 3.62985 3.01641 7.40403 6.22776 163 P - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 158 2.12452 7.80070 8.59366 8.66159 8.82171 6.60364 8.96242 8.36007 8.45988 5.16882 8.75378 7.60385 7.49988 8.44879 8.31710 2.88005 0.20658 7.30233 10.15671 9.21334 164 T - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.15530 8.87756 0.61948 0.77267 0.48579 0.95505 - 159 7.86844 9.62418 7.18084 0.00954 9.72469 7.80190 8.96223 9.72746 8.36889 9.03501 10.12255 7.81645 8.53455 8.32245 8.83677 5.15061 8.32384 9.09670 10.38318 9.63458 165 E - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14976 8.87271 0.61948 0.77267 0.48579 0.95505 - 160 1.31149 4.00229 7.75707 7.27533 6.63556 2.37617 7.54288 3.58848 7.08679 5.74001 6.65358 1.79046 7.19492 7.21849 7.11452 2.54252 1.19851 3.95862 8.14800 4.22756 166 t - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14976 8.87271 0.61948 0.77267 0.48579 0.95505 - 161 2.24995 2.82664 7.40973 6.85591 6.25218 3.77903 3.19471 5.59785 6.68401 2.61870 6.27159 6.83927 7.05276 3.72496 6.75679 2.05309 0.68690 3.58425 7.76948 6.59390 167 T - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14976 8.87271 0.61948 0.77267 0.48579 0.95505 - 162 4.04352 6.78561 7.39420 6.77868 3.53960 4.05253 6.92286 1.46086 6.56034 2.59970 4.20572 6.75442 6.94989 6.68857 4.41990 4.46634 2.77021 0.65888 7.41083 6.23525 168 V - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14976 8.87271 0.61948 0.77267 0.48579 0.95505 - 163 2.42038 2.14936 2.15767 3.90649 2.55693 2.82656 2.97559 3.07055 6.42677 3.45663 3.00955 2.63664 6.91474 4.86441 6.48569 4.01115 3.51347 2.22352 2.86815 3.04837 169 c - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14976 8.87271 0.61948 0.77267 0.48579 0.95505 - 164 1.35353 2.83479 7.38183 6.76562 3.77331 6.57501 6.90980 4.39783 6.54728 3.72617 5.89642 3.51962 6.93822 6.67552 6.55075 1.39581 1.86507 2.04321 7.39916 3.01154 170 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14976 8.87271 0.61948 0.77267 0.48579 0.95505 - 165 2.60360 4.61720 7.37038 6.75555 5.87110 3.45756 3.88177 2.83581 6.53929 3.14911 4.06268 3.75561 6.93716 6.66960 6.54692 2.33743 0.55882 3.19278 7.40087 6.22460 171 T - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00043 8.14976 8.87271 0.61948 0.77267 0.48579 0.95505 - 166 2.13155 3.05829 7.29550 3.97047 2.70132 3.60934 3.15256 1.91390 3.85610 3.22534 3.75421 6.70147 6.92605 4.34824 2.46288 2.51902 4.22693 2.59665 3.09918 2.03243 172 i - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00000 * * 0.00000 * 0.00000 * -// -HMMER3/f [3.4 | Aug 2023] -NAME AMP-binding_C -LENG 50 -ALPH amino -RF no -MM no -CONS yes -CS no -MAP yes -DATE Tue Jul 27 20:16:06 2004 -COM [1] hmmbuild aroundLys517.hmm aroundLys517.aln -COM [2] hmmcalibrate aroundLys517.hmm -NSEQ 849 -STATS LOCAL MSV -7.7800 0.71027 -STATS LOCAL VITERBI -7.7798 0.71027 -STATS LOCAL FORWARD -5.2714 0.71027 -HMM A C D E F G H I K L M N P Q R S T V W Y - m->m m->i m->d i->m i->i d->m d->d - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00285 * 5.86340 0.00000 * 0.00000 * - 1 2.76078 5.46822 1.53391 2.77326 4.55396 4.26561 5.04262 4.07430 4.06321 1.94356 4.09163 2.95140 3.04983 3.44492 3.68544 2.15567 2.23261 3.42828 4.36195 5.43425 25 d - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01764 9.44305 4.05106 0.61948 0.77267 0.48579 0.95505 - 2 1.70580 5.37255 4.17340 2.55490 4.20736 4.22677 4.37649 2.22288 3.98556 2.40102 4.38065 5.41691 2.03504 3.86564 2.98119 2.86820 2.47242 2.33032 8.44665 5.77734 26 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00350 9.43307 5.68106 0.61948 0.77267 0.52539 0.89484 - 3 1.55738 8.33844 2.38500 1.89217 5.47643 2.67959 4.61347 4.65713 3.19113 3.87388 5.66982 2.96308 3.51136 2.64770 3.11973 2.20131 2.71632 4.21421 8.54361 7.70698 27 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00791 9.45065 4.85370 0.61948 0.77267 0.40964 1.09031 - 4 1.77158 5.96096 2.03151 1.51165 5.13473 3.06915 3.58971 5.53121 3.01925 3.41642 5.87778 4.44574 5.47922 2.25956 2.94716 2.76486 3.16481 3.87459 6.83571 4.89837 28 e - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.45187 10.17413 0.61948 0.77267 0.11060 2.25659 - 5 3.21125 6.08296 5.32188 7.74859 4.00352 7.60303 5.95819 1.59553 7.58154 0.56897 3.78379 7.72988 6.22228 6.08227 7.58362 7.03257 4.72301 2.31224 4.45476 4.34593 29 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 6 3.30199 8.33216 4.84633 3.33111 4.64809 7.11084 4.12615 3.65342 2.29832 2.91383 4.53441 4.24260 4.89693 3.09405 0.55990 3.75947 4.23289 4.13308 6.46067 4.87405 30 R - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 7 1.61282 6.16056 2.95128 1.67867 7.95303 2.98456 3.56957 4.99538 2.71631 4.27450 5.52147 3.97784 5.80636 2.24358 2.55827 2.16248 2.83969 4.99399 7.10116 5.67119 31 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 8 2.10433 5.21726 4.12486 3.08722 2.08423 3.64659 1.71617 4.75770 3.21822 3.27783 5.51115 4.07149 7.44087 2.16256 2.67271 3.59737 3.64381 4.44163 3.31526 2.44328 32 h - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 9 2.62159 4.12364 8.81971 8.20835 6.17466 8.02120 8.36501 3.39237 7.99487 0.28152 3.28285 8.19033 5.67975 8.11963 7.99902 5.62430 5.70401 2.65833 8.83981 7.66909 33 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00238 9.46314 6.07573 0.61948 0.77267 0.48579 0.95505 - 10 1.35029 6.06716 6.15657 2.96948 8.33028 2.80035 5.30885 5.36361 2.11137 3.21278 4.84999 3.91286 7.63852 2.19246 1.99630 1.91936 4.00366 5.63810 9.41644 4.74117 34 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46088 10.18314 0.61948 0.77267 0.92590 0.50447 - 11 1.67529 8.98522 2.76423 1.92483 8.33159 3.05743 4.92685 4.63919 2.37191 3.47678 4.53868 3.25359 4.83119 2.08910 2.57569 2.65956 2.83839 3.61125 9.41706 5.98112 35 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46088 10.18314 0.61948 0.77267 0.28474 1.39516 - 12 3.24536 4.91723 4.26360 2.82670 4.51729 4.33915 2.89602 3.67442 2.30199 2.82046 5.09468 3.47895 7.64685 2.41359 1.54576 2.22436 2.34912 2.85859 5.05448 4.73008 36 r - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.02416 3.87667 5.76064 0.62656 0.76449 0.48579 0.95505 - 13 5.59770 6.35531 8.66280 5.82159 5.46392 7.85459 4.33271 4.34934 5.95120 0.12253 4.03742 8.02163 8.21780 5.96992 5.62265 7.16629 6.91537 3.11415 8.67735 5.91308 39 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00089 9.45957 7.12089 0.61948 0.77267 1.05159 0.42983 - 14 3.18063 8.41043 5.76538 4.66674 5.75775 4.65565 7.74778 5.49852 6.69836 5.64616 6.08492 5.26562 0.12108 5.13739 6.09740 5.00985 4.67298 5.18244 8.97742 7.72075 40 P - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.02296 9.45877 3.78883 0.61948 0.77267 0.88666 0.53108 - 15 1.87756 8.96152 1.51989 1.56495 8.30789 2.67191 3.97779 4.95444 4.09563 4.37913 8.00221 3.71786 3.13077 3.43645 2.97134 2.35029 3.90640 3.84263 9.39335 5.10693 41 d - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00275 9.43648 5.92639 0.61948 0.77267 2.46813 0.08855 - 16 3.31335 8.03992 8.64504 8.03022 3.04510 6.00692 2.32700 5.04899 7.81118 4.94017 7.15963 5.92860 5.40319 7.93872 7.81396 4.27544 4.83065 4.80223 5.00740 0.28014 42 Y - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00284 5.87796 10.15676 0.11414 2.22685 0.15684 1.92991 - 17 4.52782 5.97719 8.65759 5.02619 5.43792 5.24384 4.77943 4.89726 5.29998 2.90932 0.15406 8.01851 8.21536 4.85013 7.82720 4.68863 5.63339 4.32195 8.67630 5.93213 44 M - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.45950 10.18245 0.61948 0.77267 1.05159 0.42983 - 18 4.24663 4.67014 8.66128 8.04507 5.73066 6.07515 6.29003 1.34026 4.62717 2.61288 3.77390 8.02012 8.21628 4.27227 3.67894 5.13801 4.60498 0.61592 5.46934 7.50095 45 V - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.45950 10.18245 0.61948 0.77267 0.24663 1.52064 - 19 8.06269 10.62941 5.26515 5.50567 10.37087 5.68242 8.96655 10.02152 5.84046 6.21337 10.41662 7.64403 0.02634 8.17983 9.10934 5.87442 8.47442 5.53963 11.58873 9.91131 46 P - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00260 5.96990 10.18493 0.12035 2.17692 0.48579 0.95505 - 20 1.19783 6.88164 3.58919 3.54691 5.58199 3.72851 4.23312 6.34445 3.83664 4.47711 6.20998 3.47621 5.14253 3.45264 4.20817 1.12644 2.11625 3.49423 6.55725 6.25087 48 s - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 21 1.17971 5.64219 4.47424 4.78338 2.90703 4.57890 2.20765 3.78594 4.03132 2.74692 4.37858 4.94627 7.93512 3.36104 2.41005 3.25846 3.25361 2.50293 5.39404 2.50223 49 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 6.11067 3.66178 0.02830 0.01418 4.26317 0.48579 0.95505 - 22 3.01842 5.68773 6.67269 6.21729 5.05211 6.18887 6.97144 1.85740 6.17848 1.46646 4.76723 6.36424 6.37672 6.41137 6.32820 5.63643 4.77000 0.66241 7.21473 6.01073 51 V - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 1.25113 5.88551 0.34103 0.61948 0.77267 5.96087 0.00258 - 23 3.28011 5.40461 3.48944 3.07355 4.97624 3.84849 4.12991 4.40370 1.08699 3.88939 4.75235 3.51647 1.43911 3.28219 2.83857 3.29674 3.54143 4.02455 5.93694 4.72463 52 k - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 1.29619 0.93368 1.09864 0.09981 2.35393 0.00158 6.45062 - 24 5.78791 5.34221 8.67209 8.05658 0.93518 5.63680 8.19729 2.19948 7.83754 1.82518 3.92750 6.12685 8.22709 7.96508 7.83962 7.17628 6.92467 2.28197 2.83995 1.98253 54 f - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00581 5.15797 10.18260 0.05921 2.85606 0.26525 1.45677 - 25 3.83649 4.89977 4.92750 4.64262 4.16712 5.21724 4.12969 1.65862 5.41478 2.38504 3.06640 8.02240 8.21926 3.94808 4.37645 7.16706 2.90836 0.72425 6.11278 4.72441 56 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00103 9.46318 6.95607 0.61948 0.77267 0.48579 0.95505 - 26 2.60273 4.22054 5.68447 3.49551 2.63393 4.08538 3.81713 2.93059 3.22726 2.66997 3.76999 5.05440 2.14872 2.31300 2.29082 3.24667 3.07685 1.95949 3.69721 4.87002 57 v - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46227 10.18453 0.61948 0.77267 0.37763 1.15673 - 27 4.46412 3.71552 8.66529 8.04908 4.46897 7.85708 5.99736 2.36111 5.31045 0.47991 2.44221 8.02413 5.01517 7.95758 5.09766 5.92320 4.98398 2.13376 8.67984 5.89686 58 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 28 2.58257 5.50973 0.96961 1.50819 8.33361 3.65279 5.52844 7.82068 3.32493 5.24633 8.02793 3.64655 2.71080 4.33415 3.73181 2.64703 3.22234 4.96630 9.41908 8.00714 59 d - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 29 1.36538 5.32533 3.34362 1.96842 5.13194 3.41294 3.50928 6.02263 2.67612 6.13284 8.02791 3.84823 7.64044 2.34410 2.24082 2.32054 2.97279 4.09222 5.73221 3.54325 60 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01532 4.18876 10.18517 0.02368 3.75489 0.48579 0.95505 - 30 5.12032 8.08214 8.69072 8.07451 1.86946 7.88321 6.12469 1.98937 5.91051 0.73616 1.75994 8.05095 8.24434 7.98163 7.85756 6.72288 5.48769 4.09862 3.80819 7.52901 62 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00276 9.46284 5.92155 0.61948 0.77267 0.48579 0.95505 - 31 5.33343 9.16099 9.09722 5.98568 10.14318 6.07371 10.07941 9.68709 9.46597 5.52335 10.07525 8.74510 0.02670 9.49370 6.94153 4.56473 7.83223 8.64598 11.46085 10.45579 63 P - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00481 6.01856 6.04490 0.12548 2.13769 0.98431 0.46792 - 32 4.96626 6.08430 8.65865 8.04244 4.13379 7.85114 4.88169 3.50025 3.30062 0.41921 3.42678 6.01222 8.21434 4.36183 2.80572 4.80267 3.22368 2.52361 6.09193 5.88884 65 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.45811 10.18037 0.61948 0.77267 0.62656 0.76449 - 33 5.05299 8.31772 5.26232 5.81545 7.45475 4.14774 6.66179 3.94465 5.18954 3.24734 4.21151 2.32130 5.97141 7.16155 7.21492 2.35457 0.37841 5.79743 8.89996 5.61444 66 T - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46019 10.18245 0.61948 0.77267 0.98431 0.46792 - 34 1.30244 8.86675 3.99393 4.82778 5.23813 3.24048 4.76055 3.22453 4.62469 3.55863 5.47518 4.44101 1.22480 4.97612 4.37031 2.37751 2.82528 2.42326 9.33116 7.95249 67 p - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00227 6.10405 10.18253 0.13443 2.07316 0.98431 0.46792 - 35 4.07582 9.25917 7.10348 5.16614 8.79615 4.98800 3.35425 5.83849 7.00228 7.81396 8.60969 0.37164 8.19450 5.83294 7.49372 1.59851 3.50951 5.91058 10.00916 6.29250 69 N - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46019 10.18245 0.61948 0.77267 0.98431 0.46792 - 36 4.80890 6.03716 3.94177 6.21737 8.25592 0.11837 5.90338 7.72150 5.07715 5.23103 5.48888 4.02218 7.67229 4.93367 4.62799 4.64116 4.35073 6.11410 9.38644 7.99460 70 G - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46019 10.18245 0.61948 0.77267 0.98431 0.46792 - 37 8.18241 9.09875 5.90958 5.13534 9.04677 8.43056 5.91236 8.66484 0.01852 8.17548 8.74525 8.07498 8.58444 7.42550 5.63510 8.14290 8.17340 8.51928 9.09737 8.73416 71 K - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46019 10.18245 0.61948 0.77267 0.98431 0.46792 - 38 3.97384 6.05744 8.90350 8.30046 5.38370 8.11955 8.47722 1.51871 8.09321 0.98707 5.29013 8.28730 6.02556 8.22768 4.84721 7.43958 3.33199 1.11253 8.95410 7.77714 72 l - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46019 10.18245 0.61948 0.77267 0.26622 1.45358 - 39 5.49608 6.15665 0.12974 4.63520 9.62724 5.68947 5.95772 9.16699 5.12802 8.60069 9.42970 2.71656 8.53900 4.41963 4.49102 7.51869 7.92972 6.16844 10.72380 7.06468 73 D - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 40 4.72777 8.80833 5.74462 4.50458 5.38418 7.30697 3.60141 5.13950 2.73428 3.38030 5.58728 5.73977 5.41191 4.23217 0.31035 4.53161 3.51061 3.48288 6.41004 4.93087 74 R - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 41 2.25768 8.98745 3.85053 4.12225 5.44962 3.38266 4.04253 5.95631 1.04051 4.11739 8.02813 2.85587 5.59449 3.37989 1.37323 3.03816 3.83875 5.13563 9.41928 5.19385 75 k - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 42 0.47107 5.43747 5.12902 3.15424 5.02574 4.33675 5.36469 7.81358 2.75291 3.57567 4.79908 4.75680 7.64098 3.07799 2.68775 3.13968 4.06088 4.55440 9.41613 5.59273 76 A - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 43 6.00191 4.16368 10.37706 9.87660 8.02174 6.22926 10.40547 4.27181 9.80521 0.08451 4.30370 10.04573 9.86551 9.71441 9.78719 9.24307 4.91298 3.67709 10.33339 9.36783 77 L - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.46296 10.18522 0.61948 0.77267 0.48579 0.95505 - 44 2.79484 8.96939 4.84170 4.23936 5.77607 4.76823 5.03024 4.96855 3.22113 3.40689 5.09332 5.71022 0.46379 3.41521 2.31033 4.18391 4.06538 4.34472 9.40608 6.03322 78 P - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.01198 9.46304 4.43703 0.61948 0.77267 0.48579 0.95505 - 45 1.09792 6.91481 2.89040 1.83127 8.32051 4.00290 5.43771 3.76861 2.53550 3.25984 5.57010 3.81575 5.25749 2.65958 2.83702 3.31114 3.14270 3.15102 6.27434 6.13294 79 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00012 9.45118 10.17344 0.61948 0.77267 1.84289 0.17240 - 46 3.34148 5.96158 4.93711 4.36249 4.22802 6.03921 4.56766 3.60765 5.48885 2.17283 3.40248 5.95049 0.56265 3.95145 2.92975 4.17187 4.08038 3.32900 3.95284 5.49994 80 P - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.07901 9.44759 2.57850 0.61948 0.77267 0.61884 0.77342 - 47 2.12428 4.95856 1.39301 1.91842 3.68317 2.63444 5.95254 4.02905 3.82042 2.88813 4.63694 3.77467 3.68248 3.38581 3.58613 3.41978 3.26105 2.97408 4.84974 3.37957 81 d - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.04117 6.05491 3.27054 0.13868 2.04414 0.12946 2.10840 - 48 1.77092 8.92212 3.08860 2.24157 2.76143 3.40051 4.00979 3.48300 3.67431 2.37604 4.99544 3.51142 3.21752 2.65746 2.70182 2.88204 3.48438 2.97977 4.15327 3.05671 83 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.12402 9.37823 2.14940 0.61948 0.77267 0.03372 3.40657 - 49 1.88184 5.98319 2.36704 2.51676 4.68492 2.38922 4.49015 3.28269 3.38319 3.33745 6.14954 2.86195 3.11703 2.34555 3.42964 2.31020 2.75659 3.11079 4.85821 5.36213 84 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.04457 3.13393 9.92262 0.01094 4.52124 0.01426 4.25770 - 50 1.51653 6.21260 2.95065 2.92431 3.93145 2.76974 3.81084 3.31455 4.12068 2.33513 3.73390 3.24939 3.17037 3.04699 3.21889 2.23671 2.90490 2.98600 6.55571 4.33902 86 a - - - - 2.54091 4.18909 2.92766 2.70561 3.22625 2.66633 3.77575 2.83006 2.82275 2.33953 3.73926 3.18354 3.03052 3.22984 2.91696 2.68331 2.91750 2.69798 4.47296 3.49288 - 0.00000 * * 0.00000 * 0.00000 * -// diff --git a/src/retromol_antismash/inference/factory.py b/src/retromol_antismash/inference/factory.py index 83ac59c..e04d637 100644 --- a/src/retromol_antismash/inference/factory.py +++ b/src/retromol_antismash/inference/factory.py @@ -6,6 +6,13 @@ from the same config, instead of each hardcoding its own model choice. Switching predictors (or adding a new one) is a pmp.yml edit plus one branch here, not a multi-file change. + +There is deliberately no pyhmmer-based model here: "paras_cli" +(retromol_antismash.inference.model_paras_cli.ParasCliModel, backed by +src/retromol_paras/) is the only NRPS substrate-prediction model, running domain +extraction via command-line HMMER2/HMMER3/MUSCLE3 and training its own +RandomForestClassifier against this repo's pinned scikit-learn version, rather than +unpickling a pretrained model file built under someone else's environment. """ from pathlib import Path @@ -20,7 +27,6 @@ def build_nrps_a_domain_model( threshold: float = 0.1, keep_top: int = 3, cache_dir: str | Path | None = None, - model_path: str | Path | None = None, force_retrain: bool = False, ) -> DomainInferenceModel | None: """ @@ -33,12 +39,9 @@ def build_nrps_a_domain_model( :param threshold: minimum predicted probability for a substrate call to be kept (passed through to whichever model is built). :param keep_top: number of top-scoring substrate predictions to keep per domain. - :param cache_dir: model/training cache directory (meaning is model-specific: a - download cache for "paras", a training-signature + fitted-model cache for - "paras_cli"). - :param model_path: "paras"-only: path to a custom PARAS model file. - :param force_retrain: "paras_cli"-only: retrain from scratch even if a cached - model is present. + :param cache_dir: training-signature + fitted-model cache directory (see + retromol_paras.train.train_model). + :param force_retrain: retrain from scratch even if a cached model is present. :return: a DomainInferenceModel, or None if the selected method reads antiSMASH's own GenBank qualifier instead of running a model (source: qualifier) -- there's nothing to build or register in that case; @@ -53,10 +56,6 @@ def build_nrps_a_domain_model( if method.source != "model": return None - if method.model == "paras": - from retromol_antismash.inference.model_paras import ParasModel - return ParasModel(threshold=threshold, keep_top=keep_top, cache_dir=cache_dir, model_path=model_path) - if method.model == "paras_cli": from retromol_antismash.inference.model_paras_cli import ParasCliModel return ParasCliModel(threshold=threshold, keep_top=keep_top, cache_dir=cache_dir, force_retrain=force_retrain) diff --git a/src/retromol_antismash/inference/model_paras.py b/src/retromol_antismash/inference/model_paras.py deleted file mode 100644 index 0d5e4a5..0000000 --- a/src/retromol_antismash/inference/model_paras.py +++ /dev/null @@ -1,868 +0,0 @@ -"""Module for the PARAS domain inference model.""" - -import logging -import os -from dataclasses import dataclass -from importlib.resources import files -from pathlib import Path -from typing import Any, TYPE_CHECKING - -import joblib -import numpy as np - -import retromol_antismash.data -from retromol_antismash.inference.base import DomainInferenceModel -from retromol_antismash.model import Domain, InferenceResult -from retromol_antismash.utils import download_and_prepare - -try: - from pyhmmer import easel, plan7, hmmer - PYHMMER_AVAILABLE = True - - HMM_DB_PATH = str(files(retromol_antismash.data).joinpath("AMP-binding_converted.hmm")) - with plan7.HMMFile(HMM_DB_PATH) as hmm_file: - HMM_DB = list(hmm_file) - -except ImportError: - plan7 = None - PYHMMER_AVAILABLE = False - HMM_DB = None - -if TYPE_CHECKING: - from pyhmmer import easel, plan7, hmmer - -log = logging.getLogger(__name__) - - -PARAS_CACHE_DIR = os.getenv("PARAS_CACHE_DIR", "paras_cache") -PARAS_DOWNLOAD_URL = "https://zenodo.org/records/17224548/files/all_substrates_model.paras.gz?download=1" - - -_PARAS_MODEL_PATH_CACHE: dict[str, Path] = {} -_PARAS_MODEL_OBJ_CACHE: dict[str, object] = {} - -VALID = set("ACDEFGHIKLMNPQRSTVWY-") - - -FEATURE_NAMES = [ - "WOLS870101", - "WOLS870102", - "WOLS870103", - "FAUJ880109", - "GRAR740102", - "RADA880108", - "ZIMJ680103", - "TSAJ990101", - "CHOP780201", - "CHOP780202", - "CHOP780203", - "ZIMJ680104", - "NEU1", - "NEU2", - "NEU3", -] - - -FEATURES = { - "-": [0.00, 0.00, 0.00, 1, 8.3, 0.21, 13.59, 145.2, 1.00, 1.03, 0.99, 6.03, 0.06, 0.00, 0.10], - "A": [0.07, -1.73, 0.09, 0, 8.1, -0.06, 0.00, 90.0, 1.42, 0.83, 0.66, 6.00, 0.06, -0.25, 0.25], - "C": [0.71, -0.97, 4.13, 0, 5.5, 1.36, 1.48, 103.3, 0.70, 1.19, 1.19, 5.05, -0.56, -0.40, -0.14], - "D": [3.64, 1.13, 2.36, 1, 13.0, -0.80, 49.70, 117.3, 1.01, 0.54, 1.46, 2.77, 0.97, -0.08, 0.08], - "E": [3.08, 0.39, -0.07, 1, 12.3, -0.77, 49.90, 142.2, 1.51, 0.37, 0.74, 3.22, 0.85, -0.10, -0.05], - "F": [-4.92, 1.30, 0.45, 0, 5.2, 1.27, 0.35, 191.9, 1.13, 1.38, 0.60, 5.48, -0.99, 0.18, 0.15], - "G": [2.23, -5.36, 0.30, 0, 9.0, -0.41, 0.00, 64.9, 0.57, 0.75, 1.56, 5.97, 0.32, -0.32, 0.28], - "H": [2.41, 1.74, 1.11, 1, 10.4, 0.49, 51.60, 160.0, 1.00, 0.87, 0.95, 7.59, 0.15, -0.03, -0.10], - "I": [-4.44, -1.68, -1.03, 0, 5.2, 1.31, 0.13, 163.9, 1.08, 1.60, 0.47, 6.02, -1.00, -0.03, 0.10], - "K": [2.84, 1.41, -3.14, 2, 11.3, -1.18, 49.50, 167.3, 1.16, 0.74, 1.01, 9.74, 1.00, 0.32, 0.11], - "L": [-4.19, -1.03, -0.98, 0, 4.9, 1.21, 0.13, 164.0, 1.21, 1.30, 0.59, 5.98, -0.83, 0.05, 0.01], - "M": [-2.49, -0.27, -0.41, 0, 5.7, 1.27, 1.43, 167.0, 1.45, 1.05, 0.60, 5.74, -0.68, -0.01, 0.04], - "N": [3.22, 1.45, 0.84, 2, 11.6, -0.48, 3.38, 124.7, 0.67, 0.89, 1.56, 5.41, 0.70, -0.06, 0.17], - "P": [-1.22, 0.88, 2.23, 0, 8.0, 1.1, 1.58, 122.9, 0.57, 0.55, 1.52, 6.30, 0.45, 0.23, 0.41], - "Q": [2.18, 0.53, -1.14, 2, 10.5, -0.73, 3.53, 149.4, 1.11, 1.10, 0.98, 5.65, 0.71, -0.02, 0.12], - "R": [2.88, 2.52, -3.44, 4, 10.5, -0.84, 52.00, 194.0, 0.98, 0.93, 0.95, 10.76, 0.80, 0.19, -0.41], - "S": [1.96, -1.63, 0.57, 1, 9.2, -0.50, 1.67, 95.4, 0.77, 0.75, 1.43, 5.68, 0.48, -0.15, 0.23], - "T": [0.92, -2.09, -1.40, 1, 8.6, -0.27, 1.66, 121.5, 0.83, 1.19, 0.96, 5.66, 0.38, -0.10, 0.29], - "V": [-2.69, -2.53, -1.29, 0, 5.9, 1.09, 0.13, 139.0, 1.06, 1.70, 0.50, 5.96, -0.75, -0.19, 0.03], - "W": [-4.75, 3.65, 0.85, 1, 5.4, 0.88, 2.10, 228.2, 1.08, 1.37, 0.96, 5.89, -0.57, 0.31, 0.34], - "Y": [1.39, 2.32, 0.01, 1, 6.2, 0.33, 1.61, 197.0, 0.69, 1.47, 1.14, 5.66, -0.35, 0.40, -0.02], -} - -POSITIONS_ACTIVE_SITE = [ - 13, - 16, - 17, - 41, - 46, - 47, - 48, - 49, - 50, - 51, - 52, - 55, - 93, - 94, - 125, - 126, - 127, - 128, - 129, - 152, - 153, - 154, - 155, - 156, - 157, - 158, - 159, - 160, - 161, - 162, - 163, - 164, - 165, - 166, -] - - -LABEL_TO_SMILES = { - "(2S,3R)-2-amino-3-hydroxy-4-(4-nitrophenyl)butanoic acid": r"C1=CC(=CC=C1C[C@H]([C@@H](C(=O)O)N)O)[N+](=O)[O-]", - "(2S,6R)-diamino-(5R,7)-dihydroxy-heptanoic acid": r"C(C[C@@H](C(=O)O)N)[C@H]([C@@H](CO)N)O", - "(4S)-5,5,5-trichloroleucine": r"CCC(=O)CCCCC[C@@H](C(=O)O)N", - "(E)-4-methylhex-2-enoic acid": r"CCC(C)/C=C/C(=O)O", - "(S,E)-2-amino-4-decenoic acid": r"CCCCC/C=C/C[C@@H](C(=O)O)N", - "1-(1,1-dimethylallyl)-tryptophan": r"CC(C)(C=C)N1C=C(C2=CC=CC=C21)C[C@@H](C(=O)O)N", - "1-aminocyclopropane-1-carboxylic acid": r"C(O)(=O)C1(CC1)(N)", - "1-pyrroline-5-carboxylic acid": r"O=C(O)C1/N=C\CC1", - "10,14-dimethyloctadecanoic acid": r"OC(CCCCCCCCC(C)CCCC(C)CCCC)=O", - "2,3-diaminobutyric acid": r"NC(C)[C@@H](C(=O)O)N", - "2,3-diaminopropionic acid": r"C([C@@H](C(=O)O)N)N", - "2,3-dihydroxy-para-aminobenzoic acid": r"C1=CC(=C(C(=C(N)1)O)O)C(=O)O", - "2,3-dihydroxybenzoic acid": r"C1=CC(=C(C(=C1)O)O)C(=O)O", - "2,3-dihydroxyhexadecanoic acid": r"CCCCCCCCCCCCCC(C(C(=O)O)O)O", - "2,4-diaminobutyric acid": r"C(CN)[C@@H](C(=O)O)N", - "2,4-dihydroxypentanoic acid": r"CC(CC(C(=O)O)O)O", - "2-(1-methylcyclopropyl)-D-glycine": r"CC1(CC1)[C@H](C(=O)O)N", - "2-amino-3,5-dimethyl-4-hexenoic Acid": r"CC(C=C(C)C)C(C(=O)O)N", - "2-amino-3-hydroxycyclopent-2-enone": r"C1CC(=O)C(=C1O)N", - "2-amino-6-hydroxy-4-methyl-8-oxodecanoic acid": r"CCC(=O)CC(CC(C)CC(C(=O)O)N)O", - "2-aminoadipic acid": r"C(C[C@@H](C(=O)O)N)CC(=O)O", - "2-aminobutyric acid": r"CC[C@@H](C(=O)O)N", - "2-aminoisobutyric acid": r"O=C(O)C(N)(C)C", - "2-carboxy-6-hydroxyoctahydroindole": r"N1[C@H](C(=O)O)C[C@@H]2CC[C@@H](O)C[C@H]12", - "2-chloro-3,5-dihydroxy-4-methylphenylglycine": r"CC1=C(O)C(Cl)=C(C=C(O)1)[C@@H](C(=O)O)N", - "2-chlorobenzoic acid": r"C1=CC=C(C(=C1)C(=O)O)Cl", - "2-hydroxy-4-methylpentanoic acid": r"CC(C)CC(C(=O)O)O", - "2-hydroxypent-4-enoic acid": r"C=CCC(C(=O)O)O", - "2-ketoglutaric acid": r"C(CC(=O)O)C(=O)C(=O)O", - "2-ketoisocaproic acid": r"O=C(C(=O)O)CC(C)C", - "2-ketoisovaleric acid": r"O=C(C(=O)O)C(C)C", - "2-methylserine": r"C[C@](CO)(C(=O)O)N", - "2-sulfamoylacetic acid": r"C(C(=O)O)S(=O)(=O)N", - "2R-hydroxy-3-methylpentanoic acid": r"CCC(C)[C@H](C(=O)O)O", - "2R-hydroxyisovaleric acid": r"CC(C)[C@H](C(=O)O)O", - "2S,3S-diaminobutyric acid": r"C[C@@H]([C@@H](C(=O)O)N)N", - "2S-amino decanoic acid": r"CCCCCCCC[C@H](N)C(=O)O", - "2S-amino-4-hexenoic acid": r"C/C=C/CC(C(=O)O)N", - "2S-amino-8-oxodecanoic acid": r"CCC(=O)CCCCC[C@@H](C(=O)O)N", - "2S-amino-9,10-epoxy-8-oxodecanoic acid": r"C1C(O1)C(=O)CCCCC[C@@H](C(=O)O)N", - "2S-amino-dodecanoic acid": r"CCCCCCCCCC[C@@H](C(=O)O)N", - "2S-amino-octanoic-acid": r"CCCCCC[C@@H](C(=O)O)N", - "2S-aminodecanoic acid": r"CCCCCCCC[C@@H](C(=O)O)N", - "2S-aminododecanoic acid": r"CCCCCCCCCC[C@@H](C(=O)O)N", - "2S-aminooctanoic acid": r"CCCCCC[C@@H](C(=O)O)N", - "2S-hydroxyisocaproic acid": r"CC(C)C[C@@H](C(=O)O)O", - "2S-hydroxyisovaleric acid": r"CC(C)[C@@H](C(=O)O)O", - "2S-methyl-3-oxobutyrine": r"CC(=O)[C@](C)(N)C(=O)O", - "3,3-dihomo-4-methoxytyrosine": r"N[C@@H](CCCC1=CC=C(OC)C=C1)C(=O)O", - "3,3-dihomophenylalanine": r"N[C@@H](CCCC1=CC=CC=C1)C(=O)O", - "3,3-dihomotyrosine": r"N[C@@H](CCCC1=CC=C(O)C=C1)C(=O)O", - "3,4-dehydrolysine": r"C(CCN)=C[C@@H](C(=O)O)N", - "3,4-dihydroxybenzoic acid": r"C1=CC(=C(C=C1C(=O)O)O)O", - "3,5-dichloro-4-hydroxyphenylglycine": r"C1=C(Cl)C(=C(Cl)C=C1[C@@H](C(=O)O)N)O", - "3,5-dihydroxyphenylglycine": r"N[C@H](C(=O)O)c1cc(O)cc(O)c1", - "3-(2-nitrocyclopropylalanine)": r"C1[C@H]([C@@H]1[N+](=O)[O-])C[C@@H](C(=O)O)N", - "3-(3-pyridyl)-alanine": r"C1=CC(=CN=C1)C[C@@H](C(=O)O)N", - "3-amino-2,4-dihydroxybenzoic acid": r"C1=CC(=C(C(=C1C(=O)O)O)N)O", - "3-amino-4-hydroxybenzoic acid": r"C1=CC(=C(C=C1C(=O)O)N)O", - "3-amino-6-hydroxy-2-piperidone": r"C1CC(NC(=O)C1N)O", - "3-aminoisobutyric acid": r"CC(CN)C(=O)O", - "3-chlorotyrosine": r"C1=C(Cl)C(=CC=C1C[C@@H](C(=O)O)N)O", - "3-hydroxy-4-methylproline": r"CC1C(O)[C@H](NC1)C(=O)O", - "3-hydroxy-O-methyl-5-methyltyrosine": r"C1=C(O)C(=C(C)C=C1C[C@@H](C(=O)O)N)OC", - "3-hydroxy-O-methyltyrosine": r"C1=C(O)C(=CC=C1C[C@@H](C(=O)O)N)OC", - "3-hydroxy-para-aminobenzoic acid": r"C1=CC(=C(C=C1C(=O)O)O)N", - "3-hydroxyasparagine": r"N[C@H](C(O)=O)C(O)C(N)=O", - "3-hydroxyaspartic acid": r"N[C@@H](C(C(=O)O)O)(C(=O)O)", - "3-hydroxyglutamine": r"C(C([C@@H](C(=O)O)N)O)C(=O)N", - "3-hydroxykynurenine": r"C1=CC(=C(C(=C1)O)N)C(=O)C[C@@H](C(=O)O)N", - "3-hydroxyleucine": r"CC(C)C([C@@H](C(=O)O)N)O", - "3-hydroxypicolinic acid": r"C1=CC(=C(N=C1)C(=O)O)O", - "3-hydroxyquinaldic acid": r"c1ccc2c(c1)cc(c(n2)C(=O)O)O", - "3-hydroxytyrosine": r"C1=CC(=C(C=C1C[C@@H](C(=O)O)N)O)O", - "3-hydroxyvaline": r"CC(O)(C)[C@@H](C(=O)O)N", - "3-methoxyanthranilic acid": r"COC1=CC=CC(=C1N)C(=O)O", - "3-methoxyaspartic acid": r"N[C@H](C(C(=O)O)OC)(C(=O)O)", - "3-methyl-D-aspartic acid wonky": r"C[C@@H]([C@H](C(=O)O)N)C(=O)O", - "3-methylasparagine": r"CC([C@@H](C(=O)O)N)C(=O)N", - "3-methylaspartic acid": r"CC([C@@H](C(=O)O)N)C(=O)O", - "3-methylglutamic acid": r"CC(CC(=O)O)[C@@H](C(=O)O)N", - "3-methylleucine": r"CC(C)C(C)[C@@H](C(=O)O)N", - "3-nitrotyrosine": r"C1=CC(=C(C=C1C[C@@H](C(=O)O)N)[N+](=O)[O-])O", - "3R-aminoisobutyric acid": r"C[C@H](CN)C(=O)O", - "3R-chloroproline": r"C1[C@@H](Cl)[C@H](NC1)C(=O)O", - "3R-hydroxy-2,4-diaminobutyric acid": r"NC[C@@H](O)[C@@H](C(=O)O)N", - "3R-hydroxyasparagine": r"N[C@H](C(O)=O)[C@@H](O)C(N)=O", - "3R-hydroxyaspartic acid": r"N[C@@H]([C@H](C(=O)O)O)(C(=O)O)", - "3R-hydroxyglutamine": r"C([C@H]([C@@H](C(=O)O)N)O)C(=O)N", - "3R-hydroxyhomotyrosine": r"C1=CC(=CC=C1C[C@H]([C@@H](C(=O)O)N)O)O", - "3R-hydroxyleucine": r"CC(C)[C@H]([C@@H](C(=O)O)N)O", - "3R-methyl-D-aspartic acid wonky": r"N[C@H]([C@@H](O)C(O)=O)C(O)=O", - "3R-methylbeta-alanine": r"NC[C@@H](C)C(=O)O", - "3R-methylglutamic acid": r"C[C@H](CC(=O)O)[C@@H](C(=O)O)N", - "3S,4R-dichloroproline": r"Cl[C@H]1[C@@H](Cl)[C@H](NC1)C(=O)O", - "3S,4S-dihydroxyhomotyrosine": r"C1=CC(=CC=C1[C@H](O)[C@H]([C@@H](C(=O)O)N)O)O", - "3S-aminobutyric acid": r"C[C@@H](CC(=O)O)N", - "3S-carboxypiperazine": r"C1NN[C@H](C(=O)O)CC1", - "3S-cyclohex-2-enylalanine": r"C1C=C[C@H](CC1)C[C@@H](C(=O)O)N", - "3S-hydroxy-4R-methyloctanoic acid": r"CCCC[C@H]([C@H](CC(O)=O)O)C", - "3S-hydroxy-4S-methylproline": r"C[C@@H]1[C@H](O)[C@H](NC1)C(=O)O", - "3S-hydroxy-6-chlorohistidine": r"C1=C(NC(Cl)=N1)[C@H]([C@@H](C(=O)O)N)O", - "3S-hydroxyasparagine": r"N[C@H](C(O)=O)[C@H](O)C(N)=O", - "3S-hydroxyleucine": r"CC(C)[C@@H]([C@@H](C(=O)O)N)O", - "3S-hydroxypipecolic acid": r"C1C[C@@H]([C@H](NC1)C(=O)O)O", - "3S-hydroxyproline": r"O[C@@H]1[C@H](NCC1)C(=O)O", - "3S-methyl-D-aspartic acid branched": r"C[C@@H]([C@H](C(=O)O)N)C(=O)O", - "3S-methyl-D-aspartic acid wonky": r"N[C@H]([C@H](O)C(O)=O)C(O)=O", - "3S-methylaspartic acid": r"C[C@@H]([C@@H](C(=O)O)N)C(=O)O", - "3S-methylaspartic acid branched": r"C[C@@H]([C@@H](C(=O)O)N)C(=O)O", - "3S-methylleucine": r"CC(C)[C@H](C)[C@@H](C(=O)O)N", - "3S-methylproline": r"C[C@@H]1[C@H](NCC1)C(=O)O", - "4,5-dehydroarginine": r"O=C(O)[C@@H](N)C/C=C/NC(N)=N", - "4,5-dihydroxyornithine": r"C([C@@H](C(=O)O)N)C(C(N)O)O", - "4-acetamidopyrrole-2-carboxylic acid": r"CC(=O)NC1=CNC(=C1)C(=O)O", - "4-amino-2-hydroxy-3-isopropoxybenzoic acid": r"CC(C)OC1=C(C=CC(=C1O)C(=O)O)N", - "4-aminobutyric acid": r"NCCCC(=O)O", - "4-aminophenylalanine": r"C1=CC(=CC=C1C[C@@H](C(=O)O)N)N", - "4-chlorobenzoic acid": r"C1=CC(=CC=C1C(=O)O)Cl", - "4-hydroxy-3-nitrobenzoic acid": r"C1=CC(=C(C=C1C(=O)O)[N+](=O)[O-])O", - "4-hydroxy-D-kynurenine": r"C1=C(O)C=C(C(=C1)C(=O)C[C@H](C(=O)O)N)N", - "4-hydroxybenzoic acid": r"C1=CC(=CC=C1C(=O)O)O", - "4-hydroxyglutamine": r"C(C(O)C(=O)N)[C@@H](C(=O)O)N", - "4-hydroxyindole-3-carboxylic acid": r"c1cc2c(c(c1)O)c(c[nH]2)C(=O)O", - "4-hydroxyphenylglycine": r"C1=CC(=CC=C1[C@@H](C(=O)O)N)O", - "4-hydroxyphenylpyruvic acid": r"C1=CC(=CC=C1CC(=O)C(=O)O)O", - "4-hydroxyproline": r"C1[C@H](NCC1O)C(=O)O", - "4-hydroxythreonine": r"C([C@H]([C@@H](C(=O)O)N)O)O", - "4-hydroxyvaline": r"CC(CO)[C@@H](C(=O)O)N", - "4-methoxytryptophan": r"C1=CC=C2C(=C1OC)C(=CN2)C[C@@H](C(=O)O)N", - "4-methylproline": r"CC1C[C@H](NC1)C(=O)O", - "4-nitrotryptophan": r"C1=CC=C2C(=C1[N+](=O)[O-])C(=CN2)C[C@@H](C(=O)O)N", - "4-oxoproline": r"C1[C@H](NCC1=O)C(=O)O", - "4R-E-butenyl-4R-methylthreonine": r"C/C=C/C[C@@H](C)[C@H]([C@@H](C(=O)O)N)O", - "4R-hydroxyproline": r"C1[C@H](NC[C@@H]1O)C(=O)O", - "4R-methylproline": r"C[C@@H]1C[C@H](NC1)C(=O)O", - "4R-propylproline": r"CCC[C@@H]1C[C@H](NC1)C(=O)O", - "4S,5-dihydroxy-2S-aminopentanoic acid": r"O[C@@H](C[C@@H](C(=O)O)N)CO", - "4S-acetyl-5S-methylproline": r"CC(=O)O[C@H]1C[C@H](N[C@H](C)1)C(=O)O", - "4S-hydroxylysine": r"NCC[C@H](O)C[C@@H](C(=O)O)N", - "4S-methylazetidine-2S-carboxylic acid": r"C[C@H]1C[C@H](N1)C(=O)O", - "4S-methylproline": r"C[C@H]1C[C@H](NC1)C(=O)O", - "4S-propenylproline": r"C/C=C\[C@H]1C[C@H](NC1)C(=O)O", - "5,5-dimethylpipecolic acid": r"C1C(C)(C)CN[C@@H](C1)C(=O)O", - "5-aminolevulinic acid": r"C(CC(=O)O)C(=O)CN", - "5-chloroanthranilic acid": r"C1=CC(=C(C=C1Cl)C(=O)O)N", - "5-chlorotryptophan": r"C1=CC2=C(C=C1Cl)C(=CN2)C[C@@H](C(=O)O)N", - "5-methoxytyrosine": r"C1=C(OC)C(=CC=C1C[C@@H](C(=O)O)N)O", - "5-methylorsellinic acid": r"C=1(C=C(C(=C(C1C)C)C(=O)O)O)O", - "5S-methylproline": r"C1C[C@H](N[C@@H](C)1)C(=O)O", - "6,7-dichlorotryptophan": r"C1=C(Cl)C(Cl)=C2C(=C1)C(=CN2)C[C@@H](C(=O)O)N", - "6-chloro-4-hydroxy-1-methyl-indole-3-carboxylic acid": r"C(O)1=C(Cl)C=C2C(=C1)C(=CN(C)2)C(=O)O", - "6-chloro-4-hydroxyindole-3-carboxylic acid": r"c(Cl)1cc2c(c(c1)O)c(c[nH]2)C(=O)O", - "6-chlorotryptophan": r"C1=C(Cl)C=C2C(=C1)C(=CN2)C[C@@H](C(=O)O)N", - "6-hydroxy-tetrahydro-isoquinoline-3-carboxylic acid": r"C1C(NCC2=C1C=C(C=C2)O)C(=O)O", - "6-methylsalicylic acid": r"CC1=C(C(=CC=C1)O)C(=O)O", - "6S-methyl-pipecolic acid": r"C1C[C@H](C)N[C@@H](C1)C(=O)O", - "Acetyl-Coa": r"CC(=O)SCCNC(=O)CCNC(=O)C(C(C)(C)COP(=O)(O)OP(=O)(O)OC[C@@H]1[C@H]([C@H]([C@@H](O1)N2C=NC3=C(N=CN=C32)N)O)OP(=O)(O)O)O", - "An acid hydrazine polyene (intermediate 14)": r"OC(=O)CCC(=O)NNCC(=O)O", - "Compound 4 (formed by the decarboxylative condensation of L-Phe and succinyl-CoA)": r"C1=CC=C(C=C1)C[C@@H](C(=O)CCC(=O)O)N", - "D-alanine": r"C[C@H](C(=O)O)N", - "D-aspartic acid branched": r"C([C@H](C(=O)O)N)C(=O)O", - "D-glutamic acid branched": r"C(CC(=O)O)[C@H](C(=O)O)N", - "D-isovaline": r"CC[C@](C)(C(=O)O)N", - "D-leucine": r"CC(C)C[C@H](C(=O)O)N", - "D-lysergic acid": r"CN1C[C@@H](C=C2C1CC3=CNC4=CC=CC2=C34)C(=O)O", - "D-phenylalanine": r"C1=CC=C(C=C1)C[C@H](C(=O)O)N", - "D-phenyllactic acid": r"C1=CC=C(C=C1)C[C@H](C(=O)O)O", - "D-pipecolic acid": r"C1CCN[C@H](C1)C(=O)O", - "D-serine": r"C([C@H](C(=O)O)N)O", - "Malonyl-CoA": r"CC(C)(COP(=O)(O)OP(=O)(O)OC[C@@H]1[C@H]([C@H]([C@@H](O1)N2C=NC3=C(N=CN=C32)N)O)OP(=O)(O)O)[C@H](C(=O)NCCC(=O)NCCSC(=O)CC(=O)O)O", - "N-(1-methyl)-tryptophan": r"C1=CC=C2C(=C1)C(=CN(C)2)C[C@@H](C(=O)O)N", - "N-(1-propargyl)-tryptophan": r"C1=CC=C2C(=C1)C(=CN(CC#C)2)C[C@@H](C(=O)O)N", - "N-formylglycine": r"C(C(=O)O)NC=O", - "N-hydroxyvaline": r"CC(C)[C@@H](C(=O)O)NO", - "N-methylphenylalanine": r"CN[C@@H](CC1=CC=CC=C1)C(=O)O", - "N-methyltyrosine": r"C1=CC(=CC=C1C[C@@H](C(=O)O)NC)O", - "N1-methoxytryptophan": r"C1=CC=C2C(=C1)C(=CN(OC)2)C[C@@H](C(=O)O)N", - "N5-acetyl-N5-hydroxyornithine": r"CC(=O)N(CCC[C@@H](C(=O)O)N)O", - "N5-acetyl-hydroxyornithine": r"CC(=O)N(CCC[C@@H](C(=O)O)N)O", - "N5-cis-anhydromevalonyl-N5-hydroxyornithine": r"C(N(C(=O)/C=C(/CCO)\C)O)CC[C@@H](C(O)=O)N", - "N5-formyl-N5-hydroxyornithine": r"C(C[C@@H](C(=O)O)N)CN(C=O)O", - "N5-hydroxyornithine": r"C(C[C@@H](C(=O)O)N)CNO", - "N5-nitroso-N5-hydroxyornithine": r"O=NN(CCC[C@@H](C(=O)O)N)O", - "N5-trans-anhydromevalonyl-N5-hydroxyornithine": r"C(C[C@@H](C(=O)O)N)CN(O)C(=O)/C=C(C)/CCO", - "N6-hydroxylysine": r"C(CCNO)C[C@@H](C(=O)O)N", - "O-dimethylallyl-L-tyrosine": r"CC(=CCOC1=CC=C(C=C1)C[C@@H](C(=O)O)N)C", - "O-methylthreonine": r"C[C@H]([C@@H](C(=O)O)N)OC", - "O-methyltyrosine": r"COC1=CC=C(C=C1)C[C@@H](C(=O)O)N", - "R-3-hydroxy-3-methylproline": r"O[C@](C)1[C@H](NCC1)C(=O)O", - "R-aza-beta-tyrosine": r"C1=CC(=NC=C1O)[C@@H](CC(=O)O)N", - "R-beta-hydroxyphenylalanine": r"O[C@H](C1=CC=CC=C1)[C@@H](C(=O)O)N", - "R-beta-hydroxytyrosine": r"C1=CC(=CC=C1[C@H]([C@@H](C(=O)O)N)O)O", - "R-beta-methylphenylalanine": r"C[C@H](C1=CC=CC=C1)[C@@H](C(=O)O)N", - "R-beta-methyltryptophan": r"C[C@H](C1=CNC2=CC=CC=C21)[C@@H](C(=O)O)N", - "R-beta-phenylalanine": r"C1=CC=C(C=C1)[C@@H](CC(=O)O)N", - "R-beta-tyrosine": r"C1=CC(=CC=C1[C@@H](CC(=O)O)N)O", - "S-adenosylmethionine": r"C[S+](CC[C@@H](C(=O)[O-])N)C[C@@H]1[C@H]([C@H]([C@@H](O1)N2C=NC3=C(N=CN=C32)N)O)O", - "S-beta-hydroxycyclohex-2S-enylalanine": r"C1C=C[C@H](CC1)[C@H](O)[C@@H](C(=O)O)N", - "S-beta-hydroxyenduracididine": r"C1[C@H](NC(=N1)N)[C@H](O)[C@@H](C(=O)O)N", - "S-beta-hydroxyphenylalanine": r"O[C@@H](C1=CC=CC=C1)[C@@H](C(=O)O)N", - "S-beta-methylphenylalanine": r"C[C@@H](C1=CC=CC=C1)[C@@H](C(=O)O)N", - "S-beta-tyrosine": r"C1=CC(=CC=C1[C@H](CC(=O)O)N)O", - "acetic acid": r"CC(O)=O", - "alanine": r"C[C@@H](C(=O)O)N", - "alaninol": r"C[C@@H](CO)N", - "allo-isoleucine": r"CC[C@@H](C)[C@@H](C(=O)O)N", - "allo-threonine": r"C[C@@H]([C@@H](C(=O)O)N)O", - "anthanillic acid": r"C1=CC=C(C(=C1)C(=O)O)N", - "anthranilic acid": r"C1=CC=C(C(=C1)C(=O)O)N", - "arginine": r"C(C[C@@H](C(=O)O)N)CN=C(N)N", - "argininol": r"N[C@H](CO)CCCN=C(N)N", - "asparagine": r"C([C@@H](C(=O)O)N)C(=O)N", - "aspartic acid": r"C([C@@H](C(=O)O)N)C(=O)O", - "aspartic acid branched": r"C([C@@H](C(=O)O)N)C(=O)O", - "azetidine-2-carboxylic acid": r"O=C(O)[C@H]1NCC1", - "benzoic acid": r"C1=CC=C(C=C1)C(=O)O", - "benzoxazolinate": r"c1ccc2c(c1)nc(o2)C(=O)O", - "beta-alanine": r"NCCC(=O)O", - "beta-hydroxy-3-hydroxy-O-methyl-5-methyltyrosine": r"C1=C(C)C(=C(O)C=C1C(O)[C@@H](C(=O)O)N)OC", - "beta-hydroxy-gamma-methyl-hexadecanoic acid": r"CCCCCCCCCCCCC(C)C(O)CC(=O)O", - "beta-hydroxyarginine": r"C(C(O)[C@@H](C(=O)O)N)CN=C(N)N", - "beta-hydroxyphenylalanine": r"OC(C1=CC=CC=C1)[C@@H](C(=O)O)N", - "beta-hydroxytyrosine": r"C1=CC(=CC=C1C([C@@H](C(=O)O)N)O)O", - "beta-lysine": r"C(C[C@@H](CC(=O)O)N)CN", - "beta-methylphenylalanine": r"CC(C1=CC=CC=C1)C(C(=O)O)N", - "beta-tyrosine": r"C1=CC(=CC=C1C(CC(=O)O)N)O", - "betaine": r"C[N+](C)(C)CC(=O)O", - "butyric acid": r"CCCC(=O)O", - "caffeic acid": r"OC(=O)\C=C\c1ccc(O)c(O)c1", - "capreomycidine": r"C1CN=C(N[C@H]1[C@@H](C(=O)O)N)N", - "cinnamic acid": r"C1=CC=C(C=C1)/C=C/C(=O)O", - "citrulline": r"C(C[C@@H](C(=O)O)N)CNC(=O)N", - "colletorin D acid": r"CC1=CC(=C(C(=C1C(=O)O)O)CC=C(C)C)O", - "coumaric acid": r"C1=CC(=CC=C1/C=C/C(=O)O)O", - "cysteic acid": r"C([C@@H](C(=O)O)N)S(=O)(=O)O", - "cysteine": r"C([C@@H](C(=O)O)N)S", - "cysteine branched": r"C([C@@H](C(=O)O)N)S", - "dehydroarginine": r"C(CN=C(N)N)/C=C(/C(=O)O)\N", - "dehydrophenylalanine": r"N/C(=C\C1=CC=CC=C1)/C(=O)O", - "dehydrotryptophan": r"C1=CC=C2C(=C1)C(=CN2)/C=C(/C(=O)O)\N", - "dehydrovaline": r"CC(=C(C(=O)O)N)C", - "dihydrolysergic acid": r"CN1CC(CC2C1CC3=CNC4=CC=CC2=C34)C(=O)O", - "dimethylsulfoniopropionic acid": r"C[S+](C)CCC(=O)O", - "enduracididine": r"C1[C@H](NC(=N1)N)C[C@@H](C(=O)O)N", - "fatty acid": r"O=C(O)C*", - "fumaric acid": r"C(=C/C(=O)O)\C(=O)O", - "glutamic acid": r"C(CC(=O)O)[C@@H](C(=O)O)N", - "glutamine": r"C(CC(=O)N)[C@@H](C(=O)O)N", - "glycine": r"NCC(=O)O", - "glycolic acid": r"C(C(=O)O)O", - "graminine": r"O=NN(O)CCC[C@H](N)(C(=O)O)", - "grifolic acid": r"CC(C)=CCC/C(C)=C/CC/C(C)=C/CC1=C(O)C=C(C)C(C(=O)O)=C(O)1", - "guanidinoacetic acid": r"C(C(=O)O)N=C(N)N", - "histidine": r"C1=C(NC=N1)C[C@@H](C(=O)O)N", - "homophenylalanine": r"C1=CC=C(C=C1)CC[C@@H](C(=O)O)N", - "homoserine": r"C(CO)[C@@H](C(=O)O)N", - "homotyrosine": r"C1=CC(=CC=C1CC[C@@H](C(=O)O)N)O", - "hydroxyproline": r"C(*)1C[C@H](NC(*)1)C(=O)O", - "indole pyruvic acid": r"C1=CC=C2C(=C1)C(=CN2)CC(=O)C(=O)O", - "isoleucine": r"CC[C@H](C)[C@@H](C(=O)O)N", - "isovaline": r"CC[C@@](C)(C(=O)O)N", - "kynurenine": r"C1=CC=C(C(=C1)C(=O)C[C@@H](C(=O)O)N)N", - "lactic acid": r"CC(C(=O)O)O", - "leucine": r"CC(C)C[C@@H](C(=O)O)N", - "leucinol": r"CC(C)C[C@@H](CO)N", - "linoleic acid": r"CCCCC/C=C\C/C=C\CCCCCCCC(=O)O", - "lysine": r"C(CCN)C[C@@H](C(=O)O)N", - "malic acid": r"C(C(C(=O)O)O)C(=O)O", - "malonamate": r"NC(=O)CC(=O)O", - "meta-tyrosine": r"C1=CC(=CC(=C1)O)C[C@@H](C(=O)O)N", - "methionine": r"CSCC[C@@H](C(=O)O)N", - "methylglutaconyl hydroxyornithine": r"C/C(=C\C(=O)N(CCCC(C(=O)O)N)O)/CC(=O)O", - "nicotinic acid": r"C1=CC(=CN=C1)C(=O)O", - "norcoronamic acid": r"C[C@H]1C[C@]1(C(=O)O)N", - "ochratoxin beta": r"CC1CC2=C(C(=C(C=C2)C(=O)O)O)C(=O)O1", - "ornithine": r"C(C[C@@H](C(=O)O)N)CN", - "p-hydroxybenzoylformic acid": r"C1=CC(=CC=C1C(=O)C(=O)O)O", - "p-hydroxymandelate": r"C1=CC(=CC=C1C(C(=O)O)O)O", - "para-aminobenzoic acid": r"O=C(O)c1ccc(N)cc1", - "pentanoic acid": r"CCCCC(=O)O", - "phenazine-1,6-dicarboxylic acid": r"C1=CC(=C2C(=C1)N=C3C(=N2)C=CC=C3C(=O)O)C(=O)O", - "phenylalanine": r"C1=CC=C(C=C1)C[C@@H](C(=O)O)N", - "phenylalaninol": r"C1=CC=C(C=C1)C[C@@H](CO)N", - "phenylglycine": r"C1=CC=C(C=C1)[C@@H](C(=O)O)N", - "phenyllactic acid": r"C1=CC=C(C=C1)C[C@@H](C(=O)O)O", - "phenylpyruvic acid": r"C1=CC=C(C=C1)CC(=O)C(=O)O", - "pipecolic acid": r"C1CCN[C@@H](C1)C(=O)O", - "piperazic acid": r"C1C[C@H](NNC1)C(=O)O", - "piperonylic acid": r"OC(=O)c1ccc2OCOc2c1", - "proline": r"C1C[C@H](NC1)C(=O)O", - "propionic acid": r"CCC(=O)O", - "pyrrole-2-carboxylic acid": r"C1=CNC(=C1)C(=O)O", - "pyruvic acid": r"CC(=O)C(=O)O", - "quinoxaline-2-carboxylic acid": r"C1=CC=C2C(=C1)N=CC(=N2)C(=O)O", - "salicylic acid": r"C1=CC=C(C(=C1)C(=O)O)O", - "serine": r"C([C@@H](C(=O)O)N)O", - "succinic semialdehyde": r"C(CC(=O)O)C=O", - "succinyl-hydrazinoacetic acid": r"N/N=C/C=C/C=C/C=C/C=C/C=C/C(=O)O", - "tetradecanoic acid": r"CCCCCCCCCCCCCC(=O)O", - "threonine": r"C[C@H]([C@@H](C(=O)O)N)O", - "trans-2-crotylglycine": r"C/C=C/C[C@@H](C(=O)O)N", - "trans-2-hexenoic acid": r"CCC\C=C\C(O)=O", - "tricarballylic acid": r"C(C(CC(=O)O)C(=O)O)C(=O)O", - "tryptophan": r"C1=CC=C2C(=C1)C(=CN2)C[C@@H](C(=O)O)N", - "tyrosine": r"C1=CC(=CC=C1C[C@@H](C(=O)O)N)O", - "ustethylinic acid": r"c1(C)c(O)c(C(=O)O)c(CC)cc(O)1", - "valine": r"CC(C)[C@@H](C(=O)O)N", - "valine isocyanide": r"CC(C)[C@H]([N+]#[C-])C(O)=O", - "valinol": r"CC(C)[C@@H](CO)N", -} - - -@dataclass -class ADomain: - """ - Dataclass representing an A domain. - - :param protein: Name of the protein containing the A domain. - :param start: Start position of the A domain. - :param end: End position of the A domain. - :param domain_nr: Domain number of A domain in NRPS (optional). - :param sequence: Amino acid sequence of the A domain (optional). - :param extended_signature: Extended signature of the A domain (optional). - """ - - protein: str - start: int - end: int - domain_nr: int | None = None - sequence: str | None = None - extended_signature: str | None = None - - -def _b2s(x: Any) -> str: - """ - Convert input to string. - - :param x: input object - :return: string representation - """ - if isinstance(x, (bytes, bytearray)): - return x.decode() - - if hasattr(x, "sequence"): - s = x.sequence - return s.decode() if isinstance(s, (bytes, bytearray)) else str(s) - - return str(x) - - -def extract_domain_hits( - seq_id: str, - sequence: str, - evalue_cutoff: float = 1e-5, -) -> list[dict[str, Any]]: - """ - Extract domain hits from a given protein sequence using HMMER. - - :param seq_id: Identifier for the protein sequence. - :param sequence: Amino acid sequence of the protein. - :param evalue_cutoff: E-value cutoff for HMMER hits. - :return: List of dictionaries representing domain hits. - :raises ImportError: If HMMER is not available. - """ - if not PYHMMER_AVAILABLE: - raise ImportError("HMMER is not available. Please install pyhmmer to use this function.") - - alphabet = easel.Alphabet.amino() - text_seq = easel.TextSequence(name=seq_id.encode(), sequence=sequence) - seq = text_seq.digitize(alphabet) - - hits_iter = hmmer.hmmscan([seq], HMM_DB, cpus=1, E=evalue_cutoff) - - query_hits = next(hits_iter) # expect only one sequence - - out = [] - for hit in query_hits: - model_name = _b2s(hit.name) - - for dom in hit.domains: - q_from = int(dom.env_from) - q_to = int(dom.env_to) - - aln = dom.alignment - hmm_aln = _b2s(aln.hmm_sequence) - query_aln = _b2s(aln.target_sequence) - - out.append( - dict( - seq_id=seq_id, - model=model_name, - q_from=q_from, - q_to=q_to, - evalue=float(dom.i_evalue), - score=float(dom.score), - hmm_aln=hmm_aln, - query_aln=query_aln, - domain_obj=dom, - ) - ) - - out.sort(key=lambda d: (d["q_from"], d["q_to"], d["model"])) - - return out - - -def pair_domains( - domain_hits: list[dict[str, Any]], - max_gap: int = 200, -) -> list[tuple[ADomain, str, str]]: - """ - Pair AMP-binding and AMP-binding_C domain hits. - - :param domain_hits: List of domain hit dictionaries. - :param max_gap: Maximum allowed gap between paired domains. - :return: List of tuples containing ADomain objects and their alignments. - """ - hits = sorted(domain_hits, key=lambda d: d["q_from"]) - - a_domains: list[ADomain] = [] - for h1 in hits: - if h1["model"] != "AMP-binding": - continue - - n_from, n_to = h1["q_from"], h1["q_to"] - - matched = None - for h2 in hits: - if h2["model"] != "AMP-binding_C": - continue - - c_from = h2["q_from"] - - if c_from > n_to and (c_from - n_to) <= max_gap: - matched = h2 - break - - start0 = n_from - 1 - end0 = matched["q_to"] if matched is not None else n_to - a_domains.append((ADomain( - protein=h1["seq_id"], - start=start0, - end=end0), - h1["hmm_aln"], - h1["query_aln"] - )) - - a_domains.sort(key=lambda t: t[0].start) - for i, (d, _, _) in enumerate(a_domains, start=1): - d.domain_nr = i - - return a_domains - - -def extract_signature_from_alignment(hmm_aln: str, query_aln: str) -> str | None: - """ - Extract the extended signature from the given HMM and query alignments. - - :param hmm_aln: HMM alignment string - :param query_aln: query alignment string - :return: extended signature string or None if invalid - """ - wanted = set(POSITIONS_ACTIVE_SITE) - picked: dict[int, str] = {} - - hmm_pos = 0 # 1-based counter, increment when HMM char is not a gap - - for h, q in zip(hmm_aln, query_aln): - if h != "-": - hmm_pos += 1 - if hmm_pos in wanted and hmm_pos not in picked: - picked[hmm_pos] = q - - # Quick fix - missing = wanted - set(picked.keys()) - for m in missing: - picked[m] = "-" - - out = [] - for p in POSITIONS_ACTIVE_SITE: - if p not in picked: - return None - out.append(picked[p]) - - sig = "".join(out).upper() - if not sig or not all(c in VALID for c in sig): - return None - - return sig - - -def fill_domain_sequences( - domains: list[ADomain], - protein_seq: str, - min_len: int = 100, -) -> list[ADomain]: - """ - Fill in the sequences for the given domains from the protein sequence. - - :param domains: List of ADomain objects. - :param protein_seq: Amino acid sequence of the protein. - :param min_len: Minimum length of domain sequence to keep. - :return: List of ADomain objects with sequences filled in. - """ - out = [] - - for d in domains: - seq = protein_seq[d.start:d.end] - if len(seq) >= min_len: - d.sequence = seq - out.append(d) - - return out - - -def find_a_domains( - seq_id: str, - protein_seq: str, - evalue_cutoff: float = 1e-5, -) -> list[ADomain]: - """ - Find A domains in a given protein sequence using HMMER. - - :param seq_id: Identifier for the protein sequence. - :param protein_seq: Amino acid sequence of the protein. - :param evalue_cutoff: E-value cutoff for HMMER hits. - :return: List of ADomain objects representing found A domains. - """ - hits = extract_domain_hits(seq_id, protein_seq, evalue_cutoff) - - hits = [h for h in hits if h["model"] in {"AMP-binding", "AMP-binding_C"}] - - paired = pair_domains(hits, max_gap=200) - - domains_only: list[ADomain] = [] - for d, hmm_aln, query_aln in paired: - d.extended_signature = extract_signature_from_alignment(hmm_aln, query_aln) - domains_only.append(d) - - domains_only = fill_domain_sequences(domains_only, protein_seq, min_len=100) - - domains_only = [d for d in domains_only if d.extended_signature is not None] - - domains_only.sort(key=lambda d: (d.protein, d.start)) - - return domains_only - - -def featurize_signature(sig: str) -> np.ndarray: - """ - Featurize the given extended signature into a numerical feature array. - - :param sig: Extended signature string. - :return: Numpy array of features. - """ - assert len(sig) == len(POSITIONS_ACTIVE_SITE), "signature length mismatch" - - features: np.ndarray = np.zeros((len(POSITIONS_ACTIVE_SITE), len(FEATURE_NAMES)), dtype=np.float32) - for i, aa in enumerate(sig): - aa_feats = FEATURES.get(aa) - if aa_feats is None: - raise ValueError(f"invalid amino acid '{aa}' in signature") - features[i, :] = np.array(aa_feats, dtype=np.float32) - - return features.flatten() # shape (n_positions * n_features,) - - -def get_paras_model_path(cache_dir: Path) -> Path: - """ - Get the path to the cached PARAS model, downloading it if necessary. - - :param cache_dir: Path to the cache directory. - :return: Path to the PARAS model file. - """ - cache_dir = Path(cache_dir) - cache_dir.mkdir(parents=True, exist_ok=True) - - # If we already know the path and it still exists, reuse it - cached = _PARAS_MODEL_PATH_CACHE.get(PARAS_DOWNLOAD_URL) - if cached is not None and cached.exists(): - return cached - - # Otherwise download/prepare and remember the path - model_path = download_and_prepare(PARAS_DOWNLOAD_URL, cache_dir) - _PARAS_MODEL_PATH_CACHE[PARAS_DOWNLOAD_URL] = model_path - return model_path - - -def resolve_paras_model_path(model_path: Path | None, cache_dir: Path) -> Path: - """ - Resolve the PARAS model path, downloading it to cache if necessary. - - :param model_path: User-specified model path or None. - :param cache_dir: Path to the cache directory. - :return: Path to the PARAS model file. - """ - cache_dir = Path(cache_dir) - cache_dir.mkdir(parents=True, exist_ok=True) - - if model_path is not None: - model_path = Path(model_path).expanduser().resolve() - if not model_path.exists(): - raise FileNotFoundError(f"specified PARAS model path does not exist: {model_path}") - return model_path - - # No model given -> download/prepare in cache dir - return Path(download_and_prepare(PARAS_DOWNLOAD_URL, cache_dir)) - - -def load_paras_model(model_path: Path) -> object: - """ - Load the PARAS model from the given path. - - :param model_path: Path to the PARAS model file. - :return: Loaded RandomForestClassifier model. - """ - key = str(model_path) - model = _PARAS_MODEL_OBJ_CACHE.get(key) - - if model is None: - log.info(f"loading PARAS model: {model_path}") - model = joblib.load(model_path) - _PARAS_MODEL_OBJ_CACHE[key] = model - - return model - - -class ParasModel(DomainInferenceModel): - """ - Model for predicting A domain substrate specificity using PARAS. - - :param domain: The domain to make predictions for. - :param threshold: Probability threshold for predictions. - :return: A list of InferenceResult objects containing the predictions. - """ - - name: str = "paras" - - def __init__( - self, - threshold: float = 0.1, - keep_top: int = 3, - cache_dir: Path | str | None = None, - model_path: Path | str | None = None, - ) -> None: - """ - Initialize the ParasModel. - - :param threshold: Probability threshold for predictions. - :param keep_top: Number of top predictions to keep. - :param cache_dir: Directory to cache the model. - :param model_path: Path to a custom PARAS model file. - """ - super().__init__() - - # Set cache directory - if cache_dir is None: - cache_dir = PARAS_CACHE_DIR - self.cache_dir = Path(cache_dir) - self.model_path = Path(model_path) if model_path is not None else None - - # Set other parameters - self.threshold = threshold - self.keep_top = keep_top - - def __post_init__(self) -> None: - """ - Post-initialization to set up the model. - - :raises ValueError: If threshold is not between 0 and 1. - """ - super().__post_init__() - - # Make sure threshold is between 0 and 1 - if not (0.0 <= self.threshold <= 1.0): - raise ValueError("threshold must be between 0 and 1") - - # Make sure keep_top is an int and at least 1 - if not (isinstance(self.keep_top, int) and self.keep_top >= 1): - raise ValueError("keep_top must be an integer >= 1") - - - def predict(self, domain: Domain) -> list[InferenceResult]: - """ - Predict the substrate specificity for the given domain. - - :param domain: The domain to make predictions for. - :return: A list of InferenceResult objects containing the predictions. - """ - if domain.type == "AMP-binding": - # Prepare model - model_file = resolve_paras_model_path(self.model_path, self.cache_dir) - model = load_paras_model(model_file) - - # Find A domains in the sequence - a_domains = find_a_domains(seq_id=domain.id, protein_seq=domain.sequence) - - # Make predictions - unknown_prediction = self.result(label="unknown", score=0.0, metadata={}) - - match a_domains: - case []: - log.warning(f"no A domains found in sequence {domain.id}; unable to predict substrate") - return [unknown_prediction] - case [a_domain]: - sig = a_domain.extended_signature - features = featurize_signature(sig).reshape(1, -1) - pred = model.predict_proba(features) - - # Identify top predictions - lbls = model.classes_ - top_indices = np.argsort(pred, axis=1)[0][-self.keep_top:][::-1] - top_lbls = [lbls[i] for i in top_indices] - top_prbs = [pred[0, i] for i in top_indices] - - results = [] - for top_lbl, top_prb in zip(top_lbls, top_prbs): - if top_prb >= self.threshold: - smi = LABEL_TO_SMILES.get(top_lbl) - metadata = {} - if smi is None: - log.warning(f"no SMILES found for predicted label '{top_lbl}'; returning label only") - else: - metadata["smiles"] = smi - results.append(self.result(label=top_lbl, score=round(float(top_prb), 4), metadata=metadata)) - else: - log.debug(f"prediction '{top_lbl}' for sequence {domain.id} below threshold ({top_prb:.4f} < {self.threshold}); skipping") - - if not results: - return [unknown_prediction] - - return results - case _: - log.error(f"found multiple ({len(a_domains)}) A domains in sequence {domain.id}; unable to predict substrate") - return [unknown_prediction] - - else: - # Not the domain type of interest - return [] diff --git a/src/retromol_antismash/inference/model_paras_cli.py b/src/retromol_antismash/inference/model_paras_cli.py index fae729f..527a021 100644 --- a/src/retromol_antismash/inference/model_paras_cli.py +++ b/src/retromol_antismash/inference/model_paras_cli.py @@ -1,12 +1,15 @@ """ -Alternative to model_paras.ParasModel: predicts NRPS A-domain substrate specificity using -retromol_paras, a self-contained reimplementation of PARAS that runs domain extraction via -command-line HMMER2/HMMER3/MUSCLE3 (no pyhmmer) and trains its own RandomForestClassifier -against this repo's pinned scikit-learn version (no unpickling someone else's model file). - -Registered under a different DomainInferenceModel.name ("paras_cli") than the original -("paras") so both can coexist -- point pmp.yml's "predictors.nrps.a_domain" at "paras_cli" -to use this one (see retromol_paras/__init__.py for the required system binaries). +Predicts NRPS A-domain substrate specificity using retromol_paras, a self-contained +reimplementation of PARAS that runs domain extraction via command-line HMMER2/HMMER3/ +MUSCLE3 (no pyhmmer) and trains its own RandomForestClassifier against this repo's +pinned scikit-learn version (no unpickling a pretrained model file built under +someone else's environment). + +This is the only NRPS substrate-prediction model in this repo -- registered as +DomainInferenceModel.name "paras_cli", selected by pmp.yml's +"predictors.nrps.a_domain" (see retromol_paras/__init__.py for the required system +binaries, and retromol_antismash.inference.factory for how pmp.yml resolves to +this class). """ import logging @@ -31,6 +34,7 @@ def __init__( keep_top: int = 3, cache_dir: Path | str | None = None, force_retrain: bool = False, + use_muscle_fallback: bool = True, ) -> None: """ :param threshold: minimum predicted probability for a substrate call to be kept. @@ -38,6 +42,10 @@ def __init__( :param cache_dir: directory to cache the trained model and extracted training signatures in (see retromol_paras.train.train_model). Defaults to ~/.retromol_paras. :param force_retrain: retrain from scratch even if a cached model is present. + :param use_muscle_fallback: see retromol_paras.featurisation.get_domains -- False + trades some coverage (domains HMMER2 misses go unpredicted instead of being + recovered via MUSCLE) for speed (skips the dominant per-domain cost: a MUSCLE3 + profile alignment against a ~1000-sequence reference set). """ super().__init__() if not (0.0 <= threshold <= 1.0): @@ -49,6 +57,7 @@ def __init__( self.keep_top = keep_top self.cache_dir = Path(cache_dir) if cache_dir else DEFAULT_CACHE_DIR self.force_retrain = force_retrain + self.use_muscle_fallback = use_muscle_fallback self._model = None def _get_model(self): @@ -56,32 +65,70 @@ def _get_model(self): self._model = train_model(cache_dir=self.cache_dir, force=self.force_retrain) return self._model + def _results_for(self, domain_id: str, predictions: list) -> list[InferenceResult]: + unknown = self.result(label="unknown", score=0.0, metadata={}) + + results = [] + for pred in predictions: + if pred.score >= self.threshold: + metadata = {"smiles": pred.smiles} if pred.smiles else {} + if not pred.smiles: + log.warning(f"no SMILES found for predicted label '{pred.label}'; returning label only") + results.append(self.result(label=pred.label, score=round(pred.score, 4), metadata=metadata)) + else: + log.debug(f"prediction '{pred.label}' for sequence {domain_id} below threshold ({pred.score:.4f} < {self.threshold}); skipping") + return results or [unknown] + def predict(self, domain: Domain) -> list[InferenceResult]: if domain.type != "AMP-binding": return [] - unknown = self.result(label="unknown", score=0.0, metadata={}) model = self._get_model() - domain_predictions = predict_domains( - model, {domain.id: domain.sequence}, keep_top=self.keep_top + model, {domain.id: domain.sequence}, keep_top=self.keep_top, use_muscle_fallback=self.use_muscle_fallback ) match domain_predictions: case []: log.warning(f"no A domains found in sequence {domain.id}; unable to predict substrate") - return [unknown] + return [self.result(label="unknown", score=0.0, metadata={})] case [a_domain]: - results = [] - for pred in a_domain.predictions: - if pred.score >= self.threshold: - metadata = {"smiles": pred.smiles} if pred.smiles else {} - if not pred.smiles: - log.warning(f"no SMILES found for predicted label '{pred.label}'; returning label only") - results.append(self.result(label=pred.label, score=round(pred.score, 4), metadata=metadata)) - else: - log.debug(f"prediction '{pred.label}' for sequence {domain.id} below threshold ({pred.score:.4f} < {self.threshold}); skipping") - return results or [unknown] + return self._results_for(domain.id, a_domain.predictions) case _: log.error(f"found multiple ({len(domain_predictions)}) A domains in sequence {domain.id}; unable to predict substrate") - return [unknown] + return [self.result(label="unknown", score=0.0, metadata={})] + + def predict_many(self, domains: list[Domain]) -> dict[str, list[InferenceResult]]: + """ + Predict every AMP-binding domain in `domains` in ONE HMMER2/HMMER3(/MUSCLE3 + fallback) pass, instead of one subprocess pair per domain (see + retromol_antismash.inference.registry.annotate_region, which calls this in + preference to predict() when it's available -- a region with several NRPS + modules would otherwise spawn hmmpfam2+hmmscan once *per module*, each + reloading the full HMM profile database from scratch, which is the dominant + cost of this CLI-tool-based reimplementation). + + :param domains: candidate domains -- non-"AMP-binding" ones are ignored. + :return: {domain.id: results}, same per-domain result shape predict() returns. + """ + amp_domains = [d for d in domains if d.type == "AMP-binding"] + if not amp_domains: + return {} + + model = self._get_model() + sequences = {d.id: d.sequence for d in amp_domains} + predictions_by_id = { + p.protein_name: p + for p in predict_domains(model, sequences, keep_top=self.keep_top, use_muscle_fallback=self.use_muscle_fallback) + } + + results: dict[str, list[InferenceResult]] = {} + for d in amp_domains: + prediction = predictions_by_id.get(d.id) + if prediction is None: + log.warning(f"no A domains found in sequence {d.id}; unable to predict substrate") + results[d.id] = [self.result(label="unknown", score=0.0, metadata={})] + else: + results[d.id] = self._results_for(d.id, prediction.predictions) + + return results diff --git a/src/retromol_antismash/inference/registry.py b/src/retromol_antismash/inference/registry.py index 0f1644d..9bf4eeb 100644 --- a/src/retromol_antismash/inference/registry.py +++ b/src/retromol_antismash/inference/registry.py @@ -142,12 +142,36 @@ def annotate_region( log.debug(mctx.prefix() + f"added {len(results)} results") - # Domain inference - for domain in gene.iter_domains(): - dctx = Ctx(region=region.id, gene=gene.id, domain=domain.id) - - for m in domain_models: - mctx = Ctx(region=region.id, gene=gene.id, domain=domain.id, model=m.name) + # Domain inference. Batched per model across the WHOLE region (not per gene, and + # not per domain) wherever a model supports it -- a model like paras_cli that + # shells out to command-line tools pays a large fixed cost per call (reloading an + # entire HMM profile database from scratch), so calling predict() once per domain + # instead of predict_many() once for every domain a model cares about is a major + # (not just marginal) slowdown, not a style choice. Models without predict_many + # (e.g. gene-level-adjacent PFAM domain models) fall back to the original + # per-domain predict() loop, unaffected. + all_domains = [domain for gene in region.iter_genes() for domain in gene.iter_domains()] + + for m in domain_models: + predict_many = getattr(m, "predict_many", None) + if predict_many is None: + continue + + mctx = Ctx(region=region.id, model=m.name) + log.debug(mctx.prefix() + f"running batched domain inference over {len(all_domains)} domains") + + results_by_id = predict_many(all_domains) + for domain in all_domains: + for r in results_by_id.get(domain.id, []): + domain.annotations.add(r) + + unbatched_models = [m for m in domain_models if getattr(m, "predict_many", None) is None] + if unbatched_models: + for domain in all_domains: + dctx = Ctx(region=region.id, domain=domain.id) + + for m in unbatched_models: + mctx = Ctx(region=region.id, domain=domain.id, model=m.name) log.debug(mctx.prefix() + f"running domain inference ({domain.type})") results = m.predict(domain) diff --git a/src/retromol_antismash/modules.py b/src/retromol_antismash/modules.py index a7b0c44..a460a6d 100644 --- a/src/retromol_antismash/modules.py +++ b/src/retromol_antismash/modules.py @@ -1128,10 +1128,14 @@ def module_primary_sequence_tokens(module: Module, ruleset: RuleSet) -> tuple[st rule name (this is where pmp.yml's "nrps.a_domain" `mapping` overrides take effect, and where a `source: qualifier` fallback with no SMILES gets resolved). If that doesn't match anything, and a SMILES is available (the default PARAS path), it - falls back to matching that SMILES against every rule by structure, ignoring - stereochemistry (`RuleSet.find_structural_matches`) -- PARAS' raw labels aren't - guaranteed to match a rule's `name` string verbatim, and PARAS' predicted - stereochemistry need not match the rule's. + falls back to matching that SMILES against every rule by structure + (`RuleSet.find_structural_matches`) -- PARAS' raw labels aren't guaranteed to + match a rule's `name` string verbatim. Whether that structural match also + requires matching stereochemistry follows `ruleset.match_stereochemistry`, the + same toggle every other structural match in this codebase respects -- PARAS' + predicted substrate is a specific named compound (its SMILES comes from a fixed + label->structure lookup, not a per-domain stereochemistry guess), so requiring + an exact stereo match here is meaningful, not just permissively ignored. :param module: a PKS or NRPS module from a BGC's LinearReadout. :param ruleset: the rule set to resolve the module's substrate against. @@ -1196,7 +1200,7 @@ def _by_name(name: str) -> tuple[str, list[str]] | None: except ValueError: return "X", [] - matches = ruleset.find_structural_matches(mol, match_stereochemistry=False) + matches = ruleset.find_structural_matches(mol, match_stereochemistry=ruleset.match_stereochemistry) if not matches: return "X", [] diff --git a/src/retromol_paras/featurisation.py b/src/retromol_paras/featurisation.py index 792d1d5..e394a94 100644 --- a/src/retromol_paras/featurisation.py +++ b/src/retromol_paras/featurisation.py @@ -174,13 +174,28 @@ def _extend_hmmer2_domains_with_hmmer3_bounds( domain_2.sequence = fasta[domain_2.protein_name][domain_2.start:domain_2.end] -def get_domains(path_in_fasta_file: str | Path, path_temp_dir: str | Path) -> list[AdenylationDomain]: +def get_domains( + path_in_fasta_file: str | Path, + path_temp_dir: str | Path, + hmm_timeout: float | None = None, + use_muscle_fallback: bool = True, +) -> list[AdenylationDomain]: """ Extract every adenylation domain from a (protein) fasta file, following PARAS' default pipeline: HMMER2 signature extraction first, HMMER3 + MUSCLE3 profile alignment to pick up anything HMMER2 missed. :param path_in_fasta_file: protein fasta file to scan. :param path_temp_dir: scratch directory for intermediate HMMER/MUSCLE output. + :param hmm_timeout: seconds to allow the hmmpfam2/hmmscan calls, or None for their own + default -- override this for a large batch fasta file (e.g. retromol_paras.train's + ~3654-domain training set), where the default (sized for a single/handful of domains) + would time out a legitimately-slow full-file scan. + :param use_muscle_fallback: whether to run a MUSCLE3 profile alignment (one subprocess + call per affected domain, against a ~1000-sequence reference alignment -- the + dominant per-domain cost in practice) to recover signatures for domains HMMER3 + detects but HMMER2's smaller/older profile misses entirely. False skips this + step -- those domains are dropped (no signature, no prediction) instead of + recovered, trading some coverage for speed. :return: AdenylationDomain instances, each with `signature`/`extended_signature` populated. """ path_temp_dir = Path(path_temp_dir) @@ -189,33 +204,45 @@ def get_domains(path_in_fasta_file: str | Path, path_temp_dir: str | Path) -> li hmm2_out = path_temp_dir / "run.hmm2_result" hmm3_out = path_temp_dir / "run.hmm3_result" - run_hmmpfam2(HMM2_FILE, path_in_fasta_file, hmm2_out) - run_hmmscan(HMM3_FILE, path_in_fasta_file, hmm3_out) + hmm_kwargs = {} if hmm_timeout is None else {"timeout": hmm_timeout} + run_hmmpfam2(HMM2_FILE, path_in_fasta_file, hmm2_out, **hmm_kwargs) + run_hmmscan(HMM3_FILE, path_in_fasta_file, hmm3_out, **hmm_kwargs) id_to_hit_2 = parse_hmm_results(hmm2_out, hmmer_version=2) id_to_hit_3 = parse_hmm_results(hmm3_out, hmmer_version=3) domains_2 = _hits_to_domains(id_to_hit_2, path_in_fasta_file, path_temp_dir, use_profile_alignment=False, hmm_version=2) - domains_3 = _hits_to_domains(id_to_hit_3, path_in_fasta_file, path_temp_dir, use_profile_alignment=False, hmm_version=3) - _extend_hmmer2_domains_with_hmmer3_bounds(domains_2, domains_3, path_in_fasta_file) - unique_3 = _hmmer3_only_domains(domains_2, domains_3, path_temp_dir) + if use_muscle_fallback: + domains_3 = _hits_to_domains(id_to_hit_3, path_in_fasta_file, path_temp_dir, use_profile_alignment=False, hmm_version=3) + _extend_hmmer2_domains_with_hmmer3_bounds(domains_2, domains_3, path_in_fasta_file) + unique_3 = _hmmer3_only_domains(domains_2, domains_3, path_temp_dir) + domains = domains_2 + unique_3 + else: + domains = domains_2 - domains = domains_2 + unique_3 _renumber_domains(domains) return domains -def extract_domains(path_in_fasta_file: str | Path, path_temp_dir: str | Path) -> list[AdenylationDomain]: +def extract_domains( + path_in_fasta_file: str | Path, + path_temp_dir: str | Path, + hmm_timeout: float | None = None, + use_muscle_fallback: bool = True, +) -> list[AdenylationDomain]: """ Like `get_domains`, but safe for arbitrary fasta headers: renames sequences to plain integers before running HMMER (some header formats break HMMER's parser), then restores the original headers as `protein_name` afterwards. This is the entry point to use for a fasta file with headers you don't control. + + :param hmm_timeout: see `get_domains`. + :param use_muscle_fallback: see `get_domains`. """ path_temp_dir = Path(path_temp_dir) mapping_file, renamed_fasta_file = rename_sequences(path_in_fasta_file, path_temp_dir) - domains = get_domains(renamed_fasta_file, path_temp_dir) + domains = get_domains(renamed_fasta_file, path_temp_dir, hmm_timeout=hmm_timeout, use_muscle_fallback=use_muscle_fallback) new_to_original = load_renaming_map(mapping_file) for domain in domains: diff --git a/src/retromol_paras/hmmer.py b/src/retromol_paras/hmmer.py index a82ec90..5355a78 100644 --- a/src/retromol_paras/hmmer.py +++ b/src/retromol_paras/hmmer.py @@ -3,6 +3,7 @@ Requires `hmmpfam2` (HMMER2) and `hmmscan` + `hmmpress` (HMMER3) on PATH. """ +import fcntl import subprocess from pathlib import Path @@ -11,25 +12,52 @@ from retromol_paras.fasta import parse_fasta_file +DEFAULT_TIMEOUT_S = 180 -def ensure_hmm3_pressed(hmm3_file: str | Path) -> None: - """ Run `hmmpress` on the packaged HMM3 profile once, if its binary index files aren't there yet. """ + +def ensure_hmm3_pressed(hmm3_file: str | Path, timeout: float = DEFAULT_TIMEOUT_S) -> None: + """ + Run `hmmpress` on the packaged HMM3 profile once, if its binary index files aren't + there yet. Locked (same pattern as retromol_paras.train's training lock) since this + file lives at a single shared package-data path -- concurrent worker processes each + seeing "not pressed yet" on their first call and racing to press it simultaneously + would corrupt the index files, not just waste work. + + :raises subprocess.TimeoutExpired: if `hmmpress` doesn't finish within `timeout` seconds. + """ hmm3_file = Path(hmm3_file) if all((hmm3_file.parent / f"{hmm3_file.name}.{ext}").exists() for ext in ("h3f", "h3i", "h3m", "h3p")): return - subprocess.run(["hmmpress", str(hmm3_file)], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + + with open(hmm3_file.parent / f"{hmm3_file.name}.press.lock", "w") as lock_fo: + fcntl.flock(lock_fo.fileno(), fcntl.LOCK_EX) + try: + if all((hmm3_file.parent / f"{hmm3_file.name}.{ext}").exists() for ext in ("h3f", "h3i", "h3m", "h3p")): + return # another process pressed it while we waited for the lock + subprocess.run( + ["hmmpress", str(hmm3_file)], check=True, + stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=timeout, + ) + finally: + fcntl.flock(lock_fo.fileno(), fcntl.LOCK_UN) -def run_hmmscan(hmm_file: str | Path, fasta_file: str | Path, out_file: str | Path) -> None: - """ Run HMMER3's `hmmscan` on a fasta file against a (pressed) HMM database. """ +def run_hmmscan(hmm_file: str | Path, fasta_file: str | Path, out_file: str | Path, timeout: float = DEFAULT_TIMEOUT_S) -> None: + """ Run HMMER3's `hmmscan` on a fasta file against a (pressed) HMM database. + + :raises subprocess.TimeoutExpired: if `hmmscan` doesn't finish within `timeout` seconds. + """ with open(out_file, "w") as out: - subprocess.run(["hmmscan", str(hmm_file), str(fasta_file)], check=True, stdout=out) + subprocess.run(["hmmscan", str(hmm_file), str(fasta_file)], check=True, stdout=out, timeout=timeout) -def run_hmmpfam2(hmm_file: str | Path, fasta_file: str | Path, out_file: str | Path) -> None: - """ Run HMMER2's `hmmpfam2` on a fasta file against an HMM database. """ +def run_hmmpfam2(hmm_file: str | Path, fasta_file: str | Path, out_file: str | Path, timeout: float = DEFAULT_TIMEOUT_S) -> None: + """ Run HMMER2's `hmmpfam2` on a fasta file against an HMM database. + + :raises subprocess.TimeoutExpired: if `hmmpfam2` doesn't finish within `timeout` seconds. + """ with open(out_file, "w") as out: - subprocess.run(["hmmpfam2", str(hmm_file), str(fasta_file)], check=True, stdout=out) + subprocess.run(["hmmpfam2", str(hmm_file), str(fasta_file)], check=True, stdout=out, timeout=timeout) def parse_hmm_results(path_in: str | Path, hmmer_version: int) -> dict[str, HSP]: diff --git a/src/retromol_paras/muscle.py b/src/retromol_paras/muscle.py index b717ab6..9965733 100644 --- a/src/retromol_paras/muscle.py +++ b/src/retromol_paras/muscle.py @@ -8,13 +8,22 @@ from pathlib import Path -def run_muscle_profile(path_in: str | Path, path_in_alignment: str | Path, path_out: str | Path) -> None: +DEFAULT_TIMEOUT_S = 180 + + +def run_muscle_profile( + path_in: str | Path, path_in_alignment: str | Path, path_out: str | Path, timeout: float = DEFAULT_TIMEOUT_S +) -> None: """ Align a single new sequence against an existing MUSCLE alignment via profile-profile alignment. :param path_in: fasta file with the (single) new sequence to align. :param path_in_alignment: fasta file with the existing reference alignment. :param path_out: path to write the resulting alignment to. + :param timeout: seconds to wait before giving up -- a stuck `muscle` process (seen under + Rosetta emulation of the old 3.8.1551 build on Apple Silicon) would otherwise hang + forever instead of raising. + :raises subprocess.TimeoutExpired: if `muscle` doesn't finish within `timeout` seconds. """ command = [ "muscle", "-quiet", "-profile", @@ -22,4 +31,4 @@ def run_muscle_profile(path_in: str | Path, path_in_alignment: str | Path, path_ "-in2", str(path_in), "-out", str(path_out), ] - subprocess.run(command, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL) + subprocess.run(command, check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL, timeout=timeout) diff --git a/src/retromol_paras/predict.py b/src/retromol_paras/predict.py index 6d80daf..ee693a6 100644 --- a/src/retromol_paras/predict.py +++ b/src/retromol_paras/predict.py @@ -58,6 +58,7 @@ def predict_domains( protein_sequences: dict[str, str], keep_top: int = 3, path_temp_dir: str | Path | None = None, + use_muscle_fallback: bool = True, ) -> list[DomainPrediction]: """ Detect and predict the substrate of every adenylation domain in a set of protein sequences. @@ -66,6 +67,7 @@ def predict_domains( :param protein_sequences: {sequence_id: amino_acid_sequence}. :param keep_top: number of top-scoring substrate predictions to keep per domain. :param path_temp_dir: scratch directory for HMMER/MUSCLE intermediates; a temp dir is used if not given. + :param use_muscle_fallback: see retromol_paras.featurisation.get_domains. :return: one DomainPrediction per detected adenylation domain. """ def _run(scratch: Path) -> list[DomainPrediction]: @@ -74,7 +76,7 @@ def _run(scratch: Path) -> list[DomainPrediction]: for seq_id, seq in protein_sequences.items(): fo.write(f">{seq_id}\n{seq}\n") - domains: list[AdenylationDomain] = extract_domains(fasta_file, scratch) + domains: list[AdenylationDomain] = extract_domains(fasta_file, scratch, use_muscle_fallback=use_muscle_fallback) if not domains: return [] diff --git a/src/retromol_paras/train.py b/src/retromol_paras/train.py index 8c8a756..c673c87 100644 --- a/src/retromol_paras/train.py +++ b/src/retromol_paras/train.py @@ -7,9 +7,25 @@ `train_random_forest`, but reading training examples from the flat `parasect_dataset.txt` file (see constants.PARASECT_DATASET_FILE) instead of PARASECT's SQLAlchemy database -- no database needed. + +Concurrency: callers with multiple worker PROCESSES sharing one `cache_dir` +(e.g. database/scripts/parse_gbks.py's ProcessPoolExecutor) must not all train +at once -- the extraction scratch files and the signature-cache write aren't +safe against concurrent writers. `train_model` takes an exclusive file lock +around the whole check-then-train section for exactly this reason: the first +process to reach it trains (or loads) the model, everyone else blocks until +it's done, then loads the now-cached result. Pre-training once with +scripts/train_paras.py before a parallel run still avoids paying the lock-wait +cost on every worker's first prediction, but no longer avoids correctness +issues if you forget to. """ +import contextlib +import fcntl import logging +import os +import shutil +import tempfile from pathlib import Path import joblib @@ -28,6 +44,31 @@ DEFAULT_CACHE_DIR = Path.home() / ".retromol_paras" SIGNATURE_CACHE_FILE = "extended_signatures.cache.tsv" MODEL_FILE = "model.paras.joblib" +LOCK_FILE = ".train.lock" + + +@contextlib.contextmanager +def _training_lock(cache_dir: Path): + """ Exclusive, cross-process file lock around the check-then-train critical section (see module docstring). """ + cache_dir.mkdir(parents=True, exist_ok=True) + with open(cache_dir / LOCK_FILE, "w") as lock_fo: + fcntl.flock(lock_fo.fileno(), fcntl.LOCK_EX) + try: + yield + finally: + fcntl.flock(lock_fo.fileno(), fcntl.LOCK_UN) + + +def _atomic_write_text(path: Path, text: str) -> None: + """ Write `text` to `path` such that a concurrent reader never sees a partial file. """ + fd, tmp_name = tempfile.mkstemp(dir=path.parent, prefix=f".{path.name}.") + try: + with os.fdopen(fd, "w") as fo: + fo.write(text) + os.replace(tmp_name, path) + except BaseException: + Path(tmp_name).unlink(missing_ok=True) + raise def _parse_dataset(path_in: Path) -> tuple[dict[str, str], dict[str, str]]: @@ -62,15 +103,22 @@ def _extract_training_signatures(cache_dir: Path, force: bool = False) -> dict[s id_to_seq, _ = _parse_dataset(PARASECT_DATASET_FILE) - scratch = cache_dir / "extraction_scratch" - scratch.mkdir(parents=True, exist_ok=True) - dataset_fasta = scratch / "dataset.fasta" - with open(dataset_fasta, "w") as fo: - for domain_id, seq in id_to_seq.items(): - fo.write(f">{domain_id}\n{seq}\n") - - log.info(f"extracting extended signatures for {len(id_to_seq)} training domains (this runs HMMER2/HMMER3/MUSCLE3 once, then caches) ...") - domains = extract_domains(dataset_fasta, scratch) + # A fresh temp dir per attempt (rather than a fixed cache_dir/extraction_scratch + # path) -- belt-and-braces alongside the caller's lock: callers are expected to + # hold _training_lock around this, but a unique scratch dir means a second, + # unlocked/out-of-band call (or a leftover dir from a killed run) still can't + # collide on the fixed MUSCLE temp filenames _align_to_reference uses. + scratch = Path(tempfile.mkdtemp(dir=cache_dir, prefix="extraction_scratch_")) + try: + dataset_fasta = scratch / "dataset.fasta" + with open(dataset_fasta, "w") as fo: + for domain_id, seq in id_to_seq.items(): + fo.write(f">{domain_id}\n{seq}\n") + + log.info(f"extracting extended signatures for {len(id_to_seq)} training domains (this runs HMMER2/HMMER3/MUSCLE3 once, then caches) ...") + domains = extract_domains(dataset_fasta, scratch, hmm_timeout=1800) + finally: + shutil.rmtree(scratch, ignore_errors=True) # one label per training row (domain_id); keep the first detected A-domain per header. id_to_signature = {} @@ -78,10 +126,9 @@ def _extract_training_signatures(cache_dir: Path, force: bool = False) -> dict[s if domain.protein_name not in id_to_signature and domain.extended_signature: id_to_signature[domain.protein_name] = domain.extended_signature - with open(cache_file, "w") as fo: - fo.write("domain_id\textended_signature\n") - for domain_id, signature in sorted(id_to_signature.items()): - fo.write(f"{domain_id}\t{signature}\n") + lines = ["domain_id\textended_signature\n"] + lines.extend(f"{domain_id}\t{signature}\n" for domain_id, signature in sorted(id_to_signature.items())) + _atomic_write_text(cache_file, "".join(lines)) return id_to_signature @@ -100,35 +147,53 @@ def train_model(cache_dir: str | Path | None = None, force: bool = False) -> Ran cache_dir.mkdir(parents=True, exist_ok=True) model_file = cache_dir / MODEL_FILE + # Fast path, unlocked: the common case (already trained) shouldn't pay lock + # overhead. Rechecked again just below, inside the lock, in case another + # process was mid-training when we got here (see module docstring). if model_file.exists() and not force: log.info(f"loading cached model: {model_file}") return joblib.load(model_file) - id_to_seq, id_to_spec = _parse_dataset(PARASECT_DATASET_FILE) - id_to_signature = _extract_training_signatures(cache_dir, force=force) - - features: list[list[float]] = [] - labels: list[str] = [] - for domain_id in id_to_seq: - signature = id_to_signature.get(domain_id) - if not signature: - continue - features.append(get_domain_features(signature)) - # parasect_dataset.txt can list multiple pipe-separated specificities for a promiscuous - # domain; PARAS' default (FIRST_ONLY) selection mode trains on just the first. - labels.append(id_to_spec[domain_id].split("|")[0]) - - log.info(f"training PARAS classifier on {len(labels)} domains ...") - model = RandomForestClassifier( - n_estimators=N_ESTIMATORS, - n_jobs=1, - oob_score=True, - random_state=RANDOM_STATE, - class_weight="balanced", - ) - model.fit(np.array(features), np.array(labels)) - - joblib.dump(model, model_file) - log.info(f"cached trained model: {model_file} (oob_score={model.oob_score_:.4f})") - - return model + with _training_lock(cache_dir): + if model_file.exists() and not force: + log.info(f"loading cached model (finished training while we waited for the lock): {model_file}") + return joblib.load(model_file) + + id_to_seq, id_to_spec = _parse_dataset(PARASECT_DATASET_FILE) + id_to_signature = _extract_training_signatures(cache_dir, force=force) + + features: list[list[float]] = [] + labels: list[str] = [] + for domain_id in id_to_seq: + signature = id_to_signature.get(domain_id) + if not signature: + continue + features.append(get_domain_features(signature)) + # parasect_dataset.txt can list multiple pipe-separated specificities for a + # promiscuous domain; PARAS' default (FIRST_ONLY) selection mode trains on + # just the first. + labels.append(id_to_spec[domain_id].split("|")[0]) + + log.info(f"training PARAS classifier on {len(labels)} domains ...") + model = RandomForestClassifier( + n_estimators=N_ESTIMATORS, + n_jobs=1, + oob_score=True, + random_state=RANDOM_STATE, + class_weight="balanced", + ) + model.fit(np.array(features), np.array(labels)) + + # joblib.dump isn't atomic on its own -- dump to a temp file in the same + # directory, then rename, so a concurrent reader never sees a partial model. + fd, tmp_name = tempfile.mkstemp(dir=cache_dir, prefix=f".{MODEL_FILE}.") + os.close(fd) + try: + joblib.dump(model, tmp_name) + os.replace(tmp_name, model_file) + except BaseException: + Path(tmp_name).unlink(missing_ok=True) + raise + log.info(f"cached trained model: {model_file} (oob_score={model.oob_score_:.4f})") + + return model From 78ae4bb76b46071c0bc9dd98760289ebe46b1b3f Mon Sep 17 00:00:00 2001 From: David Meijer Date: Thu, 27 Aug 2026 22:44:53 -0400 Subject: [PATCH 3/4] FIX: deployment test --- gui/scripts/dev_worker.sh | 2 +- gui/src/client/package-lock.json | 149 +++++++++++++++---------------- 2 files changed, 71 insertions(+), 80 deletions(-) diff --git a/gui/scripts/dev_worker.sh b/gui/scripts/dev_worker.sh index f3ded55..c8bd664 100755 --- a/gui/scripts/dev_worker.sh +++ b/gui/scripts/dev_worker.sh @@ -15,7 +15,7 @@ set -euo pipefail cd "$(dirname "$0")/.." # go to repo root # --- Setup environment --- -export RETROMOL_DUCKDB_PATH="$HOME/Downloads/retromol.duckdb" +export RETROMOL_DUCKDB_PATH="$HOME/Desktop/retromol.duckdb" # Redis connection (uses Dockerized Redis) export REDIS_URL="redis://localhost:6379/0" diff --git a/gui/src/client/package-lock.json b/gui/src/client/package-lock.json index 2e2a610..9819b29 100644 --- a/gui/src/client/package-lock.json +++ b/gui/src/client/package-lock.json @@ -3366,9 +3366,9 @@ } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { @@ -3731,9 +3731,9 @@ } }, "node_modules/@mui/x-data-grid/node_modules/@mui/types": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-9.3.0.tgz", - "integrity": "sha512-2JSxyfpEFWNUB2vKs/T1BvkfyNisMHWph8bLMj8T0uHwmLl/0qfAwQkfwMT6kxLXN9uIum9AEbECXU8er3amIg==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-9.4.0.tgz", + "integrity": "sha512-13DH0Oniua4WmGqeYbQAZqmiN7r4nfd0zwIoGJ5QeJwyIHgEmf+LkRw/jV1HZb6AiUoHX8Oxf4xgalq3vYHcIw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.29.7" @@ -3748,13 +3748,13 @@ } }, "node_modules/@mui/x-data-grid/node_modules/@mui/utils": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.3.0.tgz", - "integrity": "sha512-2HZdHwWJ6eB+7lVGSOHsByGw8jeRulT4g0NZ608Wb8Q57DE2jbNqrWPFuJsvkQQiBiTmlpvQL3i+/62zsiPrkw==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.4.0.tgz", + "integrity": "sha512-WkzY8uYtqUDyGKPShrRQRBomfMQHddlsyKu/gRRESYO24tDPD2z0xRE8CBoUsWqpBa+YrFs9KixiS7kQRjsPAQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.29.7", - "@mui/types": "^9.3.0", + "@mui/types": "^9.4.0", "@types/prop-types": "^15.7.15", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -3856,9 +3856,9 @@ } }, "node_modules/@mui/x-virtualizer/node_modules/@mui/types": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@mui/types/-/types-9.3.0.tgz", - "integrity": "sha512-2JSxyfpEFWNUB2vKs/T1BvkfyNisMHWph8bLMj8T0uHwmLl/0qfAwQkfwMT6kxLXN9uIum9AEbECXU8er3amIg==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@mui/types/-/types-9.4.0.tgz", + "integrity": "sha512-13DH0Oniua4WmGqeYbQAZqmiN7r4nfd0zwIoGJ5QeJwyIHgEmf+LkRw/jV1HZb6AiUoHX8Oxf4xgalq3vYHcIw==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.29.7" @@ -3873,13 +3873,13 @@ } }, "node_modules/@mui/x-virtualizer/node_modules/@mui/utils": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.3.0.tgz", - "integrity": "sha512-2HZdHwWJ6eB+7lVGSOHsByGw8jeRulT4g0NZ608Wb8Q57DE2jbNqrWPFuJsvkQQiBiTmlpvQL3i+/62zsiPrkw==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/@mui/utils/-/utils-9.4.0.tgz", + "integrity": "sha512-WkzY8uYtqUDyGKPShrRQRBomfMQHddlsyKu/gRRESYO24tDPD2z0xRE8CBoUsWqpBa+YrFs9KixiS7kQRjsPAQ==", "license": "MIT", "dependencies": { "@babel/runtime": "^7.29.7", - "@mui/types": "^9.3.0", + "@mui/types": "^9.4.0", "@types/prop-types": "^15.7.15", "clsx": "^2.1.1", "prop-types": "^15.8.1", @@ -4514,9 +4514,9 @@ } }, "node_modules/@tanstack/query-core": { - "version": "5.102.6", - "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.102.6.tgz", - "integrity": "sha512-jp+GucyQ+fel2ILb8ZLQeqMaAqZL/Bzaj+dKOQiPk4vPdf2rQPEV7heUyEVIhatpY42j4AFHav4DzBa1oTIp/A==", + "version": "5.102.8", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.102.8.tgz", + "integrity": "sha512-ZNjkJ33CqvPNec/6lZBnHqLc3EVGPZ9ySLhYahU9TcuRFdmwXewuj0c4hwSWcGHqEUwcSrKeZ+oGcvPBqXcQcg==", "license": "MIT", "funding": { "type": "github", @@ -4524,12 +4524,12 @@ } }, "node_modules/@tanstack/react-query": { - "version": "5.102.6", - "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.102.6.tgz", - "integrity": "sha512-ANz4KZ8z80D85fiz5IAHjpb8XBPLrjOb/0natlD9Ascyy/3p96V86Zw8UbOfA0HDLcvK/A4gNd95r723y5UT2w==", + "version": "5.102.8", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.102.8.tgz", + "integrity": "sha512-TYBea4OuXWD7MhaSHq069TWbFe7rcwWN6kzT7JF0OKi1K6c1gTv2IzD6A6ExJsCMozdkqBWeuIUZmu4KQg0O5A==", "license": "MIT", "dependencies": { - "@tanstack/query-core": "5.102.6" + "@tanstack/query-core": "5.102.8" }, "funding": { "type": "github", @@ -4588,9 +4588,9 @@ "license": "MIT" }, "node_modules/@testing-library/react": { - "version": "16.3.2", - "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.2.tgz", - "integrity": "sha512-XU5/SytQM+ykqMnAnvB2umaJNIOsLF3PVv//1Ew4CTcpz0/BRyy/af40qqrt7SjKpDdT1saBMc42CUok5gaw+g==", + "version": "16.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.3.tgz", + "integrity": "sha512-Uo193NgQbPMz6lrrhtRQQFcMC6Re/ELLFbbuVL30WDlZxlpZf9/lMHTAVxPRLw1q1iu9OJmR1c2BLiENRstdBg==", "dev": true, "license": "MIT", "dependencies": { @@ -5431,9 +5431,9 @@ } }, "node_modules/@ungap/structured-clone": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.3.4.tgz", - "integrity": "sha512-JL+CF0GeLHyPWI0rXu7UnxgiuOm9UQWzadi0OYOJNhNO2q6EZElpwlgXkNkfU1PzANDHq3YcwKVZprdvS+BrbQ==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.4.0.tgz", + "integrity": "sha512-1mEZtMKPM09vDmQt5y7YvmN2+DFTP7Tg0EWXdic8/C6VRnpb33e4ghisCIE3WZjsE2N8mf+QV1Zqh7ZFYLWInQ==", "dev": true, "license": "ISC" }, @@ -6533,9 +6533,9 @@ "license": "MIT" }, "node_modules/baseline-browser-mapping": { - "version": "2.11.19", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.19.tgz", - "integrity": "sha512-Grytf1xOxOEMTGRwx6rLGKkTabd4vMg3VrKdj/7joCmV0qgh4QwMMO6xh34YEXQqirAuUdgQGa5orJQQ+69RBw==", + "version": "2.11.20", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz", + "integrity": "sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -9872,9 +9872,9 @@ "license": "BSD-3-Clause" }, "node_modules/fastq": { - "version": "1.20.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", - "integrity": "sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==", + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.2.tgz", + "integrity": "sha512-UpGiiODyCGprM8EPP6JodP6jC9Rws6TCuiDOD+nn0CJhR8guI3g/ozo4ugL0vJ+Yz1UtJuuRPqvQuybVOF1VQA==", "dev": true, "license": "ISC", "dependencies": { @@ -13568,9 +13568,9 @@ } }, "node_modules/minimizer-webpack-plugin": { - "version": "5.7.0", - "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.7.0.tgz", - "integrity": "sha512-0ReIvHAVVojdDOn+kmRzrT62A6Btc9KeAK6ANTpd8+S5mnm5RDdu+EN6924xLFFzb36Rkoj+xOXkDA0jTHId/g==", + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.8.0.tgz", + "integrity": "sha512-2cT9+goJfBhtMz+gJqejSf09ClgmYhPhccRb/fb0ztVbixt0BkO8mRuI26FoPPuUNkRk6iEDryWAIouc5W8eJA==", "dev": true, "license": "MIT", "dependencies": { @@ -13796,9 +13796,9 @@ "license": "MIT" }, "node_modules/node-releases": { - "version": "2.0.53", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.53.tgz", - "integrity": "sha512-D9UOmYG3UH1V+ENW56t5QXBwJw1YEY18ruVeus89Rw+SyIgjPkCO84bRzO3uNIYosJbNwiabWVn48o3uJLjxFQ==", + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", "dev": true, "license": "MIT", "engines": { @@ -18389,6 +18389,24 @@ } } }, + "node_modules/tailwindcss/node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/tapable": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", @@ -18463,9 +18481,9 @@ } }, "node_modules/terser": { - "version": "5.51.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.0.tgz", - "integrity": "sha512-myiQ6aFnxDOjdiXdTlC8ngVccQD88uHXTx5RUQOSEnarDYgJMjDagwAQszcOusjvmf4YqWsxoD1+MY+oAJRmpw==", + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", "dev": true, "license": "BSD-2-Clause", "dependencies": { @@ -18898,7 +18916,6 @@ "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", "dev": true, "license": "(MIT OR CC0-1.0)", - "peer": true, "engines": { "node": ">=10" }, @@ -19151,9 +19168,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.1.tgz", - "integrity": "sha512-ZZ61DsRsOnakl74HAmp3oSN4aXUmEWXf+i/yv0h7tIBfICc3VdrFErQKUUKPgu3AMsTUMbcongALEN4l6GSUrQ==", + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", "dev": true, "funding": [ { @@ -19372,9 +19389,9 @@ } }, "node_modules/webpack": { - "version": "5.109.2", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.109.2.tgz", - "integrity": "sha512-U9/cvLzxObKNEZ9+TtdqrHM5/9z3lgl2c+c4BzbqGxFQvQvBAq87yql5A8pQ+rrMbS496MZJeF5enVBndIy2hw==", + "version": "5.110.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.110.1.tgz", + "integrity": "sha512-gInQB+jxXxgnZyvPwuzT5NGQmECDqeu85oxcrjinrYHqPoBex0hCAN2SFTJVyPVrK0Pq9E44VFP+e89fAc10/w==", "dev": true, "license": "MIT", "peer": true, @@ -19389,11 +19406,10 @@ "chrome-trace-event": "^1.0.2", "enhanced-resolve": "^5.24.4", "es-module-lexer": "^2.1.0", - "eslint-scope": "5.1.1", "events": "^3.2.0", "graceful-fs": "^4.2.11", "mime-db": "^1.54.0", - "minimizer-webpack-plugin": "^5.6.1", + "minimizer-webpack-plugin": "^5.7.0", "neo-async": "^2.6.2", "schema-utils": "^4.3.3", "tapable": "^2.3.0", @@ -19446,7 +19462,6 @@ "integrity": "sha512-0XavAZbNJ5sDrCbkpWL8mia0o5WPOd2YGtxrEiZkBK9FjLppIUK2TgxK6qGD2P3hUXTJNNPVibrerKcx5WkR1g==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "@types/bonjour": "^3.5.9", "@types/connect-history-api-fallback": "^1.3.5", @@ -19589,30 +19604,6 @@ "node": ">=10.13.0" } }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", - "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", - "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", - "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } - }, "node_modules/webpack/node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", From a9577640d964e32c4345e9615f86a49eb61a113d Mon Sep 17 00:00:00 2001 From: David Meijer Date: Thu, 27 Aug 2026 22:52:55 -0400 Subject: [PATCH 4/4] FIX: removed unused import --- .../client/src/components/workspace/ClusterReadoutDiagram.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gui/src/client/src/components/workspace/ClusterReadoutDiagram.tsx b/gui/src/client/src/components/workspace/ClusterReadoutDiagram.tsx index 73f33ea..d64c279 100644 --- a/gui/src/client/src/components/workspace/ClusterReadoutDiagram.tsx +++ b/gui/src/client/src/components/workspace/ClusterReadoutDiagram.tsx @@ -256,7 +256,7 @@ function RegionDiagram({ selectedIndices: number[]; onToggleIndex: (index: number) => void; }) { - const { editing, drafts, setDrafts, revertingIdx, isRowDirty, savedSequenceFor, handleRevertRow } = state; + const { editing, drafts, setDrafts, revertingIdx, isRowDirty, handleRevertRow } = state; const override = item.kind === "cluster" ? (item as ClusterItem).editedPrimarySequences?.[String(regionIndex)] : undefined; const draftBlocks = drafts[regionIndex] ?? blocksFromSequence(override ?? region.primary_sequence);