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

rust return named outputs

parent 6b3965c6
Loading
Loading
Loading
Loading
+60 −42
Original line number Diff line number Diff line
use pyo3::prelude::*;
use pyo3::exceptions::PyValueError;
use pyo3::IntoPyObject;
use std::collections::HashMap;

#[derive(FromPyObject)]
@@ -21,6 +22,13 @@ struct ReservoirState {
    spill: f64,
}

#[derive(FromPyObject, IntoPyObject)]
struct ReservoirResults {
    storage: Vec<f64>,
    release: Vec<f64>,
    spill: Vec<f64>,
}

fn simulate_timestep(
    specs: &ReservoirSpecs,
    inflow: f64,
@@ -55,59 +63,69 @@ fn simulate_cascade(
    inflow: Vec<f64>,
    release_target: Vec<f64>,
    cascade_specs: CascadeSpecs,
) -> PyResult<(Vec<f64>, Vec<f64>, Vec<f64>, Vec<f64>, Vec<f64>, Vec<f64>)> {

) -> PyResult<HashMap<String, ReservoirResults>> {

    if inflow.len() != release_target.len() {
        return Err(PyValueError::new_err("Input vectors must have the same length"));
    }

    let wolf_creek = cascade_specs.reservoirs.get("Wolf_Creek")
    .ok_or_else(|| PyValueError::new_err("Missing Wolf Creek specifications"))?;
    
    let cordell_hull = cascade_specs.reservoirs.get("Cordell_Hull")
    .ok_or_else(|| PyValueError::new_err("Missing Cordell Hull specifications"))?;
    let n = inflow.len();
    let mut results = HashMap::new();

    let reservoir_names: Vec<&String> = cascade_specs.reservoirs.keys().collect();

    let n = inflow.len();
    let mut wc_storage = vec![0.0; n];
    let mut wc_release = vec![0.0; n];
    let mut wc_spill = vec![0.0; n];
    let mut ch_storage = vec![0.0; n];
    let mut ch_release = vec![0.0; n];
    let mut ch_spill = vec![0.0; n];
    for name in reservoir_names.iter() {
        let specs = &cascade_specs.reservoirs[*name];
        let mut storage = vec![0.0; n];
        storage[0] = specs.initial_storage;
        results.insert(name.to_string(), ReservoirResults {
            storage,
            release: vec![0.0; n],
            spill: vec![0.0; n],
        });
    }

    wc_storage[0] = wolf_creek.initial_storage;
    ch_storage[0] = cordell_hull.initial_storage;

    for t in 0..n {
        // Wolf Creek simulation
        let wc_state = simulate_timestep(
            &wolf_creek,
            inflow[t],
        for (i, name) in reservoir_names.iter().enumerate() {

            let specs = &cascade_specs.reservoirs[*name];
            
            // Calculate inflow: use input inflow for first reservoir,
            // otherwise use outflow from previous reservoir
            let current_inflow = if i == 0 {
                inflow[t]
            } else {
                let prev_name = &reservoir_names[i-1];
                let prev_results = &results[*prev_name];
                prev_results.release[t] + prev_results.spill[t]
            };

            // Get previous storage for this reservoir
            let current_results = results.get_mut(*name).unwrap();  // Changed to use ReservoirResults
            let previous_storage = if t == 0 { 
                specs.initial_storage 
            } else { 
                current_results.storage[t-1]  
            };

            // Simulate this timestep
            let state = simulate_timestep(
                specs,
                current_inflow,
                release_target[t],
            if t == 0 { wolf_creek.initial_storage } else { wc_storage[t-1] },
                previous_storage,
            );

        wc_storage[t] = wc_state.storage;
        wc_release[t] = wc_state.release;
        wc_spill[t] = wc_state.spill;

        // Cordell Hull simulation
        let ch_inflow = wc_state.release + wc_state.spill;
        let ch_state = simulate_timestep(
            &cordell_hull,
            ch_inflow,
            release_target[t],  // Note: might want separate release targets later
            if t == 0 { cordell_hull.initial_storage } else { ch_storage[t-1] },
        );
            // Store results
            current_results.storage[t] = state.storage;
            current_results.release[t] = state.release;
            current_results.spill[t] = state.spill;

        ch_storage[t] = ch_state.storage;
        ch_release[t] = ch_state.release;
        ch_spill[t] = ch_state.spill;
    }
}

    Ok((wc_storage, wc_release, wc_spill, ch_storage, ch_release, ch_spill))
Ok(results)

}