About

April 15, 2026 · View on GitHub

PyPI Version License: LGPL v3 Docs Status Python Versions GitHub stars GitHub last commit Open In Colab
My Image

About

Last updated April 15th 2026

STARLING (conSTruction of intrinsicAlly disoRdered proteins ensembles efficientLy vIa multi-dimeNsional Generative models) is a latent-space probabilistic denoising diffusion model for predicting coarse-grained ensembles of intrinsically disordered regions.

STARLING was developed by Borna Novak and Jeff Lotthammer in the Holehouse lab (with some occasional help from Ryan and Alex, as is their wont).

For more information, please take a look at our paper!

Novak, B., Lotthammer, J. M., Emenecker, R. J. & Holehouse, A. S. Accurate predictions of disordered protein ensembles with STARLING. Nature 652, 240–250 (2026).

Documentation

Detailed documentation is provdied on readthedocs, although this readme is probably enough to do most things.

https://idptools-starling.readthedocs.io/en/latest/

Colab notebook

A Google Colab notebook for predicting ensembles and performing rudimentary analysis is available here.


Installation

STARLING is available on GitHub (bleeding edge) and on PyPi (stable).

We recommend creating a fresh conda environment for STARLING (although in principle, there's nothing special about the STARLING environment)

conda create -n starling  python=3.11 -y
conda activate starling

You can then install STARLING from PyPI using pip (or uv):

pip install idptools-starling

Or you can clone and install the bleeding-edge version from GitHub:

pip install git+https://github.com/idptools/starling.git

To check that STARLING has been installed correctly, run

starling --help

A Docker image is also available — see the Docker documentation for details.


Quickstart

The easiest way to use STARLING for ensemble generation is with the starling command-line tool.

starling <amino acid sequence> -c 400 --outname my_cool_idr -r

Example:

starling MDVFMKGLSKAKEGVVAAAEKTKQGVAEAAGKTKEGVLYVGSKTKEGVVHGVATVAEKTKEQVTNVGGAVVTGVTAVAQKTVEGAGSIAAATGFVKKDQLGKNEEGAPQEGILEDMPVDPDNEAYEMPSEEGYQDYEPEA --outname synuclein -r

Will generate three files:

  • synuclein.starling — the full STARLING ensemble file. This holds all the information associated with the ensemble.
  • synuclein_STARLING.pdb — the topology file for the ensemble.
  • synuclein_STARLING.xtc — the trajectory file for the ensemble.

By default, STARLING generates 400 conformations — to change the number of conformations, use the -c flag (e.g., -c 1000 would generate an ensemble with 1000 conformations).

Performance

STARLING is VERY fast on GPUs and — honestly — VERY fast on Apple Silicon as well. It is a bit slower on CPUs, but we're talking minutes instead of seconds for ensemble generation.


Command-Line Interface (CLI)

STARLING installs several command-line tools. Below is a complete reference for all of them.

starling — Ensemble Generation

The main CLI tool. Generates conformational ensembles from amino acid sequences.

starling <input> [options]

Input formats: a raw amino acid sequence, a .fasta file, a .tsv file (name<TAB>sequence), or a .seq.in file.

Examples:

# Single sequence, 400 conformations with 3D structures
starling MKVIFLAVLGLGIVVTTVLY -c 400 -r --outname my_protein

# From a FASTA file, using GPU
starling proteins.fasta -c 200 -d cuda:0 -r -o ./results

# Print STARLING configuration info
starling --info

Options

FlagTypeDefaultDescription
user_inputpositionalSequence string, FASTA file, TSV file, or .seq.in file
-c, --conformationsint400Number of conformations to generate
--stepsint30Number of DDIM denoising steps
-d, --devicestrautoDevice: cpu, cuda:0, cuda:1, mps, etc.
-b, --batch_sizeint100Batch size for sampling
-o, --output_directorystr.Output directory for saving results
--outnamestrautoOverride output filename prefix (single sequence only)
-r, --return_structuresflagoffGenerate PDB + XTC 3D structures
--ionic_strengthint150Solvent ionic strength in mM (20, 150, or 300)
--num-cpusintautoMax CPUs for MDS reconstruction
--num-mds-initint4Number of parallel MDS initializations
-v, --verboseflagoffEnable verbose output
--disable_progress_barflagoffHide progress bars
--infoflagPrint STARLING configuration and exit
--versionflagPrint version and exit

Output files

FileDescription
*.starlingBinary ensemble archive (distance maps + metadata)
*_STARLING.pdbPDB topology (when -r is used)
*_STARLING.xtcXTC trajectory with all conformations (when -r is used)

starling-benchmark — Performance Benchmarking

Profile model throughput and measure performance across different configurations.

starling-benchmark [options]

Examples:

# Default benchmark sweep (10 to 1000 conformations)
starling-benchmark --device cuda:0

# Single run with 500 conformations and model compilation
starling-benchmark --device cuda:0 --single-run 500 --compile

Options

FlagTypeDefaultDescription
--devicestrautoDevice for benchmarking
--batch-sizeint100Batch size
--stepsint30Diffusion steps
--sequencestralpha-synucleinTest sequence (default: 140 aa)
--cooltimeint20Cooldown seconds between runs
--single-runint0Single test with N conformations (0 = sweep series)
--compileflagoffEnable PyTorch model compilation (CUDA only)

File Conversion Tools

STARLING ships with several converters for working with .starling ensemble archives.

starling2pdb — Convert to PDB

starling2pdb my_ensemble.starling -o ./output

Generates a multi-model PDB trajectory file.

starling2xtc — Convert to XTC

starling2xtc my_ensemble.starling -o ./output

Generates a PDB topology file plus a compressed XTC trajectory file.

starling2numpy — Convert to NumPy

starling2numpy my_ensemble.starling -o ./output

Exports the raw distance maps as a NumPy .npy array with shape (n_conformations, n_residues, n_residues).

starling2sequence — Print sequence

starling2sequence my_ensemble.starling

Prints the amino acid sequence stored in the .starling archive to stdout.

starling2info — Print ensemble metadata

starling2info my_ensemble.starling

Displays metadata about the ensemble, including creation date, sequence, number of conformations, radius of gyration, end-to-end distance, and model weights used.

starling2starling — Repair/validate an archive

# Check for errors
starling2starling my_ensemble.starling --error-check

# Check and remove problematic conformations
starling2starling my_ensemble.starling --error-check --remove-errors -o fixed_

# Overwrite the original file
starling2starling my_ensemble.starling --error-check --remove-errors --overwrite

numpy2starling — Restore from NumPy

numpy2starling distance_maps.npy -s MKVIFLAVLGLGIVVTTVLY -o ./output

Converts a NumPy distance map array and a sequence back into a .starling archive. Supports optional --build-structures to reconstruct 3D coordinates, and -x / -p to attach existing XTC/PDB trajectories.

xtc2starling — Convert XTC trajectory to STARLING

xtc2starling --xtc trajectory.xtc --pdb topology.pdb -o ./output

Converts an existing XTC trajectory and PDB topology into a .starling archive.

Converter summary

CommandInputOutputDescription
starling2pdb.starling.pdbMulti-model PDB trajectory
starling2xtc.starling.pdb + .xtcTopology + compressed trajectory
starling2numpy.starling.npyRaw distance maps as NumPy array
starling2sequence.starlingstdoutPrint amino-acid sequence
starling2info.starlingstdoutPrint metadata (version, date, Rg, etc.)
starling2starling.starling.starlingRe-save with optional error removal
numpy2starling.npy.starlingRestore archive from NumPy
xtc2starling.xtc + .pdb.starlingConvert MD trajectory to STARLING

STARLING includes a FAISS-based similarity search engine that uses ensemble-aware sequence embeddings. It has two subcommands: build and query.

starling-search query — Find similar sequences

Search the pre-built FAISS index for sequences with similar ensemble properties.

starling-search query \
  --seq MDVFMKGLSKAKEGVVAAAEKTKQGVAEAAGKT \
  --k 20 \
  --nprobe 128 \
  --exclude-exact \
  --out search_results
# With filtering by sequence identity and length
starling-search query \
  --seq MKVIFLAVLGLGIVVTTVLY \
  --k 50 \
  --sequence-identity-max 0.9 \
  --length-min 40 \
  --length-max 800 \
  --rerank \
  --out-format csv \
  --out filtered_results

Query options

FlagTypeDefaultDescription
--indexstrdefaultFAISS index path; default auto-downloads the pre-built index
--seqstrQuery sequence(s), can be specified multiple times
--kint10Number of nearest neighbors to return
--nprobeint64FAISS probe count (higher = slower but more accurate)
--metricstrcosineDistance metric: cosine or l2
--exclude-exactflagonSkip exact sequence matches in results
--sequence-identity-maxfloatMaximum sequence identity threshold
--identity-denominatorstrqueryHow to compute identity: query, target, max, min, avg
--length-minintMinimum target sequence length
--length-maxintMaximum target sequence length
--max-cosine-similarityfloatPre-filter upper bound on cosine similarity
--min-l2-distancefloatPre-filter lower bound on L2 distance
--rerankflagonRe-embed top hits with full encoder for more accurate ranking
--rerank-batch-sizeint64Batch size for reranking
--rerank-devicestrautoDevice for reranking
--rerank-ionic-strengthintautoIonic strength for reranking
--devicestrcuda:0Device for query embedding
--batch-sizeint256Batch size for embedding
--ionic-strengthint150Ionic strength in mM for encoding
-o, --outstrnearest_neighborsOutput file basename
--out-formatstrcsvOutput format: csv or jsonl
--verboseflagonVerbose logging

starling-search build — Build a custom FAISS index

Build a FAISS index from pre-tokenized sequences (advanced usage).

starling-search build \
  --root /data/corpus \
  --tokens /data/corpus/tokens \
  --index /indexes/my_index.faiss \
  --sample-size 1000000 \
  --nlist 32768 \
  --use-gpu

Build options

FlagTypeDefaultDescription
--rootstrrequiredRoot data directory
--indexstrrequiredOutput FAISS index path
--tokensstrrequiredDirectory with pre-tokenized sequences
--metricstrcosineDistance metric: cosine or l2
--sample-sizeint655360Training sample size
--nlistint16384FAISS IVF nlist parameter
--mint64HNSW M parameter
--nbitsint8Quantization bits
--add-batch-sizeint100000Batch size for adding vectors
--nprobeint16FAISS probe count
--use-gpuflagonUse GPU for index building
--gpu-deviceint0GPU device ID
--gpu-fp16-lutflagonUse FP16 lookup tables on GPU
--opqflagoffEnable Optimized Product Quantization
--compressflagoffCompress sequences
--shard-regexstrRegex filter for shard files
--verboseflagonVerbose output

starling-pretokenize — Pre-tokenize Sequences

Pre-encode FASTA files for rapid FAISS index construction (used before starling-search build).

starling-pretokenize sequences/*.fasta \
  --output tokens_dir \
  --combined \
  --workers 4

Options

FlagTypeDefaultDescription
fastaspositionalInput FASTA file(s)
-o, --outputstrrequiredOutput directory for token files
--combinedflagoffMerge all into a single .pt file
--prefixstrpretokenizedPrefix for combined output file
--sequencesstrText file with FASTA paths (one per line)
--workersint1Number of parallel tokenizer workers
--no-progressflagoffHide progress bars

Training CLIs (Advanced)

These tools are primarily used for model development and retraining.

CommandDescription
starling-vae-trainTrain the VAE encoder model
starling-ddpm-trainTrain the diffusion model
starling-sampleGenerate samples from the VAE
ae-trainTrain the autoencoder

Python Library

As well as the command-line tools, STARLING provides a powerful Python API for generating and analyzing ensembles programmatically.

Supported input formats

All main API functions accept sequences in multiple formats:

FormatExample
Single sequence string'MKVIFLAVLGLGIVVTTVLY'
List of sequences['MKVIFLA...', 'MDVFMKG...']
Dictionary of name→sequence{'protein_a': 'MKVIFLA...', 'protein_b': 'MDVFMKG...'}
Path to a .fasta file'proteins.fasta'
Path to a .tsv / .seq.in file'sequences.tsv' (tab-separated name\tsequence)

generate() — Generate Ensembles

The generate function is the main entry point for generating conformational ensembles using the STARLING model. It accepts various input types, generates conformations using DDIM/DDPM, and optionally returns 3D structures.

from starling import generate

Basic usage

# Single sequence → single Ensemble object
E = generate('MKVIFLAVLGLGIVVTTVLY', return_single_ensemble=True)

# List of sequences → dict of Ensemble objects
E_dict = generate(['MKVIFLAVLGLGIVVTTVLY', 'MDVFMKGLSKAKEGVVAAAEKTKQGVAE'])

# Dictionary of sequences → dict of Ensemble objects
E_dict = generate({'seq1': 'MKVIFLAVLGLGIVVTTVLY', 'seq2': 'MDVFMKGLSKAKEGVVAAAEKTKQGVAE'})

# From a FASTA file, with 3D structures, saved to disk
E_dict = generate('proteins.fasta', conformations=500, return_structures=True, output_directory='./results')

Parameters

ParameterTypeDefaultDescription
user_inputstr / list / dictInput sequences (see supported formats above)
conformationsint400Number of conformations to generate
ionic_strengthint150Solvent ionic strength in mM (20, 150, or 300)
devicestrNone (auto)Device: 'cpu', 'cuda:0', 'mps', etc.
stepsint30Number of denoising steps
samplerstr'ddim'Sampler backend
return_structuresboolFalseGenerate 3D structures (PDB/XTC)
batch_sizeint100Batch size for sampling
num_cpus_mdsintautoMax CPUs for MDS reconstruction
num_mds_initint4Number of parallel MDS initializations
output_directorystrNoneSave directory (if set, writes .starling files to disk)
output_namestrNoneOverride filename prefix (single-sequence mode)
return_databoolTrueReturn Ensemble objects (set False for fire-and-forget disk saves)
verboseboolFalsePrint status messages
show_progress_barboolTrueShow global progress bar
show_per_step_progress_barboolTrueShow per-step denoising progress bar
pdb_trajectoryboolFalseSave PDB trajectory alongside XTC
return_single_ensembleboolFalseReturn a single Ensemble instead of a dict (single-sequence mode)
constraintConstraintNoneConstraint object for guided generation
encoder_pathstrNoneCustom encoder model checkpoint
ddpm_pathstrNoneCustom diffusion model checkpoint

Returns

  • dict[str, Ensemble] — by default (one entry per input sequence)
  • Ensemble — when return_single_ensemble=True and a single sequence is provided
  • None — when return_data=False

sequence_encoder() — Ensemble-Aware Sequence Embeddings

STARLING jointly trains a transformer-based sequence encoder that produces embeddings optimized for ensemble generation. Sequences with similar ensemble properties tend to have similar embeddings, making them useful for search and design applications.

from starling import sequence_encoder

Basic usage

# Residue-level embeddings (returns dict of name → tensor with shape (L, D))
embeddings = sequence_encoder('proteins.fasta')

# Protein-level embeddings via mean pooling
embeddings = sequence_encoder('proteins.fasta', aggregate=True)

# With custom settings
embeddings = sequence_encoder(
    {'prot_a': 'MKVIFLA...', 'prot_b': 'MDVFMKG...'},
    ionic_strength=150,
    batch_size=64,
    aggregate=True,
    device='cuda:0',
)

Parameters

ParameterTypeDefaultDescription
sequence_dictstr / list / dictInput sequences (same formats as generate())
ionic_strengthint150Ionic strength in mM
batch_sizeint32Sequences per batch
aggregateboolFalseReturn protein-level (mean-pooled) embeddings instead of residue-level
devicestrNone (auto)Target device
output_directorystrNoneOptional directory to save embeddings
encoder_pathstrNoneCustom encoder checkpoint
ddpm_pathstrNoneCustom diffusion model checkpoint
pretokenizedboolFalseSkip tokenization if inputs are already tokenized
bucketboolFalseAdaptive bucketing by sequence length (improves throughput for variable-length inputs)
bucket_sizeint32Max unique lengths per bucket
free_cuda_cacheboolFalseRelease CUDA memory after each batch
return_on_cpuboolTrueMove tensors to CPU before returning

Returns

  • dict[str, torch.Tensor] — keys are sequence names, values are tensors with shape (L, D) (residue-level) or (D,) (aggregated)

load_ensemble() — Load a Saved Ensemble

Reload a previously generated and saved STARLING ensemble from disk.

from starling import load_ensemble

ensemble = load_ensemble('path/to/my_favorite_ensemble.starling')

# Load without 3D structures (faster)
ensemble = load_ensemble('my_ensemble.starling', ignore_structures=True)

Parameters

ParameterTypeDefaultDescription
filenamestrPath to a .starling file
ignore_structuresboolFalseSkip loading 3D structures for faster loading

Returns

  • Ensemble object

set_compilation_options() — PyTorch Model Compilation

If you intend to use STARLING repeatedly (e.g., in loops or batch processing), enable torch.compile to optimize model kernels. This adds overhead during the first call but improves subsequent runs by approximately 40% (tested on NVIDIA A5000).

import starling

# Enable compilation
starling.set_compilation_options(enabled=True)

# Enable with custom options
starling.set_compilation_options(
    enabled=True,
    mode='max-autotune',
    backend='inductor',
    fullgraph=True,
)

Parameters

ParameterTypeDefaultDescription
enabledboolNoneEnable or disable compilation
modestr'default'Compilation mode: 'default', 'reduce-overhead', 'max-autotune'
backendstr'inductor'Compilation backend
fullgraphboolTrueCompile full graph
dynamicboolNoneHandle dynamic shapes

Returns

  • dict with the current compilation settings

Ensemble Class

The Ensemble class represents an ensemble of conformations for a protein chain. It stores distance maps from which all structural parameters can be derived.

Properties

PropertyTypeDescription
.sequencestrAmino acid sequence
.number_of_conformationsintTotal number of conformations
.sequence_lengthintNumber of residues
.has_structuresboolWhether 3D structures are available
.trajectorySSProtein3D trajectory object (lazy-built on first access)

Structural analysis methods

.rij() — Inter-residue distance

Ensemble.rij(i, j, return_mean=False, use_bme_weights=False)

Returns the distance between residues i and j across all conformations, or the mean distance if return_mean=True.

.end_to_end_distance() — End-to-end distance

Ensemble.end_to_end_distance(return_mean=False, use_bme_weights=False)

Returns the end-to-end distance across all conformations, or the mean.

.radius_of_gyration() — Radius of gyration

Ensemble.radius_of_gyration(return_mean=False, force_recompute=False, use_bme_weights=False)

Returns the radius of gyration across all conformations, or the mean.

.hydrodynamic_radius() — Hydrodynamic radius

Ensemble.hydrodynamic_radius(return_mean=False, force_recompute=False, mode='nygaard', alpha1=0.216, alpha2=4.06, alpha3=0.821)

Computes the hydrodynamic radius from the ensemble.

.local_radius_of_gyration() — Local Rg for a sub-region

Ensemble.local_radius_of_gyration(start, end, return_mean=False, use_bme_weights=False)

Returns the radius of gyration for a sub-region defined by residues start to end.

.distance_maps() — Pairwise distance maps

Ensemble.distance_maps(return_mean=False, use_bme_weights=False)

Returns the raw distance maps as (n, L, L) NumPy arrays, or the average distance map if return_mean=True.

.contact_map() — Contact maps

Ensemble.contact_map(contact_thresh=11, return_mean=False, return_summed=False)

Returns binary contact maps using a distance threshold. If return_mean=True, returns the contact probability (0–1) for each residue pair. If return_summed=True, returns summed contacts instead.

3D structure reconstruction

.build_ensemble_trajectory()

Ensemble.build_ensemble_trajectory(
    batch_size=100,
    num_cpus_mds=configs.DEFAULT_CPU_COUNT_MDS,
    num_mds_init=configs.DEFAULT_MDS_NUM_INIT,
    device=None,
    force_recompute=False,
    progress_bar=True,
)

Reconstructs 3D coordinates from distance maps using multidimensional scaling (MDS). Returns an SSProtein trajectory object.

Error checking

.check_for_errors()

Ensemble.check_for_errors(remove_errors=False, verbose=True, rebuild_trajectory=False)

Scans for problematic conformations (e.g., impossible distances). Returns a list of bad frame indices. If remove_errors=True, removes them in place.

Bayesian Maximum Entropy (BME) reweighting

.reweight_bme()

Ensemble.reweight_bme(experimental_data, ensemble_properties, weights=None, verbose=True)

Performs BME reweighting against experimental data. After reweighting, structural property methods accept use_bme_weights=True for reweighted statistics.

File I/O

.save() — Save an ensemble to disk

Ensemble.save(filename_prefix, compress=False, reduce_precision=None, compression_algorithm='lzma', verbose=True)

Saves the ensemble as a .starling archive.

.save_trajectory() — Save 3D trajectory

Ensemble.save_trajectory(filename_prefix, pdb_trajectory=False)

Saves the 3D trajectory as XTC (or PDB if pdb_trajectory=True).


Constrained Generation

STARLING allows you to generate structural ensembles with constraints — such as experimentally measured distances or local/global shape features. These are passed to generate() via the constraint parameter.

Available constraint types

from starling.inference.constraints import (
    DistanceConstraint,
    RgConstraint,
    ReConstraint,
    HelicityConstraint,
    BondConstraint,
    StericClashConstraint,
    MultiConstraint,
)

DistanceConstraint — target distance between two residues

constraint = DistanceConstraint(resid1=10, resid2=200, target=50)

RgConstraint — target radius of gyration

constraint = RgConstraint(target=50)

ReConstraint — target end-to-end distance

constraint = ReConstraint(target=100)

HelicityConstraint — enforce helical structure in a range

constraint = HelicityConstraint(resid_start=10, resid_end=100)

BondConstraint — maintain consecutive residue spacing

constraint = BondConstraint(bond_length=3.81)

StericClashConstraint — prevent steric clashes

constraint = StericClashConstraint(steric_clash_definition=5.0)

MultiConstraint — combine multiple constraints

constraint = MultiConstraint([
    DistanceConstraint(resid1=10, resid2=200, target=50),
    RgConstraint(target=30),
])

Applying constraints

ensemble = generate(sequence, constraint=constraint)

Tuning constraint parameters

All constraints accept the following keyword arguments:

ParameterTypeDefaultDescription
force_constantfloat2.0Strength of the constraint
tolerancefloat0.0Tolerance around the target value
schedulestr'cosine'Weight schedule: 'cosine' or 'bell_shaped'
guidance_startfloat0.0When to start applying the constraint (0.0 = start of denoising)
guidance_endfloat1.0When to stop applying the constraint (1.0 = end of denoising)

Guidance timing reference:

Windowguidance_startguidance_endWhat's being denoised
Early0.00.3Mostly noise, minimal structural information
Mid0.30.7Emerging structure, useful features begin to form
Late0.71.0Fine details, near-final structural refinement

Experimenting with these parameters for your particular application is recommended.


FAQs/Help

I get a NumPy compilation warning error!?

Oh no! You get the following error message:

A module that was compiled using NumPy 1.x cannot be run in
NumPy 2.2.3 as it may crash. To support both 1.x and 2.x
versions of NumPy, modules must be compiled with NumPy 2.0.
Some module may need to rebuild instead e.g. with 'pybind11>=2.12'.

If you are a user of the module, the easiest solution will be to
downgrade to 'numpy<2' or try to upgrade the affected module.
We expect that some modules will need time to support NumPy 2.

We have seen this if folks are trying to install on Intel Macs because (Py)Torch stopped supporting Intel Macs after torch=2.2.2. If you're NOT on an Intel mac, the recommended way to resolve us by upgrading torch:

# recommended, but ANY version above 2.2.2 should work
pip install torch==2.6.0	

or if you're on an Intel mac and torch > 2.2.2 is not available, downgrade numpy:

pip install numpy==1.26.1	

Potential PyTorch / CUDA version issues

If you are on an older version of CUDA, a torch version that does not have the correct CUDA version will be installed. This can cause a segfault when running STARLING. To fix this, you need to install torch for your specific CUDA version. For example, to install PyTorch on Linux using pip with a CUDA version of 12.1, you would run:

pip install torch --index-url https://download.pytorch.org/whl/cu121

To figure out which version of CUDA you currently have (assuming you have a CUDA-enabled GPU that is set up correctly), you need to run:

nvidia-smi

This should return information about your GPU, NVIDIA driver version, and your CUDA version at the top.

Please see the PyTorch install instructions for more info.

Maximum sequence length

STARLING currently supports sequences up to 380 residues in length.


Copyright (c) 2024-2026, Borna Novak, Jeffrey Lotthammer, Alex Holehouse