Source code for packing_defect.run_defect

"""CLI entrypoint for packing-defect analysis.

Provides a convenience builder for a PackingDefectAnalyzer and a
command-line interface that mirrors the common options used in notebooks.

Examples
--------
Run against a topology and trajectory and write outputs to a folder::

    python -m packing_defect.run_defect \
      --top system.gro \
      --traj traj.xtc \
      --out results \
      --leaflet both --start 0 --stop 100 --stride 1

"""

import argparse
import os
import json
import MDAnalysis as mda

from packing_defect.core.classification import DefaultClassification, UserDictClassification
from packing_defect.core.topology import TopologyReader
from packing_defect.core.analyzers.packing import PackingDefectAnalyzer
from packing_defect.run_utils import run_analysis


[docs] def build_packing_analyzer( top_file: str, traj_file: str, out_dir: str, class_json: str | None = None, leaflet: str = "both", start: int | None = None, stop: int | None = None, stride: int = 1, ): """Construct a PackingDefectAnalyzer configured for a typical workflow. Parameters ---------- top_file : str Topology file readable by MDAnalysis (e.g., GRO, PSF, PDB). traj_file : str Trajectory file (e.g., XTC, DCD) aligned with ``top_file``. out_dir : str Directory where results and artifacts will be written. class_json : str, optional Path to a user JSON classification mapping. If omitted, uses ``DefaultClassification``. leaflet : {"both", "up", "dw"}, optional Which leaflet(s) to analyze. start, stop, stride : int, optional Frame slicing parameters (as in ``trajectory[start:stop:stride]``). Returns ------- PackingDefectAnalyzer Configured analyzer instance ready to ``run()``. """ # load radii radii_file = os.path.join(os.path.dirname(__file__), "data", "radii.json") with open(radii_file, encoding="utf-8") as f: types_radii = json.load(f) classifier = ( UserDictClassification.from_json(class_json) if class_json else DefaultClassification() ) topo_reader = TopologyReader(types_radii, classifier.classify) radii = { resname: topo_reader.read(resname, os.path.join(os.path.dirname(__file__), "data", "top", topo)) for resname, topo in { "POPC": "top_all36_lipid.rtf", "DOPE": "top_all36_lipid.rtf", "TRIO": "TRIO.rtf", }.items() } u = mda.Universe(top_file, traj_file) memb = u.select_atoms("resname " + " ".join(radii.keys())) return PackingDefectAnalyzer( universe=u, atomgroups=[memb], radii=radii, output_dir=out_dir, leaflet=leaflet, defect_types=["PLacyl", "TGglyc", "TGacyl"], defect_thresholds={"PLacyl": 1, "TGglyc": 2, "TGacyl": 3}, start=start, stop=stop, stride=stride, )
if __name__ == "__main__": parser = argparse.ArgumentParser( description="Run packing defect analysis (radius stamping + clustering)" ) parser.add_argument("--top", required=True) parser.add_argument("--traj", required=True) parser.add_argument("--out", required=True) parser.add_argument("--class-json", help="Optional classification rules JSON") parser.add_argument("--leaflet", choices=["both", "up", "dw"], default="both") parser.add_argument("--start", type=int, default=None, help="First frame") parser.add_argument("--stop", type=int, default=None, help="Last frame (exclusive)") parser.add_argument("--stride", type=int, default=1, help="Stride between frames") args = parser.parse_args() analyzer = build_packing_analyzer( args.top, args.traj, args.out, args.class_json, args.leaflet, args.start, args.stop, args.stride ) run_analysis(analyzer)