Skip to content

Commit

Permalink
Time-keeping removed from context.
Browse files Browse the repository at this point in the history
  • Loading branch information
Tyler Coles committed May 23, 2024
1 parent 8104bae commit 0627fde
Show file tree
Hide file tree
Showing 6 changed files with 32 additions and 46 deletions.
28 changes: 1 addition & 27 deletions epymorph/engine/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@
with simulation data, for example, accessing geo and parameter attributes,
calculating the simulation clock, initializing the world state, and so on.
"""
from datetime import timedelta
from functools import cached_property
from typing import Iterable

import numpy as np
from numpy.typing import NDArray

Expand All @@ -15,7 +11,7 @@
from epymorph.geo.geo import Geo
from epymorph.params import NormalizedParams, NormalizedParamsDict
from epymorph.simulation import (CachingGetAttributeMixin, GeoData,
SimDimensions, Tick, TickDelta)
SimDimensions)


class RumeContext(CachingGetAttributeMixin):
Expand Down Expand Up @@ -47,15 +43,6 @@ def __init__(
self._params = params
CachingGetAttributeMixin.__init__(self, geo, params, dim)

def clock(self) -> Iterable[Tick]:
"""Generate the simulation clock signal: a series of Tick objects describing each time step."""
return _simulation_clock(self.dim)

def resolve_tick(self, tick: Tick, delta: TickDelta) -> int:
"""Add a delta to a tick to get the index of the resulting tick."""
return -1 if delta.days == -1 else \
tick.index - tick.step + (self.dim.tau_steps * delta.days) + delta.step

def update_param(self, attr_name: str, value: AttributeArray) -> None:
"""Updates a params value."""
self._params[attr_name] = value.copy()
Expand All @@ -79,16 +66,3 @@ def compartment_mobility(self) -> NDArray[np.bool_]:
def params(self) -> NormalizedParams:
"""The params values."""
return self._params


def _simulation_clock(dim: SimDimensions) -> Iterable[Tick]:
"""Generator for the sequence of ticks which makes up the simulation clock."""
one_day = timedelta(days=1)
tau_steps = list(enumerate(dim.tau_step_lengths))
curr_index = 0
curr_date = dim.start_date
for day in range(dim.days):
for step, tau in tau_steps:
yield Tick(curr_index, day, curr_date, step, tau)
curr_index += 1
curr_date += one_day
4 changes: 2 additions & 2 deletions epymorph/engine/mm_exec.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
from epymorph.movement.movement_model import (MovementContext, MovementModel,
PredefData, TravelClause)
from epymorph.movement.parser import MovementSpec
from epymorph.simulation import Tick
from epymorph.simulation import Tick, resolve_tick
from epymorph.util import row_normalize


Expand Down Expand Up @@ -173,7 +173,7 @@ def apply(self, world: World, tick: Tick) -> None:
travelers = clause_event.actual

returns = clause.returns(self._ctx, tick)
return_tick = self._ctx.resolve_tick(tick, returns)
return_tick = resolve_tick(self._ctx.dim, tick, returns)
world.apply_travel(travelers, return_tick)
total += travelers.sum()

Expand Down
4 changes: 2 additions & 2 deletions epymorph/engine/standard_sim.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
from epymorph.movement.movement_model import MovementModel, validate_mm
from epymorph.movement.parser import MovementSpec
from epymorph.params import NormalizedParamsDict, RawParams, normalize_params
from epymorph.simulation import TimeFrame
from epymorph.simulation import TimeFrame, simulation_clock
from epymorph.util import Subscriber


Expand Down Expand Up @@ -157,7 +157,7 @@ def run(self) -> Output:

self.on_start.publish(OnStart(dim=ctx.dim, time_frame=self.time_frame))

for tick in ctx.clock():
for tick in simulation_clock(self.dim):
# First do movement
with error_gate("executing the movement model", MmSimException, AttributeException):
movement_exec.apply(world, tick)
Expand Down
4 changes: 0 additions & 4 deletions epymorph/movement/movement_model.py
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,6 @@ def version(self) -> int:
"""
raise NotImplementedError

@abstractmethod
def resolve_tick(self, tick: Tick, delta: TickDelta) -> int:
"""Add a delta to a tick to get the index of the resulting tick."""


PredefData = ParamsData
PredefClause = Callable[[MovementContext], PredefData]
Expand Down
32 changes: 25 additions & 7 deletions epymorph/simulation.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,24 +3,23 @@
import textwrap
from abc import abstractmethod
from dataclasses import dataclass, field
from datetime import date
from functools import partial
from datetime import date, timedelta
from importlib import reload
from typing import Any, Callable, Literal, Mapping, NamedTuple, Protocol, Self
from typing import (Callable, Iterable, Literal, Mapping, NamedTuple, Protocol,
Self)

import numpy as np
import sympy
from numpy.random import SeedSequence

from epymorph.code import ImmutableNamespace, base_namespace
from epymorph.data_shape import (AttributeGetter, DataShape, Shapes,
SimDimensions)
from epymorph.data_type import (AttributeArray, AttributeScalar, DataDType,
DataPyScalar, SimDType, dtype_as_np,
dtype_check, dtype_str)
DataPyScalar, dtype_as_np, dtype_check,
dtype_str)
from epymorph.error import AttributeException
from epymorph.sympy_shim import to_symbol
from epymorph.util import MemoDict, pairwise_haversine, row_normalize
from epymorph.util import MemoDict


class DataSource(Protocol):
Expand Down Expand Up @@ -186,6 +185,25 @@ class TickDelta(NamedTuple):
"""


def resolve_tick(dim: SimDimensions, tick: Tick, delta: TickDelta) -> int:
"""Add a delta to a tick to get the index of the resulting tick."""
return -1 if delta.days == -1 else \
tick.index - tick.step + (dim.tau_steps * delta.days) + delta.step


def simulation_clock(dim: SimDimensions) -> Iterable[Tick]:
"""Generator for the sequence of ticks which makes up the simulation clock."""
one_day = timedelta(days=1)
tau_steps = list(enumerate(dim.tau_step_lengths))
curr_index = 0
curr_date = dim.start_date
for day in range(dim.days):
for step, tau in tau_steps:
yield Tick(curr_index, day, curr_date, step, tau)
curr_index += 1
curr_date += one_day


class CachingGetAttributeMixin:
"""
A mixin for adding cached attribute getter behavior to a context class.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,7 @@
import unittest
from datetime import date

from epymorph.data_shape import SimDimensions
from epymorph.engine.context import _simulation_clock
from epymorph.simulation import Tick
from epymorph.simulation import SimDimensions, Tick, simulation_clock


class TestClock(unittest.TestCase):
Expand All @@ -16,7 +14,7 @@ def test_clock(self):
# sim clock doesn't depend on GEO/IPM dimensions
nodes=99, compartments=99, events=99,
)
clock = _simulation_clock(dim)
clock = simulation_clock(dim)
act = list(clock)
exp = [
Tick(0, 0, date(2023, 1, 1), 0, 2 / 3),
Expand Down

0 comments on commit 0627fde

Please sign in to comment.