Inter-chain distance ==================== The ``odist`` tool computes **inter-chain distances** between pairs of atoms, where each atom belongs to a different chain. It is designed for analyzing LLPS condensates, oligomers, and multi-chain systems where the distance between representative atoms on different chains is an important metric. This tool is implemented in ``inter_distance.py``. Overview -------- ``dps odist`` performs: 1. Load a trajectory (TPR + XTC + optional NDX). 2. Select two atom groups: - **reference group** (one atom per chain) - **selection group** (one atom per chain) 3. Split each group into chains (using ``splitch``). 4. Validate that each chain contributes exactly *one* atom. 5. For each frame: - compute distances between all reference–selection atom pairs 6. Reshape into a time × (reference × selection) matrix 7. Optionally remove self-pairs (i = j) 8. Output: - verbose per-pair distances - averaged off-diagonal distances Usage ----- .. code-block:: bash dps odist -s run.tpr -f run.xtc -ref 0 -sel 1 -ov verbose.xvg Arguments --------- Required -------- .. option:: -s, --run-input TPR TPR file containing topology, residue/chain mapping, atom properties. .. option:: -f, --input XTC XTC trajectory used for distance calculations. Optional -------- Index file ~~~~~~~~~~ .. option:: -n, --index NDX Optional NDX file defining custom index groups. Group selection ~~~~~~~~~~~~~~~ Exactly **one atom per chain** must be selected. .. option:: -ref, --reference INT Group index for the **reference atoms** (one per chain). .. option:: -sel, --selection INT Group index for the **selection atoms** (one per chain). If omitted, the program enters interactive selection mode. Time control ~~~~~~~~~~~~ .. option:: -b, --start-time INT .. option:: -e, --end-time INT .. option:: -dt, --delta-time INT Determine which frames to evaluate; converted to indices via ``trajectory.time2frame``. PBC handling ~~~~~~~~~~~~ .. option:: -pbc, --treat-pbc Apply MDAnalysis ``unwrap`` transformation so distances reflect the real molecular coordinates, not wrapped positions. Output ~~~~~~ At least one of: .. option:: -ov, --output-verbose FILE Write **all pairwise distances** for each time point. .. option:: -oa, --output-average FILE Write the **off-diagonal chain-averaged distance** vs time. Program Workflow ---------------- (1) **Load trajectory** .. code-block:: python trajectory = trajectory_class(tpr, ndx, xtc) Errors during loading abort execution. (2) **PBC transform** .. code-block:: python unwrap(trajectory.Universe.atoms) if ``--treat-pbc`` is provided. (3) **Frame indices** .. code-block:: python start, end, step = trajectory.time2frame(b, e, dt) frame_list = range(start, end, step) (4) **Group selection** - If ``--ref`` given: `group ` - Else: interactive selection - Same for ``--sel`` (5) **Chain splitting** .. code-block:: python reference_splitchains = trajectory.index.splitch_indices(reference.indices) selection_splitchains = trajectory.index.splitch_indices(selection.indices) Validation: - each chain must contribute exactly **one atom** - reference and selection must have equal chain counts Errors such as: - *“multiple atoms in single chain for reference group”* - *“Number of atoms in reference and selection groups not match.”* are reported explicitly. (6) **Pair construction** .. code-block:: python pairs = [[a1, a2] for a1 in reference.indices for a2 in selection.indices] (7) **Distance computation** For each frame: .. code-block:: python v = pos1 - pos2 dist = norm(v, axis=1) All distances stored in a matrix: :: distances[time, pair_index] (8) **Matrix reshape** To a 3-D matrix: :: distances_matrix[time, ref_chain, sel_chain] (9) **Off-diagonal mask (i != j)** Diagonal entries (chain self-distance) are zeroed: .. code-block:: python distances_no_diag[:, i, i] = 0 Output Files ------------ Verbose distances ~~~~~~~~~~~~~~~~~ Generated when ``--output-verbose`` is set. - X-axis: time (ns) - Columns: distance of each pair (j,i) - Legends: :: Chain X – Chain Y A legend for every pair i > j. Average distances ~~~~~~~~~~~~~~~~~ Generated when ``--output-average`` is set. The value written is: .. math:: \langle d \rangle (t) = \frac{1}{N^2 - N} \sum_{i \ne j} d_{ij}(t) Output units: **nanometers**. File created using: .. code-block:: python write_xvg(filename, time_list, avg_values) Example ------- Compute all inter-chain distances between group 0 and group 1: .. code-block:: bash dps odist \ -s run.tpr \ -f run.xtc \ -n run.ndx \ -ref 0 -sel 1 \ -ov all_pairs.xvg Compute only the chain-averaged distance: .. code-block:: bash dps odist \ -s run.tpr \ -f run.xtc \ -ref 5 -sel 5 \ -oa avg_distance.xvg \ -pbc Error Messages -------------- **“multiple atoms in single chain for reference group.”** Reference selection must contain exactly 1 atom per chain. **“Number of atoms in reference and selection groups not match.”** Both groups must span the same number of chains. **“Distance will be calculated without periodic boundary conditions.”** Printed when ``--treat-pbc`` is omitted. **“An exception occurred when trying to open trajectory file …”** TPR/XTC path invalid or file corrupted. Summary ------- ``dps odist`` computes detailed inter-chain distance matrices for any atom pairing scheme where each chain contributes one representative atom. It provides: - full pairwise distances - off-diagonal per-time averages - optional PBC handling - flexible interactive selection This tool is highly useful for tracking chain-chain separation, oligomerization, and condensate organization during LLPS simulations.