Metadata-Version: 2.4
Name: pharmacon
Version: 1.0.1
Summary: Pharmacon: A Molecular Dynamics Analysis Suite.
Author: Kyriakos Georgiou
License-Expression: GPL-3.0-only
Project-URL: Homepage, https://github.com/k-georgiou/pharmacon
Project-URL: Documentation, https://pharmacon.readthedocs.io/
Project-URL: Repository, https://github.com/k-georgiou/pharmacon
Project-URL: Issues, https://github.com/k-georgiou/pharmacon/issues
Keywords: molecular-dynamics,simulation,analysis,chemistry,hdf5,mdanalysis
Classifier: Development Status :: 5 - Production/Stable
Classifier: Environment :: Console
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Chemistry
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Classifier: Operating System :: OS Independent
Classifier: Intended Audience :: Science/Research
Classifier: Typing :: Typed
Requires-Python: >=3.12
Description-Content-Type: text/markdown
License-File: LICENSE.txt
License-File: NOTICE
Requires-Dist: MDAnalysis>=2.7
Requires-Dist: configobj>=5.0
Requires-Dist: h5py>=3.10
Requires-Dist: matplotlib>=3.8
Requires-Dist: networkx>=3.2
Requires-Dist: numpy>=1.26
Requires-Dist: periodictable>=1.7
Requires-Dist: psutil>=5.9
Requires-Dist: pyarrow>=14.0
Requires-Dist: pyfiglet>=1.0
Requires-Dist: pyjokes>=0.7
Requires-Dist: rdkit>=2024.03.1
Requires-Dist: rich>=13.0
Requires-Dist: rich-argparse>=1.4
Requires-Dist: scipy>=1.11
Requires-Dist: typing_extensions>=4.0
Provides-Extra: mpi
Requires-Dist: mpi4py>=3.1; extra == "mpi"
Provides-Extra: dev
Requires-Dist: pytest>=8.0; extra == "dev"
Requires-Dist: MDAnalysisTests>=2.7; extra == "dev"
Provides-Extra: docs
Requires-Dist: sphinx>=7.0; extra == "docs"
Requires-Dist: sphinx-rtd-theme>=2.0; extra == "docs"
Requires-Dist: myst-parser>=2.0; extra == "docs"
Dynamic: license-file

<p align="left">
  <img src="https://raw.githubusercontent.com/k-georgiou/pharmacon/main/resources/pharmacon_logo.png" alt="Pharmacon logo" width="600"/>
</p>

# Pharmacon

### A Molecular Dynamics Simulation Analysis Toolkit

A unified command-line toolkit for analyzing molecular-dynamics trajectories and
static structures &mdash; persisting results as **signed, self-describing HDF5
artifacts** and producing **publication-ready plots**.

<sub>Developed by **Kyriakos Georgiou** &middot; 2026</sub>

> [!IMPORTANT]
> **If you use Pharmacon in your research, please cite:**
>
> Georgiou, K.; Kolocouris, A. *Pharmacon: A Molecular Dynamics Simulation Analysis Toolkit.*
> [Journal of Chemical Information and Modeling (2026)](https://doi.org/10.1021/acs.jcim.6c00837) &middot; DOI: `10.1021/acs.jcim.6c00837`

[![Python](https://img.shields.io/badge/python-%E2%89%A53.12-blue.svg?logo=python&logoColor=white)](https://www.python.org/)
[![Status](https://img.shields.io/badge/status-stable-brightgreen.svg)]()
[![Version](https://img.shields.io/badge/version-1.0.1-blue.svg)]()
[![License](https://img.shields.io/badge/license-GPLv3-blue.svg)](LICENSE.txt)
[![Docs](https://readthedocs.org/projects/pharmacon/badge/?version=latest)](https://pharmacon.readthedocs.io/en/latest/?badge=latest)
[![Powered by MDAnalysis](https://img.shields.io/badge/powered%20by-MDAnalysis-orange.svg?logoWidth=16&logo=data:image/x-icon;base64,AAABAAEAEBAAAAEAIAAoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAA)](https://www.mdanalysis.org/)
[![Powered by RDKit](https://img.shields.io/badge/powered%20by-RDKit-3838ff.svg?logo=data:image/x-icon;base64,AAABAAEAEBAAAAEAIAAoBAAAFgAAACgAAAAQAAAAIAAAAAEAIAAAAAAAAAQAAAAAAAAAAAAAAAAAAAAAAAA)](https://www.rdkit.org/)
[![HDF5](https://img.shields.io/badge/data-HDF5-1572B6.svg?logo=hdf5&logoColor=white)](https://www.hdfgroup.org/solutions/hdf5/)
[![h5py](https://img.shields.io/badge/h5py-1572B6.svg?logo=python&logoColor=white)](https://www.h5py.org/)
[![NumPy](https://img.shields.io/badge/NumPy-013243.svg?logo=numpy&logoColor=white)](https://numpy.org/)
[![SciPy](https://img.shields.io/badge/SciPy-8CAAE6.svg?logo=scipy&logoColor=white)](https://scipy.org/)
[![Matplotlib](https://img.shields.io/badge/Matplotlib-11557c.svg?logo=python&logoColor=white)](https://matplotlib.org/)
[![NetworkX](https://img.shields.io/badge/NetworkX-2C5BB4.svg)](https://networkx.org/)
[![Rich](https://img.shields.io/badge/TUI-Rich-ff69b4.svg)](https://github.com/Textualize/rich)
[![configobj](https://img.shields.io/badge/INI-configobj-yellow.svg)](https://configobj.readthedocs.io/)
[![argparse](https://img.shields.io/badge/CLI-argparse-green.svg?logo=python&logoColor=white)](https://docs.python.org/3/library/argparse.html)
[![hashlib](https://img.shields.io/badge/crypto-hashlib-lightgrey.svg?logo=python&logoColor=white)](https://docs.python.org/3/library/hashlib.html)

---

## Table of Contents

- [Overview](#overview)
- [Project Architecture](#project-architecture)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Command Layout](#command-layout)
  - [`trajectory`](#trajectory--trajectory-analysis)
  - [`structure`](#structure--static-structure-analysis)
  - [`merge`](#merge--replicate-aggregation)
  - [`plot`](#plot--visualization)
  - [`export`](#export--data-export)
  - [`dump`](#dump--artifact-inspection)
- [Analyzer Module](#analyzer-module)
  - [RMSD](#rmsd)
  - [RMSF](#rmsf)
  - [Non-Covalent Interactions](#non-covalent-interactions-proteinligand--proteinprotein)
  - [Hydrogen Bonds](#hydrogen-bonds)
  - [Principal Component Analysis (PCA)](#principal-component-analysis-pca)
  - [Distances](#distances)
  - [Angles](#angles)
  - [Average Structure](#average-structure)
  - [Sequence Extraction](#sequence-extraction)
  - [Molecular Properties](#molecular-properties)
- [Periodic Boundary Conditions (PBC)](#periodic-boundary-conditions-pbc)
- [File Formats](#file-formats)
  - [Pharmacon Trajectory Analysis (`.pta`)](#pharmacon-trajectory-analysis-pta)
  - [Pharmacon Structure Analysis (`.psa`)](#pharmacon-structure-analysis-psa)
  - [Pharmacon INI plot-settings files](#pharmacon-ini-plot-settings-files)
- [CLI Reference](#cli-reference)
  - [General syntax](#general-syntax)
  - [Shared flags](#shared-flags)
  - [Getting help at every level](#getting-help-at-every-level)
- [Usage Examples](#usage-examples)
- [Plot Configuration via INI](#plot-configuration-via-ini)
- [Example INI Configs](#example-ini-configs)
- [Logging & Workspaces](#logging--workspaces)
- [Development](#development)
- [Author](#author)
- [License](#license)

---

## Overview

**Pharmacon** is a pure-Python, command-line toolkit for analyzing molecular
dynamics (MD) simulations of biomacromolecules. It folds the many tedious,
time-consuming steps of MD post-processing into a single, automated, and
reproducible `git`-style workflow — making routine analysis faster, more
accessible, and easier to reproduce.

**Supported MD engines.** Pharmacon reads trajectories from the most widely
used simulation packages out of the box:

**Amber** &nbsp;·&nbsp; **GROMACS** &nbsp;·&nbsp; **CHARMM** &nbsp;·&nbsp; **NAMD** &nbsp;·&nbsp; **OpenMM**

It is built on [MDAnalysis](https://www.mdanalysis.org/) for trajectory handling
and [NumPy](https://numpy.org/) for data processing.

**What it does.** From a single `pharmacon` command you can:

- Quantify structural change and flexibility — **RMSD**, **RMSF**, distances, and angles
- Profile **non-covalent interactions** — protein–ligand and protein–protein (9 interaction types) plus dedicated **hydrogen-bond** analysis
- Explore conformational space with **PCA** — projections, scree plots, and free-energy / probability surfaces
- Extract amino-acid **sequences** and compute small-molecule **descriptors & fingerprints**
- Aggregate replicate runs with **`merge`**, then render **publication-ready plots**

Every result is persisted as a **signed, self-describing HDF5 artifact**
(`.pta` / `.psa`), so analyses stay reproducible and inspectable long after the
run — readable with `h5py`, `h5dump`, or any HDF5 viewer.

As a proof of concept, Pharmacon was benchmarked against other toolkits on MD
simulations of several protein complexes — three membrane proteins and one
soluble complex — reproducing their intermolecular-interaction and geometric
measures (see the [citation](#pharmacon) above).


## Project Architecture

<p align="justify">
Pharmacon is shipped as a single Python package providing a command-line
executable <code>pharmacon</code> that can be used to perform a wide range of
analyses on MD simulation trajectories, structures, and more. It follows a
<b>strict</b> command-line syntax &mdash; similar to <code>git</code> commands
and subcommands &mdash; ensuring proper argument parsing and validation at
every level (see <a href="#cli-reference">CLI Reference</a>).
</p>

The project is organized around the following core modules:

| Module             | What it does                                                                                                                                           |
|--------------------|--------------------------------------------------------------------------------------------------------------------------------------------------------|
| **Logger**         | Structured terminal and file logging with multiple verbosity levels and colored output.                                                                |
| **Workspace**      | Manages working and temporary directories with automatic cleanup on exit.                                                                              |
| **File I/O**       | Reads and writes signed, self-describing HDF5 files ([.pta](#pharmacon-trajectory-analysis-pta) / [.psa](#pharmacon-structure-analysis-psa)).          |
| **Analyzer**       | Computes RMSD, distances, angles, PCA, hydrogen bonds, protein-ligand and protein-protein interactions, sequence extraction, and molecular properties. |
| **Plotter**        | Generates publication-ready figures (heatmaps, stacked columns, pie charts, scatter plots, time series) directly from analysis artifacts.              |
| **CLI Dispatcher** | Routes commands and subcommands to the appropriate analysis, plotting, or export module.                                                               |
| **Plot Settings**  | Provides a fully customizable settings system driven by simple [INI configuration files](#pharmacon-ini-plot-settings-files).                          |
| **Fingerprint**    | Generates deterministic identity tokens and tamper-detection checksums for every output file.                                                          |
| **Merge**          | Merges many Trajectory Analysis (.pta) files into one with std data.                                                                                   |


## Installation

Requires **Python ≥ 3.12**. Choose one of the three methods below.

### Option 1 — Install from PyPI (recommended)

<p align="justify">
The simplest way to install Pharmacon. This pulls a pre-built wheel from the
Python Package Index and installs it along with all required dependencies.
It is recommended to create a virtual environment first to avoid conflicts
with other packages.
</p>

```bash
python3.12 -m venv venv         # Create a virtual environment
source venv/bin/activate        # Activate the virtual environment

pip install pharmacon           # Install Pharmacon from PyPI
```

### Option 2 — Install with Conda

<p align="justify">
Recommended if you prefer managing environments and binary dependencies
(especially RDKit and MDAnalysis) through Conda. An
<code>environment.yml</code> is provided at the root of the repository.
</p>

```bash
# Create and activate the environment
conda env create -f environment.yml
conda activate pharmacon

# Install Pharmacon into the environment
pip install pharmacon
```

Or install directly from conda-forge (Not yet supported):

```bash
conda install -c conda-forge pharmacon
```

### Option 3 — Install from source (development)

<p align="justify">
Clone the repository and install in editable mode. This is the recommended
approach for contributors or if you want to stay on the latest development
version.
</p>

```bash
git clone https://github.com/k-georgiou/pharmacon.git
cd pharmacon
python -m venv venv && source venv/bin/activate
pip install -e ".[dev]"   # includes pytest
```

Run the test suite:

```bash
python -m pytest
```

### Verify the installation

After installing via any method, confirm that Pharmacon is available:

```bash
pharmacon --help     # Prints the CLI help and exit
```

## Quick Start

```bash
# Discover pharmacon commands
pharmacon --help

# Discover subcommands for a given command
pharmacon trajectory --help

# Discover subcommand flags for a given subcommand
pharmacon trajectory rmsd --help
```

---

## Command Layout

<p align="justify">
Pharmacon follows a <b>git-style</b> command structure where each top-level
command groups a family of related subcommands. The general syntax is:
</p>

```
pharmacon <command> <subcommand> [options]
```

### `trajectory` — Trajectory Analysis

<p align="justify">
Analyzes molecular-dynamics trajectories frame by frame. Each subcommand reads
a topology and trajectory file and writes results to a signed
<a href="#pharmacon-trajectory-analysis-pta"><code>.pta</code></a> file.
</p>

| Subcommand | Description |
|---|---|
| `rmsd` | Root Mean Square Deviation against a reference frame for one or more atom selections. |
| `rmsf` | Per-atom Root Mean Square Fluctuation over a trajectory for one or more atom selections. |
| `distances` | Pairwise or group-to-group distance time series. |
| `angles` | Three-atom, vector, and dihedral angle time series. |
| `h-bonds` | Hydrogen-bond detection across a trajectory. |
| `pl-interactions` | Protein–ligand non-covalent interactions (9 interaction types). |
| `pp-interactions` | Protein–protein non-covalent interactions (same 9 types). |
| `pca` | Principal Component Analysis on selected atoms. |
| `average-st` | Average structure over a specified frame range. |

### `structure` — Static Structure Analysis

<p align="justify">
Analyzes a single topology or structure file without requiring a trajectory.
Results are written to a
<a href="#pharmacon-structure-analysis-psa"><code>.psa</code></a> file.
</p>

| Subcommand | Description |
|---|---|
| `sequence` | Extract amino-acid sequences from a topology, organized by chain. |
| `properties` | Compute molecular descriptors and fingerprints for small molecules. |

### `merge` — Replicate Aggregation

<p align="justify">
Combines multiple <code>.pta</code> files produced from the same topology
(e.g. independent replicate runs) into a single merged artifact. Merged files
replace per-frame datasets with aggregate summary tables. The merge operation
verifies that all inputs share the same blueprint before proceeding.
</p>

| Subcommand | Description                                                       |
|---|-------------------------------------------------------------------|
| `results` | Merge many <code>.pta</code> replicates into one aggregated file. |

### `plot` — Visualization

<p align="justify">
Renders publication-ready plots directly from analysis artifacts. The plotter
auto-discovers which analysis groups are present in the file and dispatches to
the appropriate rendering functions. Plot appearance can be fully customized
via <a href="#pharmacon-ini-plot-settings-files">INI configuration files</a>.
</p>

| Subcommand | Description |
|---|---|
| `pta` | Render every compatible plot type for every group in a <code>.pta</code> file. |

### `export` — Data Export

<p align="justify">
Converts analysis files to flat file formats for use in external tools
such as spreadsheets, R, pandas, or bioinformatics pipelines.
</p>

| Subcommand | Description |
|---|---|
| `pta` | Export <code>.pta</code> tables to CSV or TSV. |
| `psa` | Export <code>.psa</code> tables to CSV, TSV, or FASTA. |

### `dump` — Artifact Inspection

<p align="justify">
Prints file metadata and the internal group/dataset tree to the terminal.
Useful for verifying that an artifact is intact, checking which analyses it
contains, and inspecting run parameters without opening an HDF5 viewer.
</p>

| Subcommand | Description |
|---|---|
| `pta` | Dump <code>.pta</code> metadata and group tree. |
| `psa` | Dump <code>.psa</code> metadata and table contents. |

---

## Analyzer Module

<p align="justify">
The analyzer module is the computational core of Pharmacon. It contains all
analysis algorithms as standalone, stateless routines that operate on
MDAnalysis selections and return raw numerical results. The module currently
supports the following analysis types:
</p>

### RMSD

<p align="justify">
Computes the Root Mean Square Deviation of atomic positions relative to a
reference frame. Supports multiple selections per run (e.g. backbone C-alpha,
ligand heavy atoms), with fitting group for alignment. Results are
stored per-frame in the <code>.pta</code> file and can be plotted as
time series.
</p>

### RMSF

<p align="justify">
Computes the per-atom Root Mean Square Fluctuation &mdash; the time-averaged
positional fluctuation of each atom about its mean position. Supports multiple
selections per run (e.g. backbone C-alpha, ligand heavy atoms) with a dedicated
fitting group for in-memory alignment. Alignment defaults to a two-pass scheme
(align to the initial frame, build the average structure, then re-align to it),
or can target a single reference frame via <code>-r</code>. Per-selection RMSF
values plus aggregate statistics are stored in the <code>.pta</code> file and
can be plotted as RMSF profiles.
</p>

### Non-Covalent Interactions (Protein–Ligand & Protein–Protein)

<p align="justify">
Detects and quantifies nine types of non-covalent interactions on a
per-frame basis across a trajectory:
</p>

- **Hydrophobic contacts** — distance-based detection between non-polar atoms.
- **Hydrogen bonds** — donor–hydrogen–acceptor geometry with distance and angle criteria.
- **Ionic / salt-bridge interactions** — oppositely charged groups within a distance cutoff.
- **Halogen bonds** — C–X···A geometry with angle validation.
- **Metal contacts** — coordination between metal ions and nearby electronegative atoms.
- **Water bridges (1st degree)** — a single bridging water molecule mediating a hydrogen-bond chain between two groups.
- **Water bridges (2nd degree)** — two bridging water molecules forming an extended hydrogen-bond network. (Not Yet Implemented)
- **Pi–cation interactions** — aromatic ring to charged group, with distance and angle thresholds.
- **Pi–stacking interactions** — parallel or T-shaped aromatic ring pairs, classified by geometry.

**Further information on distance cutoffs and interaction types can be found in
the Pharmacon paper (see the [citation](#pharmacon) above; DOI: 10.1021/acs.jcim.6c00837).**


<p align="justify">
Each interaction record includes full atom metadata (name, residue, chain,
segment) for both partners, plus interaction-specific geometric details
(distances, angles, orientation). Atom-type detection leverages RDKit
SMARTS pattern matching for accurate classification.
</p>

### Hydrogen Bonds

<p align="justify">
Dedicated hydrogen-bond analysis that can be run independently from the full
interaction analysis. Uses the same donor–acceptor detection and geometric
criteria, but produces a focused output containing only hydrogen-bond records. Usefull when 
the hydrogen bonding network is the only thing of interest.
</p>

### Principal Component Analysis (PCA)

<p align="justify">
Performs PCA on atomic coordinates across a trajectory to identify the
dominant modes of conformational motion. Outputs include eigenvalues
(explained variance ratios), eigenvectors (principal components), and
per-frame projections onto the selected components. Results support scatter
plots, time-series projections, variance-ratio scree plots, free-energy
surface (FES) heatmaps, and probability density heatmaps.
</p>

### Distances

<p align="justify">
Computes pairwise or group-to-group distance time series between user-defined
atom selections across a trajectory. Supports minimum-distance,
maximum-distance, center-of-mass, and center-of-geometry modes with periodic
boundary condition (PBC) awareness.
</p>

### Angles

<p align="justify">
Measures geometric angles across a trajectory. Three measurement types are
supported: three-atom angles (A&ndash;B&ndash;C), vector angles between two
pairs of atoms (AB vs CD), and dihedral / torsion angles
(A&ndash;B&ndash;C&ndash;D). All calculations are PBC-aware when box
dimensions are available. Angle selections are defined using MDAnalysis
selection strings in one of the following forms:
</p>

- **Three-atom angle** — select three atoms (e.g. `"index 10 or index 11 or index 12"`). Pharmacon measures the angle formed at the central atom.
- **Vector angle** — define two vectors using the arrow syntax '->' (e.g. `"index 10 or index 100 -> index 300 or index 301"`). Pharmacon computes the angle between the two resulting vectors.
- **Dihedral angle** — select four atoms (e.g. `"index 10 or index 11 or index 12 or index 13"`). Pharmacon measures the torsion angle around the central bond.

### Average Structure

<p align="justify">
Computes the per-atom mean coordinates over a specified frame range of a
trajectory, with optional alignment to a reference frame. The resulting
average structure can be written out as a coordinate file for visualization
or further analysis.
</p>

### Sequence Extraction

<p align="justify">
Extracts amino-acid sequences from a topology file, organized by chain. Outputs
include single-letter and three-letter representations along with residue ID
mappings. Supports FASTA export for downstream bioinformatics workflows.
</p>

### Molecular Properties

<p align="justify">
Computes structural and chemical descriptors for small molecules using RDKit,
including molecular weight, LogP, topological polar surface area (TPSA),
rotatable bond count, ring count, aromaticity, stereocenter count, net charge,
element composition, molecular volume, and fragment counts. Also generates
molecular fingerprints (Morgan/ECFP, topological torsion, atom pair, MACCS
keys) for similarity searching and machine-learning applications.
</p>

---

## Periodic Boundary Conditions (PBC)

<p align="justify">
Most MD engines write trajectories in which solute molecules diffuse across the
edges of the simulation box, get wrapped back through the opposite face, or
end up split between periodic images. Distances, angles, and contacts measured
on such raw frames are physically meaningless unless the box geometry is taken
into account. Pharmacon handles this in two complementary ways: <b>geometry-aware
calculations</b> that consult the box at every frame, and an <b>opt-in
transformation pipeline</b> that rewrites coordinates before the analysis sees
them.
</p>

### PBC-aware calculations

<p align="justify">
The trajectory analyzers that measure geometric quantities — <code>distances</code>,
<code>angles</code>, <code>h-bonds</code>, <code>pl-interactions</code>,
<code>pp-interactions</code> — read the per-frame unit-cell dimensions from the
trajectory and use the <b>minimum-image convention</b> when box information is
available. Concretely, this means a hydrogen-bond donor in the primary image
and an acceptor in a neighbouring image are still detected as a single contact
at the correct distance, without any user intervention.
</p>

<p align="justify">
If the trajectory has no box dimensions (e.g. a stripped <code>.dcd</code> or a
gas-phase run), Pharmacon falls back to plain Euclidean geometry and logs the
fact at <code>DEBUG</code> level.
</p>

### The `-at / --add-transformations` flag

<p align="justify">
PBC-aware distances handle the <i>measurement</i> side, but they cannot help
when a molecule is visually broken across box faces (e.g. a protein straddling
the box boundary), when downstream tools require whole molecules
(RDKit SMARTS matching, RMSD fitting, average-structure export), or when the
ligand drifts out of the protein's primary image. For these cases most
trajectory subcommands that consume coordinates (all except <code>rmsd</code>
and <code>rmsf</code>) accept:
</p>

```
-at, --add-transformations    Apply PBC unwrapping transformations to the
                              MDAnalysis Universe before analysis.
                              (default: False)
```

<p align="justify">
When the flag is set, Pharmacon attaches an <b>on-the-fly transformation
pipeline</b> to the MDAnalysis <code>Universe</code> in
<code>pharmacon.utils.mda.create_universe()</code>. The pipeline is built and
applied in a fixed order:
</p>

1. **`unwrap`** — `MDAnalysis.transformations.unwrap(u.atoms)`. Makes every
   molecule whole by reversing the wrapping that the MD engine applied on
   write. Required before any per-molecule operation (RMSD fit, COM/COG
   distance, SMARTS perception).
2. **`center_in_box`** — `center_in_box(ref, center="geometry")`. Re-centers
   the system on the geometric centre of the protein (falling back to all
   atoms if no `protein` selection exists). This keeps the receptor stationary
   in the primary image and prevents it from drifting toward a box face over
   long simulations.
3. **`wrap`** — `MDAnalysis.transformations.wrap(u.atoms, compound="atoms")`.
   After unwrapping and centering, wraps everything back into the primary
   image so that downstream distance/contact searches stay numerically
   well-behaved.

<p align="justify">
The transformations are <b>lazy</b>: they are attached once to
<code>u.trajectory</code> and re-evaluated on every frame iteration, so memory
usage stays flat regardless of trajectory length. If the pipeline cannot be
applied (e.g. missing bond topology required by <code>unwrap</code>),
Pharmacon logs a warning and continues with the untransformed trajectory
rather than aborting the run — the flag is treated as a convenience, not a
hard requirement.
</p>

### When to enable `--add-transformations`

| Situation                                                            | Recommendation                               |
|----------------------------------------------------------------------|----------------------------------------------|
| Trajectory already imaged / centered by the MD engine                | Leave **off** (default)                      |
| Protein visibly split across box edges in the input trajectory       | Enable                                       |
| Ligand drifts out of the primary box during a long run               | Enable                                       |
| PCA or average-structure on a periodic system                        | Enable                                       |
| Protein–ligand or protein–protein interactions with periodic ligands | Enable                                       |
| Box dimensions are missing from the trajectory                       | Has no effect — pipeline is silently skipped |

<p align="justify">
The flag is <i>idempotent</i> on already-imaged trajectories: re-running with
<code>-at</code> on a clean trajectory simply re-applies the same identity
pass and produces the same results.
</p>

### Recommended: pre-image the trajectory yourself

> [!WARNING]
> The on-the-fly `unwrap → center → wrap` pipeline runs on **every** frame
> iteration, **every time** you launch an analysis. On long trajectories or
> workflows that touch the same trajectory repeatedly (RMSD, PCA, then
> PL-interactions, then H-bonds, …) this overhead is paid over and over again
> and can **heavily affect calculation speed** — sometimes dominating the
> total runtime.

> [!TIP]
> For best performance, **pre-process the trajectory once with your MD engine's
> native tooling**, then feed the cleaned-up trajectory to Pharmacon *without*
> `-at`. Native tools are implemented in C/Fortran, operate frame-by-frame in a
> single streaming pass, and write the result to disk — so the cost is paid
> exactly once.

**Examples of native equivalents:**

- **GROMACS** — `gmx trjconv -pbc whole`, then `gmx trjconv -center -pbc mol -ur compact` (or `-pbc nojump` for unwrapped trajectories).
- **Amber / cpptraj** — `autoimage` followed by `center` and `image familiar`.
- **CHARMM / NAMD (VMD)** — the `pbctools` plugin: `pbc unwrap`, `pbc wrap -center com -centersel "protein" -compound res`.
- **MDAnalysis (Python)** — write a short script that mirrors the same
  `unwrap → center_in_box → wrap` chain and dumps the result with a
  `MDAnalysis.coordinates.XTC.XTCWriter`.

> [!NOTE]
> Not sure how to do this with your engine of choice? **It is perfectly fine to
> just pass `-at`** and let Pharmacon handle it for you — the result is
> numerically identical, you just have to wait a bit longer for the analysis to
> finish. The flag exists exactly for this case.

### Subcommands that accept `-at`

<p align="justify">
The flag is exposed on the trajectory subcommands that consume coordinates
(all except <code>rmsd</code> and <code>rmsf</code>):
</p>

- `pharmacon trajectory distances`
- `pharmacon trajectory angles`
- `pharmacon trajectory h-bonds`
- `pharmacon trajectory pl-interactions`
- `pharmacon trajectory pp-interactions`
- `pharmacon trajectory pca`
- `pharmacon trajectory average-st`

Example:

```bash
pharmacon trajectory pl-interactions \
    -p out.dms -x out.xtc -o pli.pta \
    -prt "chainid R" -lig "resname LIG" \
    -w "resname T3P and around 5 resname LIG" \
    --add-transformations \
    --workers 10
```

<p align="justify">
The <code>add_transformations</code> setting is persisted in the resulting
<code>.pta</code> file's root-level metadata, so a downstream consumer can
verify which PBC treatment a given artifact was produced under without
re-reading the original trajectory.
</p>

---

## File Formats

Pharmacon persists every analysis result as a **signed, self-describing HDF5
artifact**. There are two concrete formats — `.pta` for trajectory analysis and
`.psa` for structure analysis — both implemented on top of the shared
`PharmaconHDF5File` base class in `pharmacon.fileio.base`. Under the hood they
are plain HDF5 files and can be opened with `h5py`, `h5dump`, `HDFView`, or any
HDF5-aware library; the Pharmacon-specific metadata lives in HDF5 attributes
and a predictable group hierarchy.

### Common root-level attributes

Every Pharmacon artifact (`.pta` or `.psa`) carries the same base metadata
block on the root group. These are set automatically at write time from
`pharmacon.constants.BASE_PHARMACON_META` plus the command that produced the
file.

| Attribute                | Type  | Meaning                                                                                           |
|--------------------------|-------|---------------------------------------------------------------------------------------------------|
| `pharmacon_version`      | `str` | Version of Pharmacon that wrote the file (e.g. `"1.0.0"`).                                        |
| `schema_version`         | `str` | Schema contract version for on-disk layout.                                                       |
| `file_type`              | `str` | `PharmaconHDF5Types.TRAJECTORY_ANALYSIS` or `…STRUCTURE_ANALYSIS`.                                |
| `command`                | `str` | High-level command label (e.g. `"Trajectory Analysis"`).                                          |
| `subcommand`             | `str` | Specific subcommand (`rmsd`, `pl-interactions`, `sequence`, …).                                   |
| `description`            | `str` | Human-readable one-liner describing the run.                                                      |
| `created_at`             | `str` | ISO-8601 UTC timestamp at which the file was opened for writing.                                  |
| `signature`              | `str` | `PHARMACON::<COMMAND>::<SUBCOMMAND>::<chunked-SHA256-prefix>` identity token.                     |
| `fingerprint`            | `str` | 128-bit BLAKE2b hex digest over the same payload (tamper-check hint).                             |
| `blueprint`              | `str` | Deterministic digest of the run inputs — used by `pharmacon merge` to refuse incompatible inputs. |
| `artifact_token`         | `str` | HMAC-style token bound to the blueprint.                                                          |
| `artifact_token_version` | `str` | Token scheme version (currently `"1"`).                                                           |
| `artifact_status`        | `str` | `"SUCCESS"` iff `run()` finished cleanly.                                                         |
| `artifact_status_code`   | `str` | Exit code of the run (`"0"` on success).                                                          |
| `completed`              | `str` | `"True"` once the writer has closed the file with all groups fully populated.                     |
| `is_merged`              | `str` | `"True"` if the file was produced by `pharmacon merge results`.                                   |


In addition, each subcommand adds its own attributes (e.g. `begin`, `end`,
`step`, `total_frames`, `ligand`, `protein`, `water`, `disable_hbonds`, …) so
a file is fully reproducible from its metadata alone.

#### Signature, fingerprint, and blueprint — what's the difference?

These three tokens look similar but answer different questions:

- **`signature`** — a stable *identity* string built by
  `pharmacon.utils.fingerprint.create_pharmacon_signature()`. It is a SHA-256
  of `PHARMACON::<format>::<version>::<command>::<subcommand>::<salt>`, prefix-
  chunked for readability (e.g. `PHARMACON::TRAJECTORY ANALYSIS::PL-INTERACTIONS::9E11-C28C-85DE-…`).
  Two files with the same signature were produced by the same
  command+subcommand flavour of Pharmacon. Useful for routing plots and
  export logic.
- **`fingerprint`** — a 128-bit BLAKE2b over the same payload. Same
  determinism, different hash family: acts as a cheap tamper-check hint for
  the identity block.
- **`blueprint`** — generated by `pharmacon.utils.identifiers`, hashes the
  *actual inputs* (topology, trajectory, selections, flags). Two files share a
  blueprint only if they were run against equivalent inputs. `pharmacon merge
  results` uses this to refuse merging incompatible replicates.

None of these are cryptographic signatures — they are integrity hints, not
authentication.

### Pharmacon Trajectory Analysis (`.pta`)

A `.pta` file stores one or more **analysis groups** at the root, each
containing per-frame datasets. The concrete layout depends on the subcommand
that wrote the file, but the general pattern is:

```
pl_interactions.pta
├── @ pharmacon_version, signature, fingerprint, blueprint,
│     command="Trajectory Analysis", subcommand="pl-interactions",
│     begin, end, step, total_frames, ligand, protein, water, …
└── pl_interactions/                       ← analysis group
    ├── @ completed=True
    ├── frame_0/
    │   └── interactions        ← variable-length JSON-row dataset
    ├── frame_1/
    │   └── interactions
    ├── …
    ├── frame_500/
    │   └── interactions
    └── modes/                   ← optional aggregated views
        ├── mode1/table
        ├── mode2/table
        └── mode3/table
```

Typical top-level group names (one per analysis):

| Subcommand        | Root group(s)     | Per-frame dataset(s)                          |
|-------------------|-------------------|-----------------------------------------------|
| `rmsd`            | `rmsd`            | `frame_<N>/rmsd`                              |
| `rmsf`            | `rmsf`            | per-selection RMSF arrays + statistics        |
| `angles`          | `angles`          | `frame_<N>/angles`                            |
| `distances`       | `distances`       | `frame_<N>/distances`                         |
| `h-bonds`         | `hydrogen_bonds`  | `frame_<N>/interactions`                      |
| `pl-interactions` | `pl_interactions` | `frame_<N>/interactions`                      |
| `pp-interactions` | `pp_interactions` | `frame_<N>/interactions`                      |
| `pca`             | `pca`             | `components`, `projections`, `variance_ratio` |


#### Interaction row schema

The `interactions` dataset for `pl-interactions`, `pp-interactions`, and
`h-bonds` is a variable-length array of JSON-encoded rows with a fixed 21-column
core schema (`PharmaconPTAFile.INTERACTION_COLUMNS`):

| Column         | Description                                                                                                       |
|----------------|-------------------------------------------------------------------------------------------------------------------|
| `frame_number` | Frame index in the source trajectory.                                                                             |
| `interaction`  | Interaction type tag (see below).                                                                                 |
| `atom1_*`      | 9 fields for the first partner: `index`, `name`, `id`, `type`, `element`, `resname`, `resid`, `chainid`, `segid`. |
| `atom2_*`      | 9 fields for the second partner, same schema as `atom1_*`.                                                        |
| `details`      | Dict of interaction-specific extra fields (see table below).                                                      |

`PharmaconPTAFile.INTERACTION_DETAIL_SCHEMA` declares the `details` fields per
interaction type:

| Interaction tag  | `details` fields                                                                                                       |
|------------------|------------------------------------------------------------------------------------------------------------------------|
| `HYDROPHOBIC`    | `distance`, `is_hydrogen`                                                                                              |
| `HYDROGEN-BOND`  | `distance`, `angle_dha`, `angle_hax`, `orientation`                                                                    |
| `IONIC`          | `distance`, `orientation`                                                                                              |
| `HALOGEN-BOND`   | `distance`, `angle_cxa`, `angle_xay`, `orientation`                                                                    |
| `METAL-CONTACT`  | `distance`, `role`, `orientation`                                                                                      |
| `WATER-BRIDGE-1` | 16 fields — one bridging water + two distances + two angle pairs + orientation                                         |
| `WATER-BRIDGE-2` | 28 fields — two bridging waters + three distances + three angle pairs + orientation *(reserved — not yet implemented)* |
| `PI-CATION`      | `distance`, `theta`, `orientation`                                                                                     |
| `PI-STACKING`    | `distance`, `angle`, `stacking_type`, `orientation`                                                                    |

#### Aggregated interaction views: `modes/` and `modes_merged/`

For interaction analyses, Pharmacon additionally writes **mode tables** next
to the per-frame data:

- `modes/mode<N>/table` — per-file aggregated tables (residue × frame, residue
  × interaction type, residue × ligand atom, …) computed at write time so
  plotters don't have to re-walk every frame.
- `modes_merged/<mode_name>/table` — present only on files produced by
  `pharmacon merge results`. Contains the aggregate across every merged
  replicate. Merged files intentionally drop per-frame datasets in favour of
  these tables.

Plotters respect `is_merged`: plot types that require per-frame data (e.g. the
PLI timeline heatmap) are silently skipped on merged files.

### Pharmacon Structure Analysis (`.psa`)

A `.psa` file is the structure-level counterpart to `.pta`, produced by the
`pharmacon structure …` subcommands. It inherits the entire `.pta` API via
`PharmaconPSAFile(PharmaconPTAFile)` and adds structure-specific groups:

```
3eml.psa
├── @ pharmacon_version, signature, fingerprint,
│     command="Structure Analysis", subcommand="sequence",
│     topology_file, selection, n_chains, …
└── sequence/                ← one group per analysis
    ├── @ completed=True
    └── A/                   ← per-chain subgroup
        ├── aa1_seq          ← 1-letter amino-acid sequence
        ├── aa3_list         ← 3-letter residue list
        └── resid_seq        ← residue ID sequence
```

| Subcommand | Root group(s) | Notable datasets |
|---|---|---|
| `sequence` | `sequence` | `<chain>/aa1_seq`, `<chain>/aa3_list`, `<chain>/resid_seq` |
| `properties` | `properties` | `properties_table`, `fingerprints/<kind>`, optional `metadata` sidecar |

`PSAFile` exposes helpers for FASTA export, parquet fingerprint dumps, CSV
property exports, and an ML-ready joined export — see
`pharmacon.fileio.psa.PharmaconPSAFile` for the full writer/reader API.

### Inspecting a Pharmacon artifact

```bash
# Pharmacon's own dumper (pretty panels, validity badge, metadata tables)
pharmacon dump pta -i run.pta
pharmacon dump psa -i structure.psa
```

Or inline with `h5py`:

```python
import h5py

with h5py.File("run.pta", "r") as f:
    print(dict(f.attrs))                         # root metadata
    print(list(f.keys()))                        # analysis groups
```

### Pharmacon INI plot-settings files

A [configobj](https://configobj.readthedocs.io/)-style INI file whose top-level
sections match aliases on `PlotSettingsBase` subclasses. Example:

```ini
[PTA-UNIFIED]
fig_size_width = 12
fig_dpi        = 300
enable_grid    = true

[PLI-STACKED-COLUMN-1]
fig_format  = svg
font_family = DejaVu Sans
bar_width   = 0.9
```

For ready-to-use templates covering every plot type with all available
variables, see [`examples/plot_ini/`](examples/plot_ini/) and the
accompanying [`examples/README.md`](examples/README.md).

---

## CLI Reference

<p align="justify">
Pharmacon uses a hierarchical command structure. Every invocation starts with
<code>pharmacon</code>, followed by a <b>command</b> (the analysis family),
a <b>subcommand</b> (the specific task), and any required or optional
<b>flags</b>.
</p>

### General syntax

```
pharmacon                                      # show top-level help
pharmacon <command> --help                     # show help for a command group
pharmacon <command> <subcommand> --help        # show help for a specific task
pharmacon <command> <subcommand> [options]     # run a task
```

**Examples:**

```bash
pharmacon --help                               # list all available commands
pharmacon trajectory --help                    # list trajectory subcommands
pharmacon trajectory rmsd --help               # show all RMSD options
pharmacon trajectory rmsd -p top.prmtop -x md.xtc -f "protein and name CA" \
                          -sel "protein and name CA" -n "backbone_ca" -o rmsd.pta
```

### Shared flags

<p align="justify">
Most subcommands accept the following common flags. Not every flag applies to
every command &mdash; use <code>--help</code> on any subcommand to see its
exact options.
</p>

**Input / output:**

| Flag                        | Meaning                                                                                       |
|-----------------------------|-----------------------------------------------------------------------------------------------|
| `-p, --topology`            | Path to the topology file (`.prmtop`, `.pdb`, `.gro`, `.psf`, …).                             |
| `-x, --trajectory`          | Path to the trajectory file (`.xtc`, `.trr`, `.dcd`, `.nc`, …).                               |
| `-i, --input`               | Input artifact file (`.pta` or `.psa`) &mdash; used by `plot`, `export`, and `dump` commands. |
| `-o, --output`              | Output file or directory.                                                                     |
| `--overwrite`               | Replace existing output without prompting.                                                    |

**Atom selections (trajectory subcommands):**

| Flag | Meaning |
|---|---|
| `-sel, --selections` | One or more MDAnalysis selection strings (e.g. `"protein and name CA"`). |
| `-n, --names` | Label for each selection (used in output headers and plot legends). |
| `-f, --fitting-group` | Atom selection for structural alignment before analysis. |
| `-r, --reference-frame` | Frame index to use as the alignment reference (default: `0`). |

**Interaction-specific selections (for `pl-interactions` / `pp-interactions`):**

| Flag | Meaning |
|---|---|
| `-prt, --protein` | MDAnalysis selection string for the receptor / protein group. |
| `-lig, --ligand` | MDAnalysis selection string for the ligand group. |
| `-w, --water` | MDAnalysis selection string for water molecules (needed for water-bridge detection). |

> [!CAUTION]
> **Always scope the water selection dynamically around the binding site / interface.**
> Prefer `-w "resname WAT and around 5 resname LIG"` over a global `-w "resname WAT"`.
> A global selection forces Pharmacon to test **every** water molecule in the box for
> bridging on **every** frame, which can **dramatically increase runtime**. Restricting
> waters to the neighbourhood of the interaction site yields identical results for the
> relevant bridges at a fraction of the cost. (Adjust `WAT`/`LIG` and the `around`
> cutoff to match your system.)

**Distance-specific selections (for `distances`):**

| Flag | Meaning |
|---|---|
| `-sel1, --selection1` | First atom group(s) for distance calculation. |
| `-sel2, --selection2` | Second atom group(s) for distance calculation. |
| `-m, --method` | Distance method per pair: `MIN`, `MAX`, `COM` (center of mass), or `COG` (center of geometry). |

**Frame range:**

| Flag | Meaning |
|---|---|
| `-b, --begin` | First frame to process (default: `0`). |
| `-e, --end` | Last frame to process (default: last frame in trajectory). |
| `-s, --step` | Process every Nth frame (default: `1`). |

**PBC / transformations:**

| Flag | Meaning |
|---|---|
| `-at, --add-transformations` | Apply PBC unwrapping transformations to the MDAnalysis Universe before analysis. |

**Parallelization:**

| Flag | Meaning | Applies to |
|---|---|---|
| `--workers` | Number of parallel workers for frame processing (default: `1`). | `pl-interactions`, `pp-interactions`, `h-bonds` |
| `--parallel` | Number of parallel workers for frame processing (default: `1`). | `pca` |

**Interaction toggles (for `pl-interactions` / `pp-interactions`):**

| Flag                      | Meaning                             |
|---------------------------|-------------------------------------|
| `--disable-hydrophobic`   | Skip hydrophobic contact detection. |
| `--disable-hbonds`        | Skip hydrogen-bond detection.       |
| `--disable-pi-stacking`   | Skip pi-stacking detection.         |
| `--disable-pi-cation`     | Skip pi-cation detection.           |
| `--disable-ionic`         | Skip ionic / salt-bridge detection. |
| `--disable-water-bridges` | Skip water-bridge detection.        |
| `--disable-halogen`       | Skip halogen-bond detection.        |
| `--disable-metal`         | Skip metal-contact detection.       |

**PCA-specific:**

| Flag               | Meaning                                                   |
|--------------------|-----------------------------------------------------------|
| `-c, --components` | Number of principal components to compute (default: `3`). |

**Logging:**

| Flag                            | Meaning                                                                              |
|---------------------------------|--------------------------------------------------------------------------------------|
| `-l, --log`                     | Path to the log file.                                                                |
| `-fl, --file-logging-level`     | Verbosity of the log file: `TRACE`, `DEBUG`, `INFO`, `WARNING`, `ERROR`, `CRITICAL`. |
| `-tl, --terminal-logging-level` | Verbosity of terminal output (same levels as above).                                 |

**Plot-specific flags (for `pharmacon plot pta`):**

| Flag                 | Meaning                                                                                          |
|----------------------|--------------------------------------------------------------------------------------------------|
| `-c, --config`       | Path to a [Pharmacon INI file](#pharmacon-ini-plot-settings-files) with plot-settings overrides. |
| `-mw, --maxwarnings` | Maximum coercion warnings per plot before skipping it (default: `0`).                            |

### Getting help at every level

<p align="justify">
You can append <code>--help</code> at any point in the command chain to see
what is available. Pharmacon will display a Rich-formatted help panel with
all accepted flags, their types, defaults, and a brief description.
</p>

```bash
pharmacon --help                               # all commands
pharmacon trajectory --help                    # all trajectory subcommands
pharmacon trajectory pl-interactions --help    # all PLI options
pharmacon plot pta --help                      # all plotting options
pharmacon export psa --help                    # all PSA export options
```

---

## Usage Examples

### RMSD + plotting

```bash
pharmacon trajectory rmsd \
    -p protein.prmtop -x md.nc \
    -sel "protein and name CA" "resname LIG and not name H*" \
    -n "bb_ca" "ligand_heavy" \
    -f "protein and name CA" \
    -r 0 -b 0 -e 10000 -s 10 \
    -o rmsd.pta

pharmacon plot pta -i rmsd.pta -o plots/ --overwrite
```

### Protein–ligand interactions across replicates

```bash
# Analyze each replicate separately
for rep in rep1 rep2 rep3; do
  pharmacon trajectory pl-interactions \
      -p $rep/topo.prmtop -x $rep/md.nc \
      -lig "resname LIG" -prt "protein" \
      -o $rep/pli.pta
done

# Merge into one aggregated artifact
pharmacon merge results -i rep1/pli.pta rep2/pli.pta rep3/pli.pta \
                        -o pli_merged.pta

# Plot the merged artifact (per-frame-only plots are auto-skipped)
pharmacon plot pta -i pli_merged.pta -o plots/merged/ --overwrite \
                   -c my_plot_theme.ini
```

### PCA on a trajectory

```bash
pharmacon trajectory pca \
    -p protein.prmtop -x md.nc \
    -sel "protein and name CA" -c 5 \
    -o pca.pta

pharmacon plot pta -i pca.pta -o pca_plots/ --overwrite
# -> pca_plots/{pca_timeseries, pca_scatter, pca_variance_ratio,
#               pca_probability, pca_heatmap_fes}.png
```

### Dump + export

```bash
pharmacon dump   pta -i rmsd.pta                 # pretty-print metadata + tree
pharmacon export pta -i rmsd.pta -o rmsd.csv --format csv
```

---

## Plot Configuration via INI

Every plot-settings dataclass registers one or more aliases via its
`alias: ClassVar[Tuple[str, ...]]` field. The INI section header must match one
of those aliases (case-insensitive). Unknown sections are reported as a
warning but do not abort the run.

```ini
# ── Shared figure theme ──
[PTA-UNIFIED]
fig_dpi          = 300
fig_format       = svg
font_family      = DejaVu Sans
enable_grid      = true
grid_style       = dashed
grid_alpha       = 0.4

# ── Per-plot overrides ──
[PLI-STACKED-COLUMN-1]
bar_width        = 0.9
bar_alpha        = 0.85
color_hydrophobic = "#b39ddb"

[PLI-HEATMAP-2]
cmap             = viridis
threshold        = 0.05

[PCA-SCATTER]
cmap             = plasma
scatter_size     = 14
disable_colorbar = false
```

Each override goes through the dataclass' `_validate_fields()`, which may
**coerce** an unsupported value (e.g. an unknown color name) and emit a
warning. The `--maxwarnings / -mw` flag controls how many such warnings a plot
may accumulate before it is skipped entirely.

---

## Example INI Configs

Ready-to-copy configuration files for **every plot type** live in
[`examples/plot_ini/`](examples/plot_ini/). Each file exposes the full set of variables
for its plot with inline comments and default values — use them as templates,
edit the fields you care about, and point any `pharmacon plot …` command at
them with `-c`.

| File                                                                           | Plot                                            | Section alias(es)           |
|--------------------------------------------------------------------------------|-------------------------------------------------|-----------------------------|
| [`all_plots.ini`](examples/plot_ini/all_plots.ini)                             | Master file covering every plot                 | *(every alias below)*       |
| [`pli_stacked_column_1.ini`](examples/plot_ini/pli_stacked_column_1.ini)       | PLI stacked column (per interaction type)       | `PLI-STACKED-COLUMN-1`      |
| [`pli_stacked_column_2.ini`](examples/plot_ini/pli_stacked_column_2.ini)       | PLI stacked column (backbone vs side-chain)     | `PLI-STACKED-COLUMN-2`      |
| [`pli_heatmap_1.ini`](examples/plot_ini/pli_heatmap_1.ini)                     | PLI heatmap (residue × frame)                   | `PLI-HEATMAP-1`             |
| [`pli_heatmap_2.ini`](examples/plot_ini/pli_heatmap_2.ini)                     | PLI heatmap (interaction × frame)               | `PLI-HEATMAP-2`             |
| [`pli_pie_charts_1.ini`](examples/plot_ini/pli_pie_charts_1.ini)               | PLI pie charts (collage)                        | `PLI-PIE-CHARTS-1`          |
| [`pli_ligand_monitor.ini`](examples/plot_ini/pli_ligand_monitor.ini)           | Residue × ligand-atom contact heatmap           | `PLI-LIGAND-MONITOR`        |
| [`ppi_timeline_pairs.ini`](examples/plot_ini/ppi_timeline_pairs.ini)           | PPI timeline heatmap for top residue-pairs      | `PPI-TIMELINE-PAIRS`        |
| [`ppi_heatmap.ini`](examples/plot_ini/ppi_heatmap.ini)                         | PPI residue × residue heatmap                   | `PPI-HEATMAP`               |
| [`ppi_stacked_column.ini`](examples/plot_ini/ppi_stacked_column.ini)           | PPI per-pair stacked column                     | `PPI-STACKED-COLUMN`        |
| [`pta_unified.ini`](examples/plot_ini/pta_unified.ini)                         | Universal PTA time series (RMSD/RMSF/Rg/SASA/…) | `PTA-UNIFIED`               |
| [`pca_timeseries.ini`](examples/plot_ini/pca_timeseries.ini)                   | PCA projections vs time                         | `PCA-TIMESERIES`            |
| [`pca_scatter.ini`](examples/plot_ini/pca_scatter.ini)                         | PCA scatter of two components                   | `PCA-SCATTER`               |
| [`pca_variance_ratio.ini`](examples/plot_ini/pca_variance_ratio.ini)           | PCA explained-variance scree plot               | `PCA-VARIANCE-RATIO`        |
| [`pca_fes_heatmap.ini`](examples/plot_ini/pca_fes_heatmap.ini)                 | PCA Free-Energy Surface heatmap                 | `PCA-FES-HEATMAP`           |
| [`pca_probability_heatmap.ini`](examples/plot_ini/pca_probability_heatmap.ini) | PCA probability density heatmap                 | `PCA-PROBABILITY-HEATMAP`   |

**Usage:**

```bash
# Single-plot config
pharmacon plot pta -i run.pta -c examples/plot_ini/pta_unified.ini

# Master config that covers every plot type
pharmacon plot pta -i run.pta -c examples/plot_ini/all_plots.ini
pharmacon plot pca -i run.pta -c examples/plot_ini/all_plots.ini
```

Sections not recognised by the invoked subcommand are silently ignored, so
`all_plots.ini` can safely be reused across different `plot` commands.

---

## Logging & Workspaces

Every subcommand except `dump` and `export` accepts:

```
-l,  --log FILE
-fl, --file-logging-level  {TRACE,DEBUG,INFO,WARNING,ERROR,CRITICAL}
-tl, --terminal-logging-level {TRACE,DEBUG,INFO,WARNING,ERROR,CRITICAL}
```

Internally, `run()` always does:

```python
setup_logger(terminal=True, file=True,
             terminal_level=args.terminal_logging_level,
             file_level=args.file_logging_level,
             log_file=args.log)
log = get_logger(__name__)
ws  = PharmaconWorkspace(is_tmp_dir_needed=False)
```

`PharmaconWorkspace` respects two environment variables:

| Variable            | Default   | Meaning                                  |
|---------------------|-----------|------------------------------------------|
| `PHARMACON_WORKDIR` | `.`       | Base working directory                   |
| `PHARMACON_TEMPDIR` | `None`    | Base directory for per-run scratch space |

Any temporary directory created with `is_tmp_dir_needed=True` is cleaned up
via `atexit` unless `cleanup_on_exit=False` is passed.

---

## Development

```bash
git clone https://github.com/k-georgiou/pharmacon.git
cd pharmacon
python -m venv venv && source venv/bin/activate
pip install -e ".[dev]"   # editable install + pytest
pharmacon --help
```

**Running the test suite:**

```bash
python -m pytest          # all tests
python -m pytest tests/test_<module>.py   # single file
```

Adding a new subcommand is a 4-step pattern:

1. Create `src/pharmacon/command_line/<group>/<name>.py` with
   `SUBCOMMAND_NAME`, `SUMMARY`, `build_parser`, `validate`, `run`.
2. Put the heavy lifting in `pharmacon.analyzer.<name>` so it stays unit-testable.
3. If the output is a new HDF5 artifact, extend `pharmacon.fileio`.
4. If it needs plots, add a settings dataclass to `pharmacon.constants.plots`
   and a rendering function to `pharmacon.plotter`.

## Author

**Kyriakos Georgiou**<br>
Department of Pharmacy, University of Athens<br>
Manuscript: *Journal of Chemical Information and Modeling* (2026) — DOI: 10.1021/acs.jcim.6c00837<br>
GitHub: https://github.com/k-georgiou/pharmacon

## Acknowledgments

Special thanks to **Antonios Kolocouris** (Department of Pharmacy, University
of Athens) for his supervision, scientific guidance, and support throughout
the project and the associated manuscript.

## License

Pharmacon is licensed under the **GNU General Public License v3.0 only**
(GPL-3.0-only). See [`LICENSE.txt`](LICENSE.txt) for the full text, and
[`NOTICE`](NOTICE) for copyright, citation, and third-party-component
information.

> **Note on copyleft.** Pharmacon imports MDAnalysis (GPL-2.0-or-later) at
> runtime, so any distributed combined work is bound by the GPL terms.
> If you modify Pharmacon and distribute the result, you must release your
> changes under GPL-3.0-only.
