@@ -9,9 +9,26 @@ use std::collections::BTreeSet;
99
1010use super :: expr:: Expr ;
1111
12+ #[ derive( Default ) ]
1213pub ( crate ) struct FallbackExpr {
13- pub ( crate ) prefer_meters : bool ,
14- pub ( crate ) meter_fallback_for_meters : bool ,
14+ prefer_meters : bool ,
15+ meter_fallback_for_meters : bool ,
16+ }
17+
18+ impl FallbackExpr {
19+ pub fn new ( ) -> Self {
20+ Self :: default ( )
21+ }
22+
23+ pub fn prefer_meters ( mut self , prefer : bool ) -> Self {
24+ self . prefer_meters = prefer;
25+ self
26+ }
27+
28+ pub fn meter_fallback_for_meters ( mut self , enable : bool ) -> Self {
29+ self . meter_fallback_for_meters = enable;
30+ self
31+ }
1532}
1633
1734impl FallbackExpr {
@@ -84,6 +101,21 @@ impl FallbackExpr {
84101 return Ok ( Some ( Expr :: component ( component_id) ) ) ;
85102 }
86103
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+
87119 let mut coalesced = Expr :: component ( component_id) ;
88120
89121 if !self . prefer_meters {
@@ -203,76 +235,56 @@ mod tests {
203235 assert_eq ! ( meter_bat_chain. component_id( ) , 2 ) ;
204236
205237 let graph = builder. build ( None ) ?;
206- let expr = FallbackExpr {
207- prefer_meters : true ,
208- meter_fallback_for_meters : true ,
209- }
210- . generate ( & graph, BTreeSet :: from ( [ 1 ] ) ) ?;
211- assert_eq ! ( expr. to_string( ) , "COALESCE(#1, #2)" ) ;
212-
213- let expr = FallbackExpr {
214- prefer_meters : true ,
215- meter_fallback_for_meters : true ,
216- }
217- . generate ( & graph, BTreeSet :: from ( [ 1 , 2 ] ) ) ?;
218- assert_eq ! ( expr. to_string( ) , "COALESCE(#1, #2) + COALESCE(#2, #3, 0.0)" ) ;
238+ let expr = FallbackExpr :: new ( )
239+ . prefer_meters ( true )
240+ . meter_fallback_for_meters ( true )
241+ . generate ( & graph, BTreeSet :: from ( [ 1 ] ) ) ?;
242+ assert_eq ! ( expr. to_string( ) , "#1" ) ;
243+
244+ let expr = FallbackExpr :: new ( )
245+ . prefer_meters ( true )
246+ . meter_fallback_for_meters ( true )
247+ . generate ( & graph, BTreeSet :: from ( [ 1 , 2 ] ) ) ?;
248+ assert_eq ! ( expr. to_string( ) , "#1 + COALESCE(#2, #3, 0.0)" ) ;
219249
220- let expr = FallbackExpr {
221- prefer_meters : false ,
222- meter_fallback_for_meters : false ,
223- }
224- . generate ( & graph, BTreeSet :: from ( [ 1 , 2 ] ) ) ?;
250+ let expr = FallbackExpr :: new ( ) . generate ( & graph, BTreeSet :: from ( [ 1 , 2 ] ) ) ?;
225251 assert_eq ! ( expr. to_string( ) , "#1 + COALESCE(#3, #2, 0.0)" ) ;
226252
227- let expr = FallbackExpr {
228- prefer_meters : true ,
229- meter_fallback_for_meters : false ,
230- }
231- . generate ( & graph, BTreeSet :: from ( [ 1 , 2 ] ) ) ?;
253+ let expr = FallbackExpr :: new ( )
254+ . prefer_meters ( true )
255+ . generate ( & graph, BTreeSet :: from ( [ 1 , 2 ] ) ) ?;
232256 assert_eq ! ( expr. to_string( ) , "#1 + COALESCE(#2, #3, 0.0)" ) ;
233257
234- let expr = FallbackExpr {
235- prefer_meters : true ,
236- meter_fallback_for_meters : false ,
237- }
238- . generate ( & graph, BTreeSet :: from ( [ 3 ] ) ) ?;
258+ let expr = FallbackExpr :: new ( )
259+ . prefer_meters ( true )
260+ . generate ( & graph, BTreeSet :: from ( [ 3 ] ) ) ?;
239261 assert_eq ! ( expr. to_string( ) , "COALESCE(#2, #3, 0.0)" ) ;
240- let expr = FallbackExpr {
241- prefer_meters : true ,
242- meter_fallback_for_meters : true ,
243- }
244- . generate ( & graph, BTreeSet :: from ( [ 3 ] ) ) ?;
262+ let expr = FallbackExpr :: new ( )
263+ . prefer_meters ( true )
264+ . meter_fallback_for_meters ( true )
265+ . generate ( & graph, BTreeSet :: from ( [ 3 ] ) ) ?;
245266 assert_eq ! ( expr. to_string( ) , "COALESCE(#2, #3, 0.0)" ) ;
246- let expr = FallbackExpr {
247- prefer_meters : true ,
248- meter_fallback_for_meters : true ,
249- }
250- . generate ( & graph, BTreeSet :: from ( [ 2 ] ) ) ?;
267+ let expr = FallbackExpr :: new ( )
268+ . prefer_meters ( true )
269+ . meter_fallback_for_meters ( true )
270+ . generate ( & graph, BTreeSet :: from ( [ 2 ] ) ) ?;
251271 assert_eq ! ( expr. to_string( ) , "COALESCE(#2, #3, 0.0)" ) ;
252272
253273 let graph = builder. build ( Some ( ComponentGraphConfig {
254274 disable_fallback_components : true ,
255275 ..Default :: default ( )
256276 } ) ) ?;
257- let expr = FallbackExpr {
258- prefer_meters : false ,
259- meter_fallback_for_meters : false ,
260- }
261- . generate ( & graph, BTreeSet :: from ( [ 1 , 2 ] ) ) ?;
277+ let expr = FallbackExpr :: new ( ) . generate ( & graph, BTreeSet :: from ( [ 1 , 2 ] ) ) ?;
262278 assert_eq ! ( expr. to_string( ) , "#1 + #2" ) ;
263279
264- let expr = FallbackExpr {
265- prefer_meters : true ,
266- meter_fallback_for_meters : false ,
267- }
268- . generate ( & graph, BTreeSet :: from ( [ 1 , 2 ] ) ) ?;
280+ let expr = FallbackExpr :: new ( )
281+ . prefer_meters ( true )
282+ . generate ( & graph, BTreeSet :: from ( [ 1 , 2 ] ) ) ?;
269283 assert_eq ! ( expr. to_string( ) , "#1 + #2" ) ;
270284
271- let expr = FallbackExpr {
272- prefer_meters : true ,
273- meter_fallback_for_meters : false ,
274- }
275- . generate ( & graph, BTreeSet :: from ( [ 3 ] ) ) ?;
285+ let expr = FallbackExpr :: new ( )
286+ . prefer_meters ( true )
287+ . generate ( & graph, BTreeSet :: from ( [ 3 ] ) ) ?;
276288 assert_eq ! ( expr. to_string( ) , "#3" ) ;
277289
278290 // Add a battery meter with three inverter and three batteries
@@ -282,11 +294,7 @@ mod tests {
282294 assert_eq ! ( meter_bat_chain. component_id( ) , 5 ) ;
283295
284296 let graph = builder. build ( None ) ?;
285- let expr = FallbackExpr {
286- prefer_meters : false ,
287- meter_fallback_for_meters : false ,
288- }
289- . generate ( & graph, BTreeSet :: from ( [ 3 , 5 ] ) ) ?;
297+ let expr = FallbackExpr :: new ( ) . generate ( & graph, BTreeSet :: from ( [ 3 , 5 ] ) ) ?;
290298 assert_eq ! (
291299 expr. to_string( ) ,
292300 concat!(
@@ -299,11 +307,9 @@ mod tests {
299307 )
300308 ) ;
301309
302- let expr = FallbackExpr {
303- prefer_meters : true ,
304- meter_fallback_for_meters : false ,
305- }
306- . generate ( & graph, BTreeSet :: from ( [ 2 , 5 ] ) ) ?;
310+ let expr = FallbackExpr :: new ( )
311+ . prefer_meters ( true )
312+ . generate ( & graph, BTreeSet :: from ( [ 2 , 5 ] ) ) ?;
307313 assert_eq ! (
308314 expr. to_string( ) ,
309315 concat!(
@@ -312,11 +318,9 @@ mod tests {
312318 )
313319 ) ;
314320
315- let expr = FallbackExpr {
316- prefer_meters : true ,
317- meter_fallback_for_meters : false ,
318- }
319- . generate ( & graph, BTreeSet :: from ( [ 2 , 6 , 7 , 8 ] ) ) ?;
321+ let expr = FallbackExpr :: new ( )
322+ . prefer_meters ( true )
323+ . generate ( & graph, BTreeSet :: from ( [ 2 , 6 , 7 , 8 ] ) ) ?;
320324 assert_eq ! (
321325 expr. to_string( ) ,
322326 concat!(
@@ -325,11 +329,9 @@ mod tests {
325329 )
326330 ) ;
327331
328- let expr = FallbackExpr {
329- prefer_meters : true ,
330- meter_fallback_for_meters : false ,
331- }
332- . generate ( & graph, BTreeSet :: from ( [ 2 , 7 , 8 ] ) ) ?;
332+ let expr = FallbackExpr :: new ( )
333+ . prefer_meters ( true )
334+ . generate ( & graph, BTreeSet :: from ( [ 2 , 7 , 8 ] ) ) ?;
333335 assert_eq ! (
334336 expr. to_string( ) ,
335337 "COALESCE(#2, #3, 0.0) + COALESCE(#7, 0.0) + COALESCE(#8, 0.0)"
@@ -339,32 +341,22 @@ mod tests {
339341 disable_fallback_components : true ,
340342 ..Default :: default ( )
341343 } ) ) ?;
342- let expr = FallbackExpr {
343- prefer_meters : false ,
344- meter_fallback_for_meters : false ,
345- }
346- . generate ( & graph, BTreeSet :: from ( [ 3 , 5 ] ) ) ?;
344+ let expr = FallbackExpr :: new ( ) . generate ( & graph, BTreeSet :: from ( [ 3 , 5 ] ) ) ?;
347345 assert_eq ! ( expr. to_string( ) , "#3 + #5" ) ;
348346
349- let expr = FallbackExpr {
350- prefer_meters : true ,
351- meter_fallback_for_meters : false ,
352- }
353- . generate ( & graph, BTreeSet :: from ( [ 2 , 5 ] ) ) ?;
347+ let expr = FallbackExpr :: new ( )
348+ . prefer_meters ( true )
349+ . generate ( & graph, BTreeSet :: from ( [ 2 , 5 ] ) ) ?;
354350 assert_eq ! ( expr. to_string( ) , "#2 + #5" ) ;
355351
356- let expr = FallbackExpr {
357- prefer_meters : true ,
358- meter_fallback_for_meters : false ,
359- }
360- . generate ( & graph, BTreeSet :: from ( [ 2 , 6 , 7 , 8 ] ) ) ?;
352+ let expr = FallbackExpr :: new ( )
353+ . prefer_meters ( true )
354+ . generate ( & graph, BTreeSet :: from ( [ 2 , 6 , 7 , 8 ] ) ) ?;
361355 assert_eq ! ( expr. to_string( ) , "#2 + #6 + #7 + #8" ) ;
362356
363- let expr = FallbackExpr {
364- prefer_meters : true ,
365- meter_fallback_for_meters : false ,
366- }
367- . generate ( & graph, BTreeSet :: from ( [ 2 , 7 , 8 ] ) ) ?;
357+ let expr = FallbackExpr :: new ( )
358+ . prefer_meters ( true )
359+ . generate ( & graph, BTreeSet :: from ( [ 2 , 7 , 8 ] ) ) ?;
368360 assert_eq ! ( expr. to_string( ) , "#2 + #7 + #8" ) ;
369361
370362 let meter = builder. meter ( ) ;
@@ -379,11 +371,9 @@ mod tests {
379371 assert_eq ! ( pv_inverter. component_id( ) , 14 ) ;
380372
381373 let graph = builder. build ( None ) ?;
382- let expr = FallbackExpr {
383- prefer_meters : true ,
384- meter_fallback_for_meters : false ,
385- }
386- . generate ( & graph, BTreeSet :: from ( [ 5 , 12 ] ) ) ?;
374+ let expr = FallbackExpr :: new ( )
375+ . prefer_meters ( true )
376+ . generate ( & graph, BTreeSet :: from ( [ 5 , 12 ] ) ) ?;
387377 assert_eq ! (
388378 expr. to_string( ) ,
389379 concat!(
@@ -392,11 +382,7 @@ mod tests {
392382 )
393383 ) ;
394384
395- let expr = FallbackExpr {
396- prefer_meters : false ,
397- meter_fallback_for_meters : false ,
398- }
399- . generate ( & graph, BTreeSet :: from ( [ 7 , 14 ] ) ) ?;
385+ let expr = FallbackExpr :: new ( ) . generate ( & graph, BTreeSet :: from ( [ 7 , 14 ] ) ) ?;
400386 assert_eq ! ( expr. to_string( ) , "COALESCE(#7, 0.0) + COALESCE(#14, 0.0)" ) ;
401387
402388 Ok ( ( ) )
@@ -423,4 +409,30 @@ mod tests {
423409 let expr = graph. pv_formula ( None ) . unwrap ( ) . to_string ( ) ;
424410 assert_eq ! ( expr, "COALESCE(#1, 0.0) + COALESCE(#2, 0.0)" ) ;
425411 }
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+ }
426438}
0 commit comments