Skip to content

Run at issue #1598

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 2 commits into from
Closed
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 80 additions & 21 deletions brian2/core/clocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,72 @@ def check_dt(new_dt, old_dt, target_t):
f"time {t} is not a multiple of {new}."
)

class ClockArray:
def __init__(self, clock):
self.clock = clock

def __getitem__(self, timestep):
return self.clock.dt * timestep

class EventClock(VariableOwner):
def __init__(self, times, name="eventclock*"):
Nameable.__init__(self, name=name)
self.variables = Variables(self)
self.times = times
self.variables.add_array(
"timestep", size=1, dtype=np.int64, read_only=True, scalar=True
)
self.variables.add_array(
"t",
dimensions=second.dim,
size=1,
dtype=np.float64,
read_only=True,
scalar=True,
)
self.variables["timestep"].set_value(0)
self.variables["t"].set_value(self.times[0])

self.variables.add_constant("N", value=1)

self._enable_group_attributes()

self._i_end = None
logger.diagnostic(f"Created clock {self.name}")

def advance(self):
"""
Advance the clock to the next timestep.
"""
current_timestep = self.variables["timestep"].get_value()
next_timestep = current_timestep + 1
if self._i_end is not None and next_timestep > self._i_end:
raise StopIteration("Clock has reached the end of its available times.")
else:
self.variables["timestep"].set_value(next_timestep)
self.variables["t"].set_value(self.times[next_timestep])

@check_units(start=second, end=second)
def set_interval(self, start, end):
"""
Set the start and end time of the simulation.
"""
# For an EventClock with explicit times, find nearest indices
if not isinstance(self.times, ClockArray):
# Find closest time indices
start_idx = np.searchsorted(self.times, float(start))
end_idx = np.searchsorted(self.times, float(end))

self.variables["timestep"].set_value(start_idx)
self.variables["t"].set_value(self.times[start_idx])
self._i_end = end_idx - 1 # -1 since we want to include this step
else:
# For regular clocks, delegate to the specific implementation
# This will be handled by child classes that implement ClockArray
pass

class Clock(VariableOwner):

class RegularClock(EventClock):
"""
An object that holds the simulation time and the time step.

Expand All @@ -82,23 +146,13 @@ class Clock(VariableOwner):
point values. The value of ``epsilon`` is ``1e-14``.
"""

def __init__(self, dt, name="clock*"):
def __init__(self, dt, name="regularclock*"):
# We need a name right away because some devices (e.g. cpp_standalone)
# need a name for the object when creating the variables
Nameable.__init__(self, name=name)
self._old_dt = None
self.variables = Variables(self)
self.variables.add_array(
"timestep", size=1, dtype=np.int64, read_only=True, scalar=True
)
self.variables.add_array(
"t",
dimensions=second.dim,
size=1,
dtype=np.float64,
read_only=True,
scalar=True,
)
self._dt = float(dt)
self._old_dt = None # Initialize _old_dt to None
times = ClockArray(self)
super().__init__(times, name=name)
self.variables.add_array(
"dt",
dimensions=second.dim,
Expand All @@ -109,10 +163,6 @@ def __init__(self, dt, name="clock*"):
constant=True,
scalar=True,
)
self.variables.add_constant("N", value=1)
self._enable_group_attributes()
self.dt = dt
logger.diagnostic(f"Created clock {self.name} with dt={self.dt}")

@check_units(t=second)
def _set_t_update_dt(self, target_t=0 * second):
Expand All @@ -129,7 +179,10 @@ def _set_t_update_dt(self, target_t=0 * second):
# update them via the variables object directly
self.variables["timestep"].set_value(new_timestep)
self.variables["t"].set_value(new_timestep * new_dt)
logger.diagnostic(f"Setting Clock {self.name} to t={self.t}, dt={self.dt}")
# Use self.variables["t"].get_value() instead of self.t for logging
t_value = self.variables["t"].get_value()
dt_value = self.variables["dt"].get_value()
logger.diagnostic(f"Setting Clock {self.name} to t={t_value}, dt={dt_value}")

def _calc_timestep(self, target_t):
"""
Expand Down Expand Up @@ -211,6 +264,12 @@ def set_interval(self, start, end):
epsilon_dt = 1e-4


class Clock(RegularClock): # Fixed the typo here
def __init__(self, dt, name="clock*"):
super().__init__(dt, name)



class DefaultClockProxy:
"""
Method proxy to access the defaultclock of the currently active device
Expand Down
Loading