diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..6713e6e --- /dev/null +++ b/.dockerignore @@ -0,0 +1,88 @@ +# ============================================================================= +# WaterFlow Docker Ignore +# Exclude files that shouldn't be in the Docker build context +# ============================================================================= + +# Git +.git +.gitignore +.gitattributes + +# Python +__pycache__ +*.py[cod] +*$py.class +*.so +.Python +.venv +venv +ENV +env +.eggs +*.egg-info +*.egg +.mypy_cache +.pytest_cache +.ruff_cache +.coverage +htmlcov + +# IDE +.idea +.vscode +*.swp +*.swo +*~ + +# Jupyter +.ipynb_checkpoints +notebooks/ +*.ipynb + +# Data and model files (mount these as volumes instead) +data/ +*.pt +*.ckpt +*.pth +*.safetensors +*.h5 +*.hdf5 +*.pkl +*.pickle + +# W&B +wandb/ +*.wandb + +# Logs +logs/ +*.log + +# Docker +Dockerfile* +docker-compose*.yml +.docker + +# Documentation +docs/ +*.md +!README.md + +# Tests (not needed in production image) +tests/ +test_*.py +*_test.py +conftest.py + +# CI/CD +.github/ +.gitlab-ci.yml +.travis.yml +Makefile + +# Misc +.DS_Store +Thumbs.db +*.bak +*.tmp +*.temp diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..1089911 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,100 @@ +# ============================================================================= +# WaterFlow Docker image for GPU workflows (CUDA 12.6) +# ============================================================================= + +FROM nvidia/cuda:12.6.3-devel-ubuntu22.04 + +# Prevent interactive prompts during package installation +ENV DEBIAN_FRONTEND=noninteractive + +# Install system dependencies +# Note: rm -rf /var/lib/apt/lists/* removes apt cache to reduce image size (~30MB savings) +RUN apt-get update && apt-get install -y --no-install-recommends \ + software-properties-common \ + curl \ + git \ + build-essential \ + && add-apt-repository ppa:deadsnakes/ppa \ + && apt-get update \ + && apt-get install -y --no-install-recommends \ + python3.12 \ + python3.12-dev \ + python3.12-venv \ + && rm -rf /var/lib/apt/lists/* + +# Set Python 3.12 as default +RUN update-alternatives --install /usr/bin/python python /usr/bin/python3.12 1 \ + && update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.12 1 + +# Install uv package manager (pinned for reproducible builds) +COPY --from=ghcr.io/astral-sh/uv:0.7.3 /uv /usr/local/bin/uv + +# Set working directory +WORKDIR /app + +# Copy dependency files first for better layer caching +COPY pyproject.toml uv.lock ./ + +# Create virtual environment and install dependencies +ENV UV_COMPILE_BYTECODE=1 +ENV UV_LINK_MODE=copy +RUN uv sync --frozen --no-install-project + +# Copy source code +COPY src/ ./src/ +COPY scripts/ ./scripts/ + +# Install the project itself +RUN uv sync --frozen + +# Pre-download ESM3 model to bake it into the image. +# The generate script loads esm3-open without authentication, so no HF token is needed. +ENV HF_HOME=/app/.cache/huggingface +RUN . .venv/bin/activate && python -c "\ +from esm.models.esm3 import ESM3; \ +ESM3.from_pretrained('esm3-open'); \ +print('ESM3 model downloaded successfully')" + +# Compile Python bytecode for faster startup +RUN . .venv/bin/activate && python -m compileall -q src/ scripts/ + +# Verify core GPU and preprocessing imports work +RUN . .venv/bin/activate && python <<'EOF' +import torch +print(f'PyTorch {torch.__version__}, CUDA {torch.version.cuda}') +from torch_scatter import scatter_add +print('torch-scatter OK') +from torch_cluster import radius_graph +print('torch-cluster OK') +import pymol2 +print('pymol2 OK') +EOF + +# Copy entrypoint script +COPY docker/entrypoint.sh /app/entrypoint.sh +RUN chmod +x /app/entrypoint.sh + +# Create mount points for data volumes +RUN mkdir -p /data/pdb /data/cache /data/checkpoints /data/outputs /data/logs /data/splits + +# Environment variables +ENV VIRTUAL_ENV=/app/.venv +ENV PATH="/app/.venv/bin:$PATH" +ENV PYTHONPATH=/app +ENV PYTHONDONTWRITEBYTECODE=1 +ENV PYTHONUNBUFFERED=1 + +# CUDA configuration for H100 GPUs +ENV CUDA_HOME=/usr/local/cuda +ENV TORCH_CUDA_ARCH_LIST="9.0" + +# Default data paths (can be overridden via docker run -e) +ENV WATERFLOW_PDB_DIR=/data/pdb +ENV WATERFLOW_CACHE_DIR=/data/cache +ENV WATERFLOW_CHECKPOINT_DIR=/data/checkpoints +ENV WATERFLOW_OUTPUT_DIR=/data/outputs +ENV WATERFLOW_LOG_DIR=/data/logs +ENV WATERFLOW_SPLITS_DIR=/data/splits + +ENTRYPOINT ["/app/entrypoint.sh"] +CMD ["--help"] diff --git a/README.md b/README.md index bbd681c..3ee5e48 100644 --- a/README.md +++ b/README.md @@ -241,7 +241,6 @@ To resume training from a checkpoint, you can load the model weights and optimiz | `--save_dir` | `../flow_checkpoints` | Directory to save checkpoints | | `--save_every` | `10` | Save checkpoint every N epochs | | `--eval_every` | `5` | Run evaluation every N epochs | -| `--edia_dir` | (none) | Root directory for EDIA CSV files | | `--min_edia` | `0.4` | Minimum EDIA score threshold for waters | | `--no_filter_by_edia` | - | Disable EDIA-based water filtering | @@ -286,12 +285,10 @@ These filters remove individual low-quality waters (can be toggled): EDIA measures how well an atom's position is supported by the experimental electron density map. Higher EDIA scores indicate more reliable atomic positions. **Configuration:** -- EDIA filtering is enabled by default but only activates if `--edia_dir` is provided -- If `--edia_dir` is not set, EDIA filtering is skipped (with a warning logged) +- EDIA filtering is enabled by default +- The EDIA data lives in the `json` file of the format `_final.json` in the same directory as the `pdb` file, and is obtained from PDB-REDO. - Use `--no_filter_by_edia` to explicitly disable EDIA filtering -**Directory structure:** `{edia_dir}/{pdb_id}/{pdb_id}_residue_stats.csv` - ## Inference diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..889b125 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,71 @@ +# ============================================================================= +# WaterFlow Docker Compose Configuration +# Local development with GPU passthrough +# ============================================================================= + +services: + waterflow: + build: + context: . + dockerfile: Dockerfile + image: waterflow:latest + runtime: nvidia + + # GPU configuration - expose all GPUs + deploy: + resources: + reservations: + devices: + - driver: nvidia + count: all + capabilities: [gpu] + + # Shared memory size for PyTorch DataLoader + shm_size: 16gb + + # Environment variables + environment: + - NVIDIA_VISIBLE_DEVICES=all + - WANDB_API_KEY=${WANDB_API_KEY:-} + - WANDB_PROJECT=${WANDB_PROJECT:-waterflow} + - WATERFLOW_PDB_DIR=/data/pdb + - WATERFLOW_CACHE_DIR=/data/cache + - WATERFLOW_CHECKPOINT_DIR=/data/checkpoints + - WATERFLOW_OUTPUT_DIR=/data/outputs + - WATERFLOW_LOG_DIR=/data/logs + - WATERFLOW_SPLITS_DIR=/data/splits + + # Volume mounts + volumes: + # Input PDB files (read-only) + - ${PDB_DIR:-./data/pdb}:/data/pdb:ro + # Cache for embeddings and preprocessed data + - ${CACHE_DIR:-./data/cache}:/data/cache + # Model checkpoints + - ${CHECKPOINT_DIR:-./data/checkpoints}:/data/checkpoints + # Inference outputs + - ${OUTPUT_DIR:-./data/outputs}:/data/outputs + # W&B and training logs + - ${LOG_DIR:-./data/logs}:/data/logs + # Train/val/test split files + - ${SPLITS_DIR:-./splits}:/data/splits:ro + + # Interactive mode for development + stdin_open: true + tty: true + + # Development profile with source code mounted + waterflow-dev: + extends: + service: waterflow + volumes: + # Mount source for live development + - ./src:/app/src:ro + - ./scripts:/app/scripts:ro + # Data volumes + - ${PDB_DIR:-./data/pdb}:/data/pdb:ro + - ${CACHE_DIR:-./data/cache}:/data/cache + - ${CHECKPOINT_DIR:-./data/checkpoints}:/data/checkpoints + - ${OUTPUT_DIR:-./data/outputs}:/data/outputs + - ${LOG_DIR:-./data/logs}:/data/logs + - ${SPLITS_DIR:-./splits}:/data/splits:ro diff --git a/docker/entrypoint.sh b/docker/entrypoint.sh new file mode 100755 index 0000000..ecd8950 --- /dev/null +++ b/docker/entrypoint.sh @@ -0,0 +1,108 @@ +#!/bin/bash +# ============================================================================= +# WaterFlow Docker Entrypoint +# Unified CLI that dispatches commands to the appropriate scripts +# ============================================================================= + +set -e + +# Show help if no arguments +show_help() { + cat << EOF +WaterFlow Docker Container + +Usage: docker run waterflow [options] + +Commands: + train Run training pipeline + inference Run inference on PDB files + generate-esm Generate ESM3 embeddings for PDB files + python Run arbitrary Python script or command + --help Show this help message + +For interactive shell: docker run --entrypoint /bin/bash -it waterflow + +Examples: + # Training + docker run --gpus all -v /path/to/data:/data waterflow train \\ + --train_list /data/splits/train.txt \\ + --val_list /data/splits/val.txt \\ + --encoder_type esm \\ + --epochs 200 + + # Generate ESM embeddings + docker run --gpus all -v /path/to/data:/data waterflow generate-esm \\ + --split_file /data/splits/train.txt + + # Inference + docker run --gpus all -v /path/to/data:/data waterflow inference \\ + --run_dir /data/checkpoints/run_name \\ + --pdb_list /data/splits/test.txt \\ + --output_dir /data/outputs + +Environment Variables: + WATERFLOW_PDB_DIR Base directory for PDB files (default: /data/pdb) + WATERFLOW_CACHE_DIR Cache directory for embeddings (default: /data/cache) + WATERFLOW_CHECKPOINT_DIR Checkpoint directory (default: /data/checkpoints) + WATERFLOW_OUTPUT_DIR Output directory (default: /data/outputs) + WATERFLOW_LOG_DIR Log directory (default: /data/logs) + WATERFLOW_SPLITS_DIR Split/list files directory (default: /data/splits) + WANDB_API_KEY Weights & Biases API key (set via -e or docker-compose) + WANDB_PROJECT W&B project name (set via -e or docker-compose) + +EOF +} + +# Get the command +COMMAND="${1:-}" + +case "$COMMAND" in + train) + shift + exec python /app/scripts/train.py \ + --base_pdb_dir "${WATERFLOW_PDB_DIR}" \ + --processed_dir "${WATERFLOW_CACHE_DIR}" \ + --save_dir "${WATERFLOW_CHECKPOINT_DIR}" \ + --wandb_dir "${WATERFLOW_LOG_DIR}" \ + "$@" + ;; + + inference) + shift + exec python /app/scripts/inference.py \ + --base_pdb_dir "${WATERFLOW_PDB_DIR}" \ + --processed_dir "${WATERFLOW_CACHE_DIR}" \ + --output_dir "${WATERFLOW_OUTPUT_DIR}" \ + "$@" + ;; + + generate-esm) + shift + exec python /app/scripts/generate_esm_embeddings.py \ + --base_pdb_dir "${WATERFLOW_PDB_DIR}" \ + --cache_dir "${WATERFLOW_CACHE_DIR}" \ + "$@" + ;; + + python) + shift + exec python "$@" + ;; + + --help|-h|help) + show_help + exit 0 + ;; + + "") + show_help + exit 0 + ;; + + *) + echo "Error: Unknown command '$COMMAND'" + echo "" + show_help + exit 1 + ;; +esac diff --git a/scripts/inference.py b/scripts/inference.py index e6ae9b2..e73b919 100644 --- a/scripts/inference.py +++ b/scripts/inference.py @@ -216,7 +216,6 @@ def _extract_dataset_filter_config(config: dict) -> dict: "clash_dist": config.get("clash_dist", 2.0), "interface_dist_threshold": config.get("interface_dist_threshold", 4.0), "min_water_residue_ratio": config.get("min_water_residue_ratio", 0.6), - "edia_dir": config.get("edia_dir"), "max_protein_dist": config.get("max_protein_dist", 5.0), "min_edia": config.get("min_edia", 0.4), "max_bfactor_zscore": config.get("max_bfactor_zscore", 1.5), diff --git a/scripts/train.py b/scripts/train.py index ee61acf..eabf39d 100644 --- a/scripts/train.py +++ b/scripts/train.py @@ -72,7 +72,6 @@ def parse_args(): # Current hardcoded paths: # - processed_dir: /home/srivasv/flow_cache/ # - base_pdb_dir: /sb/wankowicz_lab/data/srivasv/pdb_redo_data - # - edia_dir: /sb/wankowicz_lab/data/srivasv/edia_results # - save_dir: /home/srivasv/flow_checkpoints # - wandb_dir: /home/srivasv/wandb_logs p = argparse.ArgumentParser() @@ -111,15 +110,6 @@ def parse_args(): default=1, help="If training on single sample, duplicate it N times for more gradient updates per epoch", ) - p.add_argument( - "--edia_dir", - type=str, - default="/sb/wankowicz_lab/data/srivasv/edia_results", - help=( - "Water filter: EDIA root directory " - "({edia_dir}/{pdb_id}/{pdb_id}_residue_stats.csv)." - ), - ) # dataset quality checks (always on) p.add_argument( @@ -332,7 +322,6 @@ def _extract_quality_config(args: argparse.Namespace) -> dict: def _extract_water_filter_config(args: argparse.Namespace) -> dict: """Extract per-water filtering parameters (toggleable).""" return { - "edia_dir": args.edia_dir, "max_protein_dist": args.max_protein_dist, "min_edia": args.min_edia, "max_bfactor_zscore": args.max_bfactor_zscore, @@ -408,11 +397,6 @@ def _log_dataset_filter_config(args, quality_kwargs: dict): if ignored: logger.info(f"Ignored water-filter thresholds (disabled): {ignored}") - if args.filter_by_edia and args.edia_dir is None: - logger.info( - "EDIA filter enabled but --edia_dir is not set; EDIA filtering will be skipped." - ) - def _required_embedding_field(encoder_type: str) -> str | None: """ diff --git a/src/dataset.py b/src/dataset.py index badd668..742b135 100644 --- a/src/dataset.py +++ b/src/dataset.py @@ -12,11 +12,11 @@ from __future__ import annotations import itertools +import json from pathlib import Path import biotite.structure as bts import numpy as np -import pandas as pd import pymol2 import torch import torch.nn.functional as F @@ -426,48 +426,51 @@ def check_water_residue_ratio( def load_edia_for_pdb( - edia_dir: Path, - pdb_id: str, + json_path: str | Path, ) -> dict[tuple[str, int, str], float] | None: """ - Load EDIA scores for water molecules from CSV file. + Load EDIA scores for water molecules from a JSON file. Args: - edia_dir: Directory containing EDIA results - pdb_id: PDB ID to load + json_path: Path to JSON file containing EDIA scores for the structure Returns: Dictionary mapping (chain_id, res_id, ins_code) -> EDIA score for waters, or None if file not found or error """ - csv_path = edia_dir / pdb_id / f"{pdb_id}_residue_stats.csv" - - if not csv_path.exists(): + json_path = Path(json_path) + if not json_path.exists(): return None try: - df = pd.read_csv(csv_path) + with open(json_path, "r") as f: + data = json.load(f) - # filter for water molecules only - water_df = df[df["compID"].isin(["HOH", "WAT"])] + edia_lookup = {} + for entry in data: + # Filter for water molecules only + if entry.get("compID") in ["HOH", "WAT"]: + # The identifying information is nested inside the "pdb" key in the JSON + pdb_info = entry.get("pdb", {}) - if water_df.empty: - return {} + chain_id = str(pdb_info.get("strandID", "")) + res_id = int(pdb_info.get("seqNum", 0)) - # Optional insertion-code column in EDIA outputs. - ins_code_col = "pdb_insCode" if "pdb_insCode" in water_df.columns else None + # Extract and normalize insertion code, defaulting to an empty string + raw_ins_code = pdb_info.get("insCode", "") + ins_code = normalize_ins_code(raw_ins_code) if raw_ins_code else "" - # build lookup dictionary: (chain_id, res_id, ins_code) -> EDIAm - edia_lookup = {} - for _, row in water_df.iterrows(): - ins_code = normalize_ins_code(row[ins_code_col]) if ins_code_col else "" - key = (str(row["pdb_strandID"]), int(row["pdb_seqNum"]), ins_code) - edia_lookup[key] = float(row["EDIAm"]) + # Build the lookup key and extract the EDIAm score + key = (chain_id, res_id, ins_code) + edia_lookup[key] = float(entry.get("EDIAm", 0.0)) + + if not edia_lookup: + return {} return edia_lookup except Exception as e: - logger.warning(f"Warning: Could not load EDIA data for {pdb_id}: {e}") + logger.warning(f"Warning: Could not load EDIA JSON data for {json_path}: {e}") return None @@ -670,7 +673,6 @@ def __init__( clash_dist: float = 2.0, interface_dist_threshold: float = 4.0, min_water_residue_ratio: float = 0.6, - edia_dir: str | None = None, max_protein_dist: float = 5.0, min_edia: float = 0.4, max_bfactor_zscore: float = 1.5, @@ -708,7 +710,6 @@ def __init__( Structures below this are filtered (poor solvent modeling). Per-water filtering (toggleable): - edia_dir: Directory containing EDIA CSV files. Structure: {edia_dir}/{pdb_id}/{pdb_id}_residue_stats.csv max_protein_dist: Remove waters farther than this from nearest protein atom (Angstroms). min_edia: Remove waters with EDIA score below this threshold. max_bfactor_zscore: Remove waters with normalized B-factor (z-score) above this. @@ -738,7 +739,6 @@ def __init__( self.interface_dist_threshold = interface_dist_threshold self.min_water_residue_ratio = min_water_residue_ratio - self.edia_dir = Path(edia_dir) if edia_dir is not None else None self.max_protein_dist = max_protein_dist self.min_edia = min_edia self.max_bfactor_zscore = max_bfactor_zscore @@ -894,7 +894,7 @@ def _preprocess_one(self, entry: dict, cache_path: Path): # Per-water filtering is optional; structure-level quality checks below always run. use_distance_filter = self.filter_by_distance - use_edia_filter = self.filter_by_edia and self.edia_dir is not None + use_edia_filter = self.filter_by_edia use_bfactor_filter = self.filter_by_bfactor any_filter_enabled = ( use_distance_filter or use_edia_filter or use_bfactor_filter @@ -904,10 +904,12 @@ def _preprocess_one(self, entry: dict, cache_path: Path): # load EDIA data only when the EDIA filter is active edia_lookup = None if use_edia_filter: - edia_lookup = load_edia_for_pdb(self.edia_dir, entry["pdb_id"]) + edia_json_path = Path(pdb_path).with_suffix(".json") + edia_lookup = load_edia_for_pdb(edia_json_path) if edia_lookup is None: - logger.warning( - f"Warning: EDIA file not found for {entry['pdb_id']}, skipping EDIA filtering" + raise ValueError( + f"EDIA filtering enabled but JSON file missing for {entry['pdb_id']}. " + f"Expected file: {edia_json_path.name} in the same directory as the PDB." ) # compute normalized B-factors only when the B-factor filter is active diff --git a/tests/conftest.py b/tests/conftest.py index ded4e5e..449b9c6 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -22,10 +22,18 @@ def pdb_base_dir(): def _resolve_pdb_path(pdb_id): - """Resolves a PDB path, skipping if missing.""" + """Resolves a PDB path, raising an error if missing.""" path = PDB_BASE_DIR / pdb_id / f"{pdb_id}_final.pdb" if not path.exists(): - pytest.skip(f"PDB file not found: {path}") + raise FileNotFoundError(f"PDB file not found: {path}") + return str(path) + + +def _resolve_edia_path(pdb_id): + """Resolves an EDIA JSON path, raising an error if missing.""" + path = PDB_BASE_DIR / pdb_id / f"{pdb_id}_final.json" + if not path.exists(): + raise FileNotFoundError(f"EDIA JSON file not found: {path}") return str(path) @@ -35,6 +43,12 @@ def pdb_6eey(): return _resolve_pdb_path("6eey") +@pytest.fixture +def edia_6eey(): + """6eey EDIA JSON file with water quality scores from PDB-REDO.""" + return _resolve_edia_path("6eey") + + @pytest.fixture def pdb_2b5w(): """2b5w - fails COM distance check.""" diff --git a/tests/test_dataset.py b/tests/test_dataset.py index b8b4dae..da44844 100644 --- a/tests/test_dataset.py +++ b/tests/test_dataset.py @@ -19,6 +19,9 @@ All test cases created with assistance from Claude Code. """ +import json +from pathlib import Path + import numpy as np import pytest import torch @@ -1011,49 +1014,102 @@ def test_custom_geometry_cache_name( @pytest.mark.unit class TestLoadEdiaForPdb: - """Tests for EDIA data loading from CSV files.""" + """Tests for EDIA data loading from JSON files.""" def test_returns_none_for_missing_file(self, tmp_path): """Should return None if EDIA file doesn't exist.""" - result = load_edia_for_pdb(tmp_path, "nonexistent_pdb") + result = load_edia_for_pdb(tmp_path / "nonexistent.json") assert result is None def test_loads_water_edia_scores(self, tmp_path): """Should load EDIA scores for water molecules.""" - # Create mock EDIA CSV - pdb_id = "test_pdb" - pdb_dir = tmp_path / pdb_id - pdb_dir.mkdir() - - csv_content = """compID,pdb_strandID,pdb_seqNum,EDIAm,RSCCS -HOH,A,101,0.85,0.92 -HOH,A,102,0.45,0.88 -HOH,B,201,0.72,0.90 -ALA,A,1,0.95,0.98 -""" - (pdb_dir / f"{pdb_id}_residue_stats.csv").write_text(csv_content) + json_path = tmp_path / "test_pdb.json" + json_path.write_text( + json.dumps( + [ + { + "compID": "HOH", + "EDIAm": 0.85, + "pdb": {"strandID": "A", "seqNum": 101}, + }, + { + "compID": "HOH", + "EDIAm": 0.45, + "pdb": {"strandID": "A", "seqNum": 102}, + }, + { + "compID": "HOH", + "EDIAm": 0.72, + "pdb": {"strandID": "B", "seqNum": 201}, + }, + { + "compID": "ALA", + "EDIAm": 0.95, + "pdb": {"strandID": "A", "seqNum": 1}, + }, + ] + ) + ) - result = load_edia_for_pdb(tmp_path, pdb_id) + result = load_edia_for_pdb(json_path) assert result is not None assert len(result) == 3 # Only waters, not ALA + + # Verify all returned residues have correct chain_id and res_id + assert ("A", 101, "") in result + assert ("A", 102, "") in result + assert ("B", 201, "") in result + + # Verify non-water residue (ALA) was filtered out + assert ("A", 1, "") not in result + + # Verify EDIA scores are correct assert result[("A", 101, "")] == pytest.approx(0.85) assert result[("A", 102, "")] == pytest.approx(0.45) assert result[("B", 201, "")] == pytest.approx(0.72) + def test_loads_real_edia_file(self, edia_6eey): + """Should load EDIA scores from real PDB-REDO JSON file.""" + result = load_edia_for_pdb(edia_6eey) + + assert result is not None + assert len(result) > 0 # Should have water molecules + + # All keys should be 3-tuples of (chain_id, res_id, ins_code) + for key in result: + assert len(key) == 3 + chain_id, res_id, ins_code = key + assert isinstance(chain_id, str) + assert isinstance(res_id, int) + assert isinstance(ins_code, str) + + # All values should be valid EDIA scores (0.0 to ~1.0, possibly higher) + for score in result.values(): + assert isinstance(score, float) + assert score >= 0.0 + def test_returns_empty_dict_for_no_waters(self, tmp_path): - """Should return empty dict if no water molecules in CSV.""" - pdb_id = "test_pdb" - pdb_dir = tmp_path / pdb_id - pdb_dir.mkdir() - - csv_content = """compID,pdb_strandID,pdb_seqNum,EDIAm,RSCCS -ALA,A,1,0.95,0.98 -GLY,A,2,0.90,0.95 -""" - (pdb_dir / f"{pdb_id}_residue_stats.csv").write_text(csv_content) + """Should return empty dict if no water molecules are in the JSON.""" + json_path = tmp_path / "test_pdb.json" + json_path.write_text( + json.dumps( + [ + { + "compID": "ALA", + "EDIAm": 0.95, + "pdb": {"strandID": "A", "seqNum": 1}, + }, + { + "compID": "GLY", + "EDIAm": 0.90, + "pdb": {"strandID": "A", "seqNum": 2}, + }, + ] + ) + ) - result = load_edia_for_pdb(tmp_path, pdb_id) + result = load_edia_for_pdb(json_path) assert result == {} @@ -1313,6 +1369,38 @@ def test_dataset_with_filtering_disabled( # Should have water nodes assert data["water"].num_nodes >= 0 + def test_skips_pdb_when_edia_enabled_but_file_missing(self, tmp_path, pdb_2b5w): + """Dataset should skip PDB when filter_by_edia=True but JSON file is missing.""" + # 2b5w has a PDB file but no EDIA JSON file in test_files + # Create a list file with just this PDB + list_file = tmp_path / "missing_edia.txt" + list_file.write_text("2b5w_final\n") + + # Create dataset with EDIA filtering enabled + processed_dir = tmp_path / "edia_test" + dataset = ProteinWaterDataset( + pdb_list_file=str(list_file), + processed_dir=str(processed_dir), + base_pdb_dir=str(Path(pdb_2b5w).parent.parent), + filter_by_edia=True, # EDIA filtering enabled + filter_by_distance=False, + filter_by_bfactor=False, + preprocess=True, + ) + + # Dataset should be empty since the only PDB was skipped due to missing EDIA + assert len(dataset) == 0 + + # Failure should be logged to preprocessing_failures.log + # Default include_mates=True uses geometry_mates directory + failure_log = processed_dir / "geometry_mates" / "preprocessing_failures.log" + assert failure_log.exists(), ( + "Missing EDIA should be logged to preprocessing_failures.log" + ) + log_content = failure_log.read_text() + assert "2b5w" in log_content + assert "EDIA" in log_content + # ============== Tests for check_water_residue_ratio ============== @@ -1907,18 +1995,30 @@ class TestEdiaInsertionCodes: def test_edia_with_insertion_codes(self, tmp_path): """Should handle EDIA data with insertion codes.""" - pdb_id = "test_pdb" - pdb_dir = tmp_path / pdb_id - pdb_dir.mkdir() - - csv_content = """compID,pdb_strandID,pdb_seqNum,pdb_insCode,EDIAm,RSCCS -HOH,A,52,,0.85,0.92 -HOH,A,52,A,0.75,0.88 -HOH,A,52,B,0.65,0.90 -""" - (pdb_dir / f"{pdb_id}_residue_stats.csv").write_text(csv_content) + json_path = tmp_path / "test_pdb.json" + json_path.write_text( + json.dumps( + [ + { + "compID": "HOH", + "EDIAm": 0.85, + "pdb": {"strandID": "A", "seqNum": 52, "insCode": ""}, + }, + { + "compID": "HOH", + "EDIAm": 0.75, + "pdb": {"strandID": "A", "seqNum": 52, "insCode": "A"}, + }, + { + "compID": "HOH", + "EDIAm": 0.65, + "pdb": {"strandID": "A", "seqNum": 52, "insCode": "B"}, + }, + ] + ) + ) - result = load_edia_for_pdb(tmp_path, pdb_id) + result = load_edia_for_pdb(json_path) assert result is not None assert len(result) == 3 @@ -1928,17 +2028,20 @@ def test_edia_with_insertion_codes(self, tmp_path): def test_edia_normalizes_insertion_codes(self, tmp_path): """Should normalize insertion codes (spaces to empty string).""" - pdb_id = "test_pdb" - pdb_dir = tmp_path / pdb_id - pdb_dir.mkdir() - - # CSV with space as insertion code (should normalize to "") - csv_content = """compID,pdb_strandID,pdb_seqNum,pdb_insCode,EDIAm,RSCCS -HOH,A,101, ,0.85,0.92 -""" - (pdb_dir / f"{pdb_id}_residue_stats.csv").write_text(csv_content) + json_path = tmp_path / "test_pdb.json" + json_path.write_text( + json.dumps( + [ + { + "compID": "HOH", + "EDIAm": 0.85, + "pdb": {"strandID": "A", "seqNum": 101, "insCode": " "}, + } + ] + ) + ) - result = load_edia_for_pdb(tmp_path, pdb_id) + result = load_edia_for_pdb(json_path) assert result is not None # Space should be normalized to empty string diff --git a/tests/test_files/6eey/6eey_final.json b/tests/test_files/6eey/6eey_final.json new file mode 100644 index 0000000..7d9b7fe --- /dev/null +++ b/tests/test_files/6eey/6eey_final.json @@ -0,0 +1 @@ +[{"EDIAm":0.609195,"NGRID":294,"OPIA":30,"RSCCS":0.907028,"RSR":0.115704,"SRSR":0.00770576,"asymID":"A","compID":"HIS","pdb":{"compID":"HIS","insCode":"","seqNum":-1,"strandID":"A"},"seqID":1},{"EDIAm":0.540021,"NGRID":143,"OPIA":50,"RSCCS":0.982807,"RSR":0.0672214,"SRSR":0.00513906,"asymID":"A","compID":"MET","pdb":{"compID":"MET","insCode":"","seqNum":0,"strandID":"A"},"seqID":2},{"EDIAm":0.780671,"NGRID":142,"OPIA":62.5,"RSCCS":0.977649,"RSR":0.0450381,"SRSR":0.00564806,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1098,"strandID":"A"},"seqID":3},{"EDIAm":0.785401,"NGRID":221,"OPIA":72.7273,"RSCCS":0.976562,"RSR":0.0577896,"SRSR":0.00477903,"asymID":"A","compID":"ARG","pdb":{"compID":"ARG","insCode":"","seqNum":1099,"strandID":"A"},"seqID":4},{"EDIAm":0.319288,"NGRID":232,"OPIA":55.5556,"RSCCS":0.968984,"RSR":0.092024,"SRSR":0.00557991,"asymID":"A","compID":"GLU","pdb":{"compID":"GLU","insCode":"","seqNum":1100,"strandID":"A"},"seqID":5},{"EDIAm":0.763078,"NGRID":123,"OPIA":62.5,"RSCCS":0.982481,"RSR":0.0489729,"SRSR":0.00509425,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1101,"strandID":"A"},"seqID":6},{"EDIAm":0.844157,"NGRID":66,"OPIA":66.6667,"RSCCS":0.9908,"RSR":0.0296509,"SRSR":0.00435797,"asymID":"A","compID":"CYS","pdb":{"compID":"CYS","insCode":"","seqNum":1102,"strandID":"A"},"seqID":7},{"EDIAm":0.784454,"NGRID":86,"OPIA":37.5,"RSCCS":0.988063,"RSR":0.0383349,"SRSR":0.00451467,"asymID":"A","compID":"ILE","pdb":{"compID":"ILE","insCode":"","seqNum":1103,"strandID":"A"},"seqID":8},{"EDIAm":0.703302,"NGRID":164,"OPIA":33.3333,"RSCCS":0.97668,"RSR":0.0746423,"SRSR":0.00536429,"asymID":"A","compID":"GLN","pdb":{"compID":"GLN","insCode":"","seqNum":1104,"strandID":"A"},"seqID":9},{"EDIAm":0.804369,"NGRID":89,"OPIA":33.3333,"RSCCS":0.992851,"RSR":0.0259737,"SRSR":0.00404927,"asymID":"A","compID":"LYS","pdb":{"compID":"LYS","insCode":"","seqNum":1105,"strandID":"A"},"seqID":10},{"EDIAm":0.79774,"NGRID":49,"OPIA":40,"RSCCS":0.990958,"RSR":0.0274143,"SRSR":0.00561668,"asymID":"A","compID":"ALA","pdb":{"compID":"ALA","insCode":"","seqNum":1106,"strandID":"A"},"seqID":11},{"EDIAm":0.801776,"NGRID":90,"OPIA":71.4286,"RSCCS":0.982127,"RSR":0.0384693,"SRSR":0.0055039,"asymID":"A","compID":"PRO","pdb":{"compID":"PRO","insCode":"","seqNum":1107,"strandID":"A"},"seqID":12},{"EDIAm":0.836941,"NGRID":53,"OPIA":75,"RSCCS":0.984039,"RSR":0.0357925,"SRSR":0.00699463,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1108,"strandID":"A"},"seqID":13},{"EDIAm":0.851088,"NGRID":113,"OPIA":77.7778,"RSCCS":0.982647,"RSR":0.0425277,"SRSR":0.00424747,"asymID":"A","compID":"GLU","pdb":{"compID":"GLU","insCode":"","seqNum":1109,"strandID":"A"},"seqID":14},{"EDIAm":0.852326,"NGRID":39,"OPIA":75,"RSCCS":0.992587,"RSR":0.024414,"SRSR":0.00600548,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1110,"strandID":"A"},"seqID":15},{"EDIAm":0.803944,"NGRID":87,"OPIA":37.5,"RSCCS":0.99011,"RSR":0.0301059,"SRSR":0.00446327,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1111,"strandID":"A"},"seqID":16},{"EDIAm":0.837013,"NGRID":39,"OPIA":75,"RSCCS":0.992886,"RSR":0.0206312,"SRSR":0.00628813,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1112,"strandID":"A"},"seqID":17},{"EDIAm":0.814161,"NGRID":88,"OPIA":50,"RSCCS":0.989083,"RSR":0.0347439,"SRSR":0.00464612,"asymID":"A","compID":"ILE","pdb":{"compID":"ILE","insCode":"","seqNum":1113,"strandID":"A"},"seqID":18},{"EDIAm":0.837691,"NGRID":80,"OPIA":66.6667,"RSCCS":0.968218,"RSR":0.064493,"SRSR":0.00560041,"asymID":"A","compID":"SER","pdb":{"compID":"SER","insCode":"","seqNum":1114,"strandID":"A"},"seqID":19},{"EDIAm":0.790708,"NGRID":94,"OPIA":37.5,"RSCCS":0.983843,"RSR":0.0390503,"SRSR":0.00477576,"asymID":"A","compID":"ILE","pdb":{"compID":"ILE","insCode":"","seqNum":1115,"strandID":"A"},"seqID":20},{"EDIAm":0.822133,"NGRID":140,"OPIA":63.6364,"RSCCS":0.98523,"RSR":0.0338476,"SRSR":0.00411365,"asymID":"A","compID":"ARG","pdb":{"compID":"ARG","insCode":"","seqNum":1116,"strandID":"A"},"seqID":21},{"EDIAm":0.911087,"NGRID":60,"OPIA":100,"RSCCS":0.970909,"RSR":0.0482356,"SRSR":0.00694063,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1117,"strandID":"A"},"seqID":22},{"EDIAm":0.790603,"NGRID":62,"OPIA":75,"RSCCS":0.985534,"RSR":0.0381517,"SRSR":0.00771565,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1118,"strandID":"A"},"seqID":23},{"EDIAm":0.739771,"NGRID":96,"OPIA":40,"RSCCS":0.971131,"RSR":0.0647635,"SRSR":0.00864171,"asymID":"A","compID":"ALA","pdb":{"compID":"ALA","insCode":"","seqNum":1119,"strandID":"A"},"seqID":24},{"EDIAm":0.668945,"NGRID":263,"OPIA":18.1818,"RSCCS":0.968178,"RSR":0.0843646,"SRSR":0.00649025,"asymID":"A","compID":"ARG","pdb":{"compID":"ARG","insCode":"","seqNum":1120,"strandID":"A"},"seqID":25},{"EDIAm":0.859234,"NGRID":67,"OPIA":75,"RSCCS":0.960238,"RSR":0.0633535,"SRSR":0.0075749,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1121,"strandID":"A"},"seqID":26},{"EDIAm":0.811126,"NGRID":130,"OPIA":60,"RSCCS":0.983706,"RSR":0.0349908,"SRSR":0.00463362,"asymID":"A","compID":"HIS","pdb":{"compID":"HIS","insCode":"","seqNum":1122,"strandID":"A"},"seqID":27},{"EDIAm":0.810939,"NGRID":65,"OPIA":60,"RSCCS":0.989475,"RSR":0.0291669,"SRSR":0.00688283,"asymID":"A","compID":"ALA","pdb":{"compID":"ALA","insCode":"","seqNum":1123,"strandID":"A"},"seqID":28},{"EDIAm":0.802411,"NGRID":56,"OPIA":75,"RSCCS":0.984662,"RSR":0.0387783,"SRSR":0.00758991,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1124,"strandID":"A"},"seqID":29},{"EDIAm":0.797658,"NGRID":123,"OPIA":50,"RSCCS":0.981804,"RSR":0.043545,"SRSR":0.00572378,"asymID":"A","compID":"ASN","pdb":{"compID":"ASN","insCode":"","seqNum":1125,"strandID":"A"},"seqID":30},{"EDIAm":0.708722,"NGRID":116,"OPIA":42.8571,"RSCCS":0.969798,"RSR":0.0636808,"SRSR":0.00703979,"asymID":"A","compID":"PRO","pdb":{"compID":"PRO","insCode":"","seqNum":1126,"strandID":"A"},"seqID":31},{"EDIAm":0.690564,"NGRID":234,"OPIA":27.2727,"RSCCS":0.964977,"RSR":0.0845628,"SRSR":0.00619657,"asymID":"A","compID":"ARG","pdb":{"compID":"ARG","insCode":"","seqNum":1127,"strandID":"A"},"seqID":32},{"EDIAm":0.700229,"NGRID":170,"OPIA":25,"RSCCS":0.962616,"RSR":0.0984137,"SRSR":0.00757829,"asymID":"A","compID":"ASP","pdb":{"compID":"ASP","insCode":"","seqNum":1128,"strandID":"A"},"seqID":33},{"EDIAm":0.717754,"NGRID":158,"OPIA":57.1429,"RSCCS":0.965376,"RSR":0.0656852,"SRSR":0.00798038,"asymID":"A","compID":"PRO","pdb":{"compID":"PRO","insCode":"","seqNum":1129,"strandID":"A"},"seqID":34},{"EDIAm":0.697318,"NGRID":157,"OPIA":42.8571,"RSCCS":0.943953,"RSR":0.0939725,"SRSR":0.00784985,"asymID":"A","compID":"THR","pdb":{"compID":"THR","insCode":"","seqNum":1130,"strandID":"A"},"seqID":35},{"EDIAm":0.763388,"NGRID":151,"OPIA":50,"RSCCS":0.983168,"RSR":0.0632154,"SRSR":0.00684286,"asymID":"A","compID":"ASP","pdb":{"compID":"ASP","insCode":"","seqNum":1131,"strandID":"A"},"seqID":36},{"EDIAm":0.711608,"NGRID":175,"OPIA":44.4444,"RSCCS":0.963171,"RSR":0.0882094,"SRSR":0.00668216,"asymID":"A","compID":"GLU","pdb":{"compID":"GLU","insCode":"","seqNum":1132,"strandID":"A"},"seqID":37},{"EDIAm":0.841289,"NGRID":56,"OPIA":75,"RSCCS":0.982143,"RSR":0.0403319,"SRSR":0.00684965,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1133,"strandID":"A"},"seqID":38},{"EDIAm":0.678204,"NGRID":119,"OPIA":75,"RSCCS":0.982322,"RSR":0.0514506,"SRSR":0.00532394,"asymID":"A","compID":"ILE","pdb":{"compID":"ILE","insCode":"","seqNum":1134,"strandID":"A"},"seqID":39},{"EDIAm":0.842361,"NGRID":128,"OPIA":72.7273,"RSCCS":0.987689,"RSR":0.0531194,"SRSR":0.00399088,"asymID":"A","compID":"PHE","pdb":{"compID":"PHE","insCode":"","seqNum":1135,"strandID":"A"},"seqID":40},{"EDIAm":0.794731,"NGRID":82,"OPIA":37.5,"RSCCS":0.990589,"RSR":0.0321781,"SRSR":0.00455016,"asymID":"A","compID":"ILE","pdb":{"compID":"ILE","insCode":"","seqNum":1136,"strandID":"A"},"seqID":41},{"EDIAm":0.86059,"NGRID":73,"OPIA":66.6667,"RSCCS":0.986339,"RSR":0.041702,"SRSR":0.00510688,"asymID":"A","compID":"SER","pdb":{"compID":"SER","insCode":"","seqNum":1137,"strandID":"A"},"seqID":42},{"EDIAm":0.331889,"NGRID":237,"OPIA":44.4444,"RSCCS":0.982912,"RSR":0.0822954,"SRSR":0.00551526,"asymID":"A","compID":"LYS","pdb":{"compID":"LYS","insCode":"","seqNum":1138,"strandID":"A"},"seqID":43},{"EDIAm":0.815189,"NGRID":77,"OPIA":57.1429,"RSCCS":0.990169,"RSR":0.0287251,"SRSR":0.0048762,"asymID":"A","compID":"VAL","pdb":{"compID":"VAL","insCode":"","seqNum":1139,"strandID":"A"},"seqID":44},{"EDIAm":0.842209,"NGRID":87,"OPIA":66.6667,"RSCCS":0.974483,"RSR":0.0522864,"SRSR":0.00553039,"asymID":"A","compID":"SER","pdb":{"compID":"SER","insCode":"","seqNum":1140,"strandID":"A"},"seqID":45},{"EDIAm":0.835365,"NGRID":97,"OPIA":57.1429,"RSCCS":0.984922,"RSR":0.0382428,"SRSR":0.00534117,"asymID":"A","compID":"PRO","pdb":{"compID":"PRO","insCode":"","seqNum":1141,"strandID":"A"},"seqID":46},{"EDIAm":0.872254,"NGRID":81,"OPIA":100,"RSCCS":0.990214,"RSR":0.0407687,"SRSR":0.00479677,"asymID":"A","compID":"THR","pdb":{"compID":"THR","insCode":"","seqNum":1142,"strandID":"A"},"seqID":47},{"EDIAm":0.897336,"NGRID":39,"OPIA":100,"RSCCS":0.994368,"RSR":0.0326343,"SRSR":0.00586249,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1143,"strandID":"A"},"seqID":48},{"EDIAm":0.825736,"NGRID":46,"OPIA":60,"RSCCS":0.992678,"RSR":0.0329569,"SRSR":0.00512694,"asymID":"A","compID":"ALA","pdb":{"compID":"ALA","insCode":"","seqNum":1144,"strandID":"A"},"seqID":49},{"EDIAm":0.79196,"NGRID":45,"OPIA":60,"RSCCS":0.990942,"RSR":0.0253283,"SRSR":0.00542899,"asymID":"A","compID":"ALA","pdb":{"compID":"ALA","insCode":"","seqNum":1145,"strandID":"A"},"seqID":50},{"EDIAm":0.851569,"NGRID":38,"OPIA":75,"RSCCS":0.980711,"RSR":0.0356744,"SRSR":0.00610502,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1146,"strandID":"A"},"seqID":51},{"EDIAm":0.827544,"NGRID":117,"OPIA":63.6364,"RSCCS":0.982765,"RSR":0.0358771,"SRSR":0.00395002,"asymID":"A","compID":"ARG","pdb":{"compID":"ARG","insCode":"","seqNum":1147,"strandID":"A"},"seqID":52},{"EDIAm":0.876552,"NGRID":80,"OPIA":75,"RSCCS":0.991136,"RSR":0.0301345,"SRSR":0.00409357,"asymID":"A","compID":"ASP","pdb":{"compID":"ASP","insCode":"","seqNum":1148,"strandID":"A"},"seqID":53},{"EDIAm":0.876539,"NGRID":39,"OPIA":100,"RSCCS":0.986724,"RSR":0.037786,"SRSR":0.00588925,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1149,"strandID":"A"},"seqID":54},{"EDIAm":0.84726,"NGRID":112,"OPIA":81.8182,"RSCCS":0.987793,"RSR":0.0294567,"SRSR":0.00383676,"asymID":"A","compID":"ARG","pdb":{"compID":"ARG","insCode":"","seqNum":1150,"strandID":"A"},"seqID":55},{"EDIAm":0.81355,"NGRID":77,"OPIA":50,"RSCCS":0.990382,"RSR":0.0348508,"SRSR":0.00443301,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1151,"strandID":"A"},"seqID":56},{"EDIAm":0.825628,"NGRID":134,"OPIA":81.8182,"RSCCS":0.987495,"RSR":0.0321875,"SRSR":0.00413794,"asymID":"A","compID":"ARG","pdb":{"compID":"ARG","insCode":"","seqNum":1152,"strandID":"A"},"seqID":57},{"EDIAm":0.779,"NGRID":82,"OPIA":42.8571,"RSCCS":0.9865,"RSR":0.0309211,"SRSR":0.00506831,"asymID":"A","compID":"VAL","pdb":{"compID":"VAL","insCode":"","seqNum":1153,"strandID":"A"},"seqID":58},{"EDIAm":0.841124,"NGRID":49,"OPIA":75,"RSCCS":0.988947,"RSR":0.0310489,"SRSR":0.00629404,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1154,"strandID":"A"},"seqID":59},{"EDIAm":0.801678,"NGRID":98,"OPIA":50,"RSCCS":0.989014,"RSR":0.0401442,"SRSR":0.0047848,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1155,"strandID":"A"},"seqID":60},{"EDIAm":0.838639,"NGRID":150,"OPIA":72.7273,"RSCCS":0.97553,"RSR":0.042055,"SRSR":0.0042806,"asymID":"A","compID":"ARG","pdb":{"compID":"ARG","insCode":"","seqNum":1156,"strandID":"A"},"seqID":61},{"EDIAm":0.779116,"NGRID":86,"OPIA":25,"RSCCS":0.9834,"RSR":0.0386662,"SRSR":0.00465174,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1157,"strandID":"A"},"seqID":62},{"EDIAm":0.769188,"NGRID":99,"OPIA":50,"RSCCS":0.982807,"RSR":0.0467555,"SRSR":0.00476502,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1158,"strandID":"A"},"seqID":63},{"EDIAm":0.844947,"NGRID":92,"OPIA":66.6667,"RSCCS":0.988641,"RSR":0.0363065,"SRSR":0.00393613,"asymID":"A","compID":"GLU","pdb":{"compID":"GLU","insCode":"","seqNum":1159,"strandID":"A"},"seqID":64},{"EDIAm":0.831153,"NGRID":72,"OPIA":85.7143,"RSCCS":0.992938,"RSR":0.0381476,"SRSR":0.00473799,"asymID":"A","compID":"VAL","pdb":{"compID":"VAL","insCode":"","seqNum":1160,"strandID":"A"},"seqID":65},{"EDIAm":0.834408,"NGRID":90,"OPIA":75,"RSCCS":0.987085,"RSR":0.0332628,"SRSR":0.00448117,"asymID":"A","compID":"ASN","pdb":{"compID":"ASN","insCode":"","seqNum":1161,"strandID":"A"},"seqID":66},{"EDIAm":0.722017,"NGRID":186,"OPIA":66.6667,"RSCCS":0.974403,"RSR":0.0610895,"SRSR":0.00543523,"asymID":"A","compID":"GLN","pdb":{"compID":"GLN","insCode":"","seqNum":1162,"strandID":"A"},"seqID":67},{"EDIAm":0.779728,"NGRID":166,"OPIA":66.6667,"RSCCS":0.98148,"RSR":0.0592066,"SRSR":0.00546245,"asymID":"A","compID":"GLN","pdb":{"compID":"GLN","insCode":"","seqNum":1163,"strandID":"A"},"seqID":68},{"EDIAm":0.860477,"NGRID":69,"OPIA":83.3333,"RSCCS":0.986719,"RSR":0.0339026,"SRSR":0.00525372,"asymID":"A","compID":"SER","pdb":{"compID":"SER","insCode":"","seqNum":1164,"strandID":"A"},"seqID":69},{"EDIAm":0.808877,"NGRID":94,"OPIA":62.5,"RSCCS":0.984697,"RSR":0.0358153,"SRSR":0.0048615,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1165,"strandID":"A"},"seqID":70},{"EDIAm":0.693785,"NGRID":138,"OPIA":25,"RSCCS":0.9725,"RSR":0.0622568,"SRSR":0.00596188,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1166,"strandID":"A"},"seqID":71},{"EDIAm":0.810642,"NGRID":55,"OPIA":50,"RSCCS":0.987167,"RSR":0.0365005,"SRSR":0.00762863,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1167,"strandID":"A"},"seqID":72},{"EDIAm":0.826009,"NGRID":122,"OPIA":62.5,"RSCCS":0.98457,"RSR":0.0418653,"SRSR":0.00497826,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1168,"strandID":"A"},"seqID":73},{"EDIAm":0.879695,"NGRID":90,"OPIA":85.7143,"RSCCS":0.988028,"RSR":0.0484612,"SRSR":0.00478725,"asymID":"A","compID":"THR","pdb":{"compID":"THR","insCode":"","seqNum":1169,"strandID":"A"},"seqID":74},{"EDIAm":0.837943,"NGRID":138,"OPIA":70,"RSCCS":0.97948,"RSR":0.0427081,"SRSR":0.00456028,"asymID":"A","compID":"HIS","pdb":{"compID":"HIS","insCode":"","seqNum":1170,"strandID":"A"},"seqID":75},{"EDIAm":0.87042,"NGRID":50,"OPIA":100,"RSCCS":0.986545,"RSR":0.0344454,"SRSR":0.00660301,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1171,"strandID":"A"},"seqID":76},{"EDIAm":0.835749,"NGRID":118,"OPIA":66.6667,"RSCCS":0.987131,"RSR":0.0325759,"SRSR":0.00445772,"asymID":"A","compID":"GLU","pdb":{"compID":"GLU","insCode":"","seqNum":1172,"strandID":"A"},"seqID":77},{"EDIAm":0.844093,"NGRID":58,"OPIA":60,"RSCCS":0.980985,"RSR":0.0421998,"SRSR":0.00570157,"asymID":"A","compID":"ALA","pdb":{"compID":"ALA","insCode":"","seqNum":1173,"strandID":"A"},"seqID":78},{"EDIAm":0.783272,"NGRID":105,"OPIA":57.1429,"RSCCS":0.970636,"RSR":0.0571256,"SRSR":0.00541746,"asymID":"A","compID":"VAL","pdb":{"compID":"VAL","insCode":"","seqNum":1174,"strandID":"A"},"seqID":79},{"EDIAm":0.748588,"NGRID":189,"OPIA":55.5556,"RSCCS":0.976019,"RSR":0.0659765,"SRSR":0.0056103,"asymID":"A","compID":"GLN","pdb":{"compID":"GLN","insCode":"","seqNum":1175,"strandID":"A"},"seqID":80},{"EDIAm":0.808418,"NGRID":105,"OPIA":75,"RSCCS":0.985745,"RSR":0.0490252,"SRSR":0.00477185,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1176,"strandID":"A"},"seqID":81},{"EDIAm":0.83703,"NGRID":88,"OPIA":62.5,"RSCCS":0.989846,"RSR":0.0433105,"SRSR":0.0044632,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1177,"strandID":"A"},"seqID":82},{"EDIAm":0.699397,"NGRID":225,"OPIA":36.3636,"RSCCS":0.967391,"RSR":0.0797376,"SRSR":0.00531239,"asymID":"A","compID":"ARG","pdb":{"compID":"ARG","insCode":"","seqNum":1178,"strandID":"A"},"seqID":83},{"EDIAm":0.858624,"NGRID":67,"OPIA":83.3333,"RSCCS":0.989263,"RSR":0.0325055,"SRSR":0.00511729,"asymID":"A","compID":"SER","pdb":{"compID":"SER","insCode":"","seqNum":1179,"strandID":"A"},"seqID":84},{"EDIAm":0.725427,"NGRID":111,"OPIA":28.5714,"RSCCS":0.983662,"RSR":0.0525451,"SRSR":0.0060025,"asymID":"A","compID":"VAL","pdb":{"compID":"VAL","insCode":"","seqNum":1180,"strandID":"A"},"seqID":85},{"EDIAm":0.862014,"NGRID":42,"OPIA":75,"RSCCS":0.988769,"RSR":0.0381707,"SRSR":0.00601359,"asymID":"A","compID":"GLY","pdb":{"compID":"GLY","insCode":"","seqNum":1181,"strandID":"A"},"seqID":86},{"EDIAm":0.856043,"NGRID":98,"OPIA":75,"RSCCS":0.984304,"RSR":0.0395041,"SRSR":0.00481272,"asymID":"A","compID":"ASP","pdb":{"compID":"ASP","insCode":"","seqNum":1182,"strandID":"A"},"seqID":87},{"EDIAm":0.838992,"NGRID":84,"OPIA":57.1429,"RSCCS":0.988991,"RSR":0.0371183,"SRSR":0.00485392,"asymID":"A","compID":"THR","pdb":{"compID":"THR","insCode":"","seqNum":1183,"strandID":"A"},"seqID":88},{"EDIAm":0.811987,"NGRID":97,"OPIA":62.5,"RSCCS":0.985775,"RSR":0.0384616,"SRSR":0.00478186,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1184,"strandID":"A"},"seqID":89},{"EDIAm":0.834885,"NGRID":93,"OPIA":85.7143,"RSCCS":0.986741,"RSR":0.0340999,"SRSR":0.00505424,"asymID":"A","compID":"THR","pdb":{"compID":"THR","insCode":"","seqNum":1185,"strandID":"A"},"seqID":90},{"EDIAm":0.850584,"NGRID":73,"OPIA":71.4286,"RSCCS":0.986692,"RSR":0.0437484,"SRSR":0.00474776,"asymID":"A","compID":"VAL","pdb":{"compID":"VAL","insCode":"","seqNum":1186,"strandID":"A"},"seqID":91},{"EDIAm":0.810924,"NGRID":77,"OPIA":50,"RSCCS":0.993653,"RSR":0.0319225,"SRSR":0.00444994,"asymID":"A","compID":"LEU","pdb":{"compID":"LEU","insCode":"","seqNum":1187,"strandID":"A"},"seqID":92},{"EDIAm":0.827997,"NGRID":80,"OPIA":71.4286,"RSCCS":0.982064,"RSR":0.0366939,"SRSR":0.00508723,"asymID":"A","compID":"VAL","pdb":{"compID":"VAL","insCode":"","seqNum":1188,"strandID":"A"},"seqID":93},{"EDIAm":0.792271,"NGRID":123,"OPIA":50,"RSCCS":0.961198,"RSR":0.0676941,"SRSR":0.00557093,"asymID":"A","compID":"CYS","pdb":{"compID":"CYS","insCode":"","seqNum":1189,"strandID":"A"},"seqID":94},{"EDIAm":0.794026,"NGRID":25,"OPIA":0,"RSCCS":0.935372,"RSR":0.0843386,"SRSR":0.0173769,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":102,"strandID":"A"},"seqID":0},{"EDIAm":0.9623,"NGRID":18,"OPIA":100,"RSCCS":0.970035,"RSR":0.0939738,"SRSR":0.0111691,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":105,"strandID":"A"},"seqID":0},{"EDIAm":0.83817,"NGRID":11,"OPIA":100,"RSCCS":0.992248,"RSR":0.0238597,"SRSR":0.00972345,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":106,"strandID":"A"},"seqID":0},{"EDIAm":0.884734,"NGRID":23,"OPIA":100,"RSCCS":0.900322,"RSR":0.105849,"SRSR":0.0128952,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":107,"strandID":"A"},"seqID":0},{"EDIAm":0.685063,"NGRID":27,"OPIA":0,"RSCCS":0.943223,"RSR":0.0745829,"SRSR":0.0176879,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":108,"strandID":"A"},"seqID":0},{"EDIAm":0.622407,"NGRID":35,"OPIA":0,"RSCCS":0.911797,"RSR":0.0989547,"SRSR":0.0162203,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":110,"strandID":"A"},"seqID":0},{"EDIAm":0.898353,"NGRID":19,"OPIA":100,"RSCCS":0.994239,"RSR":0.0430833,"SRSR":0.0123471,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":111,"strandID":"A"},"seqID":0},{"EDIAm":0.711219,"NGRID":23,"OPIA":0,"RSCCS":0.971767,"RSR":0.0879657,"SRSR":0.0206598,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":112,"strandID":"A"},"seqID":0},{"EDIAm":0.444447,"NGRID":53,"OPIA":0,"RSCCS":0.75876,"RSR":0.196999,"SRSR":0.0198705,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":113,"strandID":"A"},"seqID":0},{"EDIAm":0.650738,"NGRID":32,"OPIA":0,"RSCCS":0.936723,"RSR":0.0784592,"SRSR":0.019467,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":114,"strandID":"A"},"seqID":0},{"EDIAm":0.860329,"NGRID":15,"OPIA":100,"RSCCS":0.989482,"RSR":0.0325709,"SRSR":0.0129195,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":115,"strandID":"A"},"seqID":0},{"EDIAm":0.863292,"NGRID":29,"OPIA":100,"RSCCS":0.977187,"RSR":0.0924671,"SRSR":0.0149499,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":116,"strandID":"A"},"seqID":0},{"EDIAm":0.841908,"NGRID":40,"OPIA":100,"RSCCS":0.859645,"RSR":0.144491,"SRSR":0.014825,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":117,"strandID":"A"},"seqID":0},{"EDIAm":0.905564,"NGRID":9,"OPIA":100,"RSCCS":0.995532,"RSR":0.0330853,"SRSR":0.00913319,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":118,"strandID":"A"},"seqID":0},{"EDIAm":0.864544,"NGRID":8,"OPIA":100,"RSCCS":0.996222,"RSR":0.036281,"SRSR":0.00913022,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":120,"strandID":"A"},"seqID":0},{"EDIAm":0.648931,"NGRID":28,"OPIA":0,"RSCCS":0.866223,"RSR":0.124056,"SRSR":0.0185804,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":121,"strandID":"A"},"seqID":0},{"EDIAm":0.86217,"NGRID":13,"OPIA":100,"RSCCS":0.989741,"RSR":0.0376423,"SRSR":0.011162,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":122,"strandID":"A"},"seqID":0},{"EDIAm":0.51566,"NGRID":41,"OPIA":0,"RSCCS":0.922782,"RSR":0.0805086,"SRSR":0.0208996,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":123,"strandID":"A"},"seqID":0},{"EDIAm":0.857709,"NGRID":17,"OPIA":100,"RSCCS":0.970573,"RSR":0.0492908,"SRSR":0.0131692,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":124,"strandID":"A"},"seqID":0},{"EDIAm":0.77162,"NGRID":24,"OPIA":0,"RSCCS":0.962204,"RSR":0.060897,"SRSR":0.0155671,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":125,"strandID":"A"},"seqID":0},{"EDIAm":0.635267,"NGRID":31,"OPIA":0,"RSCCS":0.90541,"RSR":0.10354,"SRSR":0.0193904,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":126,"strandID":"A"},"seqID":0},{"EDIAm":0.916465,"NGRID":16,"OPIA":100,"RSCCS":0.991013,"RSR":0.0370719,"SRSR":0.0114246,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":128,"strandID":"A"},"seqID":0},{"EDIAm":0.946739,"NGRID":12,"OPIA":100,"RSCCS":0.988564,"RSR":0.0517469,"SRSR":0.0102533,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":129,"strandID":"A"},"seqID":0},{"EDIAm":0.81373,"NGRID":16,"OPIA":100,"RSCCS":0.987049,"RSR":0.0372628,"SRSR":0.0116751,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":130,"strandID":"A"},"seqID":0},{"EDIAm":0.673104,"NGRID":24,"OPIA":0,"RSCCS":0.962577,"RSR":0.0776189,"SRSR":0.0184111,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":131,"strandID":"A"},"seqID":0},{"EDIAm":0.772305,"NGRID":22,"OPIA":0,"RSCCS":0.952396,"RSR":0.0734146,"SRSR":0.016081,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":132,"strandID":"A"},"seqID":0},{"EDIAm":0.863399,"NGRID":18,"OPIA":100,"RSCCS":0.982839,"RSR":0.0481114,"SRSR":0.0127144,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":133,"strandID":"A"},"seqID":0},{"EDIAm":0.762442,"NGRID":25,"OPIA":0,"RSCCS":0.958863,"RSR":0.0638904,"SRSR":0.0174443,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":134,"strandID":"A"},"seqID":0},{"EDIAm":0.823704,"NGRID":16,"OPIA":100,"RSCCS":0.977831,"RSR":0.0418878,"SRSR":0.0126061,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":135,"strandID":"A"},"seqID":0},{"EDIAm":0.622895,"NGRID":36,"OPIA":0,"RSCCS":0.864709,"RSR":0.111993,"SRSR":0.0171242,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":136,"strandID":"A"},"seqID":0},{"EDIAm":0.735492,"NGRID":16,"OPIA":0,"RSCCS":0.977621,"RSR":0.074711,"SRSR":0.016054,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":137,"strandID":"A"},"seqID":0},{"EDIAm":0.748666,"NGRID":18,"OPIA":0,"RSCCS":0.986712,"RSR":0.0889445,"SRSR":0.0186179,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":138,"strandID":"A"},"seqID":0},{"EDIAm":0.949435,"NGRID":18,"OPIA":100,"RSCCS":0.978259,"RSR":0.0771433,"SRSR":0.0123472,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":139,"strandID":"A"},"seqID":0},{"EDIAm":0.705707,"NGRID":20,"OPIA":0,"RSCCS":0.97891,"RSR":0.0790487,"SRSR":0.0185311,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":140,"strandID":"A"},"seqID":0},{"EDIAm":0.633153,"NGRID":33,"OPIA":0,"RSCCS":0.862658,"RSR":0.12446,"SRSR":0.0190499,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":141,"strandID":"A"},"seqID":0},{"EDIAm":0.292118,"NGRID":45,"OPIA":0,"RSCCS":0.909514,"RSR":0.173864,"SRSR":0.0322009,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":142,"strandID":"A"},"seqID":0},{"EDIAm":0.510678,"NGRID":36,"OPIA":0,"RSCCS":0.890052,"RSR":0.16151,"SRSR":0.0263829,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":143,"strandID":"A"},"seqID":0},{"EDIAm":0.691833,"NGRID":24,"OPIA":0,"RSCCS":0.919953,"RSR":0.128611,"SRSR":0.0211014,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":144,"strandID":"A"},"seqID":0},{"EDIAm":0.665755,"NGRID":24,"OPIA":0,"RSCCS":0.951611,"RSR":0.0903587,"SRSR":0.0188717,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":145,"strandID":"A"},"seqID":0},{"EDIAm":0.618179,"NGRID":31,"OPIA":0,"RSCCS":0.957873,"RSR":0.0674069,"SRSR":0.018978,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":146,"strandID":"A"},"seqID":0},{"EDIAm":0.823362,"NGRID":30,"OPIA":100,"RSCCS":0.906427,"RSR":0.104138,"SRSR":0.0156023,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":148,"strandID":"A"},"seqID":0},{"EDIAm":0.926344,"NGRID":9,"OPIA":100,"RSCCS":0.998197,"RSR":0.0419611,"SRSR":0.00879634,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":149,"strandID":"A"},"seqID":0},{"EDIAm":0.756548,"NGRID":15,"OPIA":0,"RSCCS":0.986535,"RSR":0.0962593,"SRSR":0.0177908,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":150,"strandID":"A"},"seqID":0},{"EDIAm":0.907437,"NGRID":21,"OPIA":100,"RSCCS":0.966555,"RSR":0.0728475,"SRSR":0.0124167,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":151,"strandID":"A"},"seqID":0},{"EDIAm":0.834453,"NGRID":14,"OPIA":100,"RSCCS":0.990633,"RSR":0.0293817,"SRSR":0.0118642,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":152,"strandID":"A"},"seqID":0},{"EDIAm":0.864288,"NGRID":10,"OPIA":100,"RSCCS":0.995425,"RSR":0.0221404,"SRSR":0.00934245,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":153,"strandID":"A"},"seqID":0},{"EDIAm":0.723426,"NGRID":24,"OPIA":0,"RSCCS":0.981769,"RSR":0.0505238,"SRSR":0.0179134,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":154,"strandID":"A"},"seqID":0},{"EDIAm":0.883217,"NGRID":17,"OPIA":100,"RSCCS":0.984652,"RSR":0.0448662,"SRSR":0.0123491,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":155,"strandID":"A"},"seqID":0},{"EDIAm":0.96172,"NGRID":12,"OPIA":100,"RSCCS":0.982391,"RSR":0.0492112,"SRSR":0.0102196,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":156,"strandID":"A"},"seqID":0},{"EDIAm":0.807177,"NGRID":20,"OPIA":100,"RSCCS":0.973158,"RSR":0.0553241,"SRSR":0.0154624,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":157,"strandID":"A"},"seqID":0},{"EDIAm":0.83449,"NGRID":10,"OPIA":100,"RSCCS":0.993143,"RSR":0.0217142,"SRSR":0.0104776,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":158,"strandID":"A"},"seqID":0},{"EDIAm":0.805701,"NGRID":30,"OPIA":100,"RSCCS":0.955104,"RSR":0.0823864,"SRSR":0.0159722,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":159,"strandID":"A"},"seqID":0},{"EDIAm":0.874294,"NGRID":21,"OPIA":100,"RSCCS":0.9635,"RSR":0.0573652,"SRSR":0.0142205,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":160,"strandID":"A"},"seqID":0},{"EDIAm":0.729652,"NGRID":31,"OPIA":0,"RSCCS":0.934786,"RSR":0.0794362,"SRSR":0.017194,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":161,"strandID":"A"},"seqID":0},{"EDIAm":0.948789,"NGRID":17,"OPIA":100,"RSCCS":0.980901,"RSR":0.0535812,"SRSR":0.0121481,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":162,"strandID":"A"},"seqID":0},{"EDIAm":0.786822,"NGRID":22,"OPIA":0,"RSCCS":0.954456,"RSR":0.0968272,"SRSR":0.0180215,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":163,"strandID":"A"},"seqID":0},{"EDIAm":0.734762,"NGRID":27,"OPIA":0,"RSCCS":0.876788,"RSR":0.100929,"SRSR":0.0151485,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":164,"strandID":"A"},"seqID":0},{"EDIAm":0.876983,"NGRID":14,"OPIA":100,"RSCCS":0.993869,"RSR":0.0252258,"SRSR":0.010652,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":165,"strandID":"A"},"seqID":0},{"EDIAm":0.842169,"NGRID":13,"OPIA":100,"RSCCS":0.996163,"RSR":0.0191907,"SRSR":0.0114773,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":166,"strandID":"A"},"seqID":0},{"EDIAm":0.446824,"NGRID":33,"OPIA":0,"RSCCS":0.947021,"RSR":0.169753,"SRSR":0.0291682,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":167,"strandID":"A"},"seqID":0},{"EDIAm":0.73974,"NGRID":17,"OPIA":0,"RSCCS":0.991216,"RSR":0.0688954,"SRSR":0.0167772,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":168,"strandID":"A"},"seqID":0},{"EDIAm":0.680521,"NGRID":25,"OPIA":0,"RSCCS":0.962501,"RSR":0.0890187,"SRSR":0.0199858,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":169,"strandID":"A"},"seqID":0},{"EDIAm":0.583324,"NGRID":29,"OPIA":0,"RSCCS":0.964796,"RSR":0.111271,"SRSR":0.0234082,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":170,"strandID":"A"},"seqID":0},{"EDIAm":0.835115,"NGRID":15,"OPIA":100,"RSCCS":0.978764,"RSR":0.041191,"SRSR":0.012298,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":171,"strandID":"A"},"seqID":0},{"EDIAm":0.254422,"NGRID":57,"OPIA":0,"RSCCS":0.825648,"RSR":0.150757,"SRSR":0.0243836,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":172,"strandID":"A"},"seqID":0},{"EDIAm":0.712396,"NGRID":38,"OPIA":0,"RSCCS":0.930171,"RSR":0.0890692,"SRSR":0.0177404,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":173,"strandID":"A"},"seqID":0},{"EDIAm":0.71812,"NGRID":31,"OPIA":0,"RSCCS":0.960937,"RSR":0.0598444,"SRSR":0.01784,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":175,"strandID":"A"},"seqID":0},{"EDIAm":0.754174,"NGRID":22,"OPIA":0,"RSCCS":0.984001,"RSR":0.0534522,"SRSR":0.0165873,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":176,"strandID":"A"},"seqID":0},{"EDIAm":0.946911,"NGRID":13,"OPIA":100,"RSCCS":0.991852,"RSR":0.0661117,"SRSR":0.0102391,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":177,"strandID":"A"},"seqID":0},{"EDIAm":0.825846,"NGRID":23,"OPIA":100,"RSCCS":0.96585,"RSR":0.061234,"SRSR":0.0157038,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":178,"strandID":"A"},"seqID":0},{"EDIAm":0.753598,"NGRID":34,"OPIA":0,"RSCCS":0.946475,"RSR":0.079954,"SRSR":0.0167103,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":180,"strandID":"A"},"seqID":0},{"EDIAm":0.989106,"NGRID":11,"OPIA":100,"RSCCS":0.990498,"RSR":0.0797933,"SRSR":0.00901762,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":181,"strandID":"A"},"seqID":0},{"EDIAm":0.840134,"NGRID":22,"OPIA":100,"RSCCS":0.970769,"RSR":0.0528173,"SRSR":0.014504,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":182,"strandID":"A"},"seqID":0},{"EDIAm":0.795474,"NGRID":21,"OPIA":0,"RSCCS":0.979447,"RSR":0.0653247,"SRSR":0.0170602,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":183,"strandID":"A"},"seqID":0},{"EDIAm":0.874058,"NGRID":20,"OPIA":100,"RSCCS":0.979445,"RSR":0.0440098,"SRSR":0.0134781,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":184,"strandID":"A"},"seqID":0},{"EDIAm":0.475495,"NGRID":34,"OPIA":0,"RSCCS":0.94482,"RSR":0.116618,"SRSR":0.0259399,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":185,"strandID":"A"},"seqID":0},{"EDIAm":0.501738,"NGRID":38,"OPIA":0,"RSCCS":0.940114,"RSR":0.104331,"SRSR":0.023725,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":186,"strandID":"A"},"seqID":0},{"EDIAm":0.608935,"NGRID":23,"OPIA":0,"RSCCS":0.970794,"RSR":0.144342,"SRSR":0.0235322,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":187,"strandID":"A"},"seqID":0},{"EDIAm":0.924106,"NGRID":17,"OPIA":100,"RSCCS":0.978841,"RSR":0.0538461,"SRSR":0.0119246,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":188,"strandID":"A"},"seqID":0},{"EDIAm":0.84222,"NGRID":25,"OPIA":100,"RSCCS":0.921936,"RSR":0.103839,"SRSR":0.0136534,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":189,"strandID":"A"},"seqID":0},{"EDIAm":0.917643,"NGRID":16,"OPIA":100,"RSCCS":0.957755,"RSR":0.0809039,"SRSR":0.0111936,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":190,"strandID":"A"},"seqID":0},{"EDIAm":0.976355,"NGRID":18,"OPIA":100,"RSCCS":0.983999,"RSR":0.0912166,"SRSR":0.0113457,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":191,"strandID":"A"},"seqID":0},{"EDIAm":0.75877,"NGRID":29,"OPIA":0,"RSCCS":0.930793,"RSR":0.0774124,"SRSR":0.0168978,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":193,"strandID":"A"},"seqID":0},{"EDIAm":0.855502,"NGRID":15,"OPIA":100,"RSCCS":0.976039,"RSR":0.0451656,"SRSR":0.0123149,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":195,"strandID":"A"},"seqID":0},{"EDIAm":0.708497,"NGRID":37,"OPIA":0,"RSCCS":0.906714,"RSR":0.105164,"SRSR":0.0168994,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":196,"strandID":"A"},"seqID":0},{"EDIAm":0.882212,"NGRID":16,"OPIA":100,"RSCCS":0.985715,"RSR":0.0460328,"SRSR":0.0118717,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":197,"strandID":"A"},"seqID":0},{"EDIAm":0.595025,"NGRID":45,"OPIA":0,"RSCCS":0.832738,"RSR":0.140874,"SRSR":0.0185354,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":198,"strandID":"A"},"seqID":0},{"EDIAm":0.912799,"NGRID":16,"OPIA":100,"RSCCS":0.978033,"RSR":0.0613599,"SRSR":0.0123735,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":199,"strandID":"A"},"seqID":0},{"EDIAm":0.854738,"NGRID":28,"OPIA":100,"RSCCS":0.929796,"RSR":0.0857781,"SRSR":0.0149005,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":200,"strandID":"A"},"seqID":0},{"EDIAm":0.898764,"NGRID":24,"OPIA":100,"RSCCS":0.922986,"RSR":0.16467,"SRSR":0.0108949,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":201,"strandID":"A"},"seqID":0},{"EDIAm":0.440021,"NGRID":44,"OPIA":0,"RSCCS":0.928219,"RSR":0.0866592,"SRSR":0.0214071,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":202,"strandID":"A"},"seqID":0},{"EDIAm":0.871209,"NGRID":15,"OPIA":100,"RSCCS":0.967325,"RSR":0.0525725,"SRSR":0.0116551,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":203,"strandID":"A"},"seqID":0},{"EDIAm":0.614469,"NGRID":27,"OPIA":0,"RSCCS":0.797188,"RSR":0.147262,"SRSR":0.0132012,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":204,"strandID":"A"},"seqID":0},{"EDIAm":0.630471,"NGRID":35,"OPIA":0,"RSCCS":0.875411,"RSR":0.117223,"SRSR":0.018593,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":205,"strandID":"A"},"seqID":0},{"EDIAm":0.889576,"NGRID":28,"OPIA":100,"RSCCS":0.931477,"RSR":0.085381,"SRSR":0.0145952,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":207,"strandID":"A"},"seqID":0},{"EDIAm":0.659945,"NGRID":39,"OPIA":0,"RSCCS":0.930481,"RSR":0.0900002,"SRSR":0.0167911,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":208,"strandID":"A"},"seqID":0},{"EDIAm":0.75258,"NGRID":23,"OPIA":0,"RSCCS":0.958701,"RSR":0.0631228,"SRSR":0.0159697,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":209,"strandID":"A"},"seqID":0},{"EDIAm":0.331491,"NGRID":47,"OPIA":0,"RSCCS":0.898998,"RSR":0.137829,"SRSR":0.0268629,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":210,"strandID":"A"},"seqID":0},{"EDIAm":0.799039,"NGRID":24,"OPIA":0,"RSCCS":0.978428,"RSR":0.0486077,"SRSR":0.0164594,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":211,"strandID":"A"},"seqID":0},{"EDIAm":0.658824,"NGRID":38,"OPIA":0,"RSCCS":0.893939,"RSR":0.112039,"SRSR":0.0163228,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":212,"strandID":"A"},"seqID":0},{"EDIAm":0.727184,"NGRID":35,"OPIA":0,"RSCCS":0.936357,"RSR":0.0811358,"SRSR":0.0171723,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":213,"strandID":"A"},"seqID":0},{"EDIAm":0.476125,"NGRID":45,"OPIA":0,"RSCCS":0.906187,"RSR":0.094686,"SRSR":0.019847,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":214,"strandID":"A"},"seqID":0},{"EDIAm":0.430013,"NGRID":43,"OPIA":0,"RSCCS":0.914692,"RSR":0.0929293,"SRSR":0.0231583,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":215,"strandID":"A"},"seqID":0},{"EDIAm":0.520278,"NGRID":37,"OPIA":0,"RSCCS":0.92396,"RSR":0.0949016,"SRSR":0.0217989,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":218,"strandID":"A"},"seqID":0},{"EDIAm":0.476368,"NGRID":38,"OPIA":0,"RSCCS":0.952634,"RSR":0.0902015,"SRSR":0.0228882,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":219,"strandID":"A"},"seqID":0},{"EDIAm":0.733319,"NGRID":24,"OPIA":0,"RSCCS":0.941202,"RSR":0.0913715,"SRSR":0.0174309,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":220,"strandID":"A"},"seqID":0},{"EDIAm":0.686398,"NGRID":31,"OPIA":0,"RSCCS":0.966057,"RSR":0.0646058,"SRSR":0.0176986,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":221,"strandID":"A"},"seqID":0},{"EDIAm":0.424552,"NGRID":45,"OPIA":0,"RSCCS":0.920998,"RSR":0.0835588,"SRSR":0.021037,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":222,"strandID":"A"},"seqID":0},{"EDIAm":0.706889,"NGRID":32,"OPIA":0,"RSCCS":0.955297,"RSR":0.0685075,"SRSR":0.0164659,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":223,"strandID":"A"},"seqID":0},{"EDIAm":0.767882,"NGRID":32,"OPIA":0,"RSCCS":0.924044,"RSR":0.0932105,"SRSR":0.0171662,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":224,"strandID":"A"},"seqID":0},{"EDIAm":0.852971,"NGRID":18,"OPIA":100,"RSCCS":0.988887,"RSR":0.0397999,"SRSR":0.0121718,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":225,"strandID":"A"},"seqID":0},{"EDIAm":0.726843,"NGRID":25,"OPIA":0,"RSCCS":0.9504,"RSR":0.0863979,"SRSR":0.0183717,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":226,"strandID":"A"},"seqID":0},{"EDIAm":0.770193,"NGRID":29,"OPIA":0,"RSCCS":0.94813,"RSR":0.068639,"SRSR":0.0170623,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":228,"strandID":"A"},"seqID":0},{"EDIAm":0.722934,"NGRID":34,"OPIA":0,"RSCCS":0.954132,"RSR":0.0614373,"SRSR":0.0175075,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":229,"strandID":"A"},"seqID":0},{"EDIAm":0.693013,"NGRID":21,"OPIA":0,"RSCCS":0.986489,"RSR":0.109455,"SRSR":0.0201846,"asymID":"B","compID":"HOH","pdb":{"compID":"HOH","insCode":"","seqNum":231,"strandID":"A"},"seqID":0}]