Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add min parameter #39

Merged
merged 10 commits into from
Sep 18, 2023
45 changes: 45 additions & 0 deletions src/parameters/min.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use crate::metric::Metric;
use crate::model::Model;
use crate::parameters::{Parameter, ParameterMeta};
use crate::scenario::ScenarioIndex;
use std::any::Any;

use crate::state::State;
use crate::timestep::Timestep;
use crate::PywrError;

pub struct MinParameter {
meta: ParameterMeta,
metric: Metric,
threshold: f64,
}

impl MinParameter {
pub fn new(name: &str, metric: Metric, threshold: f64) -> Self {
Self {
meta: ParameterMeta::new(name),
metric,
threshold,
}
}
}

impl Parameter for MinParameter {
fn as_any_mut(&mut self) -> &mut dyn Any {
self
}
fn meta(&self) -> &ParameterMeta {
&self.meta
}
fn compute(
&self,
_timestep: &Timestep,
_scenario_index: &ScenarioIndex,
model: &Model,
state: &State,
_internal_state: &mut Option<Box<dyn Any + Send>>,
) -> Result<f64, PywrError> {
let x = self.metric.get_value(model, state)?;
Ok(x.min(self.threshold))
}
}
2 changes: 2 additions & 0 deletions src/parameters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ mod control_curves;
mod delay;
mod indexed_array;
mod max;
mod min;
mod negative;
mod polynomial;
mod profiles;
Expand Down Expand Up @@ -33,6 +34,7 @@ pub use control_curves::{
pub use delay::DelayParameter;
pub use indexed_array::IndexedArrayParameter;
pub use max::MaxParameter;
pub use min::MinParameter;
pub use negative::NegativeParameter;
pub use polynomial::Polynomial1DParameter;
pub use profiles::{DailyProfileParameter, MonthlyInterpDay, MonthlyProfileParameter, UniformDrawdownProfileParameter};
Expand Down
70 changes: 69 additions & 1 deletion src/schema/parameters/core.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ use crate::schema::parameters::{
};
use crate::{ParameterIndex, PywrError};
use pywr_schema::parameters::{
ConstantParameter as ConstantParameterV1, MaxParameter as MaxParameterV1, NegativeParameter as NegativeParameterV1,
ConstantParameter as ConstantParameterV1, MaxParameter as MaxParameterV1, MinParameter as MinParameterV1,
NegativeParameter as NegativeParameterV1,
};
use std::collections::HashMap;
use std::path::Path;
Expand Down Expand Up @@ -114,6 +115,73 @@ impl TryFromV1Parameter<MaxParameterV1> for MaxParameter {
}
}

/// This parameter takes the minimum of another Parameter and a constant value (threshold).
///
/// # Arguments
///
/// * `parameter` - The parameter to compare with the float.
/// * `threshold` - The threshold value to compare with the given parameter.
///
/// # Examples
///
/// ```json
/// {
/// "type": "Min",
/// "parameter": {
/// "type": "MonthlyProfile",
/// "values": [1, 4, 5, 9, 1, 5, 10, 8, 11, 9, 11 ,12]
/// },
/// "threshold": 2
/// }
/// ```
#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
pub struct MinParameter {
#[serde(flatten)]
pub meta: ParameterMeta,
pub parameter: DynamicFloatValue,
pub threshold: Option<f64>,
}

impl MinParameter {
pub fn node_references(&self) -> HashMap<&str, &str> {
HashMap::new()
}

pub fn add_to_model(
&self,
model: &mut crate::model::Model,
tables: &LoadedTableCollection,
data_path: Option<&Path>,
) -> Result<ParameterIndex, PywrError> {
let idx = self.parameter.load(model, tables, data_path)?;
let threshold = self.threshold.unwrap_or(0.0);

let p = crate::parameters::MinParameter::new(&self.meta.name, idx, threshold);
model.add_parameter(Box::new(p))
}
}

impl TryFromV1Parameter<MinParameterV1> for MinParameter {
type Error = ConversionError;

fn try_from_v1_parameter(
v1: MinParameterV1,
parent_node: Option<&str>,
unnamed_count: &mut usize,
) -> Result<Self, Self::Error> {
let meta: ParameterMeta = v1.meta.into_v2_parameter(parent_node, unnamed_count);

let parameter = v1.parameter.try_into_v2_parameter(Some(&meta.name), unnamed_count)?;

let p = Self {
meta,
parameter,
threshold: v1.threshold,
};
Ok(p)
}
}

#[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
pub struct NegativeParameter {
#[serde(flatten)]
Expand Down
10 changes: 8 additions & 2 deletions src/schema/parameters/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ pub use super::parameters::control_curves::{
ControlCurveIndexParameter, ControlCurveInterpolatedParameter, ControlCurveParameter,
ControlCurvePiecewiseInterpolatedParameter,
};
pub use super::parameters::core::{ConstantParameter, MaxParameter, NegativeParameter};
pub use super::parameters::core::{ConstantParameter, MaxParameter, MinParameter, NegativeParameter};
pub use super::parameters::delay::DelayParameter;
pub use super::parameters::indexed_array::IndexedArrayParameter;
pub use super::parameters::polynomial::Polynomial1DParameter;
Expand Down Expand Up @@ -135,6 +135,7 @@ pub enum Parameter {
MonthlyProfile(MonthlyProfileParameter),
UniformDrawdownProfile(UniformDrawdownProfileParameter),
Max(MaxParameter),
Min(MinParameter),
Negative(NegativeParameter),
Polynomial1D(Polynomial1DParameter),
ParameterThreshold(ParameterThresholdParameter),
Expand All @@ -160,6 +161,7 @@ impl Parameter {
Self::MonthlyProfile(p) => p.meta.name.as_str(),
Self::UniformDrawdownProfile(p) => p.meta.name.as_str(),
Self::Max(p) => p.meta.name.as_str(),
Self::Min(p) => p.meta.name.as_str(),
Self::Negative(p) => p.meta.name.as_str(),
Self::Polynomial1D(p) => p.meta.name.as_str(),
Self::ParameterThreshold(p) => p.meta.name.as_str(),
Expand Down Expand Up @@ -187,6 +189,7 @@ impl Parameter {
Self::MonthlyProfile(p) => p.node_references(),
Self::UniformDrawdownProfile(p) => p.node_references(),
Self::Max(p) => p.node_references(),
Self::Min(p) => p.node_references(),
Self::Negative(p) => p.node_references(),
Self::Polynomial1D(p) => p.node_references(),
Self::ParameterThreshold(p) => p.node_references(),
Expand Down Expand Up @@ -231,6 +234,7 @@ impl Parameter {
Self::MonthlyProfile(_) => "MonthlyProfile",
Self::UniformDrawdownProfile(_) => "UniformDrawdownProfile",
Self::Max(_) => "Max",
Self::Min(_) => "Min",
Self::Negative(_) => "Negative",
Self::Polynomial1D(_) => "Polynomial1D",
Self::ParameterThreshold(_) => "ParameterThreshold",
Expand Down Expand Up @@ -263,6 +267,7 @@ impl Parameter {
Self::MonthlyProfile(p) => ParameterType::Parameter(p.add_to_model(model, tables)?),
Self::UniformDrawdownProfile(p) => ParameterType::Parameter(p.add_to_model(model, tables)?),
Self::Max(p) => ParameterType::Parameter(p.add_to_model(model, tables, data_path)?),
Self::Min(p) => ParameterType::Parameter(p.add_to_model(model, tables, data_path)?),
Self::Negative(p) => ParameterType::Parameter(p.add_to_model(model, tables, data_path)?),
Self::Polynomial1D(p) => ParameterType::Parameter(p.add_to_model(model)?),
Self::ParameterThreshold(p) => ParameterType::Index(p.add_to_model(model, tables, data_path)?),
Expand Down Expand Up @@ -332,7 +337,8 @@ impl TryFromV1Parameter<ParameterV1> for Parameter {
CoreParameter::TablesArray(p) => {
Parameter::TablesArray(p.try_into_v2_parameter(parent_node, unnamed_count)?)
}
CoreParameter::Min(_) | CoreParameter::Division(_) => todo!(),
CoreParameter::Min(p) => Parameter::Min(p.try_into_v2_parameter(parent_node, unnamed_count)?),
CoreParameter::Division(_) => todo!(),
},
ParameterV1::Custom(p) => {
println!("Custom parameter: {:?} ({})", p.meta.name, p.ty);
Expand Down