Skip to content

Commit 9cbab6d

Browse files
Atualizar o 2026-03-10-dissmodel-dual-backend.md
1 parent 2b93432 commit 9cbab6d

1 file changed

Lines changed: 40 additions & 3 deletions

File tree

_posts/2026-03-10-dissmodel-dual-backend.md

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,8 @@
22
layout: post
33
title: "Two Ways to Simulate the Same World: Raster and Vector Backends in DisSModel"
44
date: 2026-03-10
5-
categories: [research, simulation, python]
6-
tags: [dissmodel, geospatial, numpy, geopandas, salabim, mangrove, coastal-dynamics]
75
categories: news
6+
tags: [dissmodel, geospatial, numpy, geopandas, salabim, mangrove, coastal-dynamics]
87
permalink: /blog/raster-vs-vector-dissmodel/
98
author: Sergio Souza Costa
109
---
@@ -70,7 +69,45 @@ Model (salabim Component)
7069

7170
The two branches are independent. A model that inherits `SpatialModel` never touches NumPy. A model that inherits `RasterModel` never touches GeoDataFrame. But both live in the same salabim environment, share the same clock, and are registered the same way.
7271

73-
### The Vector Side: legibility
72+
---
73+
74+
## A Simple Example First: Conway's Game of Life
75+
76+
Before getting into the coastal models, it's worth showing what this symmetry looks like for a simple cellular automaton.
77+
78+
Conway's Game of Life has three rules: a live cell with 2 or 3 live neighbors survives; a dead cell with exactly 3 live neighbors becomes alive; all others die or stay dead.
79+
80+
Here it is in the vector version:
81+
82+
```python
83+
class GameOfLife(CellularAutomaton):
84+
def rule(self, idx):
85+
state = self.gdf.loc[idx, self.state_attr]
86+
neighbors = (self.neighbor_values(idx, self.state_attr) == 1).sum()
87+
if state == 1:
88+
return 1 if neighbors in (2, 3) else 0
89+
return 1 if neighbors == 3 else 0
90+
```
91+
92+
And in the raster version:
93+
94+
```python
95+
class GameOfLife(RasterCellularAutomaton):
96+
def rule(self, arrays):
97+
state = arrays[self.state_attr]
98+
neighbors = self.backend.focal_sum_mask(state == 1)
99+
survive = (state == 1) & np.isin(neighbors, [2, 3])
100+
born = (state == 0) & (neighbors == 3)
101+
return {self.state_attr: np.where(survive | born, 1, 0).astype(np.int8)}
102+
```
103+
104+
The rules are identical. The only thing that changes is the contract of `rule()`: the vector version receives a cell index and returns a single value; the raster version receives a snapshot of all arrays and returns a dict of updated arrays.
105+
106+
For a 20×20 grid this difference barely matters. Both versions run in milliseconds. But the pattern is the same one that scales to a million cells when the domain demands it.
107+
108+
---
109+
110+
## The Vector Side: legibility
74111

75112
The vector backend uses GeoDataFrame + libpysal. Each cell is a polygon row. Neighborhoods are computed once via Queen or Rook weights and cached. The transition rule is a Python function called once per cell per step.
76113

0 commit comments

Comments
 (0)