Add spool dynamics for pumps and turbines
This commit is contained in:
@@ -167,50 +167,78 @@ class Reactor:
|
||||
pump_demand = overrides.get("coolant_demand", self.control.coolant_demand(state.primary_loop))
|
||||
if self.primary_pump_active:
|
||||
total_flow = 0.0
|
||||
pressure = 12.0 * pump_demand + 2.0
|
||||
target_pressure = 12.0 * pump_demand + 2.0
|
||||
loop_pressure = 0.5
|
||||
target_flow = self.primary_pump.flow_rate(pump_demand)
|
||||
for idx, pump_state in enumerate(state.primary_pumps):
|
||||
if idx < len(self.primary_pump_units) and self.primary_pump_units[idx]:
|
||||
flow = self.primary_pump.flow_rate(pump_demand)
|
||||
pump_state.active = True
|
||||
pump_state.flow_rate = flow
|
||||
pump_state.pressure = pressure
|
||||
total_flow += flow
|
||||
else:
|
||||
pump_state.active = False
|
||||
pump_state.flow_rate = 0.0
|
||||
pump_state.pressure = state.primary_loop.pressure
|
||||
unit_enabled = idx < len(self.primary_pump_units) and self.primary_pump_units[idx]
|
||||
desired_flow = target_flow if unit_enabled else 0.0
|
||||
desired_pressure = target_pressure if unit_enabled else 0.5
|
||||
pump_state.flow_rate = self._ramp_value(
|
||||
pump_state.flow_rate, desired_flow, dt, self.primary_pump.spool_time
|
||||
)
|
||||
pump_state.pressure = self._ramp_value(
|
||||
pump_state.pressure, desired_pressure, dt, self.primary_pump.spool_time
|
||||
)
|
||||
pump_state.active = unit_enabled or pump_state.flow_rate > 1.0
|
||||
total_flow += pump_state.flow_rate
|
||||
loop_pressure = max(loop_pressure, pump_state.pressure)
|
||||
state.primary_loop.mass_flow_rate = total_flow
|
||||
state.primary_loop.pressure = pressure
|
||||
state.primary_loop.pressure = loop_pressure if total_flow > 0 else self._ramp_value(
|
||||
state.primary_loop.pressure, 0.5, dt, self.primary_pump.spool_time
|
||||
)
|
||||
else:
|
||||
state.primary_loop.mass_flow_rate = 0.0
|
||||
state.primary_loop.pressure = 0.5
|
||||
state.primary_loop.mass_flow_rate = self._ramp_value(
|
||||
state.primary_loop.mass_flow_rate, 0.0, dt, self.primary_pump.spool_time
|
||||
)
|
||||
state.primary_loop.pressure = self._ramp_value(
|
||||
state.primary_loop.pressure, 0.5, dt, self.primary_pump.spool_time
|
||||
)
|
||||
for pump_state in state.primary_pumps:
|
||||
pump_state.active = False
|
||||
pump_state.flow_rate = 0.0
|
||||
pump_state.pressure = state.primary_loop.pressure
|
||||
pump_state.flow_rate = self._ramp_value(
|
||||
pump_state.flow_rate, 0.0, dt, self.primary_pump.spool_time
|
||||
)
|
||||
pump_state.pressure = self._ramp_value(
|
||||
pump_state.pressure, state.primary_loop.pressure, dt, self.primary_pump.spool_time
|
||||
)
|
||||
if self.secondary_pump_active:
|
||||
total_flow = 0.0
|
||||
pressure = 12.0 * 0.75 + 2.0
|
||||
target_pressure = 12.0 * 0.75 + 2.0
|
||||
loop_pressure = 0.5
|
||||
target_flow = self.secondary_pump.flow_rate(0.75)
|
||||
for idx, pump_state in enumerate(state.secondary_pumps):
|
||||
if idx < len(self.secondary_pump_units) and self.secondary_pump_units[idx]:
|
||||
flow = self.secondary_pump.flow_rate(0.75)
|
||||
pump_state.active = True
|
||||
pump_state.flow_rate = flow
|
||||
pump_state.pressure = pressure
|
||||
total_flow += flow
|
||||
else:
|
||||
pump_state.active = False
|
||||
pump_state.flow_rate = 0.0
|
||||
pump_state.pressure = state.secondary_loop.pressure
|
||||
unit_enabled = idx < len(self.secondary_pump_units) and self.secondary_pump_units[idx]
|
||||
desired_flow = target_flow if unit_enabled else 0.0
|
||||
desired_pressure = target_pressure if unit_enabled else 0.5
|
||||
pump_state.flow_rate = self._ramp_value(
|
||||
pump_state.flow_rate, desired_flow, dt, self.secondary_pump.spool_time
|
||||
)
|
||||
pump_state.pressure = self._ramp_value(
|
||||
pump_state.pressure, desired_pressure, dt, self.secondary_pump.spool_time
|
||||
)
|
||||
pump_state.active = unit_enabled or pump_state.flow_rate > 1.0
|
||||
total_flow += pump_state.flow_rate
|
||||
loop_pressure = max(loop_pressure, pump_state.pressure)
|
||||
state.secondary_loop.mass_flow_rate = total_flow
|
||||
state.secondary_loop.pressure = pressure
|
||||
state.secondary_loop.pressure = loop_pressure if total_flow > 0 else self._ramp_value(
|
||||
state.secondary_loop.pressure, 0.5, dt, self.secondary_pump.spool_time
|
||||
)
|
||||
else:
|
||||
state.secondary_loop.mass_flow_rate = 0.0
|
||||
state.secondary_loop.pressure = 0.5
|
||||
state.secondary_loop.mass_flow_rate = self._ramp_value(
|
||||
state.secondary_loop.mass_flow_rate, 0.0, dt, self.secondary_pump.spool_time
|
||||
)
|
||||
state.secondary_loop.pressure = self._ramp_value(
|
||||
state.secondary_loop.pressure, 0.5, dt, self.secondary_pump.spool_time
|
||||
)
|
||||
for pump_state in state.secondary_pumps:
|
||||
pump_state.active = False
|
||||
pump_state.flow_rate = 0.0
|
||||
pump_state.pressure = state.secondary_loop.pressure
|
||||
pump_state.flow_rate = self._ramp_value(
|
||||
pump_state.flow_rate, 0.0, dt, self.secondary_pump.spool_time
|
||||
)
|
||||
pump_state.pressure = self._ramp_value(
|
||||
pump_state.pressure, state.secondary_loop.pressure, dt, self.secondary_pump.spool_time
|
||||
)
|
||||
|
||||
self.thermal.step_core(state.core, state.primary_loop, total_power, dt)
|
||||
if not self.secondary_pump_active or state.secondary_loop.mass_flow_rate <= 1.0:
|
||||
@@ -219,7 +247,7 @@ class Reactor:
|
||||
transferred = heat_transfer(state.primary_loop, state.secondary_loop, total_power)
|
||||
self.thermal.step_secondary(state.secondary_loop, transferred)
|
||||
|
||||
self._step_turbine_bank(state, transferred)
|
||||
self._step_turbine_bank(state, transferred, dt)
|
||||
self._maintenance_tick(state, dt)
|
||||
|
||||
if (not self.secondary_pump_active or state.secondary_loop.mass_flow_rate <= 1.0) and total_power > 50.0:
|
||||
@@ -253,7 +281,7 @@ class Reactor:
|
||||
sum(t.load_demand_mw for t in state.turbines),
|
||||
)
|
||||
|
||||
def _step_turbine_bank(self, state: PlantState, steam_power_mw: float) -> None:
|
||||
def _step_turbine_bank(self, state: PlantState, steam_power_mw: float, dt: float) -> None:
|
||||
if not state.turbines:
|
||||
return
|
||||
active_indices = [
|
||||
@@ -265,9 +293,9 @@ class Reactor:
|
||||
break
|
||||
turbine_state = state.turbines[idx]
|
||||
if idx in active_indices:
|
||||
turbine.step(state.secondary_loop, turbine_state, steam_power_mw=power_per_unit)
|
||||
turbine.step(state.secondary_loop, turbine_state, steam_power_mw=power_per_unit, dt=dt)
|
||||
else:
|
||||
self._reset_turbine_state(turbine_state)
|
||||
self._spin_down_turbine(turbine_state, dt, turbine.spool_time)
|
||||
self._dispatch_consumer_load(state, active_indices)
|
||||
|
||||
def _reset_turbine_state(self, turbine_state: TurbineState) -> None:
|
||||
@@ -276,6 +304,23 @@ class Reactor:
|
||||
turbine_state.load_demand_mw = 0.0
|
||||
turbine_state.load_supplied_mw = 0.0
|
||||
|
||||
@staticmethod
|
||||
def _ramp_value(current: float, target: float, dt: float, time_constant: float) -> float:
|
||||
if time_constant <= 0.0:
|
||||
return target
|
||||
alpha = min(1.0, max(0.0, dt / time_constant))
|
||||
return current + (target - current) * alpha
|
||||
|
||||
def _spin_down_turbine(self, turbine_state: TurbineState, dt: float, time_constant: float) -> None:
|
||||
turbine_state.shaft_power_mw = self._ramp_value(turbine_state.shaft_power_mw, 0.0, dt, time_constant)
|
||||
turbine_state.electrical_output_mw = self._ramp_value(
|
||||
turbine_state.electrical_output_mw, 0.0, dt, time_constant
|
||||
)
|
||||
turbine_state.load_demand_mw = 0.0
|
||||
turbine_state.load_supplied_mw = self._ramp_value(
|
||||
turbine_state.load_supplied_mw, 0.0, dt, time_constant
|
||||
)
|
||||
|
||||
def _dispatch_consumer_load(self, state: PlantState, active_indices: list[int]) -> None:
|
||||
total_electrical = sum(state.turbines[idx].electrical_output_mw for idx in active_indices)
|
||||
if self.consumer:
|
||||
|
||||
Reference in New Issue
Block a user