Skip to content

Repository files navigation

Aggrescan3D cluster workflow

Static-mode Aggrescan3D scoring for PDB and mmCIF structures on a Slurm cluster. The workflow analyzes binder chain B by default, preserves residue-level results, processes several structures concurrently within one persistent Slurm allocation, and reuses only validated existing outputs.

Current implementation

The scientific runtime is pulled from:

docker://lcbio/a3d_server:latest

The validated image contains:

Aggrescan3D 0.9.11
Python 2.7
CLI: /opt/conda/bin/aggrescan
Architecture: x86_64 / amd64

The Docker image runscript starts its original server-oriented command. Therefore this workflow uses apptainer exec, not apptainer run, to invoke Aggrescan3D:

apptainer exec aggrescan3d.sif /opt/conda/bin/aggrescan --help

Host-side Python 3 code handles PDB/mmCIF parsing, chain extraction, CIF-to-PDB conversion, output parsing, metadata, cache validation, concurrency, and Slurm submission. Only the legacy Aggrescan3D calculation runs inside the SIF.

Scope

Implemented:

  • Aggrescan3D static mode;
  • PDB, .cif, and .mmcif inputs;
  • chain B by default;
  • multiple selected chains with --chains A,B;
  • all first-model chains with --all-chains;
  • FreeSASA, which is the image default because --naccess is not used;
  • residue-level normalized output;
  • per-structure summary metrics;
  • manifest-driven concurrent execution;
  • one persistent Slurm allocation rather than a job array;
  • validated cache reuse;
  • atomic output replacement;
  • per-output locking to prevent simultaneous writers.

Not implemented:

  • dynamic mode;
  • CABS-flex;
  • FoldX optimization or stability calculations;
  • mutation design;
  • automated solubility-enhancing mutation selection;
  • the Aggrescan3D web interface;
  • job arrays;
  • database-backed result tracking;
  • cross-model plotting or ranking.

See SPEC.md for the complete behavioral contract.

Repository contents

aggrescan3d_common.py
build_container.sh
CHANGELOG.md
README.md
requirements.txt
run_aggrescan3d_manifest.py
run_aggrescan3d_single.py
run_tests.sh
SOURCE_IMAGE.txt
SPEC.md
submit_aggrescan3d.py
tests/

Generated files such as aggrescan3d.sif, image metadata, test manifests, Slurm logs, and per-structure result directories are excluded by .gitignore.

Requirements

Cluster software

  • Apptainer with OCI image pull support;
  • Slurm for submit_aggrescan3d.py;
  • Python 3.9 or newer is recommended;
  • enough local or shared storage for the SIF and per-structure results.

Host Python package

Gemmi is required on the login and compute nodes:

python3 -m pip install --user -r requirements.txt
python3 -c 'import gemmi; print(gemmi.__version__)'

The current pin is:

gemmi==0.7.4

The Python interpreter used to submit the job must resolve to an interpreter that can also import Gemmi on the compute node.

Quick start

1. Obtain and validate the SIF

From the workflow directory:

chmod +x build_container.sh
./build_container.sh

build_container.sh uses apptainer pull, not a %post container build. This avoids reconstructing Aggrescan3D's obsolete Python 2 dependency stack.

The script validates:

  • container architecture;
  • Python version;
  • installed Aggrescan3D package version;
  • availability of /opt/conda/bin/aggrescan;
  • successful CLI help execution.

It creates:

aggrescan3d.sif
aggrescan3d_image_metadata.json

The metadata file records the source image, architecture, Python version, Aggrescan3D version, executable path, and SIF SHA-256 checksum. Docker's latest tag is mutable, so retain this metadata with the deployed SIF even though both are normally excluded from Git.

Manual checks:

apptainer exec aggrescan3d.sif uname -m

apptainer exec aggrescan3d.sif \
    /opt/conda/bin/python --version

apptainer exec aggrescan3d.sif \
    /opt/conda/bin/conda list | grep -i '^aggrescan3d '

apptainer exec aggrescan3d.sif \
    /opt/conda/bin/aggrescan --help

Do not use:

apptainer run aggrescan3d.sif --help

The inherited image runscript treats --help as the executable name and fails.

2. Run one structure

PDB:

./run_aggrescan3d_single.py /absolute/path/model.pdb

mmCIF:

./run_aggrescan3d_single.py /absolute/path/model.cif

The wrapper reads the first structural model, extracts chain B by default, writes a selected-chain PDB, executes Aggrescan3D, and parses its output.

Alternative selections:

./run_aggrescan3d_single.py model.pdb --chains A,B
./run_aggrescan3d_single.py model.cif --all-chains

Force recalculation:

./run_aggrescan3d_single.py model.cif --force

Record or recompute the full SIF checksum during the run:

./run_aggrescan3d_single.py model.cif --container-checksum

Override the default container:

./run_aggrescan3d_single.py model.cif \
    --container /path/to/aggrescan3d.sif

The default container path is:

/work/users/d/b/dbortone/binder_design/scripts/aggrescan3d/aggrescan3d.sif

3. Run a manifest directly

A direct manifest run is useful for local validation or execution inside an existing allocation:

./run_aggrescan3d_manifest.py \
    manifest.txt \
    results.tsv \
    --cpus 4

4. Submit through Slurm

mkdir -p slurm_logs

./submit_aggrescan3d.py \
    manifest.txt \
    slurm_logs \
    results.tsv \
    --job-suffix cd45

Inspect the generated sbatch command without submitting:

./submit_aggrescan3d.py \
    manifest.txt \
    slurm_logs \
    results.tsv \
    --job-suffix cd45 \
    --dry-run

Single-structure command options

structure                 Input .pdb, .cif, or .mmcif file
--chains B                Comma-separated chain IDs; default B
--all-chains              Analyze all chains in the first model
--output-dir PATH         Override INPUT.aggrescan3d
--container PATH          Override the default SIF
--apptainer COMMAND       Override the Apptainer executable name/path
--distance {5,10}         A3D neighborhood distance in Å; default 10
--hotspot-threshold X     Hotspot cutoff; score must be > X; default 0.0
--verbosity {0,1,2,3,4}   Aggrescan3D verbosity; default 3
--container-checksum      Compute/store the SIF SHA-256 during the run
--force                   Recalculate even when existing output is valid

Structure preparation

The wrapper uses Gemmi to parse both PDB and mmCIF inputs. It then:

  1. selects the first model;
  2. verifies the requested chains exist;
  3. requires one-character chain IDs because the selected structure is written as PDB;
  4. requires each selected chain to contain at least one CA-bearing residue;
  5. requires at least four selected CA-bearing residues in total;
  6. writes selected_input.pdb without modifying the source file.

Chain extraction is intentional. Scoring only the binder avoids having a target mask aggregation-prone binder surfaces at a predicted interface.

The wrapper does not pass Aggrescan3D's --chain option because the temporary input PDB already contains only the requested chains.

Aggrescan3D execution

The effective scientific command is equivalent to:

apptainer exec \
    --cleanenv \
    --bind <required paths> \
    --env OMP_NUM_THREADS=1 \
    --env OPENBLAS_NUM_THREADS=1 \
    --env MKL_NUM_THREADS=1 \
    --env NUMEXPR_NUM_THREADS=1 \
    --env MPLBACKEND=Agg \
    aggrescan3d.sif \
    /opt/conda/bin/aggrescan \
        -i selected_input.pdb \
        -w raw \
        -D 10 \
        -v 3

Dynamic mode, FoldX, and NACCESS are not requested. FreeSASA is therefore used by the bundled Aggrescan3D runtime.

Aggrescan3D normally writes progress messages to stderr even when the analysis succeeds. An empty stdout.txt and populated stderr.txt are not themselves errors.

Per-structure output

For model.cif, the default result directory is:

model.cif.aggrescan3d/

Expected layout:

model.cif.aggrescan3d/
├── aggrescan3d_residues.tsv
├── aggrescan3d_summary.tsv
├── run_metadata.json
├── selected_input.pdb
├── stdout.txt
├── stderr.txt
└── raw/
    ├── A3D.csv
    ├── input.pdb
    ├── output.pdb
    ├── config.ini
    ├── <chain>.png
    └── <chain>.svg

The image may vary its nonessential plot filenames for multi-chain inputs. All files produced in the Aggrescan3D work directory are preserved under raw/.

Raw A3D schema

The validated Aggrescan3D 0.9.11 CSV schema is:

protein,chain,residue,residue_name,score

Normalized residue table

aggrescan3d_residues.tsv contains:

Chain
Residue_Number
Insertion_Code
Residue_Name
A3D_Score
Source_Residue_Field

Source_Residue_Field preserves the unmodified value from A3D.csv. The parser splits a terminal insertion-code letter into Insertion_Code when possible.

Summary table

aggrescan3d_summary.tsv contains one row with:

Structure_Path
Aggrescan3D_Output_Directory
Analyzed_Chains
Residue_Count
Mean_A3D_Score
Median_A3D_Score
Maximum_A3D_Score
Minimum_A3D_Score
Positive_A3D_Residue_Count
Positive_A3D_Residue_Fraction
Sum_Positive_A3D_Score
Hotspot_Threshold
Hotspot_Residue_Count
Hotspot_Residue_Fraction
Maximum_Hotspot_Run_Length
Status
Error

Definitions:

  • positive residue: A3D_Score > 0.0;
  • hotspot residue: A3D_Score > Hotspot_Threshold;
  • default hotspot threshold: 0.0;
  • maximum hotspot run: longest run of consecutive hotspot rows within a chain; runs reset at chain boundaries.

With the default threshold, positive-residue and hotspot counts are identical. A different --hotspot-threshold changes only hotspot metrics.

Metadata

run_metadata.json records:

  • schema and workflow status;
  • input path, size, and nanosecond modification time;
  • requested and analyzed chains;
  • analysis mode, A3D distance, and hotspot threshold;
  • Aggrescan3D and Python versions;
  • solvent-accessibility implementation;
  • SIF path, size, modification time, source image, and optional checksum;
  • exact execution command;
  • start/end timestamps and runtime;
  • PDB/mmCIF conversion details;
  • available chains and CA-bearing residue counts;
  • parsed metrics;
  • warnings;
  • raw output filenames.

Existing-output reuse

Without --force, an existing result is reused only when all of the following pass:

  • output directory exists;
  • run_metadata.json parses;
  • metadata schema matches the current workflow;
  • prior status is successful and exit status is zero;
  • input path matches;
  • input size and nanosecond modification time match;
  • analysis mode is static;
  • distance and hotspot threshold match;
  • requested chain selection matches;
  • SIF path, size, and modification time match;
  • residue-level TSV exists and is nonempty;
  • summary TSV has the exact expected columns;
  • required numeric fields parse;
  • summary path and status are reusable.

A valid reused row is returned with:

Status = existing

Any mismatch triggers automatic recomputation. --force always recomputes.

Atomicity and locking

Each output path uses a sibling lock file so two processes cannot write the same result simultaneously. New output is generated in a temporary sibling directory. On success or recorded failure, the temporary directory replaces the prior output using rename-based operations. An existing complete directory is retained if replacement fails midway.

The merged manifest TSV is also written atomically after all workers finish.

Manifest format

A manifest contains one PDB/mmCIF path per line:

# Comments and blank lines are ignored
/absolute/path/model_1.pdb
relative/path/model_2.cif

Rules:

  • relative paths are resolved relative to the manifest directory;
  • blank lines are ignored;
  • lines whose first non-whitespace character is # are ignored;
  • duplicate resolved paths are warned about and ignored;
  • first-seen ordering is preserved in the final TSV;
  • missing files and unsupported extensions generate failed rows rather than stopping other work.

Example manifest generation for Boltz outputs:

find \
  /work/users/d/b/dbortone/binder_design/targets/CD45/20260601_de_novo/20_boltz2msa_on_cd45d1/outputs \
  -type f \
  -path '*/seed_*/*/predictions/*/*.cif' \
  -print | sort > manifest.txt

Manifest runner

./run_aggrescan3d_manifest.py manifest.txt results.tsv [options]

Important options:

--container PATH
--cpus N
--chains B
--all-chains
--distance {5,10}
--hotspot-threshold X
--force
--container-checksum
--apptainer COMMAND

--cpus is the maximum number of concurrent structure workers. Each worker is constrained to one CPU where applicable.

A failed structure does not stop the remaining entries. Progress resembles:

[1/200] computed: /path/model_1.cif
[2/200] existing: /path/model_2.cif
[3/200] failed: /path/model_3.cif
computed=197
existing=2
failed=1
final_tsv=/path/results.tsv

The manifest runner exits nonzero when at least one structure fails, after preserving the complete final TSV.

Slurm submitter

./submit_aggrescan3d.py \
    MANIFEST \
    SLURM_LOG_DIR \
    FINAL_TSV \
    [options]

Defaults:

container         /work/users/d/b/dbortone/binder_design/scripts/aggrescan3d/aggrescan3d.sif
chains            B
cpus              4
memory            4G
time              01:00:00
distance          10 Å
hotspot threshold 0.0
force             false
mode              static

Common overrides:

./submit_aggrescan3d.py manifest.txt slurm_logs results.tsv \
    --job-suffix cd45 \
    --cpus 8 \
    --memory 8G \
    --time 02:00:00 \
    --partition general \
    --account my_account \
    --chains B \
    --hotspot-threshold 0.0 \
    --force

The submitter creates one job using sbatch --wrap. It requests --cpus-per-task N, then starts at most N concurrent one-CPU workers inside that allocation. It does not use a job array.

Slurm log names are:

%x_%j.out
%x_%j.err

Automatic Apptainer bindings

The single-model wrapper derives bind directories from:

  • the input structure directory;
  • the output directory parent;
  • the SIF directory.

Redundant descendants are collapsed. Paths under:

/work/users/d/b/dbortone/binder_design

are represented by one project-root bind when possible. Output paths outside that root receive their own bind.

Status and exit behavior

Per-row status values:

computed  Analysis was executed successfully.
existing  A validated existing result was reused.
failed    Input validation, execution, or output validation failed.

Single-model exit behavior:

  • 0: successful computation or valid cache reuse;
  • 1: computation/output-processing failure recorded in the output directory;
  • 2: invalid input, missing container, missing Apptainer, or unsupported extension.

Manifest behavior:

  • returns 0 when no row failed;
  • returns 1 when one or more rows failed;
  • always writes the complete final TSV after workers finish.

Slurm submitter returns the sbatch command status.

Error text is sanitized to remove tabs and embedded newlines before insertion into the final TSV.

Testing

Run local workflow tests:

chmod +x run_tests.sh
./run_tests.sh

The tests cover:

  • comments, blank lines, relative paths, and duplicate manifest entries;
  • PDB chain extraction;
  • mmCIF-to-PDB conversion;
  • normalized residue parsing;
  • summary and hotspot metrics;
  • PDB/mmCIF summary equivalence;
  • valid existing-output reuse;
  • invalidation after input changes;
  • invalidation after SIF changes.

These tests mock Apptainer and Aggrescan3D. They verify orchestration logic but do not replace validation with the real SIF.

Validated cluster behavior

Validated on June 19, 2026:

  • the lcbio/a3d_server image pulled successfully as AMD64;
  • /opt/conda/bin/aggrescan --help executed successfully;
  • the image reported Aggrescan3D 0.9.11;
  • a real PDB complex was reduced to chain B and produced 104 residue scores;
  • a real Boltz mmCIF was converted and produced 96 residue scores;
  • the raw schema was confirmed as protein,chain,residue,residue_name,score;
  • a two-entry PDB/mmCIF manifest completed with two concurrent workers;
  • the merged TSV was valid;
  • cache reuse returned existing rows;
  • Slurm submission completed successfully.

Known limitations

  • Only the first model in a multi-model PDB/mmCIF structure is analyzed.
  • Selected mmCIF chain IDs must be representable as one-character PDB chain IDs.
  • Routine cache validation uses file path, size, and modification time. --container-checksum adds stronger SIF identity recording but is optional because repeated hashing of a large SIF is expensive.
  • The source image uses a mutable latest tag. Reproducibility depends on retaining the generated SIF and metadata checksum.
  • Aggrescan3D 0.9.11 is legacy Python 2 software. It is intentionally isolated inside the container.
  • Static Aggrescan3D scores are one component of developability assessment, not a substitute for experimental aggregation, expression, solubility, or off-target testing.

Citation

Analyses should cite the Aggrescan3D method and standalone software as appropriate:

  • Zambrano R. et al. AGGRESCAN3D (A3D): server for prediction of aggregation properties of protein structures. Nucleic Acids Research, 2015.
  • Kuriata A. et al. Aggrescan3D standalone package for structure-based prediction of protein aggregation properties. Bioinformatics, 2019.

Review the upstream software and container licensing terms before redistribution or commercial deployment. This repository contains workflow code and does not redistribute the SIF through Git.

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages