Skip to article frontmatterSkip to article content
Site not loading correctly?

This may be due to an incorrect BASE_URL configuration. See the MyST Documentation for reference.

Inhomogeneous Spatiotemporal Poisson Process — From Scratch and With NumPyro

Open In Colab

An inhomogeneous spatiotemporal Poisson process (IPP-ST) lets the rate vary across the slab D×[t0,t1)D \times [t_0, t_1):

λ(s,t)>0,Λ=∫t0t1 ⁣∫Dλ(s,t) ds dt,\lambda(s, t) > 0, \qquad \Lambda = \int_{t_0}^{t_1}\!\int_D \lambda(s, t)\, ds\, dt,

with Janossy log-likelihood ∑ilog⁡λ(si,ti)−Λ\sum_i \log \lambda(s_i, t_i) - \Lambda. We use an aftershock-style intensity — Omori-law decay in time around a peak time, Gaussian-bump decay in space around an epicentre — sample with Lewis–Shedler thinning, and recover the mainshock parameters with NumPyro NUTS.

Setup

/home/azureuser/localfiles/xtremax/.venv/bin/python: No module named pip
Note: you may need to restart the kernel to use updated packages.
/home/azureuser/localfiles/xtremax/.venv/lib/python3.13/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm

1. From scratch — the primitives layer

Aftershock intensity around an epicentre s0s_0:

log⁡λ(s,t)=log⁡A−∥s−s0∥22σ2−log⁡(c+t).\log \lambda(s, t) = \log A - \frac{\|s - s_0\|^2}{2\sigma^2} - \log(c + t).

Peak intensity is at (s0,t=0)(s_0, t = 0) with value A/cA / c.

λ_max = 1.132
Drew 17 aftershocks.

Plot the realisation: events clustered around the epicentre and the early time window, fading out as tt grows.

<Figure size 600x500 with 2 Axes>

Log-likelihood and integrated intensity

integrate_log_intensity_spatiotemporal computes Λ\Lambda over the slab via Halton-QMC. The Janossy log-prob is then ∑ilog⁡λ(si,ti)−Λ\sum_i \log \lambda(s_i, t_i) - \Lambda.

Λ = 22.632, log L = -64.611

Marginal intensities and intensity surface

xtremax ships closed-form-style helpers for λS(s)=∫tλ(s,t) dt\lambda_S(s) = \int_t \lambda(s, t)\, dt and λT(t)=∫Dλ(s,t) ds\lambda_T(t) = \int_D \lambda(s, t)\, ds. The latter is the standard temporal-rate-of-occurrence; here it’s the Omori law shape.

<Figure size 600x350 with 1 Axes>
<Figure size 550x500 with 2 Axes>

2. With NumPyro — recover the epicentre and decay parameters

Treat AA, σ\sigma, cc as unknown and condition on the observed events. Bake the observation into a closure so NumPyro doesn’t try to traverse the heterogeneous-shape PyTree.

    A: posterior mean = 5.882, true = 8.0
sigma: posterior mean = 1.634, true = 1.5
    c: posterior mean = 0.525, true = 0.5
<Figure size 1200x320 with 3 Axes>