Commit efc7c457 authored by Turner, Sean's avatar Turner, Sean
Browse files

effective power fix

parent 24bc7847
Loading
Loading
Loading
Loading
+1 −3
Original line number Diff line number Diff line
@@ -308,7 +308,6 @@ fn simulate_timestep(
        let mut head;
        let mut release;
        let mut target_release;
        let mut effective_power;
        let mut spill;

        for _ in 0..MAX_ITER {
@@ -322,7 +321,6 @@ fn simulate_timestep(
                &reservoir.hpf_q,
            );
            target_release = release_result.release;
            effective_power = release_result.effective_power;

            release = if below_power_pool {
                0.0
@@ -367,7 +365,7 @@ fn simulate_timestep(
            &reservoir.hpf_q,
        );
        target_release = release_result.release;
        effective_power = release_result.effective_power;
        let effective_power = release_result.effective_power;

        release = if below_power_pool {
            0.0
+66 −1
Original line number Diff line number Diff line
@@ -12,7 +12,30 @@ import pandas as pd
import pytest

import powersheds
from helpers import make_reservoir, make_cascade, run_single_reservoir
from helpers import (
    DEFAULT_HPF_H,
    DEFAULT_HPF_P,
    DEFAULT_HPF_Q,
    make_reservoir,
    make_cascade,
    run_single_reservoir,
)


def _interp_linear(x, xs, ys):
    """Simple clamped linear interpolation mirroring the Rust helper."""
    if x <= xs[0]:
        return ys[0]
    if x >= xs[-1]:
        return ys[-1]

    for i in range(len(xs) - 1):
        if xs[i] <= x <= xs[i + 1]:
            x1, x2 = xs[i], xs[i + 1]
            y1, y2 = ys[i], ys[i + 1]
            return y1 + (x - x1) * (y2 - y1) / (x2 - x1)

    return ys[0]


# =============================================================================
@@ -140,6 +163,48 @@ class TestConvergence:
                f"NaN in tailwater_elevation at t={t}"
            )

    def test_tailwater_uses_converged_outflow_not_first_pass_guess(self):
        """Tailwater should reflect the converged fixed point, not a single pass.

        With a steep TW curve and high target power, the first-pass TW estimate
        from the initial head differs materially from the converged TW. This
        test fails if the model stops after the initial guess instead of
        iterating release/head/TW to consistency.
        """
        tw_outflow = [0.0, 100.0, 200.0]
        tw_elev = [140.0, 155.0, 170.0]
        target_power = 100.0

        result = run_single_reservoir(
            n_hours=1,
            capacity=1000.0,  # avoid spill so TW depends only on release
            catchment_inflow=[10.0],
            target_power=[target_power],
            max_release=[100.0],
            set_tw_outflow=tw_outflow,
            set_tw_elevation=tw_elev,
        )

        initial_tw = _interp_linear(0.0, tw_outflow, tw_elev)
        initial_head = 200.0 - initial_tw
        first_pass_release = powersheds.compute_release(
            target_power,
            initial_head,
            DEFAULT_HPF_H,
            DEFAULT_HPF_P,
            DEFAULT_HPF_Q,
        )
        first_pass_outflow_cumecs = first_pass_release * 1_000_000.0 / 3600.0
        first_pass_tw = _interp_linear(first_pass_outflow_cumecs, tw_outflow, tw_elev)

        final_release = result["release"][0]
        final_tw = result["tailwater_elevation"][0]
        final_outflow_cumecs = final_release * 1_000_000.0 / 3600.0
        fixed_point_tw = _interp_linear(final_outflow_cumecs, tw_outflow, tw_elev)

        assert final_tw == pytest.approx(fixed_point_tw, abs=0.2)
        assert abs(final_tw - first_pass_tw) > 1.0


# =============================================================================
# Mass balance preserved