Metadata-Version: 2.1
Name: ollin-py
Version: 1.0.0
Summary: An object-oriented framework for computational physics education
Home-page: https://github.com/yoltia/ollin
Author: Luis E. Sánchez-González
Author-email: luis.sanchez25@uabc.edu.mx
Classifier: Programming Language :: Python :: 3
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Topic :: Scientific/Engineering :: Physics
Classifier: Topic :: Education
Requires-Python: >=3.8
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: numpy >=1.21
Requires-Dist: scipy >=1.7
Provides-Extra: apps
Requires-Dist: matplotlib >=3.4 ; extra == 'apps'
Provides-Extra: dev
Requires-Dist: pytest >=7.0 ; extra == 'dev'
Requires-Dist: pytest-cov ; extra == 'dev'
Provides-Extra: visualization
Requires-Dist: matplotlib >=3.4 ; extra == 'visualization'
Requires-Dist: plotly >=5.0 ; extra == 'visualization'

<div align="center">

<img src="assets/ollinlogo.svg" alt="Ollin Logo" width="160"/>

# Ollin

**An object-oriented framework for computational physics education and research**

*Named after the Nahuatl word for dynamic change and transformation*

[![PyPI version](https://img.shields.io/pypi/v/ollin?color=1a56db&logo=python&logoColor=white)](https://pypi.org/project/ollin/)
[![Python](https://img.shields.io/badge/python-3.8+-blue?logo=python&logoColor=white)](https://www.python.org)
[![Tests](https://img.shields.io/badge/tests-38%20passed-success)](tests/)
[![Organization](https://img.shields.io/badge/org-yoltia-purple)](https://github.com/yoltia)

</div>

---

## The Correspondence Principle

> *There exists a structural correspondence between physical systems and objects in the OOP paradigm, and making this correspondence explicit provides a useful pedagogical framework for teaching computational physics.*

| Physical concept | OOP concept | Level |
|---|---|---|
| Physical system | class | General |
| System instance | object | General |
| Physical parameter | attribute | General |
| Physical law | method | General |
| Universality of laws | polymorphism | General |
| ODE dynamics `du/dt = f(u,t)` | `ODESystem` + `__call__` | ODE |
| Time evolution | `Solver` | ODE |
| Numerical algorithm | `Integrator` | ODE |

---

## Installation

```bash
pip install ollin
```

For development:

```bash
git clone https://github.com/yoltia/ollin
cd ollin
pip install -e ".[dev]"
```

---

## Quick Start

```python
from ollin.core import Solver, RungeKutta4
from ollin.systems.mechanics.pendulum import NonlinearPendulum
import numpy as np

# Physical system as a class
pendulum = NonlinearPendulum(g=9.81, l=1.0, m=0.5)

# Numerical method chosen independently
solver = Solver(RungeKutta4())

# Raw NumPy arrays — full control
t, u = solver.solve(pendulum, u0=[np.pi/4, 0.0], t0=0, tf=10, h=0.01)
theta = u[:, 0]   # angle [rad]
omega = u[:, 1]   # angular velocity [rad/s]
```

The same solver works with **any** physical system:

```python
# Polymorphism: one solver, any physics
t, u = solver.solve(RLCCircuit(R=1, L=1, C=0.25), u0=[1, 0], ...)
t, u = solver.solve(LorenzAttractor(),             u0=[1, 1, 1], ...)
t, u = solver.solve(ThreeBodyProblem(Ms, Mj, Me),  u0=[...], ...)
```

---

## Package Structure

```
ollin/
├── core/                 -- Framework core
│   ├── system.py         -- PhysicalSystem + ODESystem (abstract base classes)
│   ├── solver.py         -- Solver
│   └── integrators.py    -- Euler, EulerCromer, Verlet, RungeKutta4
│
├── systems/              -- Physical systems by domain
│   ├── mechanics/        -- MRU, MRUA, friction, projectile, pendulums
│   ├── gravity/          -- Planetary orbits, Kepler, N-body
│   ├── circuits/         -- RC, RLC
│   ├── nonlinear/        -- Lorenz attractor
│   ├── nuclear/          -- Radioactive decay
│   ├── stochastic/       -- Random walks, Monte Carlo, stochastic decay
│   ├── molecular/        -- Lennard-Jones MD simulation
│   ├── variational/      -- Fermat's principle
│   ├── condensed/        -- Tight-binding, SSH, Graphene
│   └── quantum/          -- 1D Schrödinger equation
│
├── numerical/            -- Mathematical tools
│   ├── integration.py    -- Riemann, Midpoint, Trapeze, Simpson, Monte Carlo
│   ├── differentiation.py-- Forward, Backward, Central differences
│   └── equations.py      -- Bisection, Newton-Raphson, Secant
│
├── visualization/        -- Plotting utilities (separated from physics)
├── apps/                 -- Interactive tkinter/plotly applications
├── examples/             -- Minimal working examples
└── lab/                  -- Jupyter notebooks for exploration
```

---

## The Two-Level Hierarchy

```python
class PhysicalSystem(ABC):
    """General: ANY physical system.
    Identity + state + dynamics -> class + attributes + methods."""
    pass

class ODESystem(PhysicalSystem):
    """ODE specialization: du/dt = f(u, t).
    Works with any Solver and any Integrator."""
    @abstractmethod
    def __call__(self, u, t): pass
```

**ODESystem subclasses** (mechanics, circuits, gravity, chaos)
→ use the `Solver`–`Integrator` pipeline.

**PhysicalSystem subclasses** (quantum, molecular, stochastic, condensed)
→ define their own interface appropriate to their mathematical structure.

---

## Available Systems

| Module | Systems | Base class |
|---|---|---|
| `mechanics` | `SimplePendulum`, `NonlinearPendulum`, `DampedPendulum`, `ForcedPendulum`, `UniformMotion`, `ProjectileMotion`, `FrictionMotion` | `ODESystem` |
| `gravity` | `PlanetaryOrbit`, `EllipticalOrbit`, `TwoBodyProblem`, `ThreeBodyProblem` | `ODESystem` |
| `circuits` | `RCCircuit`, `RLCCircuit` | `ODESystem` |
| `nonlinear` | `LorenzAttractor` | `ODESystem` |
| `nuclear` | `RadioactiveDecay` | `ODESystem` |
| `quantum` | `Quantum1D` | `PhysicalSystem` |
| `molecular` | `LennardJones`, `MolecularDynamics2D` | `PhysicalSystem` |
| `stochastic` | `RandomWalk1D`, `RandomWalk2D`, `SelfAvoidingWalk`, `StochasticDecay` | `PhysicalSystem` |
| `condensed` | `TightBinding`, `SSH`, `Graphene` | `PhysicalSystem` |
| `variational` | `FermatPrinciple` | `PhysicalSystem` |

---

## Extending Ollin

Adding a new physical system takes exactly four things:

```python
from ollin.core import ODESystem   # or PhysicalSystem for non-ODE

class MySystem(ODESystem):
    def __init__(self, param1, param2):
        self.param1 = param1   # physical parameter as attribute
        self.param2 = param2

    def __call__(self, u, t):  # equation of motion as method
        # return du/dt
        return [...]

# That's it. Works with any Solver and any Integrator.
t, u = Solver(RungeKutta4()).solve(MySystem(p1, p2), u0, t0, tf, h)
```

---

## Running Tests

```bash
pytest tests/ -v
```

Expected: **38 passed**.

---

## Citation

```bibtex
@misc{ollin2026,
  author       = {S\'anchez-Gonz\'alez, Luis E.},
  title        = {{Ollin}: An object-oriented framework for computational physics},
  howpublished = {\url{https://github.com/yoltia/ollin}},
  year         = {2026}
}
```

---

## Part of the Yoltia Project

<div align="center">

**Ollin** is part of [Yoltia](https://github.com/yoltia):
open-source tools for computational physics education and research,
developed at Universidad Autónoma de Coahuila, México.

</div>

---

## License

 License. See [LICENSE](LICENSE) for details.
