Skip to content

Commit

Permalink
Fix data paths and model passing in GIS examples (projectmesa#177)
Browse files Browse the repository at this point in the history
This commit addresses several of the remaining issues across the GIS examples:

- Corrects data file paths in the population, rainfall, and urban growth models to use relative paths from the script directory.
- Fixes the urban growth model by passing the model object to City and UrbanCell classes, as required by mesa-geo 0.8.0.
- Updates the population model to pass the model object when creating agents, ensuring they can access Model variables and properties.
- Corrects the use of `/vsigzip/` paths for GDAL compatibility.

The `/vsigzip/` situation is super weird. It isn't part of the file path, but it's a "marker" a GDAL convention. See the PR message, mesa-geo#235 and https://gdal.org/user/virtual_file_systems.html#vsigzip-gzipped-file for more details.
  • Loading branch information
EwoutH committed Sep 3, 2024
1 parent 6f917ea commit 3d6e54e
Show file tree
Hide file tree
Showing 9 changed files with 51 additions and 35 deletions.
8 changes: 3 additions & 5 deletions gis/geo_schelling/model.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import os
import random
from pathlib import Path

import mesa
import mesa_geo as mg

script_directory = os.path.dirname(os.path.abspath(__file__))
script_directory = Path(__file__).resolve().parent


class SchellingAgent(mg.GeoAgent):
Expand Down Expand Up @@ -70,9 +70,7 @@ def __init__(self, density=0.6, minority_pc=0.2, export_data=False):

# Set up the grid with patches for every NUTS region
ac = mg.AgentCreator(SchellingAgent, model=self)
data_path = os.path.join(
script_directory, "data/nuts_rg_60M_2013_lvl_2.geojson"
)
data_path = script_directory / "data/nuts_rg_60M_2013_lvl_2.geojson"
agents = ac.from_file(filename=data_path)
self.space.add_agents(agents)

Expand Down
8 changes: 3 additions & 5 deletions gis/geo_schelling_points/geo_schelling_points/model.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
import os
import random
import uuid
from pathlib import Path

import mesa
import mesa_geo as mg

from .agents import PersonAgent, RegionAgent
from .space import Nuts2Eu

script_directory = os.path.dirname(os.path.abspath(__file__))
script_directory = Path(__file__).resolve().parent


class GeoSchellingPoints(mesa.Model):
Expand All @@ -27,9 +27,7 @@ def __init__(self, red_percentage=0.5, similarity_threshold=0.5):

# Set up the grid with patches for every NUTS region
ac = mg.AgentCreator(RegionAgent, model=self)
data_path = os.path.join(
script_directory, "../data/nuts_rg_60M_2013_lvl_2.geojson"
)
data_path = script_directory / "../data/nuts_rg_60M_2013_lvl_2.geojson"
regions = ac.from_file(data_path, unique_id="NUTS_ID")
self.space.add_regions(regions)

Expand Down
8 changes: 3 additions & 5 deletions gis/geo_sir/model.py
Original file line number Diff line number Diff line change
@@ -1,21 +1,19 @@
import os
from pathlib import Path

import mesa
import mesa_geo as mg
from shapely.geometry import Point

from .agents import NeighbourhoodAgent, PersonAgent

script_directory = os.path.dirname(os.path.abspath(__file__))
script_directory = Path(__file__).resolve().parent


class GeoSir(mesa.Model):
"""Model class for a simplistic infection model."""

# Geographical parameters for desired map
geojson_regions = os.path.join(
script_directory, "data/TorontoNeighbourhoods.geojson"
)
geojson_regions = script_directory / "data/TorontoNeighbourhoods.geojson"
unique_id = "HOODNUM"

def __init__(
Expand Down
16 changes: 12 additions & 4 deletions gis/population/population/model.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import math
import random
import uuid
from pathlib import Path

import mesa
import mesa_geo as mg
Expand All @@ -9,6 +10,8 @@

from .space import UgandaArea

script_directory = Path(__file__).resolve().parent


class Person(mg.GeoAgent):
MOBILITY_RANGE_X = 0.0
Expand Down Expand Up @@ -52,13 +55,18 @@ def step(self):
class Population(mesa.Model):
def __init__(
self,
population_gzip_file="data/popu.asc.gz",
lake_zip_file="data/lake.zip",
world_zip_file="data/clip.zip",
population_gzip_file="../data/popu.asc.gz",
lake_zip_file="../data/lake.zip",
world_zip_file="../data/clip.zip",
):
super().__init__()
self.space = UgandaArea(crs="epsg:4326")
self.space.load_data(population_gzip_file, lake_zip_file, world_zip_file)
self.space.load_data(
script_directory / population_gzip_file,
script_directory / lake_zip_file,
script_directory / world_zip_file,
model=self,
)
pixel_size_x, pixel_size_y = self.space.population_layer.resolution
Person.MOBILITY_RANGE_X = pixel_size_x / 2.0
Person.MOBILITY_RANGE_Y = pixel_size_y / 2.0
Expand Down
7 changes: 4 additions & 3 deletions gis/population/population/space.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,11 @@ class UgandaCell(Cell):

def __init__(
self,
model,
pos: mesa.space.Coordinate | None = None,
indices: mesa.space.Coordinate | None = None,
):
super().__init__(pos, indices)
super().__init__(model, pos, indices)
self.population = None

def step(self):
Expand All @@ -32,7 +33,7 @@ class UgandaArea(GeoSpace):
def __init__(self, crs):
super().__init__(crs=crs)

def load_data(self, population_gzip_file, lake_zip_file, world_zip_file):
def load_data(self, population_gzip_file, lake_zip_file, world_zip_file, model):
world_size = gpd.GeoDataFrame.from_file(world_zip_file)
raster_layer = RasterLayer.from_file(
f"/vsigzip/{population_gzip_file}",
Expand All @@ -43,7 +44,7 @@ def load_data(self, population_gzip_file, lake_zip_file, world_zip_file):
raster_layer.total_bounds = world_size.total_bounds
self.add_layer(raster_layer)
self.lake = gpd.GeoDataFrame.from_file(lake_zip_file).geometry[0]
self.add_agents(GeoAgent(uuid.uuid4().int, None, self.lake, self.crs))
self.add_agents(GeoAgent(uuid.uuid4().int, model, self.lake, self.crs))

@property
def population_layer(self):
Expand Down
8 changes: 6 additions & 2 deletions gis/rainfall/rainfall/model.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import uuid
from pathlib import Path

import mesa
import mesa_geo as mg
Expand All @@ -7,6 +8,8 @@

from .space import CraterLake

script_directory = Path(__file__).resolve().parent


class RaindropAgent(mg.GeoAgent):
def __init__(self, unique_id, model, pos):
Expand Down Expand Up @@ -63,7 +66,7 @@ def __init__(self, rain_rate=500, water_height=5, export_data=False, num_steps=2
self.export_data = export_data
self.num_steps = num_steps

self.space = CraterLake(crs="epsg:4326", water_height=water_height)
self.space = CraterLake(crs="epsg:4326", water_height=water_height, model=self)
self.schedule = mesa.time.RandomActivation(self)
self.datacollector = mesa.DataCollector(
{
Expand All @@ -73,7 +76,8 @@ def __init__(self, rain_rate=500, water_height=5, export_data=False, num_steps=2
}
)

self.space.set_elevation_layer("data/elevation.asc.gz", crs="epsg:4326")
data_path = script_directory / "../data/elevation.asc.gz"
self.space.set_elevation_layer(data_path, crs="epsg:4326")

@property
def contained(self):
Expand Down
10 changes: 7 additions & 3 deletions gis/rainfall/rainfall/space.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ class LakeCell(mg.Cell):

def __init__(
self,
model,
pos: mesa.space.Coordinate | None = None,
indices: mesa.space.Coordinate | None = None,
):
super().__init__(pos, indices)
super().__init__(model, pos, indices)
self.elevation = None
self.water_level = None
self.water_level_normalized = None
Expand All @@ -25,14 +26,17 @@ def step(self):


class CraterLake(mg.GeoSpace):
def __init__(self, crs, water_height):
def __init__(self, crs, water_height, model):
super().__init__(crs=crs)
self.model = model
self.water_height = water_height
self.outflow = 0

def set_elevation_layer(self, elevation_gzip_file, crs):
raster_layer = mg.RasterLayer.from_file(
f"/vsigzip/{elevation_gzip_file}", cell_cls=LakeCell, attr_name="elevation"
f"/vsigzip/{elevation_gzip_file}",
cell_cls=LakeCell,
attr_name="elevation",
)
raster_layer.crs = crs
raster_layer.apply_raster(
Expand Down
14 changes: 9 additions & 5 deletions gis/urban_growth/urban_growth/model.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
from pathlib import Path

import mesa
import numpy as np

from .space import City

script_directory = Path(__file__).resolve().parent


class UrbanGrowth(mesa.Model):
def __init__(
Expand Down Expand Up @@ -64,14 +68,14 @@ def _load_data(self) -> None:
width=self.world_width,
height=self.world_height,
crs="epsg:3857",
model=self,
total_bounds=[-901575.0, 1442925.0, -885645.0, 1454745.0],
)

labels = ["urban", "slope", "road1", "excluded", "landuse"]

self.space.load_datasets(
urban_data="data/urban_santafe.asc.gz",
slope_data="data/slope_santafe.asc.gz",
road_data="data/road1_santafe.asc.gz",
excluded_data="data/excluded_santafe.asc.gz",
land_use_data="data/landuse_santafe.asc.gz",
*(script_directory / f"../data/{label}_santafe.asc.gz" for label in labels)
)

def _check_suitability(self) -> None:
Expand Down
7 changes: 4 additions & 3 deletions gis/urban_growth/urban_growth/space.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,10 +26,11 @@ class UrbanCell(mg.Cell):

def __init__(
self,
model: mesa.Model | None = None,
pos: mesa.space.Coordinate | None = None,
indices: mesa.space.Coordinate | None = None,
):
super().__init__(pos, indices)
super().__init__(model, pos, indices)
self.urban = None
self.slope = None
self.road_1 = None
Expand Down Expand Up @@ -78,10 +79,10 @@ def _edge_growth(self) -> None:


class City(mg.GeoSpace):
def __init__(self, width, height, crs, total_bounds):
def __init__(self, width, height, crs, total_bounds, model):
super().__init__(crs=crs)
self.add_layer(
mg.RasterLayer(width, height, crs, total_bounds, cell_cls=UrbanCell)
mg.RasterLayer(width, height, crs, total_bounds, model, cell_cls=UrbanCell)
)

def load_datasets(
Expand Down

0 comments on commit 3d6e54e

Please sign in to comment.