Skip to content

Commit 83b6347

Browse files
authored
Merge pull request #1078 from EnergySystemsModellingLab/divisible_dispatch_flexible_capacity
Use integer capacity variables for dispatch
2 parents 6cf7598 + 255c875 commit 83b6347

File tree

2 files changed

+34
-6
lines changed

2 files changed

+34
-6
lines changed

src/simulation/optimisation.rs

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,7 +260,16 @@ impl Solution<'_> {
260260
.capacity_vars
261261
.keys()
262262
.zip(self.solution.columns()[self.variables.capacity_var_idx.clone()].iter())
263-
.map(|(asset, capacity)| (asset, Capacity(*capacity)))
263+
.map(|(asset, capacity)| {
264+
// If the asset is divisible, the capacity variable represents number of units,
265+
// so convert to total capacity
266+
let capacity_value = if let Some(unit_size) = asset.unit_size() {
267+
capacity * unit_size.value()
268+
} else {
269+
*capacity
270+
};
271+
(asset, Capacity(capacity_value))
272+
})
264273
}
265274

266275
/// Keys and dual values for commodity balance constraints.
@@ -647,10 +656,22 @@ fn add_capacity_variables(
647656
);
648657

649658
let current_capacity = asset.capacity().value();
650-
let lower = ((1.0 - capacity_margin) * current_capacity).max(0.0);
651-
let upper = (1.0 + capacity_margin) * current_capacity;
652659
let coeff = calculate_capacity_coefficient(asset);
653-
let var = problem.add_column(coeff.value(), lower..=upper);
660+
661+
let var = if let Some(unit_size) = asset.unit_size() {
662+
// Divisible asset: capacity variable represents number of units
663+
let unit_size_value = unit_size.value();
664+
let current_units = current_capacity / unit_size_value;
665+
let lower = ((1.0 - capacity_margin) * current_units).max(0.0);
666+
let upper = (1.0 + capacity_margin) * current_units;
667+
problem.add_integer_column(coeff.value() * unit_size_value, lower..=upper)
668+
} else {
669+
// Indivisible asset: capacity variable represents total capacity
670+
let lower = ((1.0 - capacity_margin) * current_capacity).max(0.0);
671+
let upper = (1.0 + capacity_margin) * current_capacity;
672+
problem.add_column(coeff.value(), lower..=upper)
673+
};
674+
654675
let existing = variables.insert(asset.clone(), var).is_some();
655676
assert!(!existing, "Duplicate entry for var");
656677
}

src/simulation/optimisation/constraints.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -230,8 +230,15 @@ where
230230
if let Some(&capacity_var) = capacity_vars.get(asset) {
231231
// Asset with flexible capacity
232232
for (ts_selection, limits) in asset.iter_activity_per_capacity_limits() {
233-
let upper_limit = limits.end().value();
234-
let lower_limit = limits.start().value();
233+
let mut upper_limit = limits.end().value();
234+
let mut lower_limit = limits.start().value();
235+
236+
// If the asset is divisible, the capacity variable represents number of units,
237+
// so we need to multiply the per-capacity limits by the unit size.
238+
if let Some(unit_size) = asset.unit_size() {
239+
upper_limit *= unit_size.value();
240+
lower_limit *= unit_size.value();
241+
}
235242

236243
// Collect capacity and activity terms
237244
// We have a single capacity term, and activity terms for all time slices in the selection

0 commit comments

Comments
 (0)