Skip to content

Commit 9f77d38

Browse files
authored
Merge pull request #953 from EnergySystemsModellingLab/report-unmet-demand-for-errors
Report regions/commodities with unmet demand if dispatch fails
2 parents 6c18774 + 0ea5664 commit 9f77d38

5 files changed

Lines changed: 296 additions & 78 deletions

File tree

docs/model/dispatch_optimisation.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -173,6 +173,9 @@ commodities:
173173
\end{aligned}
174174
\\]
175175

176+
Note that the unmet demand variables (\\( UnmetD[c,r,t] \\)) are normally not included in the
177+
optimisation and are currently only used to diagnose the source of errors when running the model.
178+
176179
### Constraints
177180

178181
The complete set of constraints that the optimisation must satisfy includes:

src/input.rs

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use indexmap::IndexMap;
1313
use itertools::Itertools;
1414
use serde::de::{Deserialize, DeserializeOwned, Deserializer};
1515
use std::collections::HashMap;
16+
use std::fmt::{self, Write};
1617
use std::fs;
1718
use std::hash::Hash;
1819
use std::path::Path;
@@ -158,25 +159,37 @@ where
158159
/// If the key already exists, it returns an error with a message indicating the key's existence.
159160
pub fn try_insert<K, V>(map: &mut HashMap<K, V>, key: &K, value: V) -> Result<()>
160161
where
161-
K: Eq + Hash + Clone + std::fmt::Debug,
162+
K: Eq + Hash + Clone + fmt::Debug,
162163
{
163164
let existing = map.insert(key.clone(), value).is_some();
164165
ensure!(!existing, "Key {key:?} already exists in the map");
165166
Ok(())
166167
}
167168

168169
/// Format a list of items with a cap on display count for error messages
169-
pub fn format_items_with_cap<T: std::fmt::Debug>(items: &[T]) -> String {
170+
pub fn format_items_with_cap<I, J, T>(items: I) -> String
171+
where
172+
I: IntoIterator<Item = T, IntoIter = J>,
173+
J: ExactSizeIterator<Item = T>,
174+
T: fmt::Debug,
175+
{
170176
const MAX_DISPLAY: usize = 10;
171-
if items.len() <= MAX_DISPLAY {
172-
format!("{items:?}")
173-
} else {
174-
format!(
175-
"{:?} and {} more",
176-
&items[..MAX_DISPLAY],
177-
items.len() - MAX_DISPLAY
178-
)
177+
178+
let items = items.into_iter();
179+
let total_count = items.len();
180+
181+
// Format items with fmt::Debug::fmt() and separate with commas
182+
let formatted_items = items
183+
.take(MAX_DISPLAY)
184+
.format_with(", ", |items, f| f(&format_args!("{items:?}")));
185+
let mut out = format!("[{formatted_items}]");
186+
187+
// If there are remaining items, include the count
188+
if total_count > MAX_DISPLAY {
189+
write!(&mut out, " and {} more", total_count - MAX_DISPLAY).unwrap();
179190
}
191+
192+
out
180193
}
181194

182195
/// Read a model from the specified directory.

src/model.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
use crate::agent::AgentMap;
33
use crate::commodity::{CommodityID, CommodityMap};
44
use crate::process::ProcessMap;
5-
use crate::region::{RegionID, RegionMap};
5+
use crate::region::{Region, RegionID, RegionMap};
66
use crate::time_slice::TimeSliceInfo;
77
use std::collections::HashMap;
88
use std::path::PathBuf;
@@ -39,7 +39,7 @@ impl Model {
3939
}
4040

4141
/// Iterate over the model's regions (region IDs).
42-
pub fn iter_regions(&self) -> impl Iterator<Item = &RegionID> + '_ {
42+
pub fn iter_regions(&self) -> indexmap::map::Keys<'_, RegionID, Region> {
4343
self.regions.keys()
4444
}
4545
}

0 commit comments

Comments
 (0)