API reference
pyEDW.model
The Exo-Daisy World model and its stochastic integrator.
This module ports updateExoDaisyWorld.m (the single time step) and
eDW_BHsim.m / exoDaisyWorld.m (the ensemble drivers) to Python. The
dynamics are the dimensionless system of Appendix B of Sowinski, Ghoshal &
Frank, Planet. Sci. J. 6, 176 (2025):
Eq. (B8)
d f_B / dt = w(T_B - 1)(f - f_B - f_W) f_B - (gamma_D/gamma_G) f_BEq. (B9)
d f_W / dt = w(T_W - 1)(f - f_B - f_W) f_W - (gamma_D/gamma_G) f_WEq. (B10)
d T / dt = (1/gamma_G tau_E)[(1 - (dA_B f_B + dA_W f_W)/(1-A_G)) L - T^4]Eq. (B11)
d L / dt = (1/gamma_G tau_S)(1 + lambda - L) + sqrt(2/gamma_G tau_S) delta (1+lambda) eta
with growth window w(x) = exp(-alpha x^4) (Eq. B7), scaled daisy
temperatures T_alpha^4 = T^4 + Q dA_B f_B + Q dA_W f_W - Q dA_alpha (Eq.
B12), and dA_alpha = A_alpha - A_G. Temperatures are in units of the
optimal temperature T_opt and luminosity in units of L_opt.
The noise is a single scalar Wiener process entering only the luminosity, so
the SDE is scalar-driven and the strong-order-1 stochastic Runge-Kutta scheme
of A. Roberts (2012) applies. Parameters packs the physical constants
into the dimensionless theta vector consumed by the integrator, whose
layout mirrors the MATLAB comment block exactly:
idx |
theta component |
|---|---|
0 |
f |
1 |
1 - A_G |
2 |
A_B - A_G |
3 |
A_W - A_G |
4 |
Q |
5 |
gamma_D / gamma_G |
6 |
1 / (gamma_G tau_E) |
7 |
1 / (gamma_G tau_S) |
8 |
8 (T_opt / Delta T)^4 |
9 |
delta |
10 |
lambda |
- class pyEDW.model.Parameters(f: float = 0.88, A_G: float = 0.3, A_B: float = 0.1, A_W: float = 0.6, T_opt: float = 300.0, Q: float = 0.1, gamma_G: float = 1.0, gamma_D: float = 0.2, tau_S: float = 3.0, tau_E: float = 5.0, dT: float = 30.0, delta: float = 0.05, lam: float = 0.0)[source]
Bases:
objectPhysical parameters of Exo-Daisy World.
All temperatures are expressed in units of the optimal temperature
T_optand luminosities in units ofL_optonce dimensionalized; the fields below are the dimensional constants of Table 1, from whichto_theta()builds the dimensionlessthetavector.- Parameters:
f (float) – Habitable land fraction.
A_G (float) – Ground, black-daisy, and white-daisy albedos (
A_B < A_G < A_W).A_B (float) – Ground, black-daisy, and white-daisy albedos (
A_B < A_G < A_W).A_W (float) – Ground, black-daisy, and white-daisy albedos (
A_B < A_G < A_W).T_opt (float) – Optimal growth temperature (sets the temperature scale).
Q (float) – Temperature-shift heat constant coupling daisy albedo to local temperature.
gamma_G (float) – Maximal growth rate and daisy decay rate.
gamma_D (float) – Maximal growth rate and daisy decay rate.
tau_S (float) – Stellar-fluctuation and environmental (thermal) timescales, in units of
1 / gamma_G.tau_E (float) – Stellar-fluctuation and environmental (thermal) timescales, in units of
1 / gamma_G.dT (float) – Growth-rate bandwidth
Delta T(range of bearable temperatures).delta (float) – Relative amplitude of the stellar-luminosity fluctuations.
lam (float) – Luminosity offset
lambda; the mean luminosity is<L> = (1 + lambda) L_opt.
- f: float = 0.88
- A_G: float = 0.3
- A_B: float = 0.1
- A_W: float = 0.6
- T_opt: float = 300.0
- Q: float = 0.1
- gamma_G: float = 1.0
- gamma_D: float = 0.2
- tau_S: float = 3.0
- tau_E: float = 5.0
- dT: float = 30.0
- delta: float = 0.05
- lam: float = 0.0
- class pyEDW.model.ExoDaisyWorld(params, x0=None, dt=0.1, rng=None)[source]
Bases:
objectThe coupled agent+environment stochastic Daisy World.
Wraps the compiled integrator behind a small stateful interface that keeps the MATLAB usage: build with
Parameters, advance withevolve()(one step) orrun()(many), and reach for the staticensemble()to sweep a luminosity axis in parallel.- Parameters:
params (Parameters) – Physical parameters.
x0 (array_like, optional) – Initial
[f_B, f_W, T, L]. Defaults to a small equal daisy seed at the equilibrium temperatureT = L**0.25forL = 1 + lambda.dt (float, optional) – Integration time step (default
0.1, as in the MATLAB).rng (numpy.random.Generator, optional) – Used only to seed NumPy’s global state for the compiled loops (Numba’s random stream). Pass an integer-seeded generator for repeatability.
- run(nsteps, record=False)[source]
Integrate
nstepssteps from the current state.- Parameters:
nsteps (int) – Number of SRK1 steps.
record (bool, optional) – If True, return the full
(nsteps + 1, 4)trajectory including the current state; otherwise advance in place and return the(4,)endpoint.
- Returns:
Endpoint or trajectory, per
record.- Return type:
numpy.ndarray
- static ensemble(params, Ls=None, nsteps=2000, N=500, dt=0.1, agent_free=False, seed=None)[source]
Parallel endpoint ensemble over a luminosity axis.
Ports
eDW_BHsim.m(biotic) and the agent-free driver ofexoDaisyWorld.m. For each luminosity,Nindependent instances are integrated fornstepssteps from freshly sampled initial conditions and their endpoints recorded.- Parameters:
params (Parameters) – Physical parameters;
params.lamis overridden per luminosity so that<L> = 1 + lambdatracks the axis.Ls (array_like, optional) – Mean luminosities. Defaults to
1 + linspace(-0.7, 1.4, 400).nsteps (int, optional) – Steps per instance (default 2000; the agent-free run used 200).
N (int, optional) – Instances per luminosity (default 500).
dt (float, optional) – Time step (default 0.1).
agent_free (bool, optional) – If True, seed both daisy fractions at zero (environment only).
seed (int, optional) – Seeds NumPy’s global RNG before the parallel loop.
- Returns:
Endpoints of shape
(len(Ls), N, 4).- Return type:
numpy.ndarray
pyEDW.metrics
Viability and the information architecture of Exo-Daisy World.
This module ports the entropy pipeline of Daisy_World_Paper_Figures.m
(lines 307-392) and the measure assembly of makeFIG4.m / makeFig5.m.
Given an endpoint ensemble data of shape (n_lum, N, 4) – the output
of pyEDW.model.ExoDaisyWorld.ensemble() – it estimates, at each
luminosity, the joint distribution p_AE(f_B, f_W, T, L) by histogramming
and reads off the Shannon information measures of Section 4.
Binning follows the paper’s square-root rule: with n living instances the
number of bins is N_bins = 1 + ceil(sqrt(n)) and each variable is split by
N_bins - 1 equally spaced interior edges spanning its observed range, so a
value lands in bin sum(v > edges) (0-indexed) – exactly the MATLAB
1 + sum(v > x) up to the index base.
Entropy table
entropy_table() returns, per luminosity, a 16-column array H whose
columns are the entropies of every marginal of p_AE needed downstream
(agent dof a_1 = f_B, a_2 = f_W; environment dof e_1 = T,
e_2 = L):
col |
entropy |
col |
entropy |
|---|---|---|---|
0 |
H[a1] |
8 |
H[a1 e1] |
1 |
H[a2] |
9 |
H[a1 a2] |
2 |
H[e1] |
10 |
H[a2 e1 e2] |
3 |
H[e2] |
11 |
H[a1 e1 e2] |
4 |
H[e1 e2] |
12 |
H[a1 a2 e2] |
5 |
H[a2 e2] |
13 |
H[a1 a2 e1] |
6 |
H[a2 e1] |
14 |
H[a1 a2 e1 e2] |
7 |
H[a1 e2] |
15 |
N_bins |
The information measures are then
I(A:E) = H[e1 e2] + H[a1 a2] - H[a1 a2 e1 e2](mutual_information())dI = I(e1:e2) - I0(e1:e2)(delta_I())C(a1:a2||E) = H[a1] + H[a2] + H[e1 e2] + H[a1 a2 e1 e2]`` - H[a1 a2] - H[a1 e1 e2] - H[a2 e1 e2]`` (cooperation())
Reference: Sowinski, Ghoshal & Frank, Planet. Sci. J. 6, 176 (2025), Section 4 and Appendix B.3.
- pyEDW.metrics.entropy_table(data)[source]
Per-luminosity entropy table for a biotic endpoint ensemble.
- Parameters:
data (numpy.ndarray) – Ensemble endpoints of shape
(n_lum, N, 4)with the last axis[f_B, f_W, T, L](frompyEDW.model.ExoDaisyWorld.ensemble()).- Returns:
Array
Hof shape(n_lum, 16); see the module docstring for the column layout. Luminosities with fewer than two living instances (f_B f_W > 1e-7) are left asNaNexcept the bin count.- Return type:
numpy.ndarray
- pyEDW.metrics.entropy_table_env(data_env)[source]
Environment-only entropy table for the agent-free ensemble.
Ports the
data_entropyEblock: with the biome removed, only(T, L)vary. The bin count is fixed by the full instance countN(not a living subset), matchingNbins = 1 + ceil(sqrt(N))in the MATLAB.- Parameters:
data_env (numpy.ndarray) – Agent-free endpoints of shape
(n_lum, N, 4).- Returns:
Array of shape
(n_lum, 4)with columns[H[e1], H[e2], H[e1 e2], N_bins].- Return type:
numpy.ndarray
- pyEDW.metrics.viability(data, f)[source]
Viability
V = E^A[(f_B + f_W)/f]per luminosity (Eq. 9).- Parameters:
data (numpy.ndarray) – Ensemble endpoints
(n_lum, N, 4).f (float) – Habitable land fraction.
- Returns:
Vof shape(n_lum,), the ensemble-mean occupied fraction of the habitable area (0 <= V <= 1).- Return type:
numpy.ndarray
- pyEDW.metrics.efficacy(data)[source]
Thermoregulatory efficacy
E = <T> - 1per luminosity.The mean planetary temperature’s deviation from the optimum (in units of
T_opt); zero means the biome holds the surface exactly atT_opt.
- pyEDW.metrics.mutual_information(H)[source]
Agent-environment mutual information
I(A:E)(bits).I(A:E) = H[e1 e2] + H[a1 a2] - H[a1 a2 e1 e2].
- pyEDW.metrics.intra_environment_information(H)[source]
Intra-environment correlation
I(e1:e2) = H[e1] + H[e2] - H[e1 e2].
- pyEDW.metrics.delta_I(H, H_env)[source]
Agent-induced change in intra-environment correlation,
dI.dI = I(e1:e2) - I0(e1:e2)(Eq. 12): the intra-environment mutual information with the biome present minus its agent-free value. Positive means the biome strengthens the temperature-luminosity correlation.- Parameters:
H (numpy.ndarray) – Biotic entropy table, shape
(..., 16)fromentropy_table().H_env (numpy.ndarray) – Agent-free table, shape
(n_lum, 4)fromentropy_table_env(), broadcast againstHalong the luminosity axis.
- Returns:
dIin bits.- Return type:
numpy.ndarray
- pyEDW.metrics.cooperation(H)[source]
Intra-agent cooperation given the environment,
C(a1:a2||E)(Eq. 14).The interaction information
C = H[a1] + H[a2] + H[e1 e2] + H[a1 a2 e1 e2]`` - H[a1 a2] - H[a1 e1 e2] - H[a2 e1 e2]``,equal to
I(a1:a2) - I(a1:a2 | E). Negative values indicate a synergistic effect where the environment enhances the correlation between the two daisy species.
pyEDW.figures
Plotting helpers that regenerate the figures of the eDW paper.
These port the visual content of makeFIG1.m – makeFig5.m. Each
function takes an endpoint ensemble (and, where needed, a precomputed entropy
table) and returns a Matplotlib (fig, axes) pair, so the caller controls
saving and styling. Colors follow the paper: white daisies in pink, black
daisies in blue, temperature in green.
ensemble_scatter()– Fig. 1: daisy fractions, albedo, and temperature scattered over luminosity for one growth-rate bandwidth.corner()– Fig. 2: pairwise joint distribution of the four dof at a single luminosity.cooperation_vs_deltaI()– Fig. 4: cooperation against the agent-induced correlation change, split by viability.information_vs_viability()– Fig. 5: I(A:E) against viability.
- pyEDW.figures.albedo(data, params)[source]
Planetary albedo per instance,
A = A_G + dA_B f_B + dA_W f_W(Eq. 2).
- pyEDW.figures.ensemble_scatter(data, params, Ls=None, s=3, alpha=0.05)[source]
Fig. 1: one bandwidth column – fractions, albedo, temperature vs L.
- Parameters:
data (numpy.ndarray) – Endpoint ensemble
(n_lum, N, 4).params (pyEDW.model.Parameters) – Parameters used to generate
data(for albedo andT_optlines).Ls (array_like, optional) – Luminosity axis; defaults to
1 + linspace(-0.7, 1.4, n_lum).s (float) – Scatter marker size and opacity.
alpha (float) – Scatter marker size and opacity.
- Returns:
Figure and its three stacked axes (fractions, albedo, temperature).
- Return type:
(matplotlib.figure.Figure, numpy.ndarray)
- pyEDW.figures.corner(data, ll, labels=('$f_B$', '$f_W$', '$T$', '$L$'), bins=40)[source]
Fig. 2: corner plot of the four dof at luminosity index
ll.Diagonal panels show the marginal histograms; lower-triangle panels show the pairwise joint densities, revealing the intra-agent (
f_Bvsf_W) and intra-environment (TvsL) correlations.- Returns:
Figure and its
4 x 4axis grid.- Return type:
(matplotlib.figure.Figure, numpy.ndarray)
- pyEDW.figures.cooperation_vs_deltaI(H, viability, v_hi=0.75, v_lo=0.3, bins=60)[source]
Fig. 4: cooperation
C(a1:a2||E)vs correlation changedI.Points are pooled over luminosity (and, if 2-D, bandwidth) and split into high- and low-viability clouds.
- Parameters:
H (numpy.ndarray) – Entropy table of shape
(..., 16)frompyEDW.metrics().viability (numpy.ndarray) – Viability broadcastable to
H[..., 0].v_hi (float) – Viability thresholds for the two clouds.
v_lo (float) – Viability thresholds for the two clouds.
- Return type:
(matplotlib.figure.Figure, matplotlib.axes.Axes)