2020 & self ,
2121 component_ids : impl IntoIterator < Item = u64 > ,
2222 prefer_meters : bool ,
23+ meter_fallback_for_meters : bool ,
2324 ) -> Result < Expr , Error > {
2425 FallbackExpr {
2526 prefer_meters,
27+ meter_fallback_for_meters,
2628 graph : self ,
2729 }
2830 . generate ( BTreeSet :: from_iter ( component_ids) )
3537 E : Edge ,
3638{
3739 pub ( crate ) prefer_meters : bool ,
40+ pub ( crate ) meter_fallback_for_meters : bool ,
3841 pub ( crate ) graph : & ' a ComponentGraph < N , E > ,
3942}
4043
6770 /// Returns a fallback expression for a meter component.
6871 fn meter_fallback ( & self , component_id : u64 ) -> Result < Option < Expr > , Error > {
6972 let component = self . graph . component ( component_id) ?;
70- if !component. is_meter ( ) || self . graph . has_meter_successors ( component_id ) ? {
73+ if !component. is_meter ( ) {
7174 return Ok ( None ) ;
7275 }
76+ let has_successor_meters = self . graph . has_meter_successors ( component_id) ?;
77+
78+ if !self . meter_fallback_for_meters && has_successor_meters {
79+ return Ok ( Some ( Expr :: component ( component_id) ) ) ;
80+ }
7381
7482 if !self . graph . has_successors ( component_id) ? {
7583 return Ok ( Some ( Expr :: component ( component_id) ) ) ;
9199
92100 let has_multiple_successors = matches ! ( sum_of_successors, Expr :: Add { .. } ) ;
93101
102+ // If a meter has exactly one successor and it is a meter, we consider
103+ // it to be a fallback meter. If there are multiple meter successors,
104+ // we return the meter without fallback.
105+ if has_successor_meters && has_multiple_successors {
106+ return Ok ( Some ( Expr :: component ( component_id) ) ) ;
107+ }
108+
94109 let mut coalesced = Expr :: component ( component_id) ;
95110
96111 if !self . prefer_meters {
@@ -102,11 +117,13 @@ where
102117 coalesced = coalesced. coalesce ( sum_of_coalesced_successors) ;
103118 } else {
104119 coalesced = coalesced. coalesce ( sum_of_successors) ;
105- coalesced = coalesced. coalesce ( Expr :: number ( 0.0 ) ) ;
120+ if !has_successor_meters {
121+ coalesced = coalesced. coalesce ( Expr :: number ( 0.0 ) ) ;
122+ }
106123 }
107124 } else if has_multiple_successors {
108125 coalesced = coalesced. coalesce ( sum_of_coalesced_successors) ;
109- } else {
126+ } else if !has_successor_meters {
110127 coalesced = coalesced. coalesce ( Expr :: number ( 0.0 ) ) ;
111128 }
112129
@@ -202,26 +219,36 @@ mod tests {
202219 assert_eq ! ( meter_bat_chain. component_id( ) , 2 ) ;
203220
204221 let graph = builder. build ( None ) ?;
205- let expr = graph. fallback_expr ( vec ! [ 1 , 2 ] , false ) ?;
222+ let expr = graph. fallback_expr ( vec ! [ 1 ] , true , true ) ?;
223+ assert_eq ! ( expr. to_string( ) , "COALESCE(#1, #2)" ) ;
224+
225+ let expr = graph. fallback_expr ( vec ! [ 1 , 2 ] , true , true ) ?;
226+ assert_eq ! ( expr. to_string( ) , "COALESCE(#1, #2) + COALESCE(#2, #3, 0.0)" ) ;
227+
228+ let expr = graph. fallback_expr ( vec ! [ 1 , 2 ] , false , false ) ?;
206229 assert_eq ! ( expr. to_string( ) , "#1 + COALESCE(#3, #2, 0.0)" ) ;
207230
208- let expr = graph. fallback_expr ( vec ! [ 1 , 2 ] , true ) ?;
231+ let expr = graph. fallback_expr ( vec ! [ 1 , 2 ] , true , false ) ?;
209232 assert_eq ! ( expr. to_string( ) , "#1 + COALESCE(#2, #3, 0.0)" ) ;
210233
211- let expr = graph. fallback_expr ( vec ! [ 3 ] , true ) ?;
234+ let expr = graph. fallback_expr ( vec ! [ 3 ] , true , false ) ?;
235+ assert_eq ! ( expr. to_string( ) , "COALESCE(#2, #3, 0.0)" ) ;
236+ let expr = graph. fallback_expr ( vec ! [ 3 ] , true , true ) ?;
237+ assert_eq ! ( expr. to_string( ) , "COALESCE(#2, #3, 0.0)" ) ;
238+ let expr = graph. fallback_expr ( vec ! [ 2 ] , true , true ) ?;
212239 assert_eq ! ( expr. to_string( ) , "COALESCE(#2, #3, 0.0)" ) ;
213240
214241 let graph = builder. build ( Some ( ComponentGraphConfig {
215242 disable_fallback_components : true ,
216243 ..Default :: default ( )
217244 } ) ) ?;
218- let expr = graph. fallback_expr ( vec ! [ 1 , 2 ] , false ) ?;
245+ let expr = graph. fallback_expr ( vec ! [ 1 , 2 ] , false , false ) ?;
219246 assert_eq ! ( expr. to_string( ) , "#1 + #2" ) ;
220247
221- let expr = graph. fallback_expr ( vec ! [ 1 , 2 ] , true ) ?;
248+ let expr = graph. fallback_expr ( vec ! [ 1 , 2 ] , true , false ) ?;
222249 assert_eq ! ( expr. to_string( ) , "#1 + #2" ) ;
223250
224- let expr = graph. fallback_expr ( vec ! [ 3 ] , true ) ?;
251+ let expr = graph. fallback_expr ( vec ! [ 3 ] , true , false ) ?;
225252 assert_eq ! ( expr. to_string( ) , "#3" ) ;
226253
227254 // Add a battery meter with three inverter and three batteries
@@ -231,7 +258,7 @@ mod tests {
231258 assert_eq ! ( meter_bat_chain. component_id( ) , 5 ) ;
232259
233260 let graph = builder. build ( None ) ?;
234- let expr = graph. fallback_expr ( vec ! [ 3 , 5 ] , false ) ?;
261+ let expr = graph. fallback_expr ( vec ! [ 3 , 5 ] , false , false ) ?;
235262 assert_eq ! (
236263 expr. to_string( ) ,
237264 concat!(
@@ -244,7 +271,7 @@ mod tests {
244271 )
245272 ) ;
246273
247- let expr = graph. fallback_expr ( vec ! [ 2 , 5 ] , true ) ?;
274+ let expr = graph. fallback_expr ( vec ! [ 2 , 5 ] , true , false ) ?;
248275 assert_eq ! (
249276 expr. to_string( ) ,
250277 concat!(
@@ -253,7 +280,7 @@ mod tests {
253280 )
254281 ) ;
255282
256- let expr = graph. fallback_expr ( vec ! [ 2 , 6 , 7 , 8 ] , true ) ?;
283+ let expr = graph. fallback_expr ( vec ! [ 2 , 6 , 7 , 8 ] , true , false ) ?;
257284 assert_eq ! (
258285 expr. to_string( ) ,
259286 concat!(
@@ -262,7 +289,7 @@ mod tests {
262289 )
263290 ) ;
264291
265- let expr = graph. fallback_expr ( vec ! [ 2 , 7 , 8 ] , true ) ?;
292+ let expr = graph. fallback_expr ( vec ! [ 2 , 7 , 8 ] , true , false ) ?;
266293 assert_eq ! (
267294 expr. to_string( ) ,
268295 "COALESCE(#2, #3, 0.0) + COALESCE(#7, 0.0) + COALESCE(#8, 0.0)"
@@ -272,16 +299,16 @@ mod tests {
272299 disable_fallback_components : true ,
273300 ..Default :: default ( )
274301 } ) ) ?;
275- let expr = graph. fallback_expr ( vec ! [ 3 , 5 ] , false ) ?;
302+ let expr = graph. fallback_expr ( vec ! [ 3 , 5 ] , false , false ) ?;
276303 assert_eq ! ( expr. to_string( ) , "#3 + #5" ) ;
277304
278- let expr = graph. fallback_expr ( vec ! [ 2 , 5 ] , true ) ?;
305+ let expr = graph. fallback_expr ( vec ! [ 2 , 5 ] , true , false ) ?;
279306 assert_eq ! ( expr. to_string( ) , "#2 + #5" ) ;
280307
281- let expr = graph. fallback_expr ( vec ! [ 2 , 6 , 7 , 8 ] , true ) ?;
308+ let expr = graph. fallback_expr ( vec ! [ 2 , 6 , 7 , 8 ] , true , false ) ?;
282309 assert_eq ! ( expr. to_string( ) , "#2 + #6 + #7 + #8" ) ;
283310
284- let expr = graph. fallback_expr ( vec ! [ 2 , 7 , 8 ] , true ) ?;
311+ let expr = graph. fallback_expr ( vec ! [ 2 , 7 , 8 ] , true , false ) ?;
285312 assert_eq ! ( expr. to_string( ) , "#2 + #7 + #8" ) ;
286313
287314 let meter = builder. meter ( ) ;
@@ -296,7 +323,7 @@ mod tests {
296323 assert_eq ! ( pv_inverter. component_id( ) , 14 ) ;
297324
298325 let graph = builder. build ( None ) ?;
299- let expr = graph. fallback_expr ( vec ! [ 5 , 12 ] , true ) ?;
326+ let expr = graph. fallback_expr ( vec ! [ 5 , 12 ] , true , false ) ?;
300327 assert_eq ! (
301328 expr. to_string( ) ,
302329 concat!(
@@ -305,7 +332,7 @@ mod tests {
305332 )
306333 ) ;
307334
308- let expr = graph. fallback_expr ( vec ! [ 7 , 14 ] , false ) ?;
335+ let expr = graph. fallback_expr ( vec ! [ 7 , 14 ] , false , false ) ?;
309336 assert_eq ! ( expr. to_string( ) , "COALESCE(#7, 0.0) + COALESCE(#14, 0.0)" ) ;
310337
311338 Ok ( ( ) )
0 commit comments