-
Notifications
You must be signed in to change notification settings - Fork 239
Fix issue run at #1602
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
base: master
Are you sure you want to change the base?
Fix issue run at #1602
Changes from 3 commits
738d92e
f4c7eb0
a42c5f8
f8975be
1b5a0cf
9019e10
a586a11
629b0fa
4b51bbe
46f34ad
ceeed3d
9a20d0c
a842da8
37fbafe
8bc0dfe
dd43b8c
7c37d40
fd4b352
bd16629
2402c23
2085b7f
49b5f71
c30592b
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -61,8 +61,98 @@ 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 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should probably sort these times (given that we assume them to be sorted later). Also, maybe include a check that it does not contain the same time twice? |
||
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().item() | ||
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. | ||
""" | ||
|
||
if not isinstance(self.times, ClockArray): | ||
|
||
class Clock(VariableOwner): | ||
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 | ||
else: | ||
|
||
pass | ||
|
||
def __lt__(self, other): | ||
return self.variables["t"].get_value().item() < other.variables["t"].get_value().item() | ||
|
||
def __eq__(self, other): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While I get the appeal of using |
||
t1 = self.variables["t"].get_value().item() | ||
t2 = other.variables["t"].get_value().item() | ||
|
||
if hasattr(self, 'dt'): | ||
dt = self.variables["dt"].get_value().item() | ||
return abs(t1 - t2) / dt < self.epsilon_dt | ||
elif hasattr(other, 'dt'): | ||
dt = other.variables["dt"].get_value().item() | ||
return abs(t1 - t2) / dt < self.epsilon_dt | ||
else: | ||
# Both are pure EventClocks without dt | ||
epsilon = 1e-10 | ||
return abs(t1 - t2) < epsilon | ||
|
||
def __le__(self, other): | ||
return self.__lt__(other) or self.__eq__(other) | ||
|
||
def __gt__(self, other): | ||
return not self.__le__(other) | ||
|
||
def __ge__(self, other): | ||
return not self.__lt__(other) | ||
|
||
|
||
class RegularClock(EventClock): | ||
""" | ||
An object that holds the simulation time and the time step. | ||
|
||
|
@@ -82,23 +172,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 | ||
times = ClockArray(self) | ||
super().__init__(times, name=name) | ||
self.variables.add_array( | ||
"dt", | ||
dimensions=second.dim, | ||
|
@@ -109,10 +189,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): | ||
|
@@ -129,7 +205,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().item() and self.variables["dt"].get_value().item() for logging | ||
t_value = self.variables["t"].get_value().item() | ||
dt_value = self.variables["dt"].get_value().item() | ||
logger.diagnostic(f"Setting Clock {self.name} to t={t_value}, dt={dt_value}") | ||
|
||
def _calc_timestep(self, target_t): | ||
""" | ||
|
@@ -211,6 +290,11 @@ def set_interval(self, start, end): | |
epsilon_dt = 1e-4 | ||
|
||
|
||
class Clock(RegularClock): | ||
def __init__(self, dt, name="clock*"): | ||
super().__init__(dt, name) | ||
|
||
|
||
class DefaultClockProxy: | ||
""" | ||
Method proxy to access the defaultclock of the currently active device | ||
|
@@ -230,4 +314,4 @@ def __setattr__(self, key, value): | |
|
||
|
||
#: The standard clock, used for objects that do not specify any clock or dt | ||
defaultclock = DefaultClockProxy() | ||
defaultclock = DefaultClockProxy() |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1035,21 +1035,17 @@ def after_run(self): | |
obj.after_run() | ||
|
||
def _nextclocks(self): | ||
clocks_times_dt = [ | ||
(c, self._clock_variables[c][1][0], self._clock_variables[c][2][0]) | ||
for c in self._clocks | ||
] | ||
minclock, min_time, minclock_dt = min(clocks_times_dt, key=lambda k: k[1]) | ||
|
||
minclock = min(self._clocks) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. While this (i.e. defining |
||
|
||
curclocks = { | ||
clock | ||
for clock, time, dt in clocks_times_dt | ||
if ( | ||
time == min_time | ||
or abs(time - min_time) / min(minclock_dt, dt) < Clock.epsilon_dt | ||
) | ||
for clock in self._clocks | ||
if clock == minclock | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See my comment about |
||
} | ||
|
||
return minclock, curclocks | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nothing to worry about before the PR is finalized, but have a look at our documentation on how to enable |
||
@device_override("network_run") | ||
@check_units(duration=second, report_period=second) | ||
def run( | ||
|
Uh oh!
There was an error while loading. Please reload this page.