11//! Code for reading process flows file
22use super :: super :: * ;
3- use crate :: commodity:: { CommodityID , CommodityMap } ;
3+ use crate :: commodity:: CommodityMap ;
44use crate :: id:: IDCollection ;
55use crate :: process:: { FlowType , Process , ProcessFlow , ProcessFlowsMap , ProcessID } ;
66use crate :: region:: parse_region_str;
@@ -25,7 +25,6 @@ struct ProcessFlowRaw {
2525 #[ serde( rename = "type" ) ]
2626 kind : FlowType ,
2727 cost : Option < f64 > ,
28- is_pac : bool ,
2928}
3029
3130impl ProcessFlowRaw {
@@ -112,7 +111,6 @@ where
112111 coeff : record. coeff ,
113112 kind : record. kind ,
114113 cost : record. cost . unwrap_or ( 0.0 ) ,
115- is_pac : record. is_pac ,
116114 } ;
117115
118116 // Insert flow into the map
@@ -134,63 +132,26 @@ where
134132 }
135133 }
136134
137- // Validate flows and sort flows so PACs are at the start
138135 for ( process_id, map) in map. iter_mut ( ) {
139136 let process = processes. get ( process_id) . unwrap ( ) ;
140137 validate_process_flows_map ( process, map) ?;
141- sort_flows ( map) ;
142138 }
143139
144140 Ok ( map)
145141}
146142
147- /// Sort flows so PACs come first
148- fn sort_flows ( map : & mut ProcessFlowsMap ) {
149- for map in map. values_mut ( ) {
150- map. sort_by ( |_, a, _, b| b. is_pac . cmp ( & a. is_pac ) ) ;
151- }
152- }
153-
154143/// Validate flows for a process
155144fn validate_process_flows_map ( process : & Process , map : & ProcessFlowsMap ) -> Result < ( ) > {
156145 let process_id = process. id . clone ( ) ;
157- let reference_years = & process. years ;
158- let reference_regions = & process. regions ;
159- for year in reference_years. iter ( ) {
160- for region in reference_regions {
146+ for year in process. years . iter ( ) {
147+ for region in process. regions . iter ( ) {
161148 // Check that the process has flows for this region/year
162- let flow_map = map. get ( & ( region. clone ( ) , * year) ) . with_context ( || {
163- format ! ( "Missing entry for process {process_id} in {region}/{year}" )
164- } ) ?;
165-
166- // Validate flows for this process/region/year
167- validate_flow_map ( flow_map) . with_context ( || {
168- format ! ( "Invalid flows for process {process_id} in {region}/{year}" )
169- } ) ?;
170- }
171- }
172- Ok ( ( ) )
173- }
174-
175- /// Validate a vector of flows for a process in a given region/year
176- fn validate_flow_map ( flow_map : & IndexMap < CommodityID , ProcessFlow > ) -> Result < ( ) > {
177- // PACs must be either all inputs or all outputs
178- let mut flow_sign: Option < bool > = None ; // False for inputs, true for outputs
179- for flow in flow_map. values ( ) . filter ( |flow| flow. is_pac ) {
180- // Check that flow sign is consistent
181- let current_flow_sign = flow. coeff > 0.0 ;
182- if let Some ( flow_sign) = flow_sign {
183149 ensure ! (
184- current_flow_sign == flow_sign ,
185- "PACs are a mix of inputs and outputs" ,
150+ map . contains_key ( & ( region . clone ( ) , * year ) ) ,
151+ "Missing entry for process {process_id} in {region}/{year}"
186152 ) ;
187153 }
188- flow_sign = Some ( current_flow_sign) ;
189154 }
190-
191- // Check that at least one PAC is defined
192- ensure ! ( flow_sign. is_some( ) , "No PACs defined" ) ;
193-
194155 Ok ( ( ) )
195156}
196157
@@ -199,15 +160,10 @@ mod tests {
199160 use super :: * ;
200161 use crate :: commodity:: { Commodity , CommodityLevyMap , CommodityType , DemandMap } ;
201162 use crate :: time_slice:: TimeSliceLevel ;
202- use indexmap:: indexmap;
203- use rstest:: { fixture, rstest} ;
204163
205- fn create_process_flow_raw (
206- coeff : f64 ,
207- kind : FlowType ,
208- cost : Option < f64 > ,
209- is_pac : bool ,
210- ) -> ProcessFlowRaw {
164+ use rstest:: fixture;
165+
166+ fn create_process_flow_raw ( coeff : f64 , kind : FlowType , cost : Option < f64 > ) -> ProcessFlowRaw {
211167 ProcessFlowRaw {
212168 process_id : "process" . into ( ) ,
213169 commodity_id : "commodity" . into ( ) ,
@@ -216,45 +172,34 @@ mod tests {
216172 coeff,
217173 kind,
218174 cost,
219- is_pac,
220175 }
221176 }
222177
223178 #[ test]
224179 fn test_validate_flow_raw ( ) {
225180 // Valid
226- let valid = create_process_flow_raw ( 1.0 , FlowType :: Fixed , Some ( 0.0 ) , true ) ;
181+ let valid = create_process_flow_raw ( 1.0 , FlowType :: Fixed , Some ( 0.0 ) ) ;
227182 assert ! ( valid. validate( ) . is_ok( ) ) ;
228183
229184 // Invalid: Bad flow value
230- let invalid = create_process_flow_raw ( 0.0 , FlowType :: Fixed , Some ( 0.0 ) , true ) ;
185+ let invalid = create_process_flow_raw ( 0.0 , FlowType :: Fixed , Some ( 0.0 ) ) ;
231186 assert ! ( invalid. validate( ) . is_err( ) ) ;
232- let invalid = create_process_flow_raw ( f64:: NAN , FlowType :: Fixed , Some ( 0.0 ) , true ) ;
187+ let invalid = create_process_flow_raw ( f64:: NAN , FlowType :: Fixed , Some ( 0.0 ) ) ;
233188 assert ! ( invalid. validate( ) . is_err( ) ) ;
234- let invalid = create_process_flow_raw ( f64:: INFINITY , FlowType :: Fixed , Some ( 0.0 ) , true ) ;
189+ let invalid = create_process_flow_raw ( f64:: INFINITY , FlowType :: Fixed , Some ( 0.0 ) ) ;
235190 assert ! ( invalid. validate( ) . is_err( ) ) ;
236- let invalid = create_process_flow_raw ( f64:: NEG_INFINITY , FlowType :: Fixed , Some ( 0.0 ) , true ) ;
191+ let invalid = create_process_flow_raw ( f64:: NEG_INFINITY , FlowType :: Fixed , Some ( 0.0 ) ) ;
237192 assert ! ( invalid. validate( ) . is_err( ) ) ;
238193
239194 // Invalid: Bad flow cost value
240- let invalid = create_process_flow_raw ( 1.0 , FlowType :: Fixed , Some ( f64:: NAN ) , true ) ;
195+ let invalid = create_process_flow_raw ( 1.0 , FlowType :: Fixed , Some ( f64:: NAN ) ) ;
241196 assert ! ( invalid. validate( ) . is_err( ) ) ;
242- let invalid = create_process_flow_raw ( 1.0 , FlowType :: Fixed , Some ( f64:: NEG_INFINITY ) , true ) ;
197+ let invalid = create_process_flow_raw ( 1.0 , FlowType :: Fixed , Some ( f64:: NEG_INFINITY ) ) ;
243198 assert ! ( invalid. validate( ) . is_err( ) ) ;
244- let invalid = create_process_flow_raw ( 1.0 , FlowType :: Fixed , Some ( f64:: INFINITY ) , true ) ;
199+ let invalid = create_process_flow_raw ( 1.0 , FlowType :: Fixed , Some ( f64:: INFINITY ) ) ;
245200 assert ! ( invalid. validate( ) . is_err( ) ) ;
246201 }
247202
248- fn create_process_flow ( commodity : Rc < Commodity > , coeff : f64 , is_pac : bool ) -> ProcessFlow {
249- ProcessFlow {
250- commodity,
251- coeff,
252- kind : FlowType :: Fixed ,
253- cost : 0.0 ,
254- is_pac,
255- }
256- }
257-
258203 #[ fixture]
259204 fn commodity1 ( ) -> Commodity {
260205 Commodity {
@@ -278,44 +223,4 @@ mod tests {
278223 levies : CommodityLevyMap :: default ( ) ,
279224 }
280225 }
281-
282- #[ rstest]
283- fn test_validate_flow_map_valid_single ( commodity1 : Commodity , commodity2 : Commodity ) {
284- // Valid: Single PAC
285- let flows = indexmap ! {
286- commodity1. id. clone( ) => create_process_flow( commodity1. into( ) , 1.0 , true ) ,
287- commodity2. id. clone( ) => create_process_flow( commodity2. into( ) , 1.0 , false ) ,
288- } ;
289- assert ! ( validate_flow_map( & flows) . is_ok( ) ) ;
290- }
291-
292- #[ rstest]
293- fn test_validate_flow_map_valid_multiple ( commodity1 : Commodity , commodity2 : Commodity ) {
294- // Valid: Multiple PACs
295- let flows = indexmap ! {
296- commodity1. id. clone( ) => create_process_flow( commodity1. into( ) , 1.0 , true ) ,
297- commodity2. id. clone( ) => create_process_flow( commodity2. into( ) , 1.0 , true ) ,
298- } ;
299- assert ! ( validate_flow_map( & flows) . is_ok( ) ) ;
300- }
301-
302- #[ rstest]
303- fn test_validate_flow_map_invalid_no_pacs ( commodity1 : Commodity , commodity2 : Commodity ) {
304- // Invalid: No PACs
305- let flows = indexmap ! {
306- commodity1. id. clone( ) => create_process_flow( commodity1. into( ) , 1.0 , false ) ,
307- commodity2. id. clone( ) => create_process_flow( commodity2. into( ) , 1.0 , false ) ,
308- } ;
309- assert ! ( validate_flow_map( & flows) . is_err( ) ) ;
310- }
311-
312- #[ rstest]
313- fn test_validate_flow_map ( commodity1 : Commodity , commodity2 : Commodity ) {
314- // Invalid: Mixed PAC flow types
315- let flows = indexmap ! {
316- commodity1. id. clone( ) => create_process_flow( commodity1. into( ) , 1.0 , true ) ,
317- commodity2. id. clone( ) => create_process_flow( commodity2. into( ) , -1.0 , true ) ,
318- } ;
319- assert ! ( validate_flow_map( & flows) . is_err( ) ) ;
320- }
321226}
0 commit comments