Run a Model

This example demonstrates basic usage of the Spatiocoexistence model.

Necessary imports

from spatiocoexistence import Model, Inventory
from spatiocoexistence.data import inventory_file, parameter_file

Initialize the model with inventory and parameter files This model will be simulated on a single thread. If an integer greater than 1 is used for ‘threads’, the simulation will run in parallel on that many threads.

inventory = Inventory.from_data(inventory_file)
model = Model(initial_inventory=inventory, parameters=parameter_file, threads=1)

Get the current parameter values and modify them

parameter_old = model.parameters
# update the minimal survival probability of the recruits, increase the radius to 20m and the dispersal range for seeds to 25m
model.update_parameters(
    {"min_recruit_survival": 0.9, "neighborhood_radius": 20, "sigma_dispersal": 25.0}
)

print(
    "Original parameters (subset):",
    {
        k: parameter_old[k]
        for k in ["neighborhood_radius", "sigma_dispersal", "min_recruit_survival"]
    },
)
print(
    "Updated parameters (subset):",
    {
        k: model.parameters[k]
        for k in ["neighborhood_radius", "sigma_dispersal", "min_recruit_survival"]
    },
)
Original parameters (subset): {'neighborhood_radius': 10, 'sigma_dispersal': 14.0, 'min_recruit_survival': 0.88}
Updated parameters (subset): {'neighborhood_radius': 20, 'sigma_dispersal': 25.0, 'min_recruit_survival': 0.9}

Run a short simulation of 100 steps (each step represents 5 years)

model.step(100)
step:  1  year:  5
step:  2  year:  10
step:  3  year:  15
step:  4  year:  20
step:  5  year:  25
step:  6  year:  30
step:  7  year:  35
step:  8  year:  40
step:  9  year:  45
step:  10  year:  50
step:  11  year:  55
step:  12  year:  60
step:  13  year:  65
step:  14  year:  70
step:  15  year:  75
step:  16  year:  80
step:  17  year:  85
step:  18  year:  90
step:  19  year:  95
step:  20  year:  100
step:  21  year:  105
step:  22  year:  110
step:  23  year:  115
step:  24  year:  120
step:  25  year:  125
step:  26  year:  130
step:  27  year:  135
step:  28  year:  140
step:  29  year:  145
step:  30  year:  150
step:  31  year:  155
step:  32  year:  160
step:  33  year:  165
step:  34  year:  170
step:  35  year:  175
step:  36  year:  180
step:  37  year:  185
step:  38  year:  190
step:  39  year:  195
step:  40  year:  200
step:  41  year:  205
step:  42  year:  210
step:  43  year:  215
step:  44  year:  220
step:  45  year:  225
step:  46  year:  230
step:  47  year:  235
step:  48  year:  240
step:  49  year:  245
step:  50  year:  250
step:  51  year:  255
step:  52  year:  260
step:  53  year:  265
step:  54  year:  270
step:  55  year:  275
step:  56  year:  280
step:  57  year:  285
step:  58  year:  290
step:  59  year:  295
step:  60  year:  300
step:  61  year:  305
step:  62  year:  310
step:  63  year:  315
step:  64  year:  320
step:  65  year:  325
step:  66  year:  330
step:  67  year:  335
step:  68  year:  340
step:  69  year:  345
step:  70  year:  350
step:  71  year:  355
step:  72  year:  360
step:  73  year:  365
step:  74  year:  370
step:  75  year:  375
step:  76  year:  380
step:  77  year:  385
step:  78  year:  390
step:  79  year:  395
step:  80  year:  400
step:  81  year:  405
step:  82  year:  410
step:  83  year:  415
step:  84  year:  420
step:  85  year:  425
step:  86  year:  430
step:  87  year:  435
step:  88  year:  440
step:  89  year:  445
step:  90  year:  450
step:  91  year:  455
step:  92  year:  460
step:  93  year:  465
step:  94  year:  470
step:  95  year:  475
step:  96  year:  480
step:  97  year:  485
step:  98  year:  490
step:  99  year:  495
step:  100  year:  500

Access the updated inventory after simulation

inv = model.inventory

# Basic analyses on the resulting inventory
num_individuals = inv.x.shape[0]
mean_dbh = inv.dbh.mean()
max_species_id = inv.species.max()
abundances = inv.species_abundance()

print(f"Number of individuals after 100 steps: {num_individuals}")
print(f"Mean DBH (dm) after 100 steps: {mean_dbh:.3f}")
print("Species abundance distribution (counts per species):", abundances[0])
Number of individuals after 100 steps: 24267
Mean DBH (dm) after 100 steps: 1.274
Species abundance distribution (counts per species): 0

Show plot of the current inventory state.

inv.plot(threshold=50, filter=1.0)
/builds/heinzej/CrowdingIndex/spatiocoexistence/inventory/_plotting.py:685: RuntimeWarning: divide by zero encountered in log
  log_abundance = np.log(sorted_abundance)

Demonstrate individual processes on the current state Store initial inventory size for comparison

initial_size = len(model.inventory.data)
print(f"Initial inventory size: {initial_size}")
Initial inventory size: 24267

Apply one growth update and show mean dbh change

prev_mean_dbh = model.inventory.dbh.mean()
delta_dbh = model.growth()
post_growth_mean_dbh = model.inventory.dbh.mean()
print(
    f"Mean DBH before growth: {prev_mean_dbh:.3f} -> after growth: {post_growth_mean_dbh:.3f}"
)
print(f"Mean DBH increase: {delta_dbh.mean():.4f}")
Mean DBH before growth: 1.274 -> after growth: 1.383
Mean DBH increase: 0.0000

Apply mortality and report how many died Note: Dead individuals are now automatically removed from the inventory

deads_inventory = model.mortality()
print(
    f"Mortality event: {deads_inventory.data.shape[0]} individuals died and were removed."
)
print(f"Inventory size after mortality: {model.inventory.data.shape[0]}")
deads_inventory.plot_map(filter=0)
Mortality event: 2263 individuals died and were removed.
Inventory size after mortality: 22004

Apply recruitment and get new recruits as an Inventory object The recruits are automatically added to the main inventory

recruits_inventory = model.recruitment()
print(f"\nRecruitment event: {len(recruits_inventory.data)} new individuals recruited")
print(f"Inventory size after recruitment: {len(model.inventory.data)}")
recruits_inventory.plot_map(filter=0, scale=10)
Recruitment event: 2614 new individuals recruited
Inventory size after recruitment: 24618

Total running time of the script: (0 minutes 10.376 seconds)