Metadata-Version: 2.4
Name: energorna
Version: 0.1.0
Summary: Glass-box local periodicity-loss observable of the mRNA stacking profile for repeat-expansion disorders (DM1, Huntington, SCA1)
Author-email: Jose Antonio Vilar Sanchez <qmetrika@proton.me>
License: MIT
Project-URL: Homepage, https://github.com/josevilar-qbioai/energorna
Project-URL: Repository, https://github.com/josevilar-qbioai/energorna
Project-URL: Issues, https://github.com/josevilar-qbioai/energorna/issues
Keywords: repeat expansion,myotonic dystrophy,huntington,SCA1,trinucleotide,age at onset,mRNA,thermodynamics,interruptions
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.8
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.12
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy>=1.20
Dynamic: license-file

# energorna

[![CI](https://github.com/josevilar-qbioai/energorna/actions/workflows/ci.yml/badge.svg)](https://github.com/josevilar-qbioai/energorna/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/energorna.svg)](https://pypi.org/project/energorna/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

**Glass-box local periodicity-loss observable of the mRNA stacking-energy profile, for
repeat-expansion disorders.** Numpy-only, no ViennaRNA / GPU / API. Part of the QMetrika
Bio-IA thermodynamic engine (same Turner nearest-neighbor parameters as `ef-synonymous`).

*[English](#english) · [Español](#español)*

---

## English

### The idea

In repeat-expansion diseases (myotonic dystrophy type 1, Huntington, SCA1, DM2…), age at
onset is not set only by *how many* repeats there are, but by whether the repeat tract is
**interrupted**. Interruptions (e.g. CCG in the CTG tract of DM1, CAA in the CAG tract of
Huntington, CAT in SCA1) break the **periodicity** of the nearest-neighbor stacking energy
profile Φ, disrupt the slipped-strand substrate that drives somatic instability, and
**delay onset**.

`energorna` computes a single glass-box observable — `periodicity_loss = 1 − ACF_period(Φ)`,
the loss of autocorrelation (at the motif period) of the Turner stacking profile — that
captures this. It **auto-calibrates the period** per motif (3 for trinucleotides, 4 for the
CCTG tetranucleotide) and, unlike simply counting interruptions, is sensitive to their
**type** and **position**.

### Install

```bash
pip install energorna
```

### Use — CLI

```bash
# pure (CTG)40 vs an interrupted allele
energorna score --repeat CTG --n 40
energorna score --seq CTGCTGCTG...CCGCTG... --motif CTG --json
energorna score --seq-file allele.fasta --motif CAG
```

Output shows the observable next to the traditional baselines:

```
motif CTG (period 3) · 62 units · longest uninterrupted run 51
  periodicity_loss      = 0.18xx   <- observable
  periodicity_loss (3') = 0.19xx
  n_interruptions       = 4        (count baseline)
  fragmentation_index   = 0.09xx   (fragmentation baseline)
```

### Use — Python

```python
import energorna as ef

ef.calibrate_lag("CCTG")                    # -> 4 (auto-detects the motif period)
ef.periodicity_loss(seq, unit="CTG")        # global observable
ef.periodicity_profile(seq, unit="CTG")     # (pos, loss) resolved 5'->3'
ef.periodicity_loss_3prime(seq, unit="CTG") # 3'-weighted
ef.n_interruptions(seq, "CTG")              # count baseline (to compare)
```

### Why it matters (validation)

Across three diseases, `periodicity_loss` (or its axis, the longest uninterrupted stretch)
predicts age at onset **better than counting repeats**:

| Disease | Data | Result |
|---|---|---|
| **DM1** | Pešović 2018, n=7 | periodicity vs onset residual **r=+0.81** (LOO robust, bootstrap CI [+0.59,+0.99], perm p=0.027) vs count +0.53; captures type (CCG≫CTC) & position |
| **Huntington** | GeM-HD 2019 (published directions) | LOI < canonical < duplication — matches onset ordering |
| **SCA1** | Menon 2013 Table S3, n=35 | longest uninterrupted stretch predicts onset **R²=0.64** vs 0.24 for total size (r=−0.80, p=5×10⁻⁵) |

### Honest scope

A **biologically motivated correlate**, not proven causality. Individual, interruption-typed
cohorts at scale (OPTIMISTIC, Enroll-HD) are access-controlled; the claim is "better
predictor than count on the available data, with a mechanistic hypothesis and falsifiable
predictions" (correlation with measured somatic instability, UV melting, MSH3 binding).
Research use only.

---

## Español

### La idea

En enfermedades de expansión de repeticiones (distrofia miotónica tipo 1, Huntington,
SCA1, DM2…), la edad de inicio no la fija solo *cuántas* repeticiones hay, sino si el
tracto está **interrumpido**. Las interrupciones (p. ej. CCG en el tracto CTG de DM1, CAA
en el CAG de Huntington, CAT en SCA1) rompen la **periodicidad** del perfil de energía de
apilamiento nearest-neighbor Φ, alteran el sustrato slipped-strand que dirige la
inestabilidad somática y **retrasan el inicio**.

`energorna` calcula un único observable glass-box — `periodicity_loss = 1 − ACF_periodo(Φ)`,
la pérdida de autocorrelación (al periodo del motivo) del perfil de apilamiento Turner —
que lo captura. **Auto-calibra el periodo** por motivo (3 en trinucleótidos, 4 en el
tetranucleótido CCTG) y, a diferencia de contar interrupciones, es sensible a su **tipo**
y **posición**.

### Instalación

```bash
pip install energorna
```

### Uso — CLI

```bash
energorna score --repeat CTG --n 40
energorna score --seq CTGCTG...CCGCTG... --motif CTG --json
energorna score --seq-file alelo.fasta --motif CAG
```

### Uso — Python

```python
import energorna as ef
ef.calibrate_lag("CCTG")                    # -> 4 (auto-detecta el periodo)
ef.periodicity_loss(seq, unit="CTG")        # observable global
ef.periodicity_profile(seq, unit="CTG")     # perfil (pos, pérdida) 5'->3'
ef.periodicity_loss_3prime(seq, unit="CTG") # ponderado 3'
```

### Por qué importa (validación)

En tres enfermedades, `periodicity_loss` (o su eje, el tramo ininterrumpido más largo)
predice la edad de inicio **mejor que contar repeticiones**: DM1 (Pešović n=7, r=+0,81),
Huntington (direcciones publicadas, LOI<canónico<duplicación) y SCA1 (Menon 2013 n=35,
R²=0,64 vs 0,24 del tamaño total). Ver la tabla en la sección en inglés.

### Alcance honesto

Es un **correlato biológicamente motivado**, no una causalidad demostrada. Los datos
individuales tipados a escala son de acceso controlado; el claim es "mejor predictor que
el conteo en los datos disponibles, con hipótesis mecanística y predicciones falsables".
Uso solo para investigación (RUO).

---

### Citation / Cita

Vilar Sánchez JA. *energoRNA: local periodicity loss of the mRNA stacking profile predicts
age at onset in repeat-expansion disorders.* QMetrika Labs, 2026. Method covered by patent
P202630522 (OEPM). Code under MIT.

- Repo: https://github.com/josevilar-qbioai/energorna
- ORCID: https://orcid.org/0009-0008-1057-4223
