Loading src/lib.rs +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)] Loading @@ -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, Loading Loading @@ -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) } Loading Loading
src/lib.rs +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)] Loading @@ -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, Loading Loading @@ -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) } Loading