Metadata-Version: 2.1
Name: treetensor
Version: 0.2.0
Summary: Kinetic plasma simulation on tree tensor networks
Requires-Python: >=3.11
Project-URL: Homepage, https://itsuwari.github.io/vlasov/
Requires-Dist: numpy>=2
Provides-Extra: test
Requires-Dist: scipy>=1.17; extra == "test"
Description-Content-Type: text/markdown

# treetensor

Kinetic plasma simulation on tree tensor networks.
The `ttn` module calls a C++20 runtime in double precision.
The same model runs in the browser as the npm package `@tensortree/plasma`.

```sh
pip install treetensor
```

Wheels exist for Linux x86_64 and aarch64 (glibc 2.17 or later) and for macOS 14 or later on Apple silicon.
Python 3.11 and later are supported.

## Landau damping

```python
import math
import ttn as t

x, v = t.periodic("x", 48, [0, 4 * math.pi]), t.periodic("v", 64, [-6, 6])
space, velocity = t.cartesian(x), t.cartesian(v)
density = t.cosine(x, 0.5, offset=1, amplitude=0.04)
electrons = t.species("electrons", charge=-1, mass=1, velocity=velocity,
                      initial=t.normalized(t.maxwellian(velocity, density=density), space.volume))
fields = t.maxwell(c_squared=16, electric=t.vector(x=-0.08 * t.sine(x, 0.5)))
plasma = t.vlasov(space=space, species=[electrons], fields=fields)
Ex = plasma.observable("Ex", t.component(plasma.fields.electric, "x"))

simulation = (t.run(plasma)
              .represent(electrons.f, t.ttn(rank=t.automatic(capacity=48)))
              .time(t.fixed_step(0.05, final_time=40))
              .compile())
while not simulation.done:
    simulation.advance()
    field = simulation.tensor(Ex)                      # NumPy copy over x
    energy = simulation.value(plasma.energy.total)     # float
```

## Workflow

1. **Axes.** `periodic(name, cells, bounds)` and `uniform(...)` create axes; `cartesian(x, y)` groups them into a frame with x, y, z components.
2. **Model.** `vlasov(space=..., species=[...], fields=...)` returns a `Plasma` with the distribution `species.f`, the equation `groups`, the time `scheme` and the `mass`, `energy` and `fields` observables.
   For other equations, create a `Model` and call `state`, `group`, `observable`, `dougherty` and `bgk` on it.
   Add every observable to the model (`plasma.observable(...)` or `model.observable(...)`) before the first `describe()` or `compile()`.
3. **Run.** `run(model)` collects numerical settings: `represent(state, ttn(...) | dense())`, `time(fixed_step(...) | adaptive_step(...))`, and for a `Model` also `scheme(...)`.
   `transport(state, maps.streaming(...))`, `streaming(state, False)` and `observe(...)` (keep a value resident, evaluated every step) are optional.
4. **Simulation.** `compile()` returns a `Simulation` with `advance()`, `retreat()`, `time`, `steps`, `done`, `report()`, and `tensor(x)` / `value(x)` for any state or observable of the model.
   A run and a model can be compiled more than once, for example to compare integrators.

## Values

Axes, states and expressions combine with `+ - * / **`; an axis stands for its coordinate, so `-v * t.diff(f, x)` is the free-streaming term.
Elementary functions (`exp`, `cos`, `sqrt`, `bessel_j0`, ...) and calculus (`diff`, `grad`, `curl`, `integrate`, `dot`, `cross`, `component`) accept any of them.

Initial values are usually profiles: `gaussian(axis, mean, sigma)`, `cosine(axis, k, amplitude=, offset=, phase=)`, `sine(...)`, `profile(axis, function)`, `samples(axis, values)` and `vector(x=..., y=..., z=...)`.
Profiles combine with `+`, `-`, `*` and `/` by a number, and stay separable, so a TTN state starts without sampling the full grid.
`normalized(profile, integral)` fixes the integral of an initial value and cannot be combined further.
A profile used in an expression becomes a coefficient table.
`sampled(indices, function)` and `tree_sampled(axes, function)` give nonseparable initial values; an expression also works.

## Numerics

- Representations: `ttn(tree="automatic" | [[x, y], [z, v]], rank=automatic(capacity=96) | adaptive(...) | fixed(rank=...) | int)` or `dense()`.
- Integrators: `strang()` (default), `lie()`, `ps_abug()`, `sgm()`, `pfg(core_flow="cayley" | "pade22" | "sdirk2")`, `coupled_midpoint()`, and `rk4()` for dense states.
  `vlasov(..., integrator=t.pfg())` selects the kinetic integrator of a recipe.
- Schemes for a `Model`: `advance(group, method)`, `strang_split(a, b)` and `compose(a, b)`.
- Time grids: `fixed_step(dt, steps=...)` or `fixed_step(dt, final_time=...)`, and `adaptive_step(initial_dt, final_time=..., tolerance=..., error=[observables])`.

Invalid settings raise `ValueError` with the path of the offending argument.
`help(t.vlasov)`, `help(t.Model)` and `help(t.run)` describe each call.

## C++ bindings

`ttn.core` mirrors the C++ API one to one: `Program`, `make_run`, `method`, `representation`, `physics`, `examples` and `compile`, which returns a C++ `Session`.
Use it to reproduce a C++ program exactly; the top-level `ttn` API builds on it.

`TTN_CPU_THREADS` sets the number of CPU executor threads.
The live browser demo is at https://itsuwari.github.io/vlasov/.
