From f28360c5ae3ac06f5a09e28d7e3c6696d97211b2 Mon Sep 17 00:00:00 2001 From: James Tomlinson Date: Wed, 7 Aug 2024 12:18:53 +0100 Subject: [PATCH] feat: Add a parent namespace to Parameters. (#234) Core Parameters can now be identified with an optional parent string. This is helpful for creating Parameters in compound nodes without risking naming conflicts with the user's own parameter names. Fixes #179. --- pywr-core/src/aggregated_node.rs | 2 +- pywr-core/src/network.rs | 25 ++-- pywr-core/src/parameters/aggregated.rs | 4 +- pywr-core/src/parameters/aggregated_index.rs | 4 +- pywr-core/src/parameters/array.rs | 11 +- pywr-core/src/parameters/asymmetric.rs | 6 +- pywr-core/src/parameters/constant.rs | 6 +- .../parameters/control_curves/apportion.rs | 4 +- .../src/parameters/control_curves/index.rs | 4 +- .../parameters/control_curves/interpolated.rs | 4 +- .../parameters/control_curves/piecewise.rs | 8 +- .../src/parameters/control_curves/simple.rs | 4 +- .../control_curves/volume_between.rs | 4 +- pywr-core/src/parameters/delay.rs | 9 +- pywr-core/src/parameters/discount_factor.rs | 8 +- pywr-core/src/parameters/division.rs | 4 +- pywr-core/src/parameters/hydropower.rs | 4 +- pywr-core/src/parameters/indexed_array.rs | 4 +- pywr-core/src/parameters/interpolated.rs | 4 +- pywr-core/src/parameters/max.rs | 4 +- pywr-core/src/parameters/min.rs | 4 +- pywr-core/src/parameters/mod.rs | 111 +++++++++++------- pywr-core/src/parameters/negative.rs | 4 +- pywr-core/src/parameters/negativemax.rs | 4 +- pywr-core/src/parameters/negativemin.rs | 4 +- pywr-core/src/parameters/offset.rs | 4 +- pywr-core/src/parameters/polynomial.rs | 4 +- pywr-core/src/parameters/profiles/daily.rs | 4 +- pywr-core/src/parameters/profiles/monthly.rs | 4 +- pywr-core/src/parameters/profiles/rbf.rs | 4 +- .../parameters/profiles/uniform_drawdown.rs | 4 +- pywr-core/src/parameters/profiles/weekly.rs | 4 +- pywr-core/src/parameters/py.rs | 22 +++- pywr-core/src/parameters/rhai.rs | 6 +- pywr-core/src/parameters/threshold.rs | 12 +- pywr-core/src/parameters/vector.rs | 4 +- pywr-core/src/test_utils.rs | 19 +-- pywr-schema/src/metric.rs | 14 +-- pywr-schema/src/nodes/delay.rs | 14 +-- pywr-schema/src/nodes/piecewise_storage.rs | 20 ++-- pywr-schema/src/nodes/turbine.rs | 7 +- pywr-schema/src/parameters/aggregated.rs | 12 +- .../src/parameters/asymmetric_switch.rs | 2 +- pywr-schema/src/parameters/control_curves.rs | 17 ++- pywr-schema/src/parameters/core.rs | 17 +-- pywr-schema/src/parameters/delay.rs | 7 +- pywr-schema/src/parameters/discount_factor.rs | 6 +- pywr-schema/src/parameters/hydropower.rs | 2 +- pywr-schema/src/parameters/indexed_array.rs | 6 +- pywr-schema/src/parameters/interpolated.rs | 2 +- pywr-schema/src/parameters/mod.rs | 2 +- pywr-schema/src/parameters/offset.rs | 6 +- pywr-schema/src/parameters/polynomial.rs | 2 +- pywr-schema/src/parameters/profiles.rs | 17 ++- pywr-schema/src/parameters/python.rs | 13 +- pywr-schema/src/parameters/tables.rs | 8 +- pywr-schema/src/parameters/thresholds.rs | 2 +- pywr-schema/src/timeseries/mod.rs | 14 +-- 58 files changed, 325 insertions(+), 206 deletions(-) diff --git a/pywr-core/src/aggregated_node.rs b/pywr-core/src/aggregated_node.rs index 446ec855..aa57ad0c 100644 --- a/pywr-core/src/aggregated_node.rs +++ b/pywr-core/src/aggregated_node.rs @@ -576,7 +576,7 @@ mod tests { network.connect_nodes(input_node, link_node1).unwrap(); network.connect_nodes(link_node1, output_node1).unwrap(); - let factor_profile = MonthlyProfileParameter::new("factor-profile", [2.0; 12], None); + let factor_profile = MonthlyProfileParameter::new("factor-profile".into(), [2.0; 12], None); let factor_profile_idx = network.add_simple_parameter(Box::new(factor_profile)).unwrap(); let factors = Some(Factors::Ratio(vec![factor_profile_idx.into(), 1.0.into()])); diff --git a/pywr-core/src/network.rs b/pywr-core/src/network.rs index 48492b9d..4dd97e90 100644 --- a/pywr-core/src/network.rs +++ b/pywr-core/src/network.rs @@ -5,7 +5,9 @@ use crate::edge::{Edge, EdgeIndex, EdgeVec}; use crate::metric::{MetricF64, SimpleMetricF64}; use crate::models::ModelDomain; use crate::node::{Node, NodeVec, StorageInitialVolume}; -use crate::parameters::{GeneralParameterType, ParameterCollection, ParameterIndex, ParameterStates, VariableConfig}; +use crate::parameters::{ + GeneralParameterType, ParameterCollection, ParameterIndex, ParameterName, ParameterStates, VariableConfig, +}; use crate::recorders::{MetricSet, MetricSetIndex, MetricSetState}; use crate::scenario::ScenarioIndex; use crate::solvers::{MultiStateSolver, Solver, SolverFeatures, SolverTimings}; @@ -1118,7 +1120,7 @@ impl Network { } /// Get a `Parameter` from a parameter's name - pub fn get_parameter_by_name(&self, name: &str) -> Result<&dyn parameters::Parameter, PywrError> { + pub fn get_parameter_by_name(&self, name: &ParameterName) -> Result<&dyn parameters::Parameter, PywrError> { match self.parameters.get_f64_by_name(name) { Some(parameter) => Ok(parameter), None => Err(PywrError::ParameterNotFound(name.to_string())), @@ -1126,7 +1128,7 @@ impl Network { } /// Get a `ParameterIndex` from a parameter's name - pub fn get_parameter_index_by_name(&self, name: &str) -> Result, PywrError> { + pub fn get_parameter_index_by_name(&self, name: &ParameterName) -> Result, PywrError> { match self.parameters.get_f64_index_by_name(name) { Some(idx) => Ok(idx), None => Err(PywrError::ParameterNotFound(name.to_string())), @@ -1142,7 +1144,7 @@ impl Network { } /// Get a `IndexParameter` from a parameter's name - pub fn get_index_parameter_by_name(&self, name: &str) -> Result<&dyn parameters::Parameter, PywrError> { + pub fn get_index_parameter_by_name(&self, name: &ParameterName) -> Result<&dyn parameters::Parameter, PywrError> { match self.parameters.get_usize_by_name(name) { Some(parameter) => Ok(parameter), None => Err(PywrError::ParameterNotFound(name.to_string())), @@ -1150,7 +1152,7 @@ impl Network { } /// Get a `IndexParameterIndex` from a parameter's name - pub fn get_index_parameter_index_by_name(&self, name: &str) -> Result, PywrError> { + pub fn get_index_parameter_index_by_name(&self, name: &ParameterName) -> Result, PywrError> { match self.parameters.get_usize_index_by_name(name) { Some(idx) => Ok(idx), None => Err(PywrError::ParameterNotFound(name.to_string())), @@ -1171,7 +1173,7 @@ impl Network { /// Get a `MultiValueParameterIndex` from a parameter's name pub fn get_multi_valued_parameter_index_by_name( &self, - name: &str, + name: &ParameterName, ) -> Result, PywrError> { match self.parameters.get_multi_index_by_name(name) { Some(idx) => Ok(idx), @@ -1729,7 +1731,7 @@ mod tests { let mut network = Network::default(); let _node_index = network.add_input_node("input", None).unwrap(); - let input_max_flow = parameters::ConstantParameter::new("my-constant", 10.0); + let input_max_flow = parameters::ConstantParameter::new("my-constant".into(), 10.0); let parameter = network.add_const_parameter(Box::new(input_max_flow)).unwrap(); // assign the new parameter to one of the nodes. @@ -1788,7 +1790,10 @@ mod tests { let recorder = AssertionRecorder::new("output-flow", MetricF64::NodeInFlow(idx), expected, None, None); model.network_mut().add_recorder(Box::new(recorder)).unwrap(); - let idx = model.network().get_parameter_index_by_name("total-demand").unwrap(); + let idx = model + .network() + .get_parameter_index_by_name(&"total-demand".into()) + .unwrap(); let expected = Array2::from_elem((366, 10), 12.0); let recorder = AssertionRecorder::new("total-demand", idx.into(), expected, None, None); model.network_mut().add_recorder(Box::new(recorder)).unwrap(); @@ -1846,7 +1851,7 @@ mod tests { // Set-up a control curve that uses the proportional volume // This should be use the initial proportion (100%) on the first time-step, and then the previous day's end value let cc = ControlCurveInterpolatedParameter::new( - "interp", + "interp".into(), MetricF64::DerivedMetric(dm_idx), vec![], vec![100.0.into(), 0.0.into()], @@ -1967,7 +1972,7 @@ mod tests { let mut model = simple_model(1); let variable = ActivationFunction::Unit { min: 0.0, max: 10.0 }; - let input_max_flow = parameters::ConstantParameter::new("my-constant", 10.0); + let input_max_flow = parameters::ConstantParameter::new("my-constant".into(), 10.0); assert!(input_max_flow.can_be_f64_variable()); diff --git a/pywr-core/src/parameters/aggregated.rs b/pywr-core/src/parameters/aggregated.rs index 5d4dbaf4..22cd2328 100644 --- a/pywr-core/src/parameters/aggregated.rs +++ b/pywr-core/src/parameters/aggregated.rs @@ -1,4 +1,4 @@ -use super::{Parameter, ParameterState, PywrError, SimpleParameter}; +use super::{Parameter, ParameterName, ParameterState, PywrError, SimpleParameter}; use crate::metric::{MetricF64, SimpleMetricF64}; use crate::network::Network; use crate::parameters::{GeneralParameter, ParameterMeta}; @@ -41,7 +41,7 @@ impl AggregatedParameter where M: Send + Sync + Clone, { - pub fn new(name: &str, metrics: &[M], agg_func: AggFunc) -> Self { + pub fn new(name: ParameterName, metrics: &[M], agg_func: AggFunc) -> Self { Self { meta: ParameterMeta::new(name), metrics: metrics.to_vec(), diff --git a/pywr-core/src/parameters/aggregated_index.rs b/pywr-core/src/parameters/aggregated_index.rs index 46eb0e00..0722791d 100644 --- a/pywr-core/src/parameters/aggregated_index.rs +++ b/pywr-core/src/parameters/aggregated_index.rs @@ -1,6 +1,6 @@ /// AggregatedIndexParameter /// -use super::{Parameter, ParameterState, PywrError}; +use super::{Parameter, ParameterName, ParameterState, PywrError}; use crate::metric::MetricUsize; use crate::network::Network; use crate::parameters::{GeneralParameter, ParameterMeta}; @@ -41,7 +41,7 @@ pub struct AggregatedIndexParameter { } impl AggregatedIndexParameter { - pub fn new(name: &str, values: Vec, agg_func: AggIndexFunc) -> Self { + pub fn new(name: ParameterName, values: Vec, agg_func: AggIndexFunc) -> Self { Self { meta: ParameterMeta::new(name), values, diff --git a/pywr-core/src/parameters/array.rs b/pywr-core/src/parameters/array.rs index 2e83288b..2163f109 100644 --- a/pywr-core/src/parameters/array.rs +++ b/pywr-core/src/parameters/array.rs @@ -1,5 +1,5 @@ use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -13,7 +13,7 @@ pub struct Array1Parameter { } impl Array1Parameter { - pub fn new(name: &str, array: Array1, timestep_offset: Option) -> Self { + pub fn new(name: ParameterName, array: Array1, timestep_offset: Option) -> Self { Self { meta: ParameterMeta::new(name), array, @@ -60,7 +60,12 @@ pub struct Array2Parameter { } impl Array2Parameter { - pub fn new(name: &str, array: Array2, scenario_group_index: usize, timestep_offset: Option) -> Self { + pub fn new( + name: ParameterName, + array: Array2, + scenario_group_index: usize, + timestep_offset: Option, + ) -> Self { Self { meta: ParameterMeta::new(name), array, diff --git a/pywr-core/src/parameters/asymmetric.rs b/pywr-core/src/parameters/asymmetric.rs index 1d36781f..a830be2f 100644 --- a/pywr-core/src/parameters/asymmetric.rs +++ b/pywr-core/src/parameters/asymmetric.rs @@ -1,6 +1,8 @@ use crate::metric::MetricUsize; use crate::network::Network; -use crate::parameters::{downcast_internal_state_mut, GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{ + downcast_internal_state_mut, GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState, +}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -13,7 +15,7 @@ pub struct AsymmetricSwitchIndexParameter { } impl AsymmetricSwitchIndexParameter { - pub fn new(name: &str, on_parameter: MetricUsize, off_parameter: MetricUsize) -> Self { + pub fn new(name: ParameterName, on_parameter: MetricUsize, off_parameter: MetricUsize) -> Self { Self { meta: ParameterMeta::new(name), on_parameter, diff --git a/pywr-core/src/parameters/constant.rs b/pywr-core/src/parameters/constant.rs index 723b652e..4ad0d9b7 100644 --- a/pywr-core/src/parameters/constant.rs +++ b/pywr-core/src/parameters/constant.rs @@ -1,6 +1,6 @@ use crate::parameters::{ downcast_internal_state_mut, downcast_internal_state_ref, downcast_variable_config_ref, ActivationFunction, - ConstParameter, Parameter, ParameterMeta, ParameterState, VariableConfig, VariableParameter, + ConstParameter, Parameter, ParameterMeta, ParameterName, ParameterState, VariableConfig, VariableParameter, }; use crate::scenario::ScenarioIndex; use crate::state::ConstParameterValues; @@ -16,7 +16,7 @@ pub struct ConstantParameter { type InternalValue = Option; impl ConstantParameter { - pub fn new(name: &str, value: f64) -> Self { + pub fn new(name: ParameterName, value: f64) -> Self { Self { meta: ParameterMeta::new(name), value, @@ -129,7 +129,7 @@ mod tests { let domain = default_domain(); let var = ActivationFunction::Unit { min: 0.0, max: 2.0 }; - let p = ConstantParameter::new("test", 1.0); + let p = ConstantParameter::new("test".into(), 1.0); let mut state = p .setup(domain.time().timesteps(), domain.scenarios().indices().first().unwrap()) .unwrap(); diff --git a/pywr-core/src/parameters/control_curves/apportion.rs b/pywr-core/src/parameters/control_curves/apportion.rs index c897d303..26f208a2 100644 --- a/pywr-core/src/parameters/control_curves/apportion.rs +++ b/pywr-core/src/parameters/control_curves/apportion.rs @@ -1,6 +1,6 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::{MultiValue, State}; use crate::timestep::Timestep; @@ -22,7 +22,7 @@ pub struct ApportionParameter { } impl ApportionParameter { - pub fn new(name: &str, metric: MetricF64, control_curve: MetricF64) -> Self { + pub fn new(name: ParameterName, metric: MetricF64, control_curve: MetricF64) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/control_curves/index.rs b/pywr-core/src/parameters/control_curves/index.rs index 0333b180..65cfe4a4 100644 --- a/pywr-core/src/parameters/control_curves/index.rs +++ b/pywr-core/src/parameters/control_curves/index.rs @@ -1,6 +1,6 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -13,7 +13,7 @@ pub struct ControlCurveIndexParameter { } impl ControlCurveIndexParameter { - pub fn new(name: &str, metric: MetricF64, control_curves: Vec) -> Self { + pub fn new(name: ParameterName, metric: MetricF64, control_curves: Vec) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/control_curves/interpolated.rs b/pywr-core/src/parameters/control_curves/interpolated.rs index 9ec8da30..eb5c3467 100644 --- a/pywr-core/src/parameters/control_curves/interpolated.rs +++ b/pywr-core/src/parameters/control_curves/interpolated.rs @@ -1,7 +1,7 @@ use crate::metric::MetricF64; use crate::network::Network; use crate::parameters::interpolate::interpolate; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -15,7 +15,7 @@ pub struct ControlCurveInterpolatedParameter { } impl ControlCurveInterpolatedParameter { - pub fn new(name: &str, metric: MetricF64, control_curves: Vec, values: Vec) -> Self { + pub fn new(name: ParameterName, metric: MetricF64, control_curves: Vec, values: Vec) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/control_curves/piecewise.rs b/pywr-core/src/parameters/control_curves/piecewise.rs index 194d535f..06a1fa85 100644 --- a/pywr-core/src/parameters/control_curves/piecewise.rs +++ b/pywr-core/src/parameters/control_curves/piecewise.rs @@ -1,7 +1,7 @@ use crate::metric::MetricF64; use crate::network::Network; use crate::parameters::interpolate::interpolate; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -18,7 +18,7 @@ pub struct PiecewiseInterpolatedParameter { impl PiecewiseInterpolatedParameter { pub fn new( - name: &str, + name: ParameterName, metric: MetricF64, control_curves: Vec, values: Vec<[f64; 2]>, @@ -85,12 +85,12 @@ mod test { let mut model = simple_model(1); // Create an artificial volume series to use for the interpolation test - let volume = Array1Parameter::new("test-x", Array1::linspace(1.0, 0.0, 21), None); + let volume = Array1Parameter::new("test-x".into(), Array1::linspace(1.0, 0.0, 21), None); let volume_idx = model.network_mut().add_parameter(Box::new(volume)).unwrap(); let parameter = PiecewiseInterpolatedParameter::new( - "test-parameter", + "test-parameter".into(), volume_idx.into(), // Interpolate with the parameter based values vec![0.8.into(), 0.5.into()], vec![[10.0, 1.0], [0.0, 0.0], [-1.0, -10.0]], diff --git a/pywr-core/src/parameters/control_curves/simple.rs b/pywr-core/src/parameters/control_curves/simple.rs index 378fa5c8..064a5ad7 100644 --- a/pywr-core/src/parameters/control_curves/simple.rs +++ b/pywr-core/src/parameters/control_curves/simple.rs @@ -1,6 +1,6 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -14,7 +14,7 @@ pub struct ControlCurveParameter { } impl ControlCurveParameter { - pub fn new(name: &str, metric: MetricF64, control_curves: Vec, values: Vec) -> Self { + pub fn new(name: ParameterName, metric: MetricF64, control_curves: Vec, values: Vec) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/control_curves/volume_between.rs b/pywr-core/src/parameters/control_curves/volume_between.rs index 45eedb12..0ad23e90 100644 --- a/pywr-core/src/parameters/control_curves/volume_between.rs +++ b/pywr-core/src/parameters/control_curves/volume_between.rs @@ -1,5 +1,5 @@ use crate::metric::SimpleMetricF64; -use crate::parameters::{Parameter, ParameterMeta, ParameterState, SimpleParameter}; +use crate::parameters::{Parameter, ParameterMeta, ParameterName, ParameterState, SimpleParameter}; use crate::scenario::ScenarioIndex; use crate::state::SimpleParameterValues; use crate::timestep::Timestep; @@ -14,7 +14,7 @@ pub struct VolumeBetweenControlCurvesParameter { } impl VolumeBetweenControlCurvesParameter { - pub fn new(name: &str, total: M, upper: Option, lower: Option) -> Self { + pub fn new(name: ParameterName, total: M, upper: Option, lower: Option) -> Self { Self { meta: ParameterMeta::new(name), total, diff --git a/pywr-core/src/parameters/delay.rs b/pywr-core/src/parameters/delay.rs index 410d684c..bc828fa4 100644 --- a/pywr-core/src/parameters/delay.rs +++ b/pywr-core/src/parameters/delay.rs @@ -1,7 +1,8 @@ use crate::metric::{MetricF64, SimpleMetricF64}; use crate::network::Network; use crate::parameters::{ - downcast_internal_state_mut, GeneralParameter, Parameter, ParameterMeta, ParameterState, SimpleParameter, + downcast_internal_state_mut, GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState, + SimpleParameter, }; use crate::scenario::ScenarioIndex; use crate::state::{SimpleParameterValues, State}; @@ -17,7 +18,7 @@ pub struct DelayParameter { } impl DelayParameter { - pub fn new(name: &str, metric: M, delay: usize, initial_value: f64) -> Self { + pub fn new(name: ParameterName, metric: M, delay: usize, initial_value: f64) -> Self { Self { meta: ParameterMeta::new(name), metric, @@ -173,13 +174,13 @@ mod test { // Create an artificial volume series to use for the delay test let volumes = Array1::linspace(1.0, 0.0, 21); - let volume = Array1Parameter::new("test-x", volumes.clone(), None); + let volume = Array1Parameter::new("test-x".into(), volumes.clone(), None); let volume_idx = model.network_mut().add_parameter(Box::new(volume)).unwrap(); const DELAY: usize = 3; // 3 time-step delay let parameter = DelayParameter::new( - "test-parameter", + "test-parameter".into(), volume_idx.into(), // Interpolate with the parameter based values DELAY, 0.0, diff --git a/pywr-core/src/parameters/discount_factor.rs b/pywr-core/src/parameters/discount_factor.rs index 579a5507..ce8de25c 100644 --- a/pywr-core/src/parameters/discount_factor.rs +++ b/pywr-core/src/parameters/discount_factor.rs @@ -1,6 +1,6 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -14,7 +14,7 @@ pub struct DiscountFactorParameter { } impl DiscountFactorParameter { - pub fn new(name: &str, discount_rate: MetricF64, base_year: i32) -> Self { + pub fn new(name: ParameterName, discount_rate: MetricF64, base_year: i32) -> Self { Self { meta: ParameterMeta::new(name), discount_rate, @@ -66,12 +66,12 @@ mod test { // Create an artificial volume series to use for the delay test let volumes = Array1::linspace(1.0, 0.0, 21); - let volume = Array1Parameter::new("test-x", volumes.clone(), None); + let volume = Array1Parameter::new("test-x".into(), volumes.clone(), None); let _volume_idx = network.add_parameter(Box::new(volume)).unwrap(); let parameter = DiscountFactorParameter::new( - "test-parameter", + "test-parameter".into(), 0.03.into(), // Interpolate with the parameter based values 2020, ); diff --git a/pywr-core/src/parameters/division.rs b/pywr-core/src/parameters/division.rs index c9d19533..905dce69 100644 --- a/pywr-core/src/parameters/division.rs +++ b/pywr-core/src/parameters/division.rs @@ -1,4 +1,4 @@ -use super::{Parameter, PywrError}; +use super::{Parameter, ParameterName, PywrError}; use crate::metric::MetricF64; use crate::network::Network; use crate::parameters::{GeneralParameter, ParameterMeta, ParameterState}; @@ -14,7 +14,7 @@ pub struct DivisionParameter { } impl DivisionParameter { - pub fn new(name: &str, numerator: MetricF64, denominator: MetricF64) -> Self { + pub fn new(name: ParameterName, numerator: MetricF64, denominator: MetricF64) -> Self { Self { meta: ParameterMeta::new(name), numerator, diff --git a/pywr-core/src/parameters/hydropower.rs b/pywr-core/src/parameters/hydropower.rs index 0d90d219..68e13015 100644 --- a/pywr-core/src/parameters/hydropower.rs +++ b/pywr-core/src/parameters/hydropower.rs @@ -1,6 +1,6 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -35,7 +35,7 @@ pub struct HydropowerTargetParameter { } impl HydropowerTargetParameter { - pub fn new(name: &str, turbine_data: HydropowerTargetData) -> Self { + pub fn new(name: ParameterName, turbine_data: HydropowerTargetData) -> Self { Self { meta: ParameterMeta::new(name), target: turbine_data.target, diff --git a/pywr-core/src/parameters/indexed_array.rs b/pywr-core/src/parameters/indexed_array.rs index 721b1c91..49be550d 100644 --- a/pywr-core/src/parameters/indexed_array.rs +++ b/pywr-core/src/parameters/indexed_array.rs @@ -1,6 +1,6 @@ use crate::metric::{MetricF64, MetricUsize}; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -13,7 +13,7 @@ pub struct IndexedArrayParameter { } impl IndexedArrayParameter { - pub fn new(name: &str, index_parameter: MetricUsize, metrics: &[MetricF64]) -> Self { + pub fn new(name: ParameterName, index_parameter: MetricUsize, metrics: &[MetricF64]) -> Self { Self { meta: ParameterMeta::new(name), index_parameter, diff --git a/pywr-core/src/parameters/interpolated.rs b/pywr-core/src/parameters/interpolated.rs index 17b823cc..c3e17e8e 100644 --- a/pywr-core/src/parameters/interpolated.rs +++ b/pywr-core/src/parameters/interpolated.rs @@ -1,7 +1,7 @@ use crate::metric::MetricF64; use crate::network::Network; use crate::parameters::interpolate::linear_interpolation; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -16,7 +16,7 @@ pub struct InterpolatedParameter { } impl InterpolatedParameter { - pub fn new(name: &str, x: MetricF64, points: Vec<(MetricF64, MetricF64)>, error_on_bounds: bool) -> Self { + pub fn new(name: ParameterName, x: MetricF64, points: Vec<(MetricF64, MetricF64)>, error_on_bounds: bool) -> Self { Self { meta: ParameterMeta::new(name), x, diff --git a/pywr-core/src/parameters/max.rs b/pywr-core/src/parameters/max.rs index 004a9a02..190755a2 100644 --- a/pywr-core/src/parameters/max.rs +++ b/pywr-core/src/parameters/max.rs @@ -1,6 +1,6 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -13,7 +13,7 @@ pub struct MaxParameter { } impl MaxParameter { - pub fn new(name: &str, metric: MetricF64, threshold: f64) -> Self { + pub fn new(name: ParameterName, metric: MetricF64, threshold: f64) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/min.rs b/pywr-core/src/parameters/min.rs index e26cd54d..8df3b131 100644 --- a/pywr-core/src/parameters/min.rs +++ b/pywr-core/src/parameters/min.rs @@ -1,6 +1,6 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -13,7 +13,7 @@ pub struct MinParameter { } impl MinParameter { - pub fn new(name: &str, metric: MetricF64, threshold: f64) -> Self { + pub fn new(name: ParameterName, metric: MetricF64, threshold: f64) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/mod.rs b/pywr-core/src/parameters/mod.rs index 7dd318d6..5c0b4e0c 100644 --- a/pywr-core/src/parameters/mod.rs +++ b/pywr-core/src/parameters/mod.rs @@ -269,19 +269,48 @@ impl From> for ParameterIndex { } } +#[derive(Debug, Clone, PartialEq, Eq)] +pub struct ParameterName { + name: String, + parent: Option, +} + +impl ParameterName { + pub fn new(name: &str, parent: Option<&str>) -> Self { + Self { + name: name.to_string(), + parent: parent.map(|p| p.to_string()), + } + } +} + +impl Display for ParameterName { + fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { + match &self.parent { + Some(parent) => write!(f, "{}.{}", parent, self.name), + None => write!(f, "{}", self.name), + } + } +} + +impl From<&str> for ParameterName { + fn from(name: &str) -> Self { + Self { + name: name.to_string(), + parent: None, + } + } +} + /// Meta data common to all parameters. #[derive(Debug, Clone)] pub struct ParameterMeta { - pub name: String, - pub comment: String, + name: ParameterName, } impl ParameterMeta { - fn new(name: &str) -> Self { - Self { - name: name.to_string(), - comment: "".to_string(), - } + fn new(name: ParameterName) -> Self { + Self { name } } } @@ -481,8 +510,8 @@ pub fn downcast_variable_config_ref(variable_config: &dyn VariableCo /// The trait is generic over the type of the value produced. pub trait Parameter: Send + Sync { fn meta(&self) -> &ParameterMeta; - fn name(&self) -> &str { - self.meta().name.as_str() + fn name(&self) -> &ParameterName { + &self.meta().name } fn setup( @@ -702,8 +731,8 @@ impl From> for ParameterType { /// the variable values being optimised but these will typically by `f64` and `u32`. pub trait VariableParameter { fn meta(&self) -> &ParameterMeta; - fn name(&self) -> &str { - self.meta().name.as_str() + fn name(&self) -> &ParameterName { + &self.meta().name } /// Return the number of variables required @@ -864,7 +893,7 @@ impl ParameterCollection { } /// Does a parameter with the given name exist in the collection. - pub fn has_name(&self, name: &str) -> bool { + pub fn has_name(&self, name: &ParameterName) -> bool { self.get_f64_index_by_name(name).is_some() || self.get_usize_index_by_name(name).is_some() || self.get_multi_index_by_name(name).is_some() @@ -879,7 +908,7 @@ impl ParameterCollection { &mut self, parameter: Box>, ) -> Result, PywrError> { - if self.has_name(parameter.meta().name.as_str()) { + if self.has_name(parameter.name()) { return Err(PywrError::ParameterNameAlreadyExists(parameter.meta().name.to_string())); } @@ -897,7 +926,7 @@ impl ParameterCollection { &mut self, parameter: Box>, ) -> Result, PywrError> { - if self.has_name(parameter.meta().name.as_str()) { + if self.has_name(parameter.name()) { return Err(PywrError::ParameterNameAlreadyExists(parameter.meta().name.to_string())); } @@ -915,7 +944,7 @@ impl ParameterCollection { } pub fn add_const_f64(&mut self, parameter: Box>) -> Result, PywrError> { - if self.has_name(parameter.meta().name.as_str()) { + if self.has_name(parameter.name()) { return Err(PywrError::ParameterNameAlreadyExists(parameter.meta().name.to_string())); } @@ -939,32 +968,32 @@ impl ParameterCollection { self.general_f64.get(*index.deref()).map(|p| p.as_ref()) } - pub fn get_f64_by_name(&self, name: &str) -> Option<&dyn Parameter> { + pub fn get_f64_by_name(&self, name: &ParameterName) -> Option<&dyn Parameter> { self.general_f64 .iter() - .find(|p| p.meta().name == name) + .find(|p| p.name() == name) .map(|p| p.as_parameter()) } - pub fn get_f64_index_by_name(&self, name: &str) -> Option> { + pub fn get_f64_index_by_name(&self, name: &ParameterName) -> Option> { if let Some(idx) = self .general_f64 .iter() - .position(|p| p.meta().name == name) + .position(|p| p.name() == name) .map(GeneralParameterIndex::new) { Some(idx.into()) } else if let Some(idx) = self .simple_f64 .iter() - .position(|p| p.meta().name == name) + .position(|p| p.name() == name) .map(SimpleParameterIndex::new) { Some(idx.into()) } else { self.constant_f64 .iter() - .position(|p| p.meta().name == name) + .position(|p| p.name() == name) .map(ConstParameterIndex::new) .map(|idx| idx.into()) } @@ -974,7 +1003,7 @@ impl ParameterCollection { &mut self, parameter: Box>, ) -> Result, PywrError> { - if self.has_name(parameter.meta().name.as_str()) { + if self.has_name(parameter.name()) { return Err(PywrError::ParameterNameAlreadyExists(parameter.meta().name.to_string())); } @@ -992,7 +1021,7 @@ impl ParameterCollection { &mut self, parameter: Box>, ) -> Result, PywrError> { - if self.has_name(parameter.meta().name.as_str()) { + if self.has_name(parameter.name()) { return Err(PywrError::ParameterNameAlreadyExists(parameter.meta().name.to_string())); } @@ -1008,7 +1037,7 @@ impl ParameterCollection { &mut self, parameter: Box>, ) -> Result, PywrError> { - if self.has_name(parameter.meta().name.as_str()) { + if self.has_name(parameter.name()) { return Err(PywrError::ParameterNameAlreadyExists(parameter.meta().name.to_string())); } @@ -1032,32 +1061,32 @@ impl ParameterCollection { self.general_usize.get(*index.deref()).map(|p| p.as_ref()) } - pub fn get_usize_by_name(&self, name: &str) -> Option<&dyn Parameter> { + pub fn get_usize_by_name(&self, name: &ParameterName) -> Option<&dyn Parameter> { self.general_usize .iter() - .find(|p| p.meta().name == name) + .find(|p| p.name() == name) .map(|p| p.as_parameter()) } - pub fn get_usize_index_by_name(&self, name: &str) -> Option> { + pub fn get_usize_index_by_name(&self, name: &ParameterName) -> Option> { if let Some(idx) = self .general_usize .iter() - .position(|p| p.meta().name == name) + .position(|p| p.name() == name) .map(GeneralParameterIndex::new) { Some(idx.into()) } else if let Some(idx) = self .simple_usize .iter() - .position(|p| p.meta().name == name) + .position(|p| p.name() == name) .map(SimpleParameterIndex::new) { Some(idx.into()) } else { self.constant_usize .iter() - .position(|p| p.meta().name == name) + .position(|p| p.name() == name) .map(ConstParameterIndex::new) .map(|idx| idx.into()) } @@ -1067,7 +1096,7 @@ impl ParameterCollection { &mut self, parameter: Box>, ) -> Result, PywrError> { - if self.has_name(parameter.meta().name.as_str()) { + if self.has_name(parameter.name()) { return Err(PywrError::ParameterNameAlreadyExists(parameter.meta().name.to_string())); } @@ -1085,7 +1114,7 @@ impl ParameterCollection { &mut self, parameter: Box>, ) -> Result, PywrError> { - if self.has_name(parameter.meta().name.as_str()) { + if self.has_name(parameter.name()) { return Err(PywrError::ParameterNameAlreadyExists(parameter.meta().name.to_string())); } @@ -1101,7 +1130,7 @@ impl ParameterCollection { &mut self, parameter: Box>, ) -> Result, PywrError> { - if self.has_name(parameter.meta().name.as_str()) { + if self.has_name(parameter.name()) { return Err(PywrError::ParameterNameAlreadyExists(parameter.meta().name.to_string())); } @@ -1127,32 +1156,32 @@ impl ParameterCollection { self.general_multi.get(*index.deref()).map(|p| p.as_ref()) } - pub fn get_multi_by_name(&self, name: &str) -> Option<&dyn Parameter> { + pub fn get_multi_by_name(&self, name: &ParameterName) -> Option<&dyn Parameter> { self.general_multi .iter() - .find(|p| p.meta().name == name) + .find(|p| p.name() == name) .map(|p| p.as_parameter()) } - pub fn get_multi_index_by_name(&self, name: &str) -> Option> { + pub fn get_multi_index_by_name(&self, name: &ParameterName) -> Option> { if let Some(idx) = self .general_multi .iter() - .position(|p| p.meta().name == name) + .position(|p| p.name() == name) .map(GeneralParameterIndex::new) { Some(idx.into()) } else if let Some(idx) = self .simple_multi .iter() - .position(|p| p.meta().name == name) + .position(|p| p.name() == name) .map(SimpleParameterIndex::new) { Some(idx.into()) } else { self.constant_multi .iter() - .position(|p| p.meta().name == name) + .position(|p| p.name() == name) .map(ConstParameterIndex::new) .map(|idx| idx.into()) } @@ -1387,7 +1416,7 @@ mod tests { impl Default for TestParameter { fn default() -> Self { Self { - meta: ParameterMeta::new("test-parameter"), + meta: ParameterMeta::new("test-parameter".into()), } } } @@ -1508,7 +1537,7 @@ mod tests { let ret = collection.add_const_f64(Box::new(TestParameter::default())); assert!(ret.is_ok()); - assert!(collection.has_name("test-parameter")); + assert!(collection.has_name(&"test-parameter".into())); // Try to add a parameter with the same name let ret = collection.add_const_f64(Box::new(TestParameter::default())); diff --git a/pywr-core/src/parameters/negative.rs b/pywr-core/src/parameters/negative.rs index 540b5e0e..307d3bda 100644 --- a/pywr-core/src/parameters/negative.rs +++ b/pywr-core/src/parameters/negative.rs @@ -1,6 +1,6 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -12,7 +12,7 @@ pub struct NegativeParameter { } impl NegativeParameter { - pub fn new(name: &str, metric: MetricF64) -> Self { + pub fn new(name: ParameterName, metric: MetricF64) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/negativemax.rs b/pywr-core/src/parameters/negativemax.rs index 8a56c8b0..6bd074f4 100644 --- a/pywr-core/src/parameters/negativemax.rs +++ b/pywr-core/src/parameters/negativemax.rs @@ -1,6 +1,6 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -13,7 +13,7 @@ pub struct NegativeMaxParameter { } impl NegativeMaxParameter { - pub fn new(name: &str, metric: MetricF64, threshold: f64) -> Self { + pub fn new(name: ParameterName, metric: MetricF64, threshold: f64) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/negativemin.rs b/pywr-core/src/parameters/negativemin.rs index 5c0c75ad..9e479c21 100644 --- a/pywr-core/src/parameters/negativemin.rs +++ b/pywr-core/src/parameters/negativemin.rs @@ -1,6 +1,6 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -13,7 +13,7 @@ pub struct NegativeMinParameter { } impl NegativeMinParameter { - pub fn new(name: &str, metric: MetricF64, threshold: f64) -> Self { + pub fn new(name: ParameterName, metric: MetricF64, threshold: f64) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/offset.rs b/pywr-core/src/parameters/offset.rs index 51c0dd37..13b5a88f 100644 --- a/pywr-core/src/parameters/offset.rs +++ b/pywr-core/src/parameters/offset.rs @@ -2,7 +2,7 @@ use crate::metric::MetricF64; use crate::network::Network; use crate::parameters::{ downcast_internal_state_mut, downcast_internal_state_ref, downcast_variable_config_ref, ActivationFunction, - GeneralParameter, Parameter, ParameterMeta, ParameterState, VariableConfig, VariableParameter, + GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState, VariableConfig, VariableParameter, }; use crate::scenario::ScenarioIndex; use crate::state::State; @@ -19,7 +19,7 @@ pub struct OffsetParameter { type InternalValue = Option; impl OffsetParameter { - pub fn new(name: &str, metric: MetricF64, offset: f64) -> Self { + pub fn new(name: ParameterName, metric: MetricF64, offset: f64) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/polynomial.rs b/pywr-core/src/parameters/polynomial.rs index 97007afc..c39982f1 100644 --- a/pywr-core/src/parameters/polynomial.rs +++ b/pywr-core/src/parameters/polynomial.rs @@ -1,6 +1,6 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -15,7 +15,7 @@ pub struct Polynomial1DParameter { } impl Polynomial1DParameter { - pub fn new(name: &str, metric: MetricF64, coefficients: Vec, scale: f64, offset: f64) -> Self { + pub fn new(name: ParameterName, metric: MetricF64, coefficients: Vec, scale: f64, offset: f64) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/profiles/daily.rs b/pywr-core/src/parameters/profiles/daily.rs index 2f1db15b..94348eef 100644 --- a/pywr-core/src/parameters/profiles/daily.rs +++ b/pywr-core/src/parameters/profiles/daily.rs @@ -1,4 +1,4 @@ -use crate::parameters::{Parameter, ParameterMeta, ParameterState, SimpleParameter}; +use crate::parameters::{Parameter, ParameterMeta, ParameterName, ParameterState, SimpleParameter}; use crate::scenario::ScenarioIndex; use crate::state::SimpleParameterValues; use crate::timestep::Timestep; @@ -11,7 +11,7 @@ pub struct DailyProfileParameter { } impl DailyProfileParameter { - pub fn new(name: &str, values: [f64; 366]) -> Self { + pub fn new(name: ParameterName, values: [f64; 366]) -> Self { Self { meta: ParameterMeta::new(name), values, diff --git a/pywr-core/src/parameters/profiles/monthly.rs b/pywr-core/src/parameters/profiles/monthly.rs index 1e1dd709..c3809e33 100644 --- a/pywr-core/src/parameters/profiles/monthly.rs +++ b/pywr-core/src/parameters/profiles/monthly.rs @@ -1,4 +1,4 @@ -use crate::parameters::{Parameter, ParameterMeta, ParameterState, SimpleParameter}; +use crate::parameters::{Parameter, ParameterMeta, ParameterName, ParameterState, SimpleParameter}; use crate::scenario::ScenarioIndex; use crate::state::SimpleParameterValues; use crate::timestep::Timestep; @@ -18,7 +18,7 @@ pub struct MonthlyProfileParameter { } impl MonthlyProfileParameter { - pub fn new(name: &str, values: [f64; 12], interp_day: Option) -> Self { + pub fn new(name: ParameterName, values: [f64; 12], interp_day: Option) -> Self { Self { meta: ParameterMeta::new(name), values, diff --git a/pywr-core/src/parameters/profiles/rbf.rs b/pywr-core/src/parameters/profiles/rbf.rs index 6b0318f6..2af03eb5 100644 --- a/pywr-core/src/parameters/profiles/rbf.rs +++ b/pywr-core/src/parameters/profiles/rbf.rs @@ -1,6 +1,6 @@ use crate::parameters::{ downcast_internal_state_mut, downcast_internal_state_ref, downcast_variable_config_ref, Parameter, ParameterMeta, - ParameterState, SimpleParameter, VariableConfig, VariableParameter, + ParameterName, ParameterState, SimpleParameter, VariableConfig, VariableParameter, }; use crate::scenario::ScenarioIndex; use crate::state::SimpleParameterValues; @@ -90,7 +90,7 @@ impl RbfProfileInternalState { } impl RbfProfileParameter { - pub fn new(name: &str, points: Vec<(u32, f64)>, function: RadialBasisFunction) -> Self { + pub fn new(name: ParameterName, points: Vec<(u32, f64)>, function: RadialBasisFunction) -> Self { Self { meta: ParameterMeta::new(name), points, diff --git a/pywr-core/src/parameters/profiles/uniform_drawdown.rs b/pywr-core/src/parameters/profiles/uniform_drawdown.rs index 443a3b57..bd8db084 100644 --- a/pywr-core/src/parameters/profiles/uniform_drawdown.rs +++ b/pywr-core/src/parameters/profiles/uniform_drawdown.rs @@ -1,4 +1,4 @@ -use crate::parameters::{Parameter, ParameterMeta, ParameterState, SimpleParameter}; +use crate::parameters::{Parameter, ParameterMeta, ParameterName, ParameterState, SimpleParameter}; use crate::scenario::ScenarioIndex; use crate::state::SimpleParameterValues; use crate::timestep::Timestep; @@ -16,7 +16,7 @@ pub struct UniformDrawdownProfileParameter { } impl UniformDrawdownProfileParameter { - pub fn new(name: &str, reset_day: u32, reset_month: u32, residual_days: u8) -> Self { + pub fn new(name: ParameterName, reset_day: u32, reset_month: u32, residual_days: u8) -> Self { // Calculate the reset day of year in a known leap year. let reset_doy = NaiveDate::from_ymd_opt(2016, reset_month, reset_day) .expect("Invalid reset day") diff --git a/pywr-core/src/parameters/profiles/weekly.rs b/pywr-core/src/parameters/profiles/weekly.rs index d3daf1bb..2043b07b 100644 --- a/pywr-core/src/parameters/profiles/weekly.rs +++ b/pywr-core/src/parameters/profiles/weekly.rs @@ -1,4 +1,4 @@ -use crate::parameters::{Parameter, ParameterMeta, ParameterState, SimpleParameter}; +use crate::parameters::{Parameter, ParameterMeta, ParameterName, ParameterState, SimpleParameter}; use crate::scenario::ScenarioIndex; use crate::state::SimpleParameterValues; use crate::timestep::Timestep; @@ -174,7 +174,7 @@ pub struct WeeklyProfileParameter { } impl WeeklyProfileParameter { - pub fn new(name: &str, values: WeeklyProfileValues, interp_day: Option) -> Self { + pub fn new(name: ParameterName, values: WeeklyProfileValues, interp_day: Option) -> Self { Self { meta: ParameterMeta::new(name), values, diff --git a/pywr-core/src/parameters/py.rs b/pywr-core/src/parameters/py.rs index ce7a14cf..b90fe5b5 100644 --- a/pywr-core/src/parameters/py.rs +++ b/pywr-core/src/parameters/py.rs @@ -1,4 +1,4 @@ -use super::{GeneralParameter, Parameter, ParameterMeta, ParameterState, PywrError, Timestep}; +use super::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState, PywrError, Timestep}; use crate::metric::{MetricF64, MetricUsize}; use crate::network::Network; use crate::parameters::downcast_internal_state_mut; @@ -30,7 +30,7 @@ impl Internal { impl PyParameter { pub fn new( - name: &str, + name: ParameterName, object: Py, args: Py, kwargs: Py, @@ -353,7 +353,14 @@ class MyParameter: let args = Python::with_gil(|py| PyTuple::new_bound(py, [0]).into()); let kwargs = Python::with_gil(|py| PyDict::new_bound(py).into()); - let param = PyParameter::new("my-parameter", class, args, kwargs, &HashMap::new(), &HashMap::new()); + let param = PyParameter::new( + "my-parameter".into(), + class, + args, + kwargs, + &HashMap::new(), + &HashMap::new(), + ); let timestepper = default_timestepper(); let time: TimeDomain = TimeDomain::try_from(timestepper).unwrap(); let timesteps = time.timesteps(); @@ -422,7 +429,14 @@ class MyParameter: let args = Python::with_gil(|py| PyTuple::new_bound(py, [0]).into()); let kwargs = Python::with_gil(|py| PyDict::new_bound(py).into()); - let param = PyParameter::new("my-parameter", class, args, kwargs, &HashMap::new(), &HashMap::new()); + let param = PyParameter::new( + "my-parameter".into(), + class, + args, + kwargs, + &HashMap::new(), + &HashMap::new(), + ); let timestepper = default_timestepper(); let time: TimeDomain = TimeDomain::try_from(timestepper).unwrap(); let timesteps = time.timesteps(); diff --git a/pywr-core/src/parameters/rhai.rs b/pywr-core/src/parameters/rhai.rs index 8582af97..ea229d41 100644 --- a/pywr-core/src/parameters/rhai.rs +++ b/pywr-core/src/parameters/rhai.rs @@ -1,4 +1,4 @@ -use super::{GeneralParameter, Parameter, ParameterMeta, ParameterState, PywrError, Timestep}; +use super::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState, PywrError, Timestep}; use crate::metric::{MetricF64, MetricUsize}; use crate::network::Network; use crate::parameters::downcast_internal_state_mut; @@ -24,7 +24,7 @@ struct Internal { impl RhaiParameter { pub fn new( - name: &str, + name: ParameterName, script: &str, initial_state: Map, metrics: &HashMap, @@ -149,7 +149,7 @@ mod tests { let initial_state = rhai::Map::new(); let param = RhaiParameter::new( - "my-counter", + "my-counter".into(), script, initial_state, &Default::default(), diff --git a/pywr-core/src/parameters/threshold.rs b/pywr-core/src/parameters/threshold.rs index 30d9c817..e8ed41c2 100644 --- a/pywr-core/src/parameters/threshold.rs +++ b/pywr-core/src/parameters/threshold.rs @@ -1,6 +1,8 @@ use crate::metric::MetricF64; use crate::network::Network; -use crate::parameters::{downcast_internal_state_mut, GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{ + downcast_internal_state_mut, GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState, +}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -39,7 +41,13 @@ pub struct ThresholdParameter { } impl ThresholdParameter { - pub fn new(name: &str, metric: MetricF64, threshold: MetricF64, predicate: Predicate, ratchet: bool) -> Self { + pub fn new( + name: ParameterName, + metric: MetricF64, + threshold: MetricF64, + predicate: Predicate, + ratchet: bool, + ) -> Self { Self { meta: ParameterMeta::new(name), metric, diff --git a/pywr-core/src/parameters/vector.rs b/pywr-core/src/parameters/vector.rs index 6f76eb98..24ec0c1a 100644 --- a/pywr-core/src/parameters/vector.rs +++ b/pywr-core/src/parameters/vector.rs @@ -1,5 +1,5 @@ use crate::network::Network; -use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterState}; +use crate::parameters::{GeneralParameter, Parameter, ParameterMeta, ParameterName, ParameterState}; use crate::scenario::ScenarioIndex; use crate::state::State; use crate::timestep::Timestep; @@ -11,7 +11,7 @@ pub struct VectorParameter { } impl VectorParameter { - pub fn new(name: &str, values: Vec) -> Self { + pub fn new(name: ParameterName, values: Vec) -> Self { Self { meta: ParameterMeta::new(name), values, diff --git a/pywr-core/src/test_utils.rs b/pywr-core/src/test_utils.rs index 86c8cd8c..2181b350 100644 --- a/pywr-core/src/test_utils.rs +++ b/pywr-core/src/test_utils.rs @@ -62,7 +62,7 @@ pub fn simple_network(network: &mut Network, inflow_scenario_index: usize, num_i network.connect_nodes(link_node, output_node).unwrap(); let inflow = Array::from_shape_fn((366, num_inflow_scenarios), |(i, j)| 1.0 + i as f64 + j as f64); - let inflow = Array2Parameter::new("inflow", inflow, inflow_scenario_index, None); + let inflow = Array2Parameter::new("inflow".into(), inflow, inflow_scenario_index, None); let inflow = network.add_parameter(Box::new(inflow)).unwrap(); @@ -71,17 +71,17 @@ pub fn simple_network(network: &mut Network, inflow_scenario_index: usize, num_i let base_demand = 10.0; - let demand_factor = ConstantParameter::new("demand-factor", 1.2); + let demand_factor = ConstantParameter::new("demand-factor".into(), 1.2); let demand_factor = network.add_const_parameter(Box::new(demand_factor)).unwrap(); let total_demand: AggregatedParameter = AggregatedParameter::new( - "total-demand", + "total-demand".into(), &[base_demand.into(), demand_factor.into()], AggFunc::Product, ); let total_demand = network.add_parameter(Box::new(total_demand)).unwrap(); - let demand_cost = ConstantParameter::new("demand-cost", -10.0); + let demand_cost = ConstantParameter::new("demand-cost".into(), -10.0); let demand_cost = network.add_const_parameter(Box::new(demand_cost)).unwrap(); let output_node = network.get_mut_node_by_name("output", None).unwrap(); @@ -124,10 +124,10 @@ pub fn simple_storage_model() -> Model { // Apply demand to the model // TODO convenience function for adding a constant constraint. - let demand = ConstantParameter::new("demand", 10.0); + let demand = ConstantParameter::new("demand".into(), 10.0); let demand = network.add_const_parameter(Box::new(demand)).unwrap(); - let demand_cost = ConstantParameter::new("demand-cost", -10.0); + let demand_cost = ConstantParameter::new("demand-cost".into(), -10.0); let demand_cost = network.add_const_parameter(Box::new(demand_cost)).unwrap(); let output_node = network.get_mut_node_by_name("output", None).unwrap(); @@ -280,7 +280,12 @@ fn make_simple_system( for x in inflow.iter_mut() { *x = inflow_distr.sample(rng).max(0.0); } - let inflow = Array2Parameter::new(&format!("inflow-{suffix}"), inflow, inflow_scenario_group_index, None); + let inflow = Array2Parameter::new( + format!("inflow-{suffix}").as_str().into(), + inflow, + inflow_scenario_group_index, + None, + ); let idx = network.add_parameter(Box::new(inflow))?; network.set_node_max_flow("input", Some(suffix), Some(idx.into()))?; diff --git a/pywr-schema/src/metric.rs b/pywr-schema/src/metric.rs index 37f1012d..608d71c0 100644 --- a/pywr-schema/src/metric.rs +++ b/pywr-schema/src/metric.rs @@ -83,7 +83,7 @@ impl Metric { // assume it is the correct one for future references to that name. This could be // improved by checking the parameter returned by name matches the definition here. - match network.get_parameter_index_by_name(definition.name()) { + match network.get_parameter_index_by_name(&definition.name().into()) { Ok(p) => { // Found a parameter with the name; assume it is the right one! Ok(p.into()) @@ -318,19 +318,17 @@ pub struct ParameterReference { impl ParameterReference { #[cfg(feature = "core")] pub fn load(&self, network: &mut pywr_core::network::Network) -> Result { + let name = self.name.as_str().into(); + match &self.key { Some(key) => { // Key given; this should be a multi-valued parameter - Ok(( - network.get_multi_valued_parameter_index_by_name(&self.name)?, - key.clone(), - ) - .into()) + Ok((network.get_multi_valued_parameter_index_by_name(&name)?, key.clone()).into()) } None => { - if let Ok(idx) = network.get_parameter_index_by_name(&self.name) { + if let Ok(idx) = network.get_parameter_index_by_name(&name) { Ok(idx.into()) - } else if let Ok(idx) = network.get_index_parameter_index_by_name(&self.name) { + } else if let Ok(idx) = network.get_index_parameter_index_by_name(&name) { Ok(idx.into()) } else { Err(SchemaError::ParameterNotFound(self.name.to_string())) diff --git a/pywr-schema/src/nodes/delay.rs b/pywr-schema/src/nodes/delay.rs index 60ac6000..eca96f1a 100644 --- a/pywr-schema/src/nodes/delay.rs +++ b/pywr-schema/src/nodes/delay.rs @@ -6,7 +6,7 @@ use crate::model::LoadArgs; use crate::nodes::{NodeAttribute, NodeMeta}; use crate::parameters::ConstantValue; #[cfg(feature = "core")] -use pywr_core::metric::MetricF64; +use pywr_core::{metric::MetricF64, parameters::ParameterName}; use pywr_schema_macros::PywrVisitAll; use pywr_v1_schema::nodes::DelayNode as DelayNodeV1; use schemars::JsonSchema; @@ -78,16 +78,12 @@ impl DelayNode { network: &mut pywr_core::network::Network, args: &LoadArgs, ) -> Result<(), SchemaError> { - // Create the delay parameter - let name = format!("{}-delay", self.meta.name.as_str()); + // Create the delay parameter using the node's name as the parent identifier + let name = ParameterName::new("delay", Some(self.meta.name.as_str())); let output_idx = network.get_node_index_by_name(self.meta.name.as_str(), Self::output_sub_name())?; let metric = MetricF64::NodeInFlow(output_idx); - let p = pywr_core::parameters::DelayParameter::new( - &name, - metric, - self.delay, - self.initial_value.load(args.tables)?, - ); + let p = + pywr_core::parameters::DelayParameter::new(name, metric, self.delay, self.initial_value.load(args.tables)?); let delay_idx = network.add_parameter(Box::new(p))?; // Apply it as a constraint on the input node. diff --git a/pywr-schema/src/nodes/piecewise_storage.rs b/pywr-schema/src/nodes/piecewise_storage.rs index 9676aeb2..5dad0383 100644 --- a/pywr-schema/src/nodes/piecewise_storage.rs +++ b/pywr-schema/src/nodes/piecewise_storage.rs @@ -9,7 +9,7 @@ use pywr_core::{ derived_metric::DerivedMetric, metric::{MetricF64, SimpleMetricF64}, node::StorageInitialVolume, - parameters::VolumeBetweenControlCurvesParameter, + parameters::{ParameterName, VolumeBetweenControlCurvesParameter}, }; use pywr_schema_macros::PywrVisitAll; use schemars::JsonSchema; @@ -103,7 +103,11 @@ impl PiecewiseStorageNode { let upper = step.control_curve.load(network, args)?; let max_volume_parameter = VolumeBetweenControlCurvesParameter::new( - format!("{}-{}-max-volume", self.meta.name, Self::step_sub_name(i).unwrap()).as_str(), + // Node's name is the parent identifier + ParameterName::new( + format!("{}-max-volume", Self::step_sub_name(i).unwrap()).as_str(), + Some(&self.meta.name), + ), max_volume.clone(), Some(upper.try_into()?), lower, @@ -142,12 +146,10 @@ impl PiecewiseStorageNode { let upper = None; let max_volume_parameter = VolumeBetweenControlCurvesParameter::new( - format!( - "{}-{}-max-volume", - self.meta.name, - Self::step_sub_name(self.steps.len()).unwrap() - ) - .as_str(), + ParameterName::new( + format!("{}-max-volume", Self::step_sub_name(self.steps.len()).unwrap()).as_str(), + Some(&self.meta.name), + ), max_volume.clone(), upper, lower, @@ -350,7 +352,7 @@ mod tests { network.add_recorder(Box::new(recorder)).unwrap(); let idx = network - .get_index_parameter_index_by_name("storage1-drought-index") + .get_index_parameter_index_by_name(&"storage1-drought-index".into()) .unwrap(); let recorder = IndexAssertionRecorder::new("storage1-drought-index", idx.into(), expected_drought_index); diff --git a/pywr-schema/src/nodes/turbine.rs b/pywr-schema/src/nodes/turbine.rs index 8f517d7b..47ea73e0 100644 --- a/pywr-schema/src/nodes/turbine.rs +++ b/pywr-schema/src/nodes/turbine.rs @@ -8,7 +8,7 @@ use crate::SchemaError; use pywr_core::{ derived_metric::{DerivedMetric, TurbineData}, metric::MetricF64, - parameters::HydropowerTargetData, + parameters::{HydropowerTargetData, ParameterName}, }; use pywr_schema_macros::PywrVisitAll; use schemars::JsonSchema; @@ -114,8 +114,7 @@ impl TurbineNode { } if let Some(target) = &self.target { - // TODO: address parameter name. See https://github.com/pywr/pywr-next/issues/107#issuecomment-1980957962 - let name = format!("{}-power", self.meta.name.as_str()); + let name = ParameterName::new("power", Some(self.meta.name.as_str())); let target_value = target.load(network, args)?; let water_elevation = self @@ -135,7 +134,7 @@ impl TurbineNode { flow_unit_conversion: Some(self.flow_unit_conversion), energy_unit_conversion: Some(self.energy_unit_conversion), }; - let p = pywr_core::parameters::HydropowerTargetParameter::new(&name, turbine_data); + let p = pywr_core::parameters::HydropowerTargetParameter::new(name, turbine_data); let power_idx = network.add_parameter(Box::new(p))?; let metric: MetricF64 = power_idx.into(); diff --git a/pywr-schema/src/parameters/aggregated.rs b/pywr-schema/src/parameters/aggregated.rs index 4b0de7db..61c406b3 100644 --- a/pywr-schema/src/parameters/aggregated.rs +++ b/pywr-schema/src/parameters/aggregated.rs @@ -92,7 +92,11 @@ impl AggregatedParameter { .map(|v| v.load(network, args)) .collect::, _>>()?; - let p = pywr_core::parameters::AggregatedParameter::new(&self.meta.name, &metrics, self.agg_func.into()); + let p = pywr_core::parameters::AggregatedParameter::new( + self.meta.name.as_str().into(), + &metrics, + self.agg_func.into(), + ); Ok(network.add_parameter(Box::new(p))?) } @@ -199,7 +203,11 @@ impl AggregatedIndexParameter { .map(|v| v.load(network, args)) .collect::, _>>()?; - let p = pywr_core::parameters::AggregatedIndexParameter::new(&self.meta.name, parameters, self.agg_func.into()); + let p = pywr_core::parameters::AggregatedIndexParameter::new( + self.meta.name.as_str().into(), + parameters, + self.agg_func.into(), + ); Ok(network.add_index_parameter(Box::new(p))?) } diff --git a/pywr-schema/src/parameters/asymmetric_switch.rs b/pywr-schema/src/parameters/asymmetric_switch.rs index a9ecd46f..56e64595 100644 --- a/pywr-schema/src/parameters/asymmetric_switch.rs +++ b/pywr-schema/src/parameters/asymmetric_switch.rs @@ -29,7 +29,7 @@ impl AsymmetricSwitchIndexParameter { let off_index_parameter = self.off_index_parameter.load(network, args)?; let p = pywr_core::parameters::AsymmetricSwitchIndexParameter::new( - &self.meta.name, + self.meta.name.as_str().into(), on_index_parameter, off_index_parameter, ); diff --git a/pywr-schema/src/parameters/control_curves.rs b/pywr-schema/src/parameters/control_curves.rs index 5f6c9bb6..a5f1db4a 100644 --- a/pywr-schema/src/parameters/control_curves.rs +++ b/pywr-schema/src/parameters/control_curves.rs @@ -48,7 +48,7 @@ impl ControlCurveInterpolatedParameter { .collect::>()?; let p = pywr_core::parameters::ControlCurveInterpolatedParameter::new( - &self.meta.name, + self.meta.name.as_str().into(), metric, control_curves, values, @@ -141,7 +141,11 @@ impl ControlCurveIndexParameter { .map(|cc| cc.load(network, args)) .collect::>()?; - let p = pywr_core::parameters::ControlCurveIndexParameter::new(&self.meta.name, metric, control_curves); + let p = pywr_core::parameters::ControlCurveIndexParameter::new( + self.meta.name.as_str().into(), + metric, + control_curves, + ); Ok(network.add_index_parameter(Box::new(p))?) } } @@ -255,7 +259,12 @@ impl ControlCurveParameter { .map(|val| val.load(network, args)) .collect::>()?; - let p = pywr_core::parameters::ControlCurveParameter::new(&self.meta.name, metric, control_curves, values); + let p = pywr_core::parameters::ControlCurveParameter::new( + self.meta.name.as_str().into(), + metric, + control_curves, + values, + ); Ok(network.add_parameter(Box::new(p))?) } } @@ -346,7 +355,7 @@ impl ControlCurvePiecewiseInterpolatedParameter { }; let p = pywr_core::parameters::PiecewiseInterpolatedParameter::new( - &self.meta.name, + self.meta.name.as_str().into(), metric, control_curves, values, diff --git a/pywr-schema/src/parameters/core.rs b/pywr-schema/src/parameters/core.rs index 826808b1..7dc8907d 100644 --- a/pywr-schema/src/parameters/core.rs +++ b/pywr-schema/src/parameters/core.rs @@ -166,7 +166,10 @@ impl ConstantParameter { network: &mut pywr_core::network::Network, args: &LoadArgs, ) -> Result, SchemaError> { - let p = pywr_core::parameters::ConstantParameter::new(&self.meta.name, self.value.load(args.tables)?); + let p = pywr_core::parameters::ConstantParameter::new( + self.meta.name.as_str().into(), + self.value.load(args.tables)?, + ); Ok(network.add_const_parameter(Box::new(p))?) } } @@ -213,7 +216,7 @@ impl MaxParameter { let idx = self.parameter.load(network, args)?; let threshold = self.threshold.unwrap_or(0.0); - let p = pywr_core::parameters::MaxParameter::new(&self.meta.name, idx, threshold); + let p = pywr_core::parameters::MaxParameter::new(self.meta.name.as_str().into(), idx, threshold); Ok(network.add_parameter(Box::new(p))?) } } @@ -269,7 +272,7 @@ impl DivisionParameter { let n = self.numerator.load(network, args)?; let d = self.denominator.load(network, args)?; - let p = pywr_core::parameters::DivisionParameter::new(&self.meta.name, n, d); + let p = pywr_core::parameters::DivisionParameter::new(self.meta.name.as_str().into(), n, d); Ok(network.add_parameter(Box::new(p))?) } } @@ -326,7 +329,7 @@ impl MinParameter { let idx = self.parameter.load(network, args)?; let threshold = self.threshold.unwrap_or(0.0); - let p = pywr_core::parameters::MinParameter::new(&self.meta.name, idx, threshold); + let p = pywr_core::parameters::MinParameter::new(self.meta.name.as_str().into(), idx, threshold); Ok(network.add_parameter(Box::new(p))?) } } @@ -368,7 +371,7 @@ impl NegativeParameter { ) -> Result, SchemaError> { let idx = self.parameter.load(network, args)?; - let p = pywr_core::parameters::NegativeParameter::new(&self.meta.name, idx); + let p = pywr_core::parameters::NegativeParameter::new(self.meta.name.as_str().into(), idx); Ok(network.add_parameter(Box::new(p))?) } } @@ -422,7 +425,7 @@ impl NegativeMaxParameter { let idx = self.metric.load(network, args)?; let threshold = self.threshold.unwrap_or(0.0); - let p = pywr_core::parameters::NegativeMaxParameter::new(&self.meta.name, idx, threshold); + let p = pywr_core::parameters::NegativeMaxParameter::new(self.meta.name.as_str().into(), idx, threshold); Ok(network.add_parameter(Box::new(p))?) } } @@ -478,7 +481,7 @@ impl NegativeMinParameter { let idx = self.metric.load(network, args)?; let threshold = self.threshold.unwrap_or(0.0); - let p = pywr_core::parameters::NegativeMinParameter::new(&self.meta.name, idx, threshold); + let p = pywr_core::parameters::NegativeMinParameter::new(self.meta.name.as_str().into(), idx, threshold); Ok(network.add_parameter(Box::new(p))?) } } diff --git a/pywr-schema/src/parameters/delay.rs b/pywr-schema/src/parameters/delay.rs index 0ac361e6..d3026f7b 100644 --- a/pywr-schema/src/parameters/delay.rs +++ b/pywr-schema/src/parameters/delay.rs @@ -27,7 +27,12 @@ impl DelayParameter { args: &LoadArgs, ) -> Result, SchemaError> { let metric = self.metric.load(network, args)?; - let p = pywr_core::parameters::DelayParameter::new(&self.meta.name, metric, self.delay, self.initial_value); + let p = pywr_core::parameters::DelayParameter::new( + self.meta.name.as_str().into(), + metric, + self.delay, + self.initial_value, + ); Ok(network.add_parameter(Box::new(p))?) } } diff --git a/pywr-schema/src/parameters/discount_factor.rs b/pywr-schema/src/parameters/discount_factor.rs index 57e6fe60..f1d47889 100644 --- a/pywr-schema/src/parameters/discount_factor.rs +++ b/pywr-schema/src/parameters/discount_factor.rs @@ -28,7 +28,11 @@ impl DiscountFactorParameter { args: &LoadArgs, ) -> Result, SchemaError> { let discount_rate = self.discount_rate.load(network, args)?; - let p = pywr_core::parameters::DiscountFactorParameter::new(&self.meta.name, discount_rate, self.base_year); + let p = pywr_core::parameters::DiscountFactorParameter::new( + self.meta.name.as_str().into(), + discount_rate, + self.base_year, + ); Ok(network.add_parameter(Box::new(p))?) } } diff --git a/pywr-schema/src/parameters/hydropower.rs b/pywr-schema/src/parameters/hydropower.rs index 708006b5..b693a0a7 100644 --- a/pywr-schema/src/parameters/hydropower.rs +++ b/pywr-schema/src/parameters/hydropower.rs @@ -104,7 +104,7 @@ impl HydropowerTargetParameter { flow_unit_conversion: self.flow_unit_conversion, energy_unit_conversion: self.energy_unit_conversion, }; - let p = pywr_core::parameters::HydropowerTargetParameter::new(&self.meta.name, turbine_data); + let p = pywr_core::parameters::HydropowerTargetParameter::new(self.meta.name.as_str().into(), turbine_data); Ok(network.add_parameter(Box::new(p))?) } } diff --git a/pywr-schema/src/parameters/indexed_array.rs b/pywr-schema/src/parameters/indexed_array.rs index 787275ad..301ccf9b 100644 --- a/pywr-schema/src/parameters/indexed_array.rs +++ b/pywr-schema/src/parameters/indexed_array.rs @@ -35,7 +35,11 @@ impl IndexedArrayParameter { .map(|v| v.load(network, args)) .collect::, _>>()?; - let p = pywr_core::parameters::IndexedArrayParameter::new(&self.meta.name, index_parameter, &metrics); + let p = pywr_core::parameters::IndexedArrayParameter::new( + self.meta.name.as_str().into(), + index_parameter, + &metrics, + ); Ok(network.add_parameter(Box::new(p))?) } diff --git a/pywr-schema/src/parameters/interpolated.rs b/pywr-schema/src/parameters/interpolated.rs index 47ad5903..efacc9a6 100644 --- a/pywr-schema/src/parameters/interpolated.rs +++ b/pywr-schema/src/parameters/interpolated.rs @@ -60,7 +60,7 @@ impl InterpolatedParameter { let points = xp.into_iter().zip(fp).collect::>(); let p = pywr_core::parameters::InterpolatedParameter::new( - &self.meta.name, + self.meta.name.as_str().into(), x, points, self.error_on_bounds.unwrap_or(true), diff --git a/pywr-schema/src/parameters/mod.rs b/pywr-schema/src/parameters/mod.rs index 5e48bd1b..fc450a11 100644 --- a/pywr-schema/src/parameters/mod.rs +++ b/pywr-schema/src/parameters/mod.rs @@ -772,7 +772,7 @@ impl ParameterIndexValue { match self { Self::Reference(name) => { // This should be an existing parameter - Ok(network.get_index_parameter_index_by_name(name)?) + Ok(network.get_index_parameter_index_by_name(&name.as_str().into())?) } Self::Inline(parameter) => { // Inline parameter needs to be added diff --git a/pywr-schema/src/parameters/offset.rs b/pywr-schema/src/parameters/offset.rs index c758a75c..d7fdcbbd 100644 --- a/pywr-schema/src/parameters/offset.rs +++ b/pywr-schema/src/parameters/offset.rs @@ -48,7 +48,11 @@ impl OffsetParameter { ) -> Result, SchemaError> { let idx = self.metric.load(network, args)?; - let p = pywr_core::parameters::OffsetParameter::new(&self.meta.name, idx, self.offset.load(args.tables)?); + let p = pywr_core::parameters::OffsetParameter::new( + self.meta.name.as_str().into(), + idx, + self.offset.load(args.tables)?, + ); Ok(network.add_parameter(Box::new(p))?) } } diff --git a/pywr-schema/src/parameters/polynomial.rs b/pywr-schema/src/parameters/polynomial.rs index 8d64be30..1ad497a6 100644 --- a/pywr-schema/src/parameters/polynomial.rs +++ b/pywr-schema/src/parameters/polynomial.rs @@ -26,7 +26,7 @@ impl Polynomial1DParameter { network.get_storage_node_metric(&self.storage_node, None, self.use_proportional_volume.unwrap_or(true))?; let p = pywr_core::parameters::Polynomial1DParameter::new( - &self.meta.name, + self.meta.name.as_str().into(), metric, self.coefficients.clone(), self.scale.unwrap_or(1.0), diff --git a/pywr-schema/src/parameters/profiles.rs b/pywr-schema/src/parameters/profiles.rs index 7e66f0cf..bcef6aed 100644 --- a/pywr-schema/src/parameters/profiles.rs +++ b/pywr-schema/src/parameters/profiles.rs @@ -30,7 +30,10 @@ impl DailyProfileParameter { args: &LoadArgs, ) -> Result, SchemaError> { let values = &self.values.load(args.tables)?[..366]; - let p = pywr_core::parameters::DailyProfileParameter::new(&self.meta.name, values.try_into().expect("")); + let p = pywr_core::parameters::DailyProfileParameter::new( + self.meta.name.as_str().into(), + values.try_into().expect(""), + ); Ok(network.add_simple_parameter(Box::new(p))?) } } @@ -100,7 +103,7 @@ impl MonthlyProfileParameter { ) -> Result, SchemaError> { let values = &self.values.load(args.tables)?[..12]; let p = pywr_core::parameters::MonthlyProfileParameter::new( - &self.meta.name, + self.meta.name.as_str().into(), values.try_into().expect(""), self.interp_day.map(|id| id.into()), ); @@ -184,7 +187,7 @@ impl UniformDrawdownProfileParameter { }; let p = pywr_core::parameters::UniformDrawdownProfileParameter::new( - &self.meta.name, + self.meta.name.as_str().into(), reset_day, reset_month, residual_days, @@ -357,7 +360,11 @@ impl RbfProfileParameter { pub fn add_to_model(&self, network: &mut pywr_core::network::Network) -> Result, SchemaError> { let function = self.function.into_core_rbf(&self.points)?; - let p = pywr_core::parameters::RbfProfileParameter::new(&self.meta.name, self.points.clone(), function); + let p = pywr_core::parameters::RbfProfileParameter::new( + self.meta.name.as_str().into(), + self.points.clone(), + function, + ); Ok(network.add_simple_parameter(Box::new(p))?) } } @@ -533,7 +540,7 @@ impl WeeklyProfileParameter { args: &LoadArgs, ) -> Result, SchemaError> { let p = pywr_core::parameters::WeeklyProfileParameter::new( - &self.meta.name, + self.meta.name.as_str().into(), WeeklyProfileValues::try_from(self.values.load(args.tables)?.as_slice()).map_err( |err: WeeklyProfileError| SchemaError::LoadParameter { name: self.meta.name.to_string(), diff --git a/pywr-schema/src/parameters/python.rs b/pywr-schema/src/parameters/python.rs index de68a5ec..afd0bb0b 100644 --- a/pywr-schema/src/parameters/python.rs +++ b/pywr-schema/src/parameters/python.rs @@ -244,7 +244,14 @@ impl PythonParameter { None => HashMap::new(), }; - let p = PyParameter::new(&self.meta.name, object, py_args, kwargs, &metrics, &indices); + let p = PyParameter::new( + self.meta.name.as_str().into(), + object, + py_args, + kwargs, + &metrics, + &indices, + ); let pt = match self.return_type { PythonReturnType::Float => network.add_parameter(Box::new(p))?.into(), @@ -309,7 +316,7 @@ mod tests { param.add_to_model(&mut network, &args).unwrap(); - assert!(network.get_parameter_by_name("my-float-parameter").is_ok()); + assert!(network.get_parameter_by_name(&"my-float-parameter".into()).is_ok()); } #[test] @@ -353,6 +360,6 @@ mod tests { param.add_to_model(&mut network, &args).unwrap(); - assert!(network.get_index_parameter_by_name("my-int-parameter").is_ok()); + assert!(network.get_index_parameter_by_name(&"my-int-parameter".into()).is_ok()); } } diff --git a/pywr-schema/src/parameters/tables.rs b/pywr-schema/src/parameters/tables.rs index 0b14ff37..f73516d1 100644 --- a/pywr-schema/src/parameters/tables.rs +++ b/pywr-schema/src/parameters/tables.rs @@ -69,7 +69,7 @@ impl TablesArrayParameter { .ok_or(SchemaError::ScenarioGroupNotFound(scenario.to_string()))?; let p = pywr_core::parameters::Array2Parameter::new( - &self.meta.name, + self.meta.name.as_str().into(), array, scenario_group_index, self.timestep_offset, @@ -77,7 +77,11 @@ impl TablesArrayParameter { Ok(network.add_parameter(Box::new(p))?) } else { let array = array.slice_move(s![.., 0]); - let p = pywr_core::parameters::Array1Parameter::new(&self.meta.name, array, self.timestep_offset); + let p = pywr_core::parameters::Array1Parameter::new( + self.meta.name.as_str().into(), + array, + self.timestep_offset, + ); Ok(network.add_parameter(Box::new(p))?) } } diff --git a/pywr-schema/src/parameters/thresholds.rs b/pywr-schema/src/parameters/thresholds.rs index dd9b2666..85fc8378 100644 --- a/pywr-schema/src/parameters/thresholds.rs +++ b/pywr-schema/src/parameters/thresholds.rs @@ -74,7 +74,7 @@ impl ParameterThresholdParameter { let threshold = self.threshold.load(network, args)?; let p = pywr_core::parameters::ThresholdParameter::new( - &self.meta.name, + self.meta.name.as_str().into(), metric, threshold, self.predicate.into(), diff --git a/pywr-schema/src/timeseries/mod.rs b/pywr-schema/src/timeseries/mod.rs index 52aa8436..898416cc 100644 --- a/pywr-schema/src/timeseries/mod.rs +++ b/pywr-schema/src/timeseries/mod.rs @@ -15,7 +15,7 @@ use polars::prelude::{DataFrame, DataType::Float64, Float64Type, IndexOrder}; #[cfg(feature = "core")] use pywr_core::{ models::ModelDomain, - parameters::{Array1Parameter, Array2Parameter, ParameterIndex}, + parameters::{Array1Parameter, Array2Parameter, ParameterIndex, ParameterName}, PywrError, }; use pywr_v1_schema::tables::TableVec; @@ -137,13 +137,13 @@ impl LoadedTimeseriesCollection { let series = df.column(col)?; let array = series.cast(&Float64)?.f64()?.to_ndarray()?.to_owned(); - let name = format!("{}_{}", name, col); + let name = ParameterName::new(col, Some(name)); match network.get_parameter_index_by_name(&name) { Ok(idx) => Ok(idx), Err(e) => match e { PywrError::ParameterNotFound(_) => { - let p = Array1Parameter::new(&name, array, None); + let p = Array1Parameter::new(name, array, None); Ok(network.add_parameter(Box::new(p))?) } _ => Err(TimeseriesError::PywrCore(e)), @@ -175,13 +175,13 @@ impl LoadedTimeseriesCollection { let series = df.column(col)?; let array = series.cast(&Float64)?.f64()?.to_ndarray()?.to_owned(); - let name = format!("{}_{}", name, col); + let name = ParameterName::new(col, Some(name)); match network.get_parameter_index_by_name(&name) { Ok(idx) => Ok(idx), Err(e) => match e { PywrError::ParameterNotFound(_) => { - let p = Array1Parameter::new(&name, array, None); + let p = Array1Parameter::new(name, array, None); Ok(network.add_parameter(Box::new(p))?) } _ => Err(TimeseriesError::PywrCore(e)), @@ -207,13 +207,13 @@ impl LoadedTimeseriesCollection { .ok_or(TimeseriesError::TimeseriesNotFound(name.to_string()))?; let array: Array2 = df.to_ndarray::(IndexOrder::default()).unwrap(); - let name = format!("timeseries.{}_{}", name, scenario); + let name = ParameterName::new(scenario, Some(name)); match network.get_parameter_index_by_name(&name) { Ok(idx) => Ok(idx), Err(e) => match e { PywrError::ParameterNotFound(_) => { - let p = Array2Parameter::new(&name, array, scenario_group_index, None); + let p = Array2Parameter::new(name, array, scenario_group_index, None); Ok(network.add_parameter(Box::new(p))?) } _ => Err(TimeseriesError::PywrCore(e)),