Skip to content

Commit

Permalink
Remove the restriction that Clock.dt can only be set once -- state up…
Browse files Browse the repository at this point in the history
…daters etc. all work fine with changing dt. Closes #84
  • Loading branch information
Marcel Stimberg committed Sep 23, 2013
1 parent e757728 commit 81356e9
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 32 deletions.
25 changes: 7 additions & 18 deletions brian2/core/clocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

from brian2.utils.logger import get_logger
from brian2.core.names import Nameable
from brian2.units.fundamentalunits import check_units
from brian2.units.fundamentalunits import check_units, Quantity
from brian2.units.allunits import second, msecond

__all__ = ['Clock', 'defaultclock']
Expand Down Expand Up @@ -40,12 +40,12 @@ class Clock(Nameable):
'''

@check_units(dt=second)
def __init__(self, dt=None, name='clock*'):
self._dt_spec = dt
def __init__(self, dt=0.1*msecond, name='clock*'):
self._dt = float(dt)
self.i = 0 #: The time step of the simulation as an integer.
self.i_end = 0 #: The time step the simulation will end as an integer
Nameable.__init__(self, name=name)
logger.debug("Created clock {self.name} with dt={self._dt_spec}".format(self=self))
logger.debug("Created clock {self.name} with dt={self._dt}".format(self=self))

def reinit(self):
'''
Expand Down Expand Up @@ -77,30 +77,19 @@ def _set_t_end(self, end):
self.i_end = int(float(end) / self.dt_)

def _get_dt_(self):
if hasattr(self, '_dt'):
return self._dt
else:
dtspec = self._dt_spec
if dtspec is None:
dtspec = 0.1*msecond
self._dt = float(dtspec)
return self._dt
return self._dt

def _set_dt_(self, dt_):
if hasattr(self, '_dt'):
raise RuntimeError("Cannot change dt, it has already been set to "+str(self.dt))
self._dt = dt_
logger.debug("Set dt for clock {self.name} to {self.dt}".format(self=self))

@check_units(dt=second)
def _set_dt(self, dt):
self.dt_ = float(dt)

dt = property(fget=lambda self: self.dt_*second,
dt = property(fget=lambda self: Quantity(self.dt_, dim=second.dim),
fset=_set_dt,
doc='''The time step of the simulation in seconds
Returns a `Quantity`, and can only
be set once. Defaults to ``0.1*ms``.''',
doc='''The time step of the simulation in seconds.''',
)

dt_ = property(fget=_get_dt_, fset=_set_dt_,
Expand Down
4 changes: 1 addition & 3 deletions brian2/tests/test_clocks.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ def test_clocks():
assert_equal(clock.i_end, 100)
clock.i_end = 200
assert_equal(clock.t_end, 200*ms)
assert_raises(RuntimeError, lambda: setattr(clock, 'dt', 2*ms))
clock.t_ = float(8*ms)
assert_equal(clock.i, 8)
clock.t = 0*ms
Expand All @@ -31,15 +30,14 @@ def test_clocks():
assert_equal(clock.t, 0*ms)

clock = Clock()
assert_equal(clock.dt, 0.1*ms)
clock.dt = 1*ms
assert_equal(clock.dt, 1*ms)
assert_raises(RuntimeError, lambda: setattr(clock, 'dt', 2*ms))

@with_setup(teardown=restore_initial_state)
def test_defaultclock():
defaultclock.dt = 1*ms
assert_equal(defaultclock.dt, 1*ms)
assert_raises(RuntimeError, lambda: setattr(defaultclock, 'dt', 2*ms))

if __name__=='__main__':
test_clocks()
Expand Down
17 changes: 6 additions & 11 deletions docs_sphinx/developer/new_magic_and_clocks.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ New magic and clock behaviour
Clocks
------

The rule for clocks was that
The rule for clocks in Brian 1 was that
you would either specify a clock explicitly, or it would guess it based on the
following rule: if there is no clock defined in the execution frame of the
object being defined, use the default clock; if there is a single clock
Expand All @@ -21,16 +21,11 @@ introduce.

Incidentally, you could also change the dt of a
clock after it had been defined, which would invalidate any state updaters that
were based on a fixed dt. Consequently, in the new design you cannot change the
dt of a clock once it has been specified. This has one huge problem, it would
mean that you couldn't change the dt of the defaultclock, which would be too
annoying in practice. So, you can now leave the dt of a clock unspecified when
you create the clock, and it can be left unspecified until the .dt attribute
is accessed. If no value is specified, it uses ``dt=0.1*ms``, and the .dt
attribute can be set precisely once (if it was left unspecified when created).
This means you can now set ``defaultclock.dt`` precisely once. Again, this is
slightly less flexible than the old system, but avoids many potentially
confusing bugs.
were based on a fixed dt. This is no longer a problem in Brian 2, since state
updaters are re-built at every run so they work fine with a changed dt. It is
important to note that the dt of the respective clock (i.e. in many cases,
``defaultclock.dt``) at the time of the `run` call, not the dt during
the `NeuronGroup` creation, for example, is relevant for the simulation.

Magic
-----
Expand Down

0 comments on commit 81356e9

Please sign in to comment.