Skip to content

Commit 6dafd03

Browse files
committed
Ensure meter fallback for meters are not component meters
Fix old tests that were treating single battery meters as fallback meters, which is incorrect. Also add new tests to ensure that meters are used as fallback meters only if they don't have asset component (inverters, chp, etc) as successors. Signed-off-by: Sahas Subramanian <[email protected]>
1 parent 9cfaa97 commit 6dafd03

File tree

2 files changed

+84
-5
lines changed

2 files changed

+84
-5
lines changed

src/graph/formulas/fallback.rs

Lines changed: 43 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,21 @@ impl FallbackExpr {
101101
return Ok(Some(Expr::component(component_id)));
102102
}
103103

104+
// If a meter fallback for a meter exists, make sure it is not a component meter.
105+
if self.meter_fallback_for_meters && has_successor_meters {
106+
// we've already established that if there are successor meters,
107+
// then there's only one successor.
108+
let successor = graph
109+
.successors(component_id)?
110+
.find(|node| node.is_meter())
111+
.ok_or(Error::internal(
112+
"Can't find successor meter of component with successor meters.",
113+
))?;
114+
if graph.is_component_meter(successor.component_id())? {
115+
return Ok(Some(Expr::component(component_id)));
116+
}
117+
}
118+
104119
let mut coalesced = Expr::component(component_id);
105120

106121
if !self.prefer_meters {
@@ -224,13 +239,13 @@ mod tests {
224239
.prefer_meters(true)
225240
.meter_fallback_for_meters(true)
226241
.generate(&graph, BTreeSet::from([1]))?;
227-
assert_eq!(expr.to_string(), "COALESCE(#1, #2)");
242+
assert_eq!(expr.to_string(), "#1");
228243

229244
let expr = FallbackExpr::new()
230245
.prefer_meters(true)
231246
.meter_fallback_for_meters(true)
232247
.generate(&graph, BTreeSet::from([1, 2]))?;
233-
assert_eq!(expr.to_string(), "COALESCE(#1, #2) + COALESCE(#2, #3, 0.0)");
248+
assert_eq!(expr.to_string(), "#1 + COALESCE(#2, #3, 0.0)");
234249

235250
let expr = FallbackExpr::new().generate(&graph, BTreeSet::from([1, 2]))?;
236251
assert_eq!(expr.to_string(), "#1 + COALESCE(#3, #2, 0.0)");
@@ -394,4 +409,30 @@ mod tests {
394409
let expr = graph.pv_formula(None).unwrap().to_string();
395410
assert_eq!(expr, "COALESCE(#1, 0.0) + COALESCE(#2, 0.0)");
396411
}
412+
413+
/// Test meters with meter fallback
414+
#[test]
415+
fn test_meters_with_meter_fallback() -> Result<(), Error> {
416+
let mut builder = ComponentGraphBuilder::new();
417+
let grid = builder.grid();
418+
419+
let meter1 = builder.meter();
420+
let meter2 = builder.meter();
421+
let bat_chain = builder.meter_bat_chain(1, 1);
422+
let pv_chain = builder.meter_pv_chain(1);
423+
424+
builder.connect(grid, meter1);
425+
builder.connect(meter1, meter2);
426+
builder.connect(meter2, bat_chain);
427+
builder.connect(meter2, pv_chain);
428+
429+
let graph = builder.build(None)?;
430+
let expr = FallbackExpr::new()
431+
.prefer_meters(true)
432+
.meter_fallback_for_meters(true)
433+
.generate(&graph, BTreeSet::from([meter1.component_id()]))?;
434+
assert_eq!(expr.to_string(), "COALESCE(#1, #2)");
435+
436+
Ok(())
437+
}
397438
}

src/graph/formulas/generators/grid.rs

Lines changed: 41 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ mod tests {
7373

7474
let graph = builder.build(None)?;
7575
let formula = graph.grid_formula()?.to_string();
76-
assert_eq!(formula, "COALESCE(#1, #2)");
76+
assert_eq!(formula, "#1");
7777

7878
// Add an additional dangling meter, and a PV chain and a battery chain
7979
// to the grid
@@ -92,7 +92,7 @@ mod tests {
9292
let formula = graph.grid_formula()?.to_string();
9393
assert_eq!(
9494
formula,
95-
"COALESCE(#1, #2) + #5 + COALESCE(#6, #7, 0.0) + COALESCE(#9, #10, 0.0)"
95+
"#1 + #5 + COALESCE(#6, #7, 0.0) + COALESCE(#9, #10, 0.0)"
9696
);
9797

9898
// Add a PV inverter to the grid, without a meter.
@@ -105,9 +105,47 @@ mod tests {
105105
let formula = graph.grid_formula()?.to_string();
106106
assert_eq!(
107107
formula,
108-
"COALESCE(#1, #2) + #5 + COALESCE(#6, #7, 0.0) + COALESCE(#9, #10, 0.0) + COALESCE(#11, 0.0)"
108+
"#1 + #5 + COALESCE(#6, #7, 0.0) + COALESCE(#9, #10, 0.0) + COALESCE(#11, 0.0)"
109109
);
110110

111111
Ok(())
112112
}
113+
114+
#[test]
115+
fn test_grid_formula_with_fallback_grid_meter() -> Result<(), Error> {
116+
let mut builder = ComponentGraphBuilder::new();
117+
let grid = builder.grid();
118+
119+
let meter1 = builder.meter();
120+
let meter2 = builder.meter();
121+
let bat_chain = builder.meter_bat_chain(1, 1);
122+
let pv_chain = builder.meter_pv_chain(1);
123+
124+
builder.connect(grid, meter1);
125+
builder.connect(meter1, meter2);
126+
builder.connect(meter2, bat_chain);
127+
builder.connect(meter2, pv_chain);
128+
129+
let graph = builder.build(None)?;
130+
let formula = graph.grid_formula()?.to_string();
131+
assert_eq!(formula, "COALESCE(#1, #2)");
132+
133+
// Add a battery chain directly to the grid
134+
let bat_chain = builder.meter_bat_chain(1, 1);
135+
builder.connect(grid, bat_chain);
136+
137+
let graph = builder.build(None)?;
138+
let formula = graph.grid_formula()?.to_string();
139+
assert_eq!(formula, "COALESCE(#1, #2) + COALESCE(#8, #9, 0.0)");
140+
141+
// Add a PV chain directly to meter1, making meter2 not a fallback
142+
let pv_chain = builder.meter_pv_chain(1);
143+
builder.connect(meter1, pv_chain);
144+
145+
let graph = builder.build(None)?;
146+
let formula = graph.grid_formula()?.to_string();
147+
assert_eq!(formula, "#1 + COALESCE(#8, #9, 0.0)");
148+
149+
Ok(())
150+
}
113151
}

0 commit comments

Comments
 (0)