topo.csp package

Submodules

topo.csp.core module

Core nascent-chain MD machinery (topo.csp.core).

This module holds the per-length / per-stage molecular-dynamics building blocks for protein synthesis — the foundation that the higher-level runners build on. It is a library, not a runner: it exposes no CLI and no outer loop.

Its consumers are:

  • topo.csp.protocol — the O’Brien Continuous Synthesis Protocol (CSP), which calls run_length() three times per residue (one per kinetic sub-stage), and

  • the Tutorial-9 cylinder runner (tutorials/09_translation_cylinder/cylinder.py), which reuses these blocks with the ribosome modelled as an analytic cylinder.

(The standalone fixed-rate elongation runner — run_elongation / the topo-elongate CLI — and its Tutorial 7 were removed: a fixed per-residue step count is not a physically meaningful synthesis model. Use CSP (topo-csp) for codon-resolved kinetics.)

The central primitive is run_length(), which builds, seeds, restrains, runs and finalizes one length-``L`` segment of nascent-chain MD:

  1. Build the length-L TOPO model on native residues 1..L (bonds, angles, torsions, Yukawa, contacts), injecting the precomputed L x L contact subset instead of recomputing (buildCoarseGrainModel(precomputed_contacts=...)).

  2. Seed coordinates. L == L0: lay residues 1..L0 extended along the tunnel axis (+x) from the P-anchor, one CG bond length apart. L > L0: residues 1..L-1 from the previous segment’s final structure; the new residue L at the optimal A-site target (one equilibrium peptide bond from residue L-1).

  3. Restrain only residue ``L`` (the current C-terminus) to a chosen anchor with a harmonic CustomExternalForce (k = restraint_k).

  4. Minimize, draw Boltzmann velocities at ref_t, run the requested step count under the per-stage stability guard (see STABILITY_POTE_LIMIT_KJ), write the per-segment outputs, and return the final NASCENT coordinates to seed the next segment.

Contacts are precomputed once on the full native PDB (precompute_contacts()); STRIDE / heavy-atom analysis are never re-run per length. The optional rigid ribosome scenery and tunnel wall are wired up via topo.csp.ribosome. Build / setup / finalize are reused from topo.engine.

class topo.csp.core.NascentDCDReporter(file, reportInterval, nascent_topology, n_keep, append=False)[source]

Bases: object

A DCD reporter that writes only the first n_keep atoms each frame.

Used in build step v2 so the (large, static) ribosome beads are not written to the trajectory every frame – only the nascent chain (indices 0..n_keep-1) is saved. Mirrors openmm.app.DCDReporter but slices the positions and uses a fixed n_keep-atom topology, so the DCD header records n_keep atoms and pairs with the nascent-only PSF.

describeNextReport(simulation)[source]

Tell the simulation when and what this reporter needs next.

Parameters:

simulation (openmm.app.Simulation) – The running simulation (queried for the current step).

Returns:

{'steps', 'periodic', 'include'} – steps until the next report, no PBC, positions only.

Return type:

dict

report(simulation, state)[source]

Write one frame of the first n_keep atoms to the DCD.

Lazily creates the underlying openmm.app.DCDFile on the first call, then writes the sliced (nascent-only) positions.

Parameters:
  • simulation (openmm.app.Simulation) – The running simulation (supplies the integrator / step info).

  • state (openmm.State) – The current state (source of the positions).

Return type:

None

class topo.csp.core.RunParams(n_steps: int = 1000, dt_ps: float = 0.015, ref_t: float = 310.0, tau_t: float = 0.05, nstout: int = 5000, device: str = 'CPU', ppn: int = 1, constraints: object = 'AllBonds', restraint_k: float = 83680.0, nascent_ev_radii: str = 'kb', minimize: bool = True, trna_tether: bool = True, tunnel_wall: bool = True, tunnel_wall_x0_nm: float | None = None, tunnel_wall_k: float = 8368.0, scale_factor: float = 4331293.0, time_stage_1: float = 0.00034, time_stage_2: float = 0.004201, uniform_codon_time: float | None = None, ribosome_traffic: bool = False, initiation_rate: float = 0.083333, random_seed: int | None = None, max_steps_per_stage: int | None = None, min_steps_per_stage: int = 1, ejection_steps: int = 0, dissociation_steps: int = 0)[source]

Bases: object

All run parameters, set once from the CLI/INI — the single CSP + elongation parameter block.

Holds both the MD / ribosome knobs consumed by the per-length helpers (run_length() / build_length_model(): timestep, temperature, rigid ribosome tunnel wall, C-terminus restraint, …) and the O’Brien kinetic knobs consumed by the high-level topo.csp.run_continuous_synthesis() (per-codon timing, stage dwell means, post-synthesis phases). This was formerly split across ElongationParams (MD) and CSPParams (kinetics); the two were merged into this one flat class so there is a single source of truth. The low-level per-length helpers simply ignore the kinetic fields.

constraints: object = 'AllBonds'
device: str = 'CPU'
dissociation_steps: int = 0
dt_ps: float = 0.015
ejection_steps: int = 0
initiation_rate: float = 0.083333
max_steps_per_stage: int | None = None
min_steps_per_stage: int = 1
minimize: bool = True
n_steps: int = 1000
nascent_ev_radii: str = 'kb'
nstout: int = 5000
ppn: int = 1
random_seed: int | None = None
ref_t: float = 310.0
restraint_k: float = 83680.0
ribosome_traffic: bool = False
scale_factor: float = 4331293.0
tau_t: float = 0.05
time_stage_1: float = 0.00034
time_stage_2: float = 0.004201
trna_tether: bool = True
tunnel_wall: bool = True
tunnel_wall_k: float = 8368.0
tunnel_wall_x0_nm: float | None = None
uniform_codon_time: float | None = None
topo.csp.core._dump_topology_psf(cgModel, path: str) None[source]

Write a PSF for the (nascent + ribosome) system via parmed.

The model’s own dumpTopology keys per-atom mass/charge off its nascent-only lists, so it cannot describe the v2 system. parmed reads masses/bonds straight from the OpenMM topology + System instead (charges default to 0 in the PSF – cosmetic; the real electrostatics live in the Yukawa force).

Parameters:
  • cgModel (topo.core.system.system) – The built (nascent + ribosome) model providing .topology and .system.

  • path (str) – Output PSF path.

Return type:

None

topo.csp.core._finalize_nascent(cfg, ctx, nascent_topology, n_keep: int, start_epoch: float) None[source]

Finalize a v2 length writing a nascent-only final structure.

Like topo.engine.finalize_simulation() but the written _final.pdb is only the first n_keep (nascent) atoms – the rigid ribosome is dropped. The saved checkpoint still holds the full system (needed for a correct restart).

Parameters:
  • cfg (topo.SimulationConfig) – The per-length config (supplies output paths and the runinfo path).

  • ctx (topo.engine.SimulationContext) – The active simulation context (simulation, checkpoint, runinfo paths).

  • nascent_topology (openmm.app.Topology) – The n_keep-atom nascent-only topology for the written _final.pdb.

  • n_keep (int) – Number of leading (nascent) atoms to keep in the final structure.

  • start_epoch (float) – Wall-clock start time (time.time()) for the elapsed-time report.

Return type:

None

topo.csp.core._make_cfg(out_dir: Path, sub_pdb: str, seed_pdb: str, params: RunParams) SimulationConfig[source]

Build a per-length SimulationConfig for the engine helpers.

Each length is a self-contained standalone run (its own output folder), so this mirrors a single topo-mdrun invocation: a constant-temperature production run of n_steps at ref_t. The contact matrices are injected at build time (not via this config), so domain_def is left unset here.

Parameters:
  • out_dir (pathlib.Path) – Output directory for this length’s run.

  • sub_pdb (str) – Length-L native CA PDB (the model’s pdb_file).

  • seed_pdb (str or None) – Seed-coordinate PDB fed via init_position (v1); None in v2 where seed coordinates are set directly on built.positions.

  • params (RunParams) – Shared per-length run parameters (steps, dt, temperature, device, …).

Returns:

The configured per-length simulation config.

Return type:

topo.SimulationConfig

topo.csp.core._ptc_bead_index(ribo, segid: str, resid: int, name: str) int[source]

Index of one named ribosome bead in a Ribosome (or raise).

topo.csp.core._vprint(*args, **kwargs) None[source]

print() only when TOPO_CSP_VERBOSE is set (see VERBOSE).

topo.csp.core._write_pdb(topology, positions_nm: ndarray, path: str) None[source]

Write a PDB from a topology and an (N, 3) nm coordinate array.

Parameters:
  • topology (openmm.app.Topology) – The topology describing the atoms to write.

  • positions_nm (numpy.ndarray) – An (N, 3) array of coordinates in nm.

  • path (str) – Output PDB path.

Return type:

None

topo.csp.core.add_cterm_restraint(system: System, particle_index: int, anchor_nm: ndarray, k: float) Force[source]

Add a harmonic restraint pulling one particle toward a fixed anchor.

U = k * ((x-x0)^2 + (y-y0)^2 + (z-z0)^2) via a CustomExternalForce. Only the current C-terminus (particle_index = L-1) is restrained – to the P-anchor – so the tether hand-off between lengths is automatic (each rebuilt step restrains only its own C-terminus). k is the force constant in OpenMM units (kJ/mol/nm^2).

k is a per-particle parameter (not a global) so this force can coexist with other CustomExternalForces that also call their global constant k – e.g. the tunnel wall (topo.csp.ribosome.add_tunnel_wall()). Two forces sharing a global parameter name with different default values is an OpenMM error; per-particle k avoids the clash (this combination – position restraint + tunnel wall in v2 – is what topo.csp uses).

Parameters:
  • system (openmm.System) – The System to add the restraint force to (modified in place).

  • particle_index (int) – Index of the restrained particle (the current C-terminus, L-1).

  • anchor_nm (numpy.ndarray) – The fixed anchor position (x0, y0, z0) in nm (the P-anchor target).

  • k (float) – Harmonic force constant in OpenMM units (kJ/mol/nm^2).

Returns:

The added CustomExternalForce restraint.

Return type:

openmm.Force

topo.csp.core.build_length_model(sub_pdb: str, R_L: ndarray, eps_L: ndarray, constraints='AllBonds', model: str = 'topo', nascent_rmin_2: ndarray | None = None)[source]

Build a length-L TOPO model, injecting the L x L contact subset.

This is the dedicated “build-once-subset” path the design anticipates (DESIGN §3.5 / PROMPT notes): it mirrors topo.models.buildCoarseGrainModel() exactly — reusing the same topo.core.system.system methods for bonds, angles, torsions, Yukawa electrostatics and per-residue mass/charge/radii — but supplies the precomputed contact matrices directly instead of recomputing them (so STRIDE / heavy-atom analysis are not re-run per length). PBC is off and the build-time large-force check is skipped (the simulated coordinates come from the seeding scheme and are minimized explicitly, so the native-structure energy is irrelevant here).

Parameters:
  • sub_pdb (str) – Length-L native CA structure (bonded terms + per-residue properties).

  • R_L (numpy.ndarray) – The L x L contact well-position (nm) and well-depth (kJ/mol) blocks.

  • eps_L (numpy.ndarray) – The L x L contact well-position (nm) and well-depth (kJ/mol) blocks.

  • constraints (str or None) – 'AllBonds' (rigid, default) or None (flexible harmonic bonds) – same semantics as buildCoarseGrainModel().

  • nascent_rmin_2 (numpy.ndarray or None) – Per-residue collision radius Rmin/2 (nm), length L, for the nascent chain – the structure-derived Karanicolas-Brooks values (Option A). Used as the particle excluded-volume radius (particle_rmin_2). This is deliberately not taken from model_parameters (whose fixed per-AA protein Rmin_2 is the rigid ribosome scenery value, not the mobile chain’s). particle_rmin_2 only feeds dumpForceFieldData, so None is harmless (the radius is left unset).

Returns:

The built model (.system, .topology, .positions ready to use).

Return type:

topo.core.system.system

topo.csp.core.cold_start_positions(L0: int, p_anchor: ndarray) ndarray[source]

Extended cold-start layout for the first length L0 (DESIGN §2.5).

Residues 1..L0 are laid along the tunnel axis (+x) from the P-anchor: the C-terminus (residue L0) sits at the P-anchor and the N-terminus (residue 1) points toward the exit (+x), one CG bond length apart. A small alternating transverse zig-zag (COLD_START_ZIGZAG_NM) breaks the exact collinearity that would make the angle force singular. Returns an (L0, 3) array in nm (row i = residue i+1).

topo.csp.core.optimal_ptc_targets(ribo, *, aa_rmin_2_nm: float = 0.5, n_starts: int = 60) Tuple[ndarray, ndarray][source]

Optimal A-site / P-site C-terminus restraint target points (nm).

Returns (a_target, p_target) – two fixed points in space (nm; NOT bonds; the CSP path restrains the C-terminus to a fixed point via add_cterm_restraint()) that sit exactly one peptide bond (_PTC_PEPTIDE_NM = 0.381 nm) apart and clear of the ribosome excluded volume. Seeding the new residue at a_target while the previous residue rests at p_target makes the always-present peptide bond start at its equilibrium length, so a rigid AllBonds constraint seeds/minimizes cleanly at 15 fs and the dt-halving stability guard is not triggered (tutorials/14 step 2).

The points are found (all in OpenMM units: nm, kJ/mol, rad) by minimizing the soft O’Brien restraint energy – the A/P tRNA bonds (_PTC_D_A_NM / _PTC_D_P_NM, harmonic kb = RESTRAINT_K_KJ) and orienting angles/improper (_PTC_ANGLE_K_KJ; continuous_synthesis_v6.py) – plus the ribosome eps*(Rmin/r)^12 excluded volume (eps = RIBO_NC_EPS_KJ, Rmin_ij = (Rmin/2)_AA + (Rmin/2)_bead sum rule), subject to:

  • the peptide bond as the only hard distance constraint (_PTC_PEPTIDE_NM = 0.381 nm – it is topo’s AllBonds constraint length, so it must hold exactly);

  • an exit-side inequality keeping each point at x >= x of its tRNA R bead (between the tRNA and the +x exit port, not buried in the ribosome); and

  • O’Brien’s two excluded-volume exclusions (new AA<->AtR:76@R, prev AA<->PtR:76@R),

over n_starts deterministic full-sphere starts. The tRNA bond lengths are soft (finite-k, as in O’Brien’s model), so |A-RA| / |P-RP| come out near 0.427 / 0.476 nm rather than exactly – and the solve stays feasible even on geometries where those distances cannot be met exactly together with the peptide bond.

Parameters:
  • ribo (Ribosome) – The parsed rigid CG ribosome (supplies the AtR/PtR 76 R/P/BR2 beads, all bead coordinates and the excluded-volume radii).

  • aa_rmin_2_nm (float, optional) – Nascent-bead Rmin/2 (nm) used in the seed excluded-volume term, combined with the ribosome per-bead Rmin/2 by O’Brien’s SUM rule (R = aa_rmin_2_nm + Rmin/2_ribo). Default 0.5 nm – a deliberately conservative CONSTANT, not the simulation’s per-residue value. In the simulation the nascent chain’s non-native Rmin/2 is set by the Karanicolas-Brooks rule from the native structure, so it is structure-dependent: there is no universal per-residue-type radius to look up when seeding a not-yet-placed residue. 0.5 nm exceeds every amino acid’s Rmin/2 (largest is TRP = 0.382 nm), so seeding against this larger radius places the new residue clear of the ribosome wall for every residue – the peptide bond then starts near its equilibrium length and dt-halving blow-ups are avoided. The seed EV is thus a conservative superset of the simulation EV, not identical to it.

  • n_starts (int, optional) – Number of deterministic multistart initial orientations (default 60).

Returns:

a_target and p_target, each a (3,) coordinate in nm.

Return type:

(numpy.ndarray, numpy.ndarray)

topo.csp.core.precompute_contacts(full_pdb: str, domain_def: str | None = None, stride_output_file: str | None = None) Tuple[ndarray, ndarray, ndarray][source]

Run TOPO’s contact builder once on the full native PDB (DESIGN §3.5).

Returns (R_full, eps_full, rmin_2_full) – the N_full x N_full well-position (nm) and well-depth (kJ/mol) matrices, plus the per-residue Karanicolas-Brooks collision radius Rmin/2 (nm, shape (N_full,)) that O’Brien uses as the nascent excluded-volume radius (the structure-derived A_i values). STRIDE is run at most once here (and cached by build_nonbonded_interaction()); each length later reuses the top-left L x L block (and rmin_2_full[:L]), so neither STRIDE nor the heavy-atom analysis is ever re-run per length.

topo.csp.core.read_anchor(pdb_file: str, segid: str, resid: int = 76, bead: str = 'R') ndarray[source]

Return the coordinate (nm) of one ribosome bead, e.g. a tRNA anchor.

Parses the (CG) ribosome PDB for the single atom whose segID (columns 73-76), residue number and atom name match segid / resid / bead. Used to pick the P-anchor (segid='PtR') and A-anchor (segid='AtR') from the truncated ribosome (both keep residue 76 — the truncation retains the tRNA acceptor ends). PDB coordinates are in angstrom; the returned vector is in nm.

Raises:

ValueError – If no matching atom (or more than one) is found.

topo.csp.core.run_length(L: int, *, full_pdb: str, R_full: ndarray, eps_full: ndarray, p_anchor: ndarray, a_anchor: ndarray, prev_final: ndarray | None, out_root: Path, params: RunParams, ribo: Ribosome | None = None, seed_override: ndarray | None = None, restrain: bool = True, out_subdir: str | None = None, n_steps_override: int | None = None, seed_point: ndarray | None = None, tether_segid: str = 'PtR', tether_prev_segid: str | None = None, nascent_rmin_2: ndarray | None = None, minimize_override: bool | None = None, label: str | None = None) ndarray[source]

Build, seed, (restrain,) minimize and run one length-L system.

Used both for an elongation step and for the post-synthesis phase (§post- synthesis below). When ribo is given (build step v2), the rigid ribosome is appended as fixed (mass-0) scenery with the ribosome<->nascent cross-interactions (topo.csp.ribosome.append_ribosome()).

Parameters that tailor the standard elongation step into the post-synthesis phase:

  • seed_override : use these (L, 3) nm nascent coordinates directly (no cold-start / new-residue placement) – e.g. the fully-synthesized structure for an ejection / stall run.

  • restrain : if False, do not add the C-terminus restraint (ejection = the tether is released and the chain is free to move).

  • out_subdir : output folder name under out_root (default L_<L>); e.g. ejection / stall.

  • n_steps_override : run this many steps instead of params.n_steps.

  • label : short stage tag (e.g. "stage 1 peptidyl-transfer") shown in the concise per-stage summary line and, under TOPO_CSP_VERBOSE, in the verbose console banner.

Returns the final nascent (L, 3) nm coordinate array.

topo.csp.core.seed_positions(prev_final: ndarray, seed_point: ndarray) ndarray[source]

Seed length L from the previous final structure + the new residue.

Residues 1..L-1 keep their coordinates from step L-1’s final structure (prev_final, shape (L-1, 3) nm). The new C-terminal residue L is placed at seed_point – the equilibrium-bond A-site target from optimal_ptc_targets() – so the always-present peptide bond L-1<->L starts at its equilibrium length and a rigid AllBonds build seeds/minimizes cleanly. Returns an (L, 3) array in nm.

topo.csp.core.write_subset_structure(full_pdb: str, L: int, out_pdb: str) None[source]

Write a CA-only PDB of the first L residues of full_pdb.

This length-L native structure supplies the bonded terms and per-residue mass/charge/radii for the length-L build; its coordinates set the native contact distances and CG bond lengths only (the simulated coordinates come from the seeding scheme, not from here). Residues are taken in file order so particle i (0..L-1) corresponds to native residue i+1, matching the L x L contact subset.

Parameters:
  • full_pdb (str) – Full native PDB of the target protein.

  • L (int) – Number of N-terminal residues to keep (the current nascent length).

  • out_pdb (str) – Path of the CA-only length-L PDB to write.

Return type:

None

Raises:

ValueError – If full_pdb has fewer than L CA atoms.

topo.csp.cylinder module

Protein synthesis through an analytic exit tunnel (topo.csp.cylinder).

A parallel of topo.csp.protocol for the cylinder ribosome model. Instead of explicit rigid CG ribosome beads, the ribosome is a pure boundary condition – an analytic exit tunnel (a bore of radius r in an otherwise-infinite wall, add_tunnel_cylinder()). There are no ribosome beads, no tRNA tether, and no A/P translocation, so each residue is a single MD segment (not the three sub-stages of the explicit protocol).

Timing is the same O’Brien kinetics as topo.csp.protocol: each residue’s MD length comes from its codon mean-first-passage time (topo.csp.kinetics), mapped to integration steps by the scale_factor / dt compression – replacing any fixed per-residue step count. The C-terminus is held on the tunnel axis at the PTC by a harmonic position restraint; the bore keeps the in-tunnel segment extended and lets the finished chain leave only through the exit.

Reused wholesale from topo.csp.core: the per-length MD machinery (build_length_model, build-once-subset contacts, coordinate seeding, minimize / run / finalize) and RunParams. New here: the analytic tunnel force, the tunnel geometry (CylinderParams), and the single-segment kinetic driver.

Drive it with an INI control file (see read_cylinder_config()):

topo-cylinder -f cylinder.ini
python -m topo.csp.cylinder -f cylinder.ini

Units: OpenMM defaults – length nm, time ps, energy kJ/mol, temperature K, force constants kJ/mol/nm^2. In-vivo dwell times in the kinetics are seconds.

class topo.csp.cylinder.CylinderConfig(pdb_file: str, L0: int, L_max: int | None = None, outdir: str = 'synth_out', mrna: str | None = None, codon_time_table_path: str | None = None, domain_def: str | None = None, stride_output_file: str | None = None, params: CylinderParams | None = None, config_file: str | None = None)[source]

Bases: object

Parsed contents of a cylinder synthesis control file (cylinder.ini).

L0: int
L_max: int | None = None
codon_time_table_path: str | None = None
config_file: str | None = None
domain_def: str | None = None
mrna: str | None = None
outdir: str = 'synth_out'
params: CylinderParams = None
pdb_file: str
stride_output_file: str | None = None
class topo.csp.cylinder.CylinderParams(n_steps: int = 1000, dt_ps: float = 0.015, ref_t: float = 310.0, tau_t: float = 0.05, nstout: int = 5000, device: str = 'CPU', ppn: int = 1, constraints: object = 'AllBonds', restraint_k: float = 83680.0, nascent_ev_radii: str = 'kb', minimize: bool = True, trna_tether: bool = True, tunnel_wall: bool = True, tunnel_wall_x0_nm: float | None = None, tunnel_wall_k: float = 8368.0, scale_factor: float = 4331293.0, time_stage_1: float = 0.00034, time_stage_2: float = 0.004201, uniform_codon_time: float | None = None, ribosome_traffic: bool = False, initiation_rate: float = 0.083333, random_seed: int | None = None, max_steps_per_stage: int | None = None, min_steps_per_stage: int = 1, ejection_steps: int = 0, dissociation_steps: int = 0, tunnel_radius_nm: float = 0.9, tunnel_length_nm: float = 10.0, tunnel_x_lo_nm: float = 0.0, tunnel_center_nm: Tuple[float, float] = (0.0, 0.0), tunnel_k: float = 8368.0, tunnel_mouth_round_nm: float = 0.2)[source]

Bases: RunParams

RunParams (MD + O’Brien kinetics) + the tunnel geometry.

Subclasses topo.csp.core.RunParams, so every MD knob (timestep, temperature, restraint constant, output, …) and every kinetic field (scale_factor, time_stage_1/time_stage_2, uniform_codon_time, max_steps_per_stage, …) is inherited unchanged; only the analytic-tunnel geometry fields are new.

tunnel_center_nm: Tuple[float, float] = (0.0, 0.0)
tunnel_k: float = 8368.0
tunnel_length_nm: float = 10.0
tunnel_mouth_round_nm: float = 0.2
tunnel_radius_nm: float = 0.9
tunnel_x_lo_nm: float = 0.0
topo.csp.cylinder.add_tunnel_cylinder(system, nascent_indices, r_nm: float, x_lo_nm: float, x_exit_nm: float, k: float = 8368.0, y0_nm: float = 0.0, z0_nm: float = 0.0, mouth_round_nm: float = 0.2) Force[source]

Add the analytic exit-tunnel restraint (a hole in an infinite wall).

One CustomExternalForce over every nascent bead penalising the penetration depth into the solid ribosome S – everything outside the bore up to the exit face, plus the closed PTC end:

S = { x < x_exit AND d > r } cup { x < x_lo },   d = |(y,z) - (y0,z0)|

The bead escapes S via whichever face is nearer – the bore wall (d - r, a radial inward push that keeps the in-tunnel chain extended) or the exit face (x_exit - x, a +x push so a cytosol bead can only re-enter through the bore, never off-axis). The 90 deg inner corner at the mouth (x_exit, r) is rounded by a fillet of radius rho so the potential is continuous (-> stable MD):

U   = k * max(0, pen)^2 + k * min(0, x - x_lo)^2
pen = (rounded) min( x_exit - x , d - r )      # 0 outside S; > 0 inside S

Returns the added CustomExternalForce (already in system).

topo.csp.cylinder.cylinder(argv: List[str] | None = None) None[source]

Console entry point: topo-cylinder -f cylinder.ini.

topo.csp.cylinder.read_cylinder_config(config_file: str, verbose: bool = True) CylinderConfig[source]

Parse a cylinder synthesis control file (INI) into a CylinderConfig.

Single [OPTIONS] section. Required: pdb_file, L0, domain_def, and – unless codon_times is a positive number (uniform timing) – mrna. No ribosome PDB (the tunnel geometry comes from the params, not a structure). Recognised keys (optional ones fall back to defaults):

  • pdb_file – full native PDB of the target protein (the nascent chain).

  • L0 / L_max – start / final nascent length (blank L_max -> full).

  • outdir – root output directory (per-length subfolders L_<L>/).

  • domain_def – domain YAML for contact nscale (one-time precompute).

  • stride_output_file – precomputed STRIDE (else STRIDE runs once if on PATH).

  • Kinetics (same as CSP): mrna (per-codon sequence, or fastest/slowest/median to auto-build a synonymous-codon mRNA), codon_times (a codon table path for per-codon timing – required, no bundled default; pick one under assets/csp/codon_dwell_times/ – or a positive number of seconds for a uniform codon time), scale_factor, time_stage_1, time_stage_2, random_seed, max_steps_per_stage, min_steps_per_stage.

  • Integrator / MD: dt, ref_t, tau_t, nstout, device, ppn, minimize (yes/no), constraints (‘None’ flexible / ‘AllBonds’ rigid), restraint_k (C-terminus position-restraint constant, kJ/mol/nm^2).

  • Tunnel geometry: tunnel_radius (nm), tunnel_length (nm), tunnel_x_lo (nm), tunnel_center ("y0,z0" nm), tunnel_k (kJ/mol/nm^2), tunnel_mouth_round (nm).

  • Post-synthesis (same keys as CSP): ejection_steps and dissociation_steps – two sequential free runs at full length (each releases the C-terminus restraint so the finished protein diffuses out the exit and folds in the cytosol; 0 = skip that phase).

Inline #/; comments are ignored. Units: OpenMM defaults.

topo.csp.cylinder.run_cylinder_synthesis(full_pdb: str, *, L0: int = 1, L_max: int | None = None, out_root: str = 'synth_out', mrna: str | None = None, codon_time_table_path: str | None = None, domain_def: str | None = None, stride_output_file: str | None = None, params: CylinderParams | None = None) None[source]

Synthesize L = L0 .. L_max through the analytic tunnel, one segment per residue.

Mirrors topo.csp.protocol.run_continuous_synthesis(), but with the cylinder confinement and a single MD segment per residue (no A/P sub-stages). Each residue’s segment length is its codon dwell time mapped to integration steps – the same O’Brien kinetics (topo.csp.kinetics) the explicit protocol uses, just not split three ways. Writes per-length trajectories under out_root/L_<L>/ and a per-residue dwell_times.dat table.

Parameters:
  • full_pdb (str) – Full native PDB of the target protein (the nascent chain at full length).

  • L0 (int) – First / final nascent length (L_max=None -> the full residue count).

  • L_max (int) – First / final nascent length (L_max=None -> the full residue count).

  • out_root (str) – Root output directory; each length writes to <out_root>/L_<L>/.

  • mrna (str, optional) – mRNA sequence file (one codon per residue) for the codon-resolved kinetics. Required for per-codon timing (i.e. unless params.uniform_codon_time is set).

  • codon_time_table_path (str) – Per-codon mean-time table (required for per-codon timing; pick one under assets/csp/codon_dwell_times/). There is no bundled default.

  • domain_def (str, optional) – Passed to the one-time contact precompute (nscale / STRIDE).

  • stride_output_file (str, optional) – Passed to the one-time contact precompute (nscale / STRIDE).

  • params (CylinderParams, optional) – Per-length run parameters + tunnel geometry (defaults to the dataclass defaults).

Raises:

ValueError – If the length schedule is invalid (1 <= L0 <= L_max <= N_full fails), or if non-uniform kinetics are requested without mrna (propagated from topo.csp.kinetics.build_codon_time_lists()).

topo.csp.cylinder.run_length(L: int, *, full_pdb: str, R_full: ndarray, eps_full: ndarray, prev_final: ndarray | None, out_root: Path, params: CylinderParams, cterm_seed: ndarray, x_lo: float, x_exit: float, seed_override: ndarray | None = None, restrain: bool = True, out_subdir: str | None = None, n_steps_override: int | None = None, label: str | None = None) ndarray[source]

Build, seed, (restrain,) minimize and run one length-L nascent System.

The System is the nascent chain only (no ribosome beads); the analytic tunnel (add_tunnel_cylinder()) supplies all ribosome confinement. Injects the L x L build-once-subset contact block exactly as the shipped runner does.

The same routine drives both an elongation step and the post-synthesis phases (ejection / dissociation); these arguments tailor it to the latter:

  • seed_override : use these (L, 3) nm coordinates directly (the fully synthesized structure) instead of cold-start / new-residue placement.

  • restrain : if False, drop the C-terminus restraint (ejection/dissociation – the finished protein is released and free to diffuse out the exit).

  • out_subdir : output folder under out_root (default L_<L>); e.g. ejection / dissociation.

  • n_steps_override : run this many steps instead of params.n_steps (the kinetic driver passes the per-residue codon-dwell step count here).

  • label : console-banner text.

Returns the final nascent (L, 3) nm coordinate array (seeds length L+1).

topo.csp.kinetics module

O’Brien continuous-synthesis kinetics: codon timing and the 3-stage schedule.

This is the timing core of the O’Brien Continuous Synthesis Protocol (continuous_synthesis_v6.py), ported to topo as pure, side-effect-free helpers (no OpenMM here – just the maths). It answers one question for every residue: how many integration steps does each of the three elongation sub-stages run for?

The pieces (all of them straight out of v6):

  1. Per-codon translation times. The mRNA is split into codons; a codon-time table maps each codon to its mean in-vivo translation time (seconds). That gives a per-residue intrinsic mean first-passage time list (codon_time_list()).

  2. The 3-stage split. For residue L the total dwell time is partitioned into peptidyl transfer (stage 1), translocation (stage 2) and tRNA binding/waiting (stage 3 = remainder). Each stage’s dwell is drawn from an exponential distribution about its mean (sample_fpt(), stage_dwell_times()) – O’Brien’s first-passage-time sampling.

  3. Time -> steps. A dwell time in seconds is mapped to in-silico nanoseconds via scale_factor and then to integration steps via the time step (seconds_to_steps()): steps = t_s * 1e9 / scale_factor / dt_ns.

(An optional per-codon ribosome-traffic correction exists in the code but is off by default and deferred – not exposed in the docs or example configs; see review/TODO.md (§B). With it off, real == intrinsic and stage 2’s mean is exactly time_stage_2.)

Indexing convention (mirrors v6 exactly): the codon/mFPT lists are 0-indexed, mfpt[i] = time of the i-th codon (the codon that makes residue i+1… see stage_dwell_times() for how the 1-indexed nascent length L reads mfpt[L] / mfpt[L-1]). The mRNA carries N+1 codons (one per residue plus a stop), so mfpt[L] is always in range for L = 1..N.

Units: times are seconds (in-vivo) until seconds_to_steps(); the time step is picoseconds; scale_factor is dimensionless.

topo.csp.kinetics.build_codon_time_lists(n_codons_needed: int, *, uniform_codon_time: float | None, mrna_path: str | None, codon_time_table_path: str | None, ribosome_traffic: bool, initiation_rate: float, verbose: bool = True) Tuple[List[float], List[float], List[str] | None][source]

Assemble the (intrinsic, real, codons) lists for a run.

  • uniform_codon_time set (uniform timing): every codon gets that mean time (no mRNA needed); real == intrinsic and codons is None.

  • uniform_codon_time is None (per-codon timing): read the mRNA + codon_time_table_path, build the intrinsic per-codon list; if ribosome_traffic and the external binary is available, replace real with its traffic-corrected output, else real == intrinsic. Per-codon timing requires both the (protein-specific) mrna and an explicit codon_time_table_path – there is no bundled default table (choose one under assets/csp/codon_dwell_times/).

n_codons_needed is the minimum list length required (L_max + 1 so that intrinsic[L_max] is valid).

Parameters:
  • n_codons_needed (int) – Minimum required list length (use L_max + 1).

  • uniform_codon_time (float or None) – If a float, uniform timing – ignore the mRNA and give every codon that mean time (seconds). If None, per-codon timing from the mRNA + table.

  • mrna_path (str or None) – Path to the mRNA file (required for per-codon timing).

  • codon_time_table_path (str or None) – Path to the codon-time table (required for per-codon timing; there is no bundled default).

  • ribosome_traffic (bool) – If True, attempt the external ribosome_traffic correction for real (falls back to real == intrinsic if the binary is unavailable).

  • initiation_rate (float) – Translation-initiation rate (1/s), passed to the traffic binary.

  • verbose (bool, optional) – Forwarded to ribosome_traffic_times() for its diagnostic messages.

Returns:

(intrinsic, real, codons) – the intrinsic and (traffic-corrected) real per-codon mFPT lists (seconds), and the codon list (or None in the uniform-timing mode).

Return type:

tuple

Raises:

ValueError – If per-codon timing is requested without mrna_path or without codon_time_table_path, or if the mRNA / traffic output has fewer than n_codons_needed entries.

topo.csp.kinetics.codon_time_list(codons: Sequence[str], codon_time_table: Dict[str, float]) List[float][source]

Map a codon list to a 0-indexed list of per-codon mean times (seconds).

time[i] = codon_time_table[codons[i]] – i.e. the per-codon intrinsic mean translation time (the intrinsic mean first-passage time; no ribosome-traffic correction). Raises if a codon is missing from the table, so an incomplete table is caught early rather than silently mis-timing a residue.

Parameters:
  • codons (sequence of str) – Codons (upper-case RNA), e.g. the output of read_mrna().

  • codon_time_table (dict of {str: float}) – Codon -> mean translation time (seconds), e.g. from read_codon_time_table().

Returns:

The intrinsic mean per-codon time (seconds) for each codon, in the same order as codons.

Return type:

list of float

Raises:

KeyError – If any codon in codons is absent from codon_time_table.

topo.csp.kinetics.parse_codon_times(value: str | None) Tuple[float | None, str | None][source]

Resolve the codon_times config value into a timing mode.

codon_times overloads a single INI key onto the two timing modes:

  • a positive number of seconds (e.g. 0.05) -> uniform timing: every codon gets that mean dwell (no mRNA needed);

  • anything else -> a path to a per-codon time table, so timing is per-codon from the mRNA;

  • None (key absent/blank) -> unset: neither timing mode is chosen. There is no bundled default table, so per-codon timing then requires an explicit table path (see build_codon_time_lists(), which raises otherwise).

A codon-time table filename must therefore not be a bare number – a value that parses as a float is always taken as a uniform time in seconds, never a filename. (Give the table a name like trans_times.txt or ./12345.txt.)

Parameters:

value (str or None) – The raw codon_times value from the INI (already stripped, or None).

Returns:

(uniform_codon_time, table_path) – exactly one is non-None in the two “set” cases: a float (uniform mean codon time, seconds) with table_path None, or a path with uniform_codon_time None. A blank/absent value returns (None, None) (neither mode chosen). Ready to fill RunParams.uniform_codon_time and the codon_time_table_path path.

Return type:

tuple

Raises:

ValueError – If value is numeric but not a positive, finite time in seconds.

topo.csp.kinetics.read_codon_time_table(path: str) Dict[str, float][source]

Read a per-codon mean-translation-time table into {codon: seconds}.

Format (the codon-time table file, e.g. the Fluitt E. coli trans_times.txt): one codon per line, CODON<whitespace>TIME – the codon is RNA (U not T), the time is the mean in-vivo translation time in seconds (e.g. UUU  0.068164). Blank lines and # comments are ignored. Codons are upper-cased and T is normalised to U so a DNA-style table still works.

Parameters:

path (str) – Path to the codon-time table file (e.g. trans_times.txt).

Returns:

dict of {str – Mapping codon -> mean in-vivo translation time (seconds). Keys are upper-case RNA codons (T normalised to U).

Return type:

float}

Raises:

ValueError – If a non-comment line cannot be parsed as CODON TIME, or if the file contains no codon/time rows at all.

topo.csp.kinetics.read_mrna(path: str, stop_at_stop: bool = True) List[str][source]

Read an mRNA sequence file and split it into a list of 3-nt codons.

The file is raw nucleotides (A/U/G/C; T normalised to U), optionally wrapped across several lines (whitespace is stripped and concatenated). The sequence length must be a multiple of 3. If stop_at_stop the list is truncated at (and including) the first stop codon – matching v6, which expects len(codons) == n_residues + 1 (one codon per residue plus the terminator).

Parameters:
  • path (str) – Path to the mRNA sequence file (raw nucleotides, blank/# lines ignored).

  • stop_at_stop (bool, optional) – If True (default), truncate the codon list at and including the first stop codon (UAA/UAG/UGA). If False, return every codon in the file.

Returns:

Codons in 5’->3’ order, each a 3-character upper-case RNA string.

Return type:

list of str

Raises:

ValueError – If the concatenated sequence length is not a multiple of 3.

topo.csp.kinetics.ribosome_traffic_times(mrna_path: str, codon_time_table_path: str, initiation_rate: float, binary: str = 'ribosome_traffic', verbose: bool = True) List[float] | None[source]

Return per-codon real mFPTs from O’Brien’s ribosome_traffic binary.

The binary models upstream-queue (traffic) effects: given the mRNA, the intrinsic per-codon times and the initiation rate it prints one traffic-corrected mean first-passage time per codon. We capture that into a list. If the binary is not on ``PATH`` (or fails to run) this returns ``None`` (the caller then falls back to real == intrinsic – no traffic), so the port stays runnable without the compiled helper. This mirrors v6’s ribosome_traffic <mrna> <codon_time_table_path> <initiation_rate> call.

Parameters:
  • mrna_path (str) – Path to the mRNA sequence file (passed through to the binary).

  • codon_time_table_path (str) – Path to the codon-time table (passed through to the binary).

  • initiation_rate (float) – Translation-initiation rate (1/s) – sets how densely ribosomes load.

  • binary (str, optional) – Name (or path) of the external executable to call (default "ribosome_traffic"); resolved on PATH via shutil.which().

  • verbose (bool, optional) – If True (default), print a message when the binary is missing/fails or produces no numeric output.

Returns:

One traffic-corrected mean first-passage time (seconds) per codon, or None if the binary is unavailable, errors out, or yields no numbers (signalling the caller to use real == intrinsic).

Return type:

list of float or None

topo.csp.kinetics.sample_fpt(mean_s: float, rng: Random) float[source]

Draw one first-passage time (seconds) from an exponential of mean mean_s.

This is v6’s sample_fpt_dist (random.expovariate(1/mean)). A single rate-limiting molecular event has an exponentially distributed waiting time, so each sub-stage dwell is sampled this way. A non-positive mean would be ill-defined, so it is floored to 1e-12 s first.

Parameters:
  • mean_s (float) – Mean of the exponential distribution (seconds); floored to 1e-12 if non-positive.

  • rng (random.Random) – Random generator to draw from (seed it for reproducible schedules).

Returns:

A single exponentially distributed dwell time (seconds).

Return type:

float

topo.csp.kinetics.seconds_to_steps(t_s: float, scale_factor: float, dt_ps: float) int[source]

Map an in-vivo dwell time (s) to a number of integration steps.

O’Brien’s two-step conversion: t_sim_ns = t_s * 1e9 / scale_factor (the scale_factor compresses real time into the in-silico timescale), then steps = t_sim_ns / dt_ns with dt_ns = dt_ps * 1e-3. Truncated to an int (like v6’s int(...)). A larger scale_factor therefore yields fewer steps (a faster run) for the same physical dwell time.

Parameters:
  • t_s (float) – In-vivo dwell time to convert (seconds).

  • scale_factor (float) – In-vivo-seconds -> in-silico-nanoseconds compression factor (dimensionless).

  • dt_ps (float) – Integration timestep (picoseconds).

Returns:

Number of integration steps (truncated toward zero); may be 0 for very short dwell times before any min/max clamp is applied.

Return type:

int

topo.csp.kinetics.stage_dwell_times(L: int, intrinsic: Sequence[float], real: Sequence[float], time_stage_1: float, time_stage_2: float, rng: Random) Tuple[float, float, float][source]

Sample the three sub-stage dwell times (seconds) for nascent length L.

Reproduces the stage-time logic of continuous_synthesis_v6.py (lines 69-86). L is the 1-indexed nascent chain length; intrinsic / real are 0-indexed per-codon mFPT lists (see module docstring). The three means are:

  • stage 1 (peptidyl transfer): time_stage_1 – a fixed mean.

  • stage 2 (translocation): time_stage_2 plus the ribosome-traffic correction real[L-1] - intrinsic[L-1] if that is positive (else just time_stage_2 – v6’s guard against a negative correction from sampling noise).

  • stage 3 (tRNA binding / waiting): the remainder intrinsic[L] - time_stage_1 - time_stage_2 – floored to a tiny positive value if a fast codon makes it non-positive.

Each mean is then passed through sample_fpt() (exponential sampling).

Parameters:
  • L (int) – 1-indexed nascent-chain length being synthesized.

  • intrinsic (sequence of float) – 0-indexed per-codon intrinsic mFPTs (seconds); intrinsic[L] (the next codon) sets the stage-3 total. Must have length >= L + 1.

  • real (sequence of float) – 0-indexed per-codon mFPTs with the ribosome-traffic correction (equals intrinsic when traffic is off). Used only via real[L-1].

  • time_stage_1 (float) – Fixed mean peptidyl-transfer dwell (seconds).

  • time_stage_2 (float) – Fixed mean translocation dwell (seconds), before any traffic correction.

  • rng (random.Random) – Random generator for the exponential sampling.

Returns:

The three sampled dwell times (t1, t2, t3) in seconds, for the peptidyl-transfer, translocation and tRNA-binding sub-stages respectively.

Return type:

tuple of (float, float, float)

topo.csp.kinetics.stage_steps(L: int, intrinsic: Sequence[float], real: Sequence[float], *, time_stage_1: float, time_stage_2: float, scale_factor: float, dt_ps: float, rng: Random, max_steps_per_stage: int | None = None, min_steps_per_stage: int = 1) Tuple[Tuple[int, int, int], Tuple[float, float, float]][source]

Full per-residue schedule: sampled dwell times and clamped step counts.

Combines stage_dwell_times() + seconds_to_steps() and applies the test clamps. max_steps_per_stage caps each stage (the tutorial uses a small cap so a residue runs ~2000 steps total instead of the production ~10^5-10^6); min_steps_per_stage floors it so every stage does at least a little MD. None cap = uncapped (production). The clamp limits MD steps only, never the sampled dwell times in seconds (which are returned unclamped for logging).

Parameters:
  • L (int) – 1-indexed nascent-chain length being synthesized.

  • intrinsic (sequence of float) – 0-indexed per-codon mFPT lists (intrinsic and traffic-corrected); see stage_dwell_times().

  • real (sequence of float) – 0-indexed per-codon mFPT lists (intrinsic and traffic-corrected); see stage_dwell_times().

  • time_stage_1 (float) – Fixed mean peptidyl-transfer / translocation dwell times (seconds).

  • time_stage_2 (float) – Fixed mean peptidyl-transfer / translocation dwell times (seconds).

  • scale_factor (float) – In-vivo-seconds -> in-silico-nanoseconds compression factor.

  • dt_ps (float) – Integration timestep (picoseconds).

  • rng (random.Random) – Random generator for the exponential dwell-time sampling.

  • max_steps_per_stage (int or None, optional) – Upper clamp on each stage’s step count (None = uncapped / production).

  • min_steps_per_stage (int, optional) – Lower clamp on each stage’s step count (default 1).

Returns:

((s1, s2, s3), (t1, t2, t3)) – the clamped integer step counts and the (unclamped) sampled dwell times in seconds they were derived from.

Return type:

tuple

topo.csp.kinetics.uniform_codon_time_list(n: int, uniform_codon_time: float) List[float][source]

A constant mean-first-passage-time list of length n (uniform timing).

Every codon gets the same mean translation time uniform_codon_time (seconds); used for uniform timing (codon_times set to a number).

Parameters:
  • n (int) – Length of the list to build (number of codons needed).

  • uniform_codon_time (float) – The single mean translation time (seconds) assigned to every codon.

Returns:

A list of n identical values, all equal to uniform_codon_time.

Return type:

list of float

Raises:

ValueError – If uniform_codon_time <= 0.

topo.csp.movie module

Stitch nascent-chain synthesis trajectories into one VMD-playable movie.

A synthesis run writes a separate trajectory per growth step, and each step has a different number of beads (length L has L CA atoms), so a single VMD molecule (which needs a constant atom count) cannot just concatenate them. This module pads every frame up to the final length – parking the not-yet-synthesized beads at a far sentinel coordinate – and writes the segments back-to-back into one fixed-width movie plus a ready-to-run movie.tcl that hides the parked beads, so the chain appears to grow N->C.

It handles two output layouts with a shared stitching core (stitch_segments()):

  • CSP (per-stage)<out>/L_<L>/stage_<1,2,3>/ from the Continuous Synthesis Protocol (topo.csp.protocol), plus ejection/ / dissociation/. Use stitch_movie() / find_stage_segments(). The movie plays the chain growing stage by stage (new residue at the A-site, settle, translocate to P).

  • Flat (per-length)<out>/L_<L>/traj.dcd from a fixed-rate per-length loop (e.g. the Tutorial-9 cylinder runner), plus ejection/ / dissociation/. Use stitch_length_movie() / find_lengths().

The main() CLI (topo-csp-movie) auto-detects the layout (per-stage if any L_<L>/stage_<s>/ folders exist, else per-length).

Usage:

topo-csp-movie -o synth_out --ribosome ribosome_trunc.pdb
python -m topo.csp.movie -o synth_out
vmd -e synth_out/movie.tcl
topo.csp.movie._is_csp_layout(out_root: str) bool[source]

Return True if out_root has the CSP per-stage layout.

Parameters:

out_root (str) – Output root to inspect.

Returns:

True if any <out_root>/L_<L>/stage_<s>/ folder exists (CSP), else False (treat as the flat per-length layout).

Return type:

bool

topo.csp.movie._pick_traj(phase_dir: str, outname: str = 'traj') str | None[source]

Pick the trajectory file to read for one stage/phase, or None if absent.

Prefer <outname>.dcd when it actually holds frames, but a coarse nstout (relative to the steps run per stage) can leave a stage’s DCD empty (0 bytes) – every frame interval landed past the end of the short run. In that case fall back to <outname>_final.pdb, the last-frame snapshot the runner always writes, so the stage still contributes its (single) final conformation instead of being silently dropped. Without this, a coarse-output CSP run yields a movie that skips most lengths.

Parameters:
  • phase_dir (str) – Directory of a single stage or post-synthesis phase (e.g. <out_root>/L_<L>/stage_<s> or <out_root>/ejection).

  • outname (str, optional) – Per-stage output basename used by the runner (default "traj"); the candidate files are <outname>.dcd and <outname>_final.pdb.

Returns:

Path to <outname>.dcd if it exists and is non-empty, else <outname>_final.pdb if present, else the empty <outname>.dcd if it exists, else None when no trajectory file is found.

Return type:

str or None

topo.csp.movie._write_tcl(path: str, psf_name: str, dcd_name: str, park: str, ribosome_name: str | None = None) None[source]

Write a VMD script that loads the movie and grows the chain N->C.

Parameters:
  • path (str) – Destination path for the generated .tcl script.

  • psf_name (str) – Basename of the movie topology file the script should load.

  • dcd_name (str) – Basename of the movie trajectory file the script should load.

  • park ({'sentinel', 'cterm'}) – Parking scheme used when stitching; sentinel adds a per-frame selection that hides the far-parked future beads, cterm shows all beads (no hiding needed).

  • ribosome_name (str, optional) – Basename of a static ribosome PDB to load as a separate scenery molecule; None to omit the ribosome block.

Return type:

None

topo.csp.movie.find_lengths(out_root: str, outname: str = 'traj') List[Tuple[int, str, str]][source]

Return [(L, psf, dcd), ...] for each <out_root>/L_<L>/ length.

Scans <out_root> for L_<L>/ length folders, sorted by L; only lengths with both a .psf and a .dcd are kept. This is the flat per-length layout (one trajectory per length, e.g. the Tutorial-9 cylinder runner), in contrast to the CSP per-stage layout (find_stage_segments()).

Parameters:
  • out_root (str) – The run’s output root (contains the L_<L>/ folders).

  • outname (str) – Per-length output basename used by the runner (default traj); the files looked for are <outname>.psf and <outname>.dcd.

Returns:

One (L, psf, dcd) per length found, sorted by ascending L; psf and dcd are the paths to that length’s topology and trajectory.

Return type:

list of tuple of (int, str, str)

topo.csp.movie.find_post(out_root: str, outname: str = 'traj') List[Tuple[str, str, str]][source]

Return [(name, psf, dcd), ...] for present post-synthesis phases (flat).

Looks for <out_root>/ejection/ and <out_root>/dissociation/ (in that order) – the optional post-synthesis runs written after the chain reaches its final length in the flat per-length layout. Only phases with both a .psf and a .dcd are returned.

Parameters:
  • out_root (str) – The run’s output root (may contain the ejection/ and/or dissociation/ folders).

  • outname (str) – Per-length output basename used by the runner (default traj); the files looked for are <outname>.psf and <outname>.dcd.

Returns:

One (name, psf, dcd) per present post-synthesis phase, in POST_PHASES_FLAT order.

Return type:

list of tuple of (str, str, str)

topo.csp.movie.find_stage_segments(out_root: str, outname: str = 'traj') List[Tuple[str, int, str, str]][source]

Return ordered [(label, n_atoms, psf, traj), ...] for a CSP run.

Walks <out_root>/L_<L>/stage_<1,2,3>/ in increasing L then stage order (only stages with a .psf and a readable trajectory are kept), then appends any ejection/ / dissociation/ phase. n_atoms is L for a stage of length L (the nascent-only output) and the post-phase psf’s atom count for the post phases. The trajectory is the stage’s .dcd when it has frames, else its _final.pdb snapshot (see _pick_traj()).

Parameters:
  • out_root (str) – CSP run output root, containing the L_<L>/ length folders and any ejection/ / dissociation/ post-synthesis phases.

  • outname (str, optional) – Per-stage output basename used by the runner (default "traj"); the per-stage psf is <outname>.psf and the trajectory is chosen by _pick_traj().

Returns:

Segments in synthesis order, each (label, n_atoms, psf, traj): label is "L=<L> s<s>" for a stage or the phase name for a post phase; n_atoms is the nascent bead count (L for a stage, the psf’s atom count for a post phase); psf and traj are the topology and trajectory paths. Stages or phases lacking a .psf or a readable trajectory are skipped.

Return type:

list of tuple of (str, int, str, str)

topo.csp.movie.main(argv: List[str] | None = None) None[source]

Command-line entry point for topo-csp-movie / python -m topo.csp.movie.

Parses arguments and stitches the synthesis trajectories under --out-root into one VMD-playable movie, auto-detecting the layout: the per-stage CSP layout (stitch_movie()) if any L_<L>/stage_<s>/ folders are present, otherwise the flat per-length layout (stitch_length_movie()). The parser exposes -o/--out-root (required), --prefix, --park (sentinel/cterm), --outname and --ribosome. With no arguments it prints help and exits 0.

Parameters:

argv (list of str or None, optional) – Argument vector to parse. If None (default), arguments are taken from sys.argv.

Return type:

None

topo.csp.movie.stitch_length_movie(out_root: str, out_prefix: str = 'movie', park: str = 'sentinel', outname: str = 'traj', ribosome_pdb: str | None = None, verbose: bool = True) Tuple[str, str, str][source]

Discover the flat per-length segments and stitch them into a movie.

The flat-layout counterpart of stitch_movie(): enumerates <out_root>/L_<L>/ per-length trajectories (find_lengths()), appends any ejection/ / dissociation/ phase (find_post()), and hands them to the shared stitch_segments() core. Used by the Tutorial-9 cylinder runner.

Parameters:
  • out_root (str) – The run’s output root (contains the L_<L>/ folders).

  • out_prefix (str) – Basename for the movie files (default movie).

  • park ({'sentinel', 'cterm'}) – Where to put not-yet-synthesized beads in each frame (passed through to the stitching core).

  • outname (str) – Per-length output basename used by the runner (default traj).

  • ribosome_pdb (str, optional) – Optional CG ribosome PDB to load as static scenery in the generated .tcl (default None).

  • verbose (bool) – When true, let the stitching core report progress.

Returns:

The (psf_path, dcd_path, tcl_path) of the written movie files.

Return type:

tuple of (str, str, str)

Raises:

SystemExit – If no per-length trajectories are found under out_root.

topo.csp.movie.stitch_movie(out_root: str, out_prefix: str = 'movie', park: str = 'sentinel', outname: str = 'traj', ribosome_pdb: str | None = None, verbose: bool = True) Tuple[str, str, str][source]

Discover the CSP per-stage segments and stitch them into a movie.

Thin CSP-aware wrapper around stitch_segments() (the shared core). Calls find_stage_segments() to enumerate the per-stage and post-synthesis segments, then hands them to the shared padding/stitching core, which writes <out_prefix>.psf / <out_prefix>.dcd / <out_prefix>.tcl.

Parameters:
  • out_root (str) – CSP run output root (contains the L_<L>/stage_<s>/ folders).

  • out_prefix (str, optional) – Basename for the stitched movie files (default "movie").

  • park (str, optional) – Where to put not-yet-synthesized beads in each frame (default "sentinel"); passed through to the stitching core.

  • outname (str, optional) – Per-stage output basename used by the runner (default "traj").

  • ribosome_pdb (str or None, optional) – Optional coarse-grained ribosome PDB to load as static scenery in the generated <out_prefix>.tcl (default None).

  • verbose (bool, optional) – If True (default), print the number of discovered segments and let the stitching core report progress.

Returns:

Paths to the written psf, dcd and tcl movie files, as returned by stitch_segments().

Return type:

tuple of (str, str, str)

Raises:

SystemExit – If no per-stage trajectories are found under out_root.

topo.csp.movie.stitch_segments(out_root: str, segments: List[Tuple[str, int, str, str]], out_prefix: str = 'movie', park: str = 'sentinel', ribosome_pdb: str | None = None, verbose: bool = True) Tuple[str, str, str][source]

Pad and concatenate an ordered list of trajectory segments into a movie.

The reusable core shared by the per-stage CSP movie (stitch_movie()) and the per-length flat movie (stitch_length_movie()). segments is an ordered list of (label, n_atoms, psf, dcd) – each a standalone trajectory with n_atoms beads; every frame is padded up to the widest segment (N = max n_atoms) by parking the extra (not-yet-synthesized) beads, and the segments are written back-to-back in the given order. Also writes a ready-to-run <out_prefix>.tcl.

Parameters:
  • out_root (str) – Directory the stitched movie files are written into.

  • segments (list of tuple of (str, int, str, str)) – Ordered playback segments, each (label, n_atoms, psf, dcd): a human label, the segment’s bead count, and its topology and trajectory paths.

  • out_prefix (str) – Basename for the movie files (default movie).

  • park ({'sentinel', 'cterm'}) – Where to put not-yet-synthesized beads in each frame. sentinel (far away, hidden by the VMD script – cleanest) or cterm (stacked on the C-terminus – no VMD selection needed, but leaves a small bead cluster at the growing tip).

  • ribosome_pdb (str, optional) – Path to a static CG ribosome PDB to copy next to the movie and load as fixed scenery in the generated .tcl; None to skip.

  • verbose (bool) – When true, print progress messages while stitching.

Returns:

The (psf_path, dcd_path, tcl_path) of the written movie files.

Return type:

tuple of (str, str, str)

Raises:
  • ValueError – If park is not 'sentinel' or 'cterm'.

  • SystemExit – If segments is empty.

topo.csp.protocol module

Continuous Synthesis Protocol (O’Brien), ported to topo (topo.csp).

This is the full O’Brien continuous-synthesis protocol – the per-codon, 3-stage elongation cycle of continuous_synthesis_v6.py – expressed in topo style. It is the kinetic upgrade of topo.csp.core: that driver grows the chain one residue per step at a fixed n_steps (collapsing the elongation cycle into a single MD segment); this driver times every residue from its codon and splits it into three sub-stages, exactly as O’Brien do.

What is reused vs. new:

  • Reused wholesale from topo.csp.core: the per-length MD machinery – run_length() (build-once-subset contacts, coordinate seeding, rigid-ribosome scenery, tunnel wall, minimize/run/finalize), read_anchor(), precompute_contacts(), and RunParams for all the MD/ribosome knobs. Nothing about the force field or the OpenMM plumbing is re-implemented here.

  • New (this module): the O’Brien kinetics (topo.csp.kinetics) and the outer loop that calls run_length() three times per residue, switching the C-terminus restraint target A->P to reproduce translocation.

The 3-stage mapping onto run_length() (L = nascent length):

stage

biology

restraint target / seed

1

peptidyl transfer / A-site delivery

A-anchor; new residue placed

2

translocation begins

A-anchor; continue stage 1

3

translocation to P-site / wait

P-anchor; continue stage 2

Stage 3’s final structure seeds the next residue’s stage 1. The cold-start segment (L == L0) is laid down the tunnel from the P-anchor (no A-site delivery yet). Because CSP needs the restraint target to switch A<->P, it drives the position restraint path (trna_tether is forced off); the supplied ribosome is always rigid scenery and the tunnel wall + excluded volume + electrostatics are on.

Drive it with an INI control file (see read_csp_config()):

topo-csp -f csp.ini
python -m topo.csp -f csp.ini

Units: OpenMM defaults – length nm, time ps, energy kJ/mol, temperature K, force constants kJ/mol/nm^2. In-vivo dwell times in the kinetics are seconds.

class topo.csp.protocol.CSPConfig(pdb_file: str, ribosome: str, L0: int = 1, L_max: int | None = None, outdir: str = 'synth_out', mrna: str | None = None, codon_time_table_path: str | None = None, domain_def: str | None = None, stride_output_file: str | None = None, params: ~topo.csp.core.RunParams = <factory>, config_file: str | None = None)[source]

Bases: object

Parsed contents of a CSP control file (csp.ini).

Bundles the run inputs (structures, the L0..L_max schedule, output directory, one-time-precompute options) with the kinetic + MD RunParams. Produced by read_csp_config() and consumed by csp() / passed straight to run_continuous_synthesis().

Variables:
  • pdb_file (str) – Full native PDB of the target protein (the nascent chain at full length).

  • ribosome (str) – Truncated CG ribosome PDB (P-/A-anchors; always rigid scenery).

  • L0 (int) – Starting nascent-chain length (default 1).

  • L_max (int or None) – Final length (None -> the full residue count).

  • outdir (str) – Root output directory (default "synth_out").

  • codon_time_table_path (mrna,) – mRNA sequence file and per-codon time table (required for per-codon timing, i.e. unless params.uniform_codon_time is set).

  • domain_def (str) – Domain-definition file (contact-nscale scaling); required via the INI.

  • stride_output_file (str or None) – Precomputed STRIDE file for the one-time contact build (optional).

  • params (RunParams) – The kinetic + MD/ribosome run parameters.

  • config_file (str or None) – Path of the INI file this config was parsed from (provenance).

L0: int = 1
L_max: int | None = None
codon_time_table_path: str | None = None
config_file: str | None = None
domain_def: str | None = None
mrna: str | None = None
outdir: str = 'synth_out'
params: RunParams
pdb_file: str
ribosome: str
stride_output_file: str | None = None
topo.csp.protocol.csp(argv: List[str] | None = None) None[source]

Console entry point: topo-csp -f csp.ini.

The O’Brien continuous synthesis protocol (per-codon, 3-stage elongation), driven by an INI control file (see read_csp_config()). -o / --device override the output directory / compute device for sweeps.

Parameters:

argv (list of str or None, optional) – Command-line arguments to parse (default None -> use sys.argv). A bare invocation (no args) prints help and exits.

Returns:

Runs the synthesis for its side effects (see run_continuous_synthesis()).

Return type:

None

topo.csp.protocol.read_csp_config(config_file: str, verbose: bool = True) CSPConfig[source]

Parse a CSP control file (INI [OPTIONS]) into a CSPConfig.

The structure / MD / ribosome keys configure the shared topo.csp.core.RunParams machinery; the O’Brien kinetic keys are added on top. Required: pdb_file, ribosome, domain_def (the protein’s domain/contact-nscale definition). L0 (default 1) and L_max (default = full residue count) are optional. Per-codon timing additionally requires mrna (codon_times is optional).

Kinetic keys

  • mrna – mRNA sequence file (raw nucleotides, wrapped ok); one codon per residue + 1 stop. Required for per-codon timing (it is protein-specific). May also be the keyword fastest / slowest / median to auto-build a synonymous-codon mRNA (each residue’s fastest/slowest/median-dwell-time codon per the codon_times table, written next to the PDB); a real filename must not be fastest/slowest/median.

  • codon_times – the codon-timing key. Either a path to a per-codon mean-time table (CODON  seconds; per-codon timing) or a positive number of seconds (uniform codon time for every codon, no mrna needed). Required for per-codon timing – there is no bundled default (pick a table under assets/csp/codon_dwell_times/). A table filename must not be a bare number. See topo.csp.kinetics.parse_codon_times().

  • scale_factor – in-vivo seconds -> in-silico ns compressor.

  • time_stage_1 / time_stage_2 – mean peptidyl-transfer / translocation dwell (s); stage 3 = codon total minus these.

  • random_seed – seed for the FPT sampler (reproducible schedules).

  • max_steps_per_stage – cap each stage’s step count (the tutorial uses a small value for a ~2000-steps/residue test; blank = uncapped production).

  • min_steps_per_stage – floor each stage’s step count (default 1).

  • ejection_steps / dissociation_steps – post-synthesis free runs (0 = skip).

MD / ribosome keys: dt, ref_t, tau_t, nstout, device, ppn, constraints (default AllBonds), restraint_k, minimize, tunnel_wall. (The supplied ribosome is always rigid scenery – there is no rigid_ribosome key – and output is always nascent-only, so there is no nascent_only_output key either. The wall plane tunnel_wall_x0 and stiffness tunnel_wall_k are not keys – the plane is auto-derived from the ribosome structure at run time and the stiffness is a fixed model constant.)

param config_file:

Path to the INI control file (must contain an [OPTIONS] section).

type config_file:

str

param verbose:

If True (default), echo the parsed configuration to stdout.

type verbose:

bool, optional

returns:

The parsed configuration (inputs, schedule and a populated RunParams), ready to pass to run_continuous_synthesis().

rtype:

CSPConfig

raises FileNotFoundError:

If config_file cannot be read.

raises ValueError:

If the [OPTIONS] section is missing, a required key (pdb_file, ribosome, domain_def) is absent/blank, or per-codon timing is requested without mrna.

topo.csp.protocol.run_continuous_synthesis(full_pdb: str, ribosome_pdb: str, *, L0: int = 1, L_max: int | None = None, out_root: str = 'synth_out', mrna: str | None = None, codon_time_table_path: str | None = None, domain_def: str | None = None, stride_output_file: str | None = None, params: RunParams | None = None) None[source]

Run the full O’Brien continuous synthesis L = L0 .. L_max.

Parameters:
  • full_pdb (str) – Full native PDB of the target protein (the nascent chain at full length).

  • ribosome_pdb (str) – Truncated CG ribosome PDB – source of the P-/A-anchors and the rigid (mass-0) scenery (always loaded; providing it is the signal to use it).

  • L0 (int, optional) – First nascent length to synthesize (default 1 – start from a single residue).

  • L_max (int or None, optional) – Final nascent length (default None -> the full residue count of the protein).

  • out_root (str) – Root output directory; each residue writes L_<L>/stage_<1,2,3>/.

  • mrna (str, optional) – mRNA sequence file (one codon per residue) – the codon-resolved kinetics. Required for per-codon timing; not needed for uniform timing (params.uniform_codon_time set).

  • codon_time_table_path (str) – Per-codon mean-time table (required for per-codon timing; pick one under assets/csp/codon_dwell_times/). There is no bundled default.

  • domain_def (str) – Domain-definition file (domain.yaml) defining the protein’s native-contact nscales – per-domain and per-interface Gō well-depth scaling factors (the structure-based analog of O’Brien’s nscal). Required via the INI.

  • stride_output_file (str, optional) – Precomputed STRIDE file for the contact build (skips re-running STRIDE).

  • params (RunParams, optional) – Run parameters (defaults to the dataclass defaults).

Returns:

Side-effecting: writes per-residue/-stage trajectories under out_root/L_<L>/stage_<1,2,3>/, a per-residue dwell_times.dat table, and (if requested) ejection/ and dissociation/ phases.

Return type:

None

Raises:

ValueError – If the length schedule is invalid (1 <= L0 <= L_max <= N_full fails), or if non-uniform kinetics are requested without mrna / codon_time_table_path (propagated from topo.csp.kinetics.build_codon_time_lists()).

topo.csp.ribosome module

Rigid ribosome scenery + cross-interactions for elongation build step v2.

Build step v1 (topo.csp.core) simulates the nascent chain only and uses the truncated ribosome merely as two fixed anchor coordinates. Build step v2 adds the truncated ribosome to the System as rigid (mass-0) scenery and wires the two ribosome <-> nascent-chain interactions, following the RNC design (see topo/csp/README.md and docs/usage/continuous_synthesis.md):

  1. Append the ribosome beads at indices L..N-1 with mass = 0 (frozen; not integrated), coordinates as-is. The P-/A-anchors are now real beads.

  2. Contact force (the nascent L×L native/non-native table): give the ribosome beads a dummy in-range id = 0 addParticle entry (never read) and restrict the force to the interaction group {nascent}×{nascent} – so the table stays L×L and ribosome beads are never evaluated by it.

  3. Ribosome-NC excluded volume: a separate CustomNonbondedForce reproducing O’Brien’s NC<->ribosome interaction – the 12-10-6 form ε[13(R/r)¹² 18(R/r)¹⁰ + 4(R/r)⁶] (ε = 0.000132 kcal/mol) with the sum combination rule R_ij = Rmin/2_i + Rmin/2_j (O’Brien’s convention; nascent Rmin/2 = per-residue K-B (Option A) or per-AA OBRIEN_SC_RMIN_2_NM, ribosome Rmin/2 from model_parameters via load_ribosome), cutoff 2.0 nm / switch 1.8 nm, interaction group {nascent}×{ribosome}. (Earlier topo used a pure ε(σ/r)¹² + average rule that was ~1000× too soft – see tutorials/15_claude_fix/TOPO_OBrien_NCribosome_nonbonded_compare.md.)

  4. Electrostatics: extend the existing Yukawa force with the ribosome charges (rRNA phosphates −1e, charged residues ±1e) and restrict it to {nascent}×{nascent} + {nascent}×{ribosome} (the rigid ribosome’s intra-interactions are constant and never computed – DESIGN §2.2).

The ribosome is held rigid, so no intra-ribosome forces are ever computed. Because the nascent chain uses flexible bonds (no constraints) and the ribosome has none, no distance constraint ever involves a mass-0 particle, so the mass-0 freezing needs no special constraint handling.

class topo.csp.ribosome.Ribosome(coords_nm: ndarray, Rmin_2_nm: List[float], charges: List[float], names: List[str], resnames: List[str], resids: List[int], segids: List[str])[source]

Bases: object

Parsed rigid CG ribosome: per-bead coordinates (nm) and force parameters.

Rmin_2_nm: List[float]
charges: List[float]
coords_nm: ndarray
property n: int

Number of ribosome beads.

Returns:

The bead count, taken as the length of Rmin_2_nm.

Return type:

int

names: List[str]
resids: List[int]
resnames: List[str]
segids: List[str]
topo.csp.ribosome._append_topology(topology, ribo: Ribosome) None[source]

Append the ribosome beads to an OpenMM topology (one chain per segID).

Beads are grouped into one chain per segment id and one residue per (segID, resid) pair, then each bead is added as a carbon atom under its residue. Mutates topology in place.

Parameters:
  • topology (openmm.app.Topology) – The topology to extend with the ribosome chains, residues, and atoms.

  • ribo (Ribosome) – The parsed ribosome supplying segment ids, residue ids/names, and atom names for each bead.

Return type:

None

topo.csp.ribosome._bead_type(name: str, resname: str) str[source]

Parameter-lookup key for a CG bead.

Protein Cα beads (atom name CA) look up by residue name; RNA beads look up by atom name with trailing digits stripped (P, R, BR1/BR2BR).

Parameters:
  • name (str) – The PDB atom name of the bead (e.g. "CA", "P", "BR1").

  • resname (str) – The PDB residue name of the bead (used for protein Cα beads).

Returns:

The key into model_parameters for this bead: resname for Cα beads, otherwise name with trailing digits stripped.

Return type:

str

topo.csp.ribosome.add_trna_tether(nascent_model, cterm_index: int, prev_index, ribo: Ribosome, L_nascent: int, segid: str = 'PtR', resid: int = 76) None[source]

Tether a nascent residue to a tRNA, the full O’Brien orienting way.

Reproduces the aminoacyl-/peptidyl-tRNA linkage of continuous_synthesis_v6.py (A_site_tRNA_binding / translocation_AtR) for the resting geometry of the given site (segid: "AtR" A-site / "PtR" P-site). For the restrained residue N (= cterm_index):

  • bond N -- tRNA:R (length/k from _TRNA_SITE_GEOM / TRNA_TETHER_BOND_K);

  • orienting angles N -- R -- P and N -- R -- PU2 (harmonic, TRNA_TETHER_ANGLE_K) – fix the residue’s bearing in the tRNA frame;

  • improper N -- R -- P -- PU2 (periodic-harmonic on |θ−θ0|, TRNA_TETHER_IMPROPER_K) – fixes the out-of-plane sense;

  • backbone orienting angle prev -- N -- R (double-Gaussian backbone form) – aims the chain down the tunnel toward the exit.

Together (vs. the single bond + 1 angle of the old version) these reproduce O’Brien’s full orientation control: the chain extrudes N-first down the tunnel rather than balling up at the PTC. The peptide bond N-1<->N is left in place (topo keeps the always-bonded chain – a deliberate deviation, DIFFERENCES.md).

prev_index is the CA(N-1) particle index, or None (skips the backbone angle). P (O’Brien R-1) and PU2 (O’Brien R+2) are resolved by topo bead name ("P" / "BR2"); a site missing either bead skips that angle/improper.

Parameters:
  • nascent_model (object) – The built nascent model whose .system receives the tether forces and whose .gaussianAngleForce receives the backbone orienting angle.

  • cterm_index (int) – System index of the restrained nascent CA(N) bead.

  • prev_index (int or None) – System index of CA(N-1), or None (skips the backbone angle).

  • ribo (Ribosome) – The parsed ribosome (supplies the tRNA R/P/BR2 beads).

  • L_nascent (int) – Number of nascent particles preceding the ribosome beads (index offset).

  • segid (str, optional) – tRNA segment id: "AtR" (A-site) or "PtR" (P-site, default).

  • resid (int, optional) – tRNA acceptor residue id. Default is 76.

Return type:

None

Raises:

ValueError – If segid is not a known tRNA site, or its R bead is not found.

topo.csp.ribosome.add_tunnel_wall(system, nascent_indices, x0_nm: float, k: float = 8368.0) Force[source]

Add O’Brien’s one-sided planar tunnel wall on the nascent chain.

U = k * min(x - x0, 0)^2 per nascent bead – penalizes x < x0 only, so the chain is kept at x >= x0 and can only extrude forward (+x). x0_nm is the plane position (nm; the C-terminal-AA addition plane / PTC) and k is the force constant in OpenMM units (kJ/mol/nm^2).

Parameters:
  • system (openmm.System) – The system to which the planar-wall force is added.

  • nascent_indices (iterable of int) – System indices of the nascent-chain beads subjected to the wall.

  • x0_nm (float) – Plane position (nm); beads are penalized only for x < x0. Always supplied by the CSP runner from the PTC-optimized A/P targets (structure-dependent); there is no default.

  • k (float, optional) – Force constant (kJ/mol/nm^2) of the one-sided restraint. Default is TUNNEL_WALL_K.

Returns:

The created CustomExternalForce (already added to system).

Return type:

openmm.Force

topo.csp.ribosome.anchor_coord(ribo: Ribosome, segid: str, resid: int = 76, bead: str = 'R') ndarray[source]

Coordinate (nm) of a named ribosome bead from a loaded Ribosome.

The Ribosome-object analog of topo.csp.core.read_anchor() (which parses a PDB): used to pick the P-/A-anchors (segid='PtR'/'AtR', resid 76, R bead) directly from the loaded Ribosome arrays. Raises if the bead is absent or non-unique.

topo.csp.ribosome.append_ribosome(nascent_model, ribo: Ribosome, nascent_rmin_2: ndarray | None = None) Tuple[List[int], List[int]][source]

Append the rigid ribosome to a built nascent model (system + topology).

Mutates nascent_model in place (its .system and .topology): appends mass-0 (fixed) ribosome particles; extends the contact and Yukawa forces with ribosome entries and restricts their interaction groups; adds the O’Brien-consistent ribosome-NC excluded-volume force (the 12-10-6 form U = eps[13(R/r)¹² - 18(R/r)¹⁰ + 4(R/r)⁶] with the sum combination rule R = rm_i + rm_j, acting on {nascent}×{ribosome} only); and extends the topology with one ribosome chain per segID.

Must be called after topo.csp.core.build_length_model() (the nascent forces must already exist).

Parameters:
  • nascent_model – The built nascent model whose .system and .topology are mutated.

  • ribo (Ribosome) – The parsed rigid ribosome (coords, per-bead Rmin/2, charges, topology).

  • nascent_rmin_2 (np.ndarray, optional) – Per-nascent-bead Rmin/2 (nm) for the NC-ribosome excluded volume. When given (length must equal the nascent atom count), these are O’Brien’s structure-derived per-residue Karanicolas-Brooks collision radii (“Option A”). When None, falls back to per-AA sidechain radii OBRIEN_SC_RMIN_2_NM (“Option B”).

Returns:

(nascent_indices, ribosome_indices)

Return type:

Tuple[List[int], List[int]]

topo.csp.ribosome.bead_system_index(ribo: Ribosome, L_nascent: int, segid: str, resid: int, bead: str = 'R') int | None[source]

System index of a named ribosome bead (e.g. the P-site tRNA R anchor).

Ribosome beads are appended after the L_nascent nascent particles in load order, so the system index is L_nascent + (position in the Ribosome arrays). Returns None if no such bead exists (e.g. a pyrimidine has no BR2).

topo.csp.ribosome.load_ribosome(pdb_file: str, model: str = 'topo') Ribosome[source]

Parse a (truncated) CG ribosome PDB into a Ribosome.

Reads each ATOM/HETATM record, derives its bead type (_bead_type()), and looks up its collision radius Rmin/2 and charge from model_parameters[model] – the fixed per-type scenery table: RNA beads (P/R/BR) by O’Brien’s per-type Rmin/2, protein Cα beads by O’Brien’s per-AA sidechain Rmin/2 (his ribosome S<aa> values; the one structure-based Go protein L24 is treated the same per-AA way – his per-residue B-type values are not reproduced). Coordinates are converted from angstrom to nm. This reproduces O’Brien’s ribosome excluded volume from topo’s own CG PDB – no .cor/.psf/.prm needed. The mobile nascent chain uses its own per-residue K-B Rmin/2 (Option A), never this table (see model_parameters).

Parameters:
  • pdb_file (str) – Path to the (truncated) coarse-grained ribosome PDB file.

  • model (str, optional) – Key selecting the parameter set in model_parameters used for radii and charge lookups. Default is "topo".

Returns:

The parsed ribosome with per-bead coordinates (nm), radii, charges, atom names, residue names, residue ids, and segment ids.

Return type:

Ribosome

Raises:

ValueError – If a parsed bead type is missing from model_parameters[model], or if no ATOM/HETATM records are found in the file.

Module contents

topo.csp – the O’Brien Continuous Synthesis Protocol, ported to topo.

The per-codon, three-stage protein synthesis protocol of continuous_synthesis_v6.py (Yang Jiang, Dan Nissley, Ed O’Brien), expressed in topo style. It is the kinetic upgrade of topo.csp.core: it times every residue from its codon and splits each into peptidyl-transfer / translocation / tRNA-binding sub-stages, reusing the translation module’s per-length MD machinery.

CLI:

topo-csp -f csp.ini
python -m topo.csp -f csp.ini

See topo.csp.protocol (explicit-ribosome runner + INI), topo.csp.cylinder (the analytic-tunnel cylinder runner – a parallel model that reuses the same kinetics), and topo.csp.kinetics (timing core).