Forecast a Sud schedule through its confirm steps, not just up to the first one
A user_wait_for_continue step used to stop SudForecastEstimator.estimate() dead, so the GUI's forecast plot only ever showed the first segment on Load. Model the wait as a zero-delay auto-confirm instead, so the whole schedule's projected curve is visible right away; correct that assumption piecewise as real confirmations actually happen, anchored at the real elapsed time and temperature. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DkkuG48uHFCGKe6dPSERFk
This commit is contained in:
+26
-15
@@ -34,18 +34,23 @@ class SudForecastEstimator:
|
||||
self.theta_amb = theta_amb
|
||||
|
||||
def estimate(self, doc, start_theta=None):
|
||||
"""Returns (t, theta, final_state): t/theta are parallel lists of
|
||||
elapsed simulated seconds and temperature for one piecewise
|
||||
segment of the schedule, starting from doc['steps'][0] - either
|
||||
all the way to the end (final_state is SudState.DONE), or, if a
|
||||
step requires user confirmation, only up to and including that
|
||||
step's hold (final_state is SudState.WAIT_USER). A real user's
|
||||
confirm time can't be forecast, so the simulation simply stops
|
||||
there instead of guessing zero delay or otherwise - the caller is
|
||||
expected to compute the next segment for real once the user
|
||||
actually confirms (see tasks/sud.py's SudTask), anchored at
|
||||
whatever the real elapsed time and temperature are by then,
|
||||
rather than this estimate continuing to guess at it.
|
||||
"""Returns (t, theta, final_state, confirm_points): t/theta are
|
||||
parallel lists of elapsed simulated seconds and temperature,
|
||||
covering doc['steps'] from the start all the way to the end
|
||||
(final_state is SudState.DONE), or, in the pathological case of
|
||||
a step whose target can never actually be reached, wherever
|
||||
MAX_TICKS cut the simulation off.
|
||||
|
||||
A step requiring user confirmation doesn't stop the simulation
|
||||
either - a human's response time genuinely can't be forecast,
|
||||
so it's modeled as zero delay (auto-confirmed the instant that
|
||||
step's hold completes) rather than leaving the estimate stuck
|
||||
there forever. confirm_points records every place that
|
||||
assumption was made, as (step_index, t) pairs, so the caller
|
||||
(tasks/sud.py's SudTask) can correct it once a real
|
||||
confirmation actually happens: truncate the forecast at that
|
||||
point and splice in a freshly anchored simulation of the
|
||||
remaining steps in place of the optimistic guess.
|
||||
|
||||
start_theta defaults to the configured ambient temperature - i.e.
|
||||
a cold start, same as the GUI's static estimate."""
|
||||
@@ -54,7 +59,7 @@ class SudForecastEstimator:
|
||||
|
||||
sud = Sud()
|
||||
if not sud.load(doc) or not sud.schedule:
|
||||
return [0.0], [start_theta], SudState.DONE
|
||||
return [0.0], [start_theta], SudState.DONE, []
|
||||
|
||||
pot = Pot(self.dt, self.plant_params, self.theta_amb)
|
||||
pot.initial(start_theta)
|
||||
@@ -87,10 +92,16 @@ class SudForecastEstimator:
|
||||
|
||||
t = [0.0]
|
||||
theta = [pot.get_temperature()]
|
||||
confirm_points = []
|
||||
|
||||
sud.start()
|
||||
ticks = 0
|
||||
while sud.state not in (SudState.DONE, SudState.WAIT_USER) and ticks < MAX_TICKS:
|
||||
while sud.state != SudState.DONE and ticks < MAX_TICKS:
|
||||
if sud.state == SudState.WAIT_USER:
|
||||
confirm_points.append((sud.index, t[-1]))
|
||||
sud.confirm()
|
||||
continue
|
||||
|
||||
pot.process()
|
||||
tc.set_theta_ist(pot.get_temperature())
|
||||
tc.process()
|
||||
@@ -105,4 +116,4 @@ class SudForecastEstimator:
|
||||
theta.append(pot.get_temperature())
|
||||
ticks += 1
|
||||
|
||||
return t, theta, sud.state
|
||||
return t, theta, sud.state, confirm_points
|
||||
|
||||
Reference in New Issue
Block a user