Polish curses dashboard warnings and turbine/generator layout
This commit is contained in:
@@ -486,33 +486,29 @@ class ReactorDashboard:
|
|||||||
[
|
[
|
||||||
("Turbines", " ".join(self._turbine_status_lines())),
|
("Turbines", " ".join(self._turbine_status_lines())),
|
||||||
("Rated Elec", f"{len(self.reactor.turbines)*self.reactor.turbines[0].rated_output_mw:7.1f} MW"),
|
("Rated Elec", f"{len(self.reactor.turbines)*self.reactor.turbines[0].rated_output_mw:7.1f} MW"),
|
||||||
("Steam Avail", f"{self._steam_available_power(state):7.1f} MW"),
|
|
||||||
("Unit1 Elec", f"{state.turbines[0].electrical_output_mw:7.1f} MW" if state.turbines else "n/a"),
|
|
||||||
(
|
(
|
||||||
"Unit2 Elec",
|
"Steam",
|
||||||
f"{state.turbines[1].electrical_output_mw:7.1f} MW" if len(state.turbines) > 1 else "n/a",
|
f"h={state.turbines[0].steam_enthalpy:5.0f} kJ/kg avail {self._steam_available_power(state):6.1f} MW "
|
||||||
|
f"flow {state.secondary_loop.mass_flow_rate * max(0.0, state.secondary_loop.steam_quality):6.0f} kg/s"
|
||||||
|
if state.turbines
|
||||||
|
else "n/a",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"Unit3 Elec",
|
"Units Elec",
|
||||||
f"{state.turbines[2].electrical_output_mw:7.1f} MW" if len(state.turbines) > 2 else "n/a",
|
" ".join([f"{t.electrical_output_mw:6.1f}MW" for t in state.turbines]) if state.turbines else "n/a",
|
||||||
),
|
),
|
||||||
("Throttle", f"{self.reactor.turbines[0].throttle:5.2f}" if self.reactor.turbines else "n/a"),
|
("Throttle", f"{self.reactor.turbines[0].throttle:5.2f}" if self.reactor.turbines else "n/a"),
|
||||||
(
|
(
|
||||||
"Condenser",
|
"Condenser",
|
||||||
(
|
(
|
||||||
f"P={state.turbines[0].condenser_pressure:4.2f}/{constants.CONDENSER_MAX_PRESSURE_MPA:4.2f} MPa "
|
f"P={state.turbines[0].condenser_pressure:4.2f}/{constants.CONDENSER_MAX_PRESSURE_MPA:4.2f} MPa "
|
||||||
f"T={state.turbines[0].condenser_temperature:6.1f}/{constants.CONDENSER_COOLING_WATER_TEMP_K:6.1f}K "
|
f"T={state.turbines[0].condenser_temperature:6.1f}K Foul={state.turbines[0].fouling_penalty*100:4.1f}%"
|
||||||
f"Foul={state.turbines[0].fouling_penalty*100:4.1f}%"
|
|
||||||
)
|
)
|
||||||
if state.turbines
|
if state.turbines
|
||||||
else "n/a",
|
else "n/a",
|
||||||
),
|
),
|
||||||
("Electrical", f"{state.total_electrical_output():7.1f} MW"),
|
("Electrical", f"{state.total_electrical_output():7.1f} MW | Load {self._total_load_supplied(state):6.1f}/{self._total_load_demand(state):6.1f} MW"),
|
||||||
("Load", f"{self._total_load_supplied(state):7.1f}/{self._total_load_demand(state):7.1f} MW"),
|
("Consumer", f"{consumer_status} demand {consumer_demand:6.1f} MW"),
|
||||||
("Consumer", f"{consumer_status}"),
|
|
||||||
("Demand", f"{consumer_demand:7.1f} MW"),
|
|
||||||
("Steam Enthalpy", f"{state.turbines[0].steam_enthalpy:7.0f} kJ/kg" if state.turbines else "n/a"),
|
|
||||||
("Steam Flow", f"{state.secondary_loop.mass_flow_rate * max(0.0, state.secondary_loop.steam_quality):7.0f} kg/s"),
|
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
right_y = self._draw_section(right_win, right_y, "Generators", self._generator_lines(state))
|
right_y = self._draw_section(right_win, right_y, "Generators", self._generator_lines(state))
|
||||||
@@ -594,7 +590,7 @@ class ReactorDashboard:
|
|||||||
win: "curses._CursesWindow",
|
win: "curses._CursesWindow",
|
||||||
start_y: int,
|
start_y: int,
|
||||||
title: str,
|
title: str,
|
||||||
lines: list[tuple[str, str] | str],
|
lines: list[tuple[str, str] | tuple[str, str, int] | str],
|
||||||
) -> int:
|
) -> int:
|
||||||
height, width = win.getmaxyx()
|
height, width = win.getmaxyx()
|
||||||
inner_width = width - 4
|
inner_width = width - 4
|
||||||
@@ -605,12 +601,16 @@ class ReactorDashboard:
|
|||||||
for line in lines:
|
for line in lines:
|
||||||
if row >= height - 1:
|
if row >= height - 1:
|
||||||
break
|
break
|
||||||
|
attr = 0
|
||||||
if isinstance(line, tuple):
|
if isinstance(line, tuple):
|
||||||
|
if len(line) == 3:
|
||||||
|
label, value, attr = line
|
||||||
|
else:
|
||||||
label, value = line
|
label, value = line
|
||||||
text = f"{label:<18}: {value}"
|
text = f"{label:<18}: {value}"
|
||||||
else:
|
else:
|
||||||
text = line
|
text = line
|
||||||
win.addstr(row, 4, text[:inner_width])
|
win.addstr(row, 4, text[:inner_width], attr)
|
||||||
row += 1
|
row += 1
|
||||||
return row + 1
|
return row + 1
|
||||||
|
|
||||||
@@ -730,37 +730,44 @@ class ReactorDashboard:
|
|||||||
]
|
]
|
||||||
|
|
||||||
def _protection_lines(self, state: PlantState) -> list[tuple[str, str]]:
|
def _protection_lines(self, state: PlantState) -> list[tuple[str, str]]:
|
||||||
lines: list[tuple[str, str]] = []
|
lines: list[tuple[str, str] | tuple[str, str, int]] = []
|
||||||
lines.append(("SCRAM", "ACTIVE" if self.reactor.shutdown else "CLEAR"))
|
lines.append(("SCRAM", "ACTIVE" if self.reactor.shutdown else "CLEAR", curses.color_pair(4) if self.reactor.shutdown else 0))
|
||||||
if self.reactor.meltdown:
|
if self.reactor.meltdown:
|
||||||
lines.append(("Meltdown", "IN PROGRESS"))
|
lines.append(("Meltdown", "IN PROGRESS", curses.color_pair(4) | curses.A_BOLD))
|
||||||
sec_flow_low = state.secondary_loop.mass_flow_rate <= 1.0 or not self.reactor.secondary_pump_active
|
sec_flow_low = state.secondary_loop.mass_flow_rate <= 1.0 or not self.reactor.secondary_pump_active
|
||||||
heat_sink_risk = sec_flow_low and state.core.power_output_mw > 50.0
|
heat_sink_risk = sec_flow_low and state.core.power_output_mw > 50.0
|
||||||
if heat_sink_risk:
|
if heat_sink_risk:
|
||||||
heat_text = "TRIPPED low secondary flow >50 MW"
|
heat_text = "TRIPPED low secondary flow >50 MW"
|
||||||
|
heat_attr = curses.color_pair(4) | curses.A_BOLD
|
||||||
elif sec_flow_low:
|
elif sec_flow_low:
|
||||||
heat_text = "ARMED (secondary off/low flow)"
|
heat_text = "ARMED (secondary off/low flow)"
|
||||||
|
heat_attr = curses.color_pair(2) | curses.A_BOLD
|
||||||
else:
|
else:
|
||||||
heat_text = "OK"
|
heat_text = "OK"
|
||||||
lines.append(("Heat sink", heat_text))
|
heat_attr = curses.color_pair(3)
|
||||||
|
lines.append(("Heat sink", heat_text, heat_attr))
|
||||||
|
|
||||||
draws = getattr(state, "aux_draws", {}) or {}
|
draws = getattr(state, "aux_draws", {}) or {}
|
||||||
demand = draws.get("total_demand", 0.0)
|
demand = draws.get("total_demand", 0.0)
|
||||||
supplied = draws.get("supplied", 0.0)
|
supplied = draws.get("supplied", 0.0)
|
||||||
if demand > 0.1 and supplied + 1e-6 < demand:
|
if demand > 0.1 and supplied + 1e-6 < demand:
|
||||||
aux_text = f"DEFICIT {supplied:5.1f}/{demand:5.1f} MW"
|
aux_text = f"DEFICIT {supplied:5.1f}/{demand:5.1f} MW"
|
||||||
|
aux_attr = curses.color_pair(2) | curses.A_BOLD
|
||||||
elif demand > 0.1:
|
elif demand > 0.1:
|
||||||
aux_text = f"OK {supplied:5.1f}/{demand:5.1f} MW"
|
aux_text = f"OK {supplied:5.1f}/{demand:5.1f} MW"
|
||||||
|
aux_attr = curses.color_pair(3)
|
||||||
else:
|
else:
|
||||||
aux_text = "Idle"
|
aux_text = "Idle"
|
||||||
lines.append(("Aux power", aux_text))
|
aux_attr = 0
|
||||||
|
lines.append(("Aux power", aux_text, aux_attr))
|
||||||
|
|
||||||
reliefs = []
|
reliefs = []
|
||||||
if self.reactor.primary_relief_open:
|
if self.reactor.primary_relief_open:
|
||||||
reliefs.append("Primary")
|
reliefs.append("Primary")
|
||||||
if self.reactor.secondary_relief_open:
|
if self.reactor.secondary_relief_open:
|
||||||
reliefs.append("Secondary")
|
reliefs.append("Secondary")
|
||||||
lines.append(("Relief valves", ", ".join(reliefs) if reliefs else "Closed"))
|
relief_attr = curses.color_pair(2) | curses.A_BOLD if reliefs else 0
|
||||||
|
lines.append(("Relief valves", ", ".join(reliefs) if reliefs else "Closed", relief_attr))
|
||||||
lines.append(
|
lines.append(
|
||||||
(
|
(
|
||||||
"SCRAM trips",
|
"SCRAM trips",
|
||||||
@@ -874,7 +881,13 @@ class _DashboardLogHandler(logging.Handler):
|
|||||||
msg = self.format(record)
|
msg = self.format(record)
|
||||||
if msg == self._last_msg:
|
if msg == self._last_msg:
|
||||||
self._repeat_count += 1
|
self._repeat_count += 1
|
||||||
if self._repeat_count > 3:
|
if self.buffer and self.buffer[-1].startswith(self._last_msg):
|
||||||
|
try:
|
||||||
|
self.buffer[-1] = f"{self._last_msg} (x{self._repeat_count + 1})"
|
||||||
|
except Exception:
|
||||||
|
self.buffer.append(f"{msg} (x{self._repeat_count + 1})")
|
||||||
|
else:
|
||||||
|
self.buffer.append(f"{msg} (x{self._repeat_count + 1})")
|
||||||
return
|
return
|
||||||
else:
|
else:
|
||||||
self._last_msg = msg
|
self._last_msg = msg
|
||||||
|
|||||||
Reference in New Issue
Block a user