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

feat: add timeseries section to model schema #99

Merged
merged 19 commits into from
Mar 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
32b5e5e
WIP: feat: add timeseries section to model schema
Batch21 Feb 7, 2024
2b308ec
add a align_and_resample timeseries mod
Batch21 Feb 10, 2024
e5c6822
Merge branch 'main' into schema-timeseries
Batch21 Feb 29, 2024
1b5c5b1
fix: check if param exists before creating param from timeseries input
Batch21 Mar 3, 2024
72fe90e
create seperate timeseries error enum
Batch21 Mar 3, 2024
5320983
wip: conversion of v1 dataframe parameters to timeseries inputs
Batch21 Mar 7, 2024
1300e77
update timeseries url in test model + remove dbg statement
Batch21 Mar 7, 2024
6b29780
feat: Implement Parameter<usize> for PyParameter.
jetuk Mar 11, 2024
da16f71
Merge branch 'main' into schema-timeseries
Batch21 Mar 11, 2024
d7d011c
Merge branch 'py-index-param' into schema-timeseries
Batch21 Mar 11, 2024
483b17e
fix: Fix and upgrade highs_sys to v1.6.2
jetuk Mar 12, 2024
413a6be
Merge branch 'main' into schema-timeseries
Batch21 Mar 12, 2024
e9805f4
Merge remote-tracking branch 'origin/fix-highs' into schema-timeseries
Batch21 Mar 12, 2024
4040da2
fix: conversion of inline dataframe parameter to timeseries
Batch21 Mar 21, 2024
bbe8187
Merge branch 'main' into schema-timeseries
Batch21 Mar 21, 2024
38f16d4
response to review comments
Batch21 Mar 23, 2024
a021b2b
fix: use index_col for time_col when converting v1 df param to timese…
Batch21 Mar 24, 2024
7de6996
Merge branch 'main' into schema-timeseries
Batch21 Mar 24, 2024
4150d54
remove dataframe parameter from schema and update test models
Batch21 Mar 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions pywr-core/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ use crate::PywrError;
pub use multi::{MultiNetworkModel, MultiNetworkTransferIndex};
pub use simple::{Model, ModelState};

#[derive(Debug)]
pub struct ModelDomain {
time: TimeDomain,
scenarios: ScenarioDomain,
Expand Down
5 changes: 5 additions & 0 deletions pywr-core/src/scenario.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,10 @@ pub struct ScenarioGroupCollection {
}

impl ScenarioGroupCollection {
pub fn new(groups: Vec<ScenarioGroup>) -> Self {
Self { groups }
}

/// Number of [`ScenarioGroup`]s in the collection.
pub fn len(&self) -> usize {
self.groups.len()
Expand Down Expand Up @@ -105,6 +109,7 @@ impl ScenarioIndex {
}
}

#[derive(Debug)]
pub struct ScenarioDomain {
scenario_indices: Vec<ScenarioIndex>,
scenario_group_names: Vec<String>,
Expand Down
16 changes: 15 additions & 1 deletion pywr-core/src/timestep.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,10 +54,15 @@ impl PywrDuration {
}
}

// Returns the fractional number of days in the duration.
/// Returns the fractional number of days in the duration.
pub fn fractional_days(&self) -> f64 {
self.0.num_seconds() as f64 / SECS_IN_DAY as f64
}

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add docstring. Would be good to make the one above a proper docstring as well.

/// Returns the number of nanoseconds in the duration.
pub fn whole_nanoseconds(&self) -> Option<i64> {
self.0.num_nanoseconds()
}
}

type TimestepIndex = usize;
Expand Down Expand Up @@ -187,6 +192,7 @@ impl Timestepper {
}

/// The time domain that a model will be simulated over.
#[derive(Debug)]
pub struct TimeDomain {
timesteps: Vec<Timestep>,
}
Expand All @@ -209,6 +215,14 @@ impl TimeDomain {
self.timesteps.len()
}

pub fn first_timestep(&self) -> &Timestep {
self.timesteps.first().expect("No time-steps defined.")
}

pub fn last_timestep(&self) -> &Timestep {
self.timesteps.last().expect("No time-steps defined.")
}

pub fn is_empty(&self) -> bool {
self.timesteps.is_empty()
}
Expand Down
23 changes: 12 additions & 11 deletions pywr-python/tests/models/aggregated-node1/model.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
"name": "input1",
"type": "Input",
"max_flow": {
"type": "Parameter",
"name": "inflow"
"type": "Timeseries",
"name": "inflow",
"columns": {
"type": "Column",
"name": "inflow"
}
}
},
{
Expand Down Expand Up @@ -69,17 +73,14 @@
"name": "demand",
"type": "Constant",
"value": 10.0
},
}
],
"timeseries": [
{
"name": "inflow",
"type": "DataFrame",
"url": "inflow.csv",
"pandas_kwargs": {
"index_col": 0
},
"columns": {
"type": "Column",
"name": "inflow"
"provider": {
"type": "Polars",
"url": "inflow.csv"
}
}
],
Expand Down
31 changes: 18 additions & 13 deletions pywr-python/tests/models/piecewise-link1/model.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,20 @@
"name": "input1",
"type": "Input",
"max_flow": {
"type": "Parameter",
"name": "inflow"
"type": "Timeseries",
"name": "inflow",
"columns": {
"type": "Column",
"name": "inflow"
}
},
"min_flow": {
"type": "Parameter",
"name": "inflow"
"type": "Timeseries",
"name": "inflow",
"columns": {
"type": "Column",
"name": "inflow"
}
}
},
{
Expand Down Expand Up @@ -74,17 +82,14 @@
"name": "demand",
"type": "Constant",
"value": 10.0
},
}
],
"timeseries": [
{
"name": "inflow",
"type": "DataFrame",
"url": "inflow.csv",
"pandas_kwargs": {
"index_col": 0
},
"columns": {
"type": "Column",
"name": "inflow"
"provider": {
"type": "Polars",
"url": "inflow.csv"
}
}
],
Expand Down
23 changes: 12 additions & 11 deletions pywr-python/tests/models/simple-custom-parameter/model.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
"name": "input1",
"type": "Input",
"max_flow": {
"type": "Parameter",
"name": "inflow"
"type": "Timeseries",
"name": "inflow",
"columns": {
"type": "Column",
"name": "inflow"
}
}
},
{
Expand Down Expand Up @@ -53,17 +57,14 @@
"kwargs": {
"multiplier": 2.0
}
},
}
],
"timeseries": [
{
"name": "inflow",
"type": "DataFrame",
"url": "inflow.csv",
"pandas_kwargs": {
"index_col": 0
},
"columns": {
"type": "Column",
"name": "inflow"
"provider": {
"type": "Polars",
"url": "inflow.csv"
}
}
],
Expand Down
23 changes: 12 additions & 11 deletions pywr-python/tests/models/simple-timeseries/model.json
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
"name": "input1",
"type": "Input",
"max_flow": {
"type": "Parameter",
"name": "inflow"
"type": "Timeseries",
"name": "inflow",
"columns": {
"type": "Column",
"name": "inflow"
}
}
},
{
Expand Down Expand Up @@ -46,17 +50,14 @@
"name": "demand",
"type": "Constant",
"value": 10.0
},
}
],
"timeseries": [
{
"name": "inflow",
"type": "DataFrame",
"url": "inflow.csv",
"pandas_kwargs": {
"index_col": 0
},
"columns": {
"type": "Column",
"name": "inflow"
"provider": {
"type": "Polars",
"url": "inflow.csv"
}
}
],
Expand Down
17 changes: 15 additions & 2 deletions pywr-python/tests/models/simple-wasm/model.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,12 @@
"name": "input1",
"type": "input",
"max_flow": {
"type": "Parameter",
"name": "inflow"
"type": "Timeseries",
"name": "inflow",
"columns": {
"type": "Column",
"name": "inflow"
}
}
},
{
Expand Down Expand Up @@ -64,6 +68,15 @@
"url": "inflow.csv.gz",
"column": "inflow"
}
],
"timeseries": [
{
"name": "inflow",
"provider": {
"type": "Polars",
"url": "inflow.csv.gz"
}
}
]
}
}
2 changes: 1 addition & 1 deletion pywr-schema/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ categories = ["science", "simulation"]

[dependencies]
svgbobdoc = { version = "0.3.0", features = ["enable"] }
polars = { workspace = true }
polars = { workspace = true, features = ["csv", "diff", "dtype-datetime", "dtype-date", "dynamic_group_by"] }
pyo3 = { workspace = true }
pyo3-polars = { workspace = true }
strum = "0.26"
Expand Down
9 changes: 9 additions & 0 deletions pywr-schema/src/error.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
use crate::data_tables::TableError;
use crate::nodes::NodeAttribute;
use crate::timeseries::TimeseriesError;
use pyo3::exceptions::PyRuntimeError;
use pyo3::PyErr;
use thiserror::Error;
Expand Down Expand Up @@ -54,6 +55,8 @@ pub enum SchemaError {
InvalidRollingWindow { name: String },
#[error("Failed to load parameter {name}: {error}")]
LoadParameter { name: String, error: String },
#[error("Timeseries error: {0}")]
Timeseries(#[from] TimeseriesError),
}

impl From<SchemaError> for PyErr {
Expand Down Expand Up @@ -103,4 +106,10 @@ pub enum ConversionError {
UnparseableDate(String),
#[error("Chrono out of range error: {0}")]
OutOfRange(#[from] chrono::OutOfRange),
#[error("The dataframe parameters '{0}' defines both a column and a scenario attribute. Only 1 is allowed.")]
AmbiguousColumnAndScenario(String),
#[error("The dataframe parameters '{0}' defines both a column and a scenario. Only 1 is allowed.")]
MissingColumnOrScenario(String),
#[error("Unable to create a timeseries for file: '{0}'. No name was found.")]
MissingTimeseriesName(String),
}
1 change: 1 addition & 0 deletions pywr-schema/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ pub mod model;
pub mod nodes;
pub mod outputs;
pub mod parameters;
pub mod timeseries;

pub use error::{ConversionError, SchemaError};
pub use model::PywrModel;
Loading