Skip to main content

cmtool_assemble/parser/
pfr_mb.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2
3use crate::{CMError, data::FlowDirection};
4use cmtool_data::PhaseCM;
5use std::collections::HashMap;
6
7///Input and output flow for one phase in one pfr
8#[derive(Default, Copy, Clone, Debug)]
9struct FlowData {
10    in_flow: f64,
11    out_flow: f64,
12}
13
14/// flow data for one pfr
15#[derive(Copy, Clone, Debug, Default)]
16pub struct PhaseFlow {
17    gas: FlowData,
18    liquid: FlowData,
19}
20
21/// Struct to hold flow data for each ID using a HashMap
22#[derive(Default, Debug)]
23pub struct PfrGlobalMassBalance {
24    flows: HashMap<String, PhaseFlow>,
25    validated: bool,
26}
27
28impl PfrGlobalMassBalance {
29    pub(super) fn new(pfr_names: &[String]) -> Self {
30        let mut flows = HashMap::new();
31        for name in pfr_names {
32            flows.insert(name.clone(), PhaseFlow::default());
33        }
34        PfrGlobalMassBalance {
35            flows,
36            validated: false,
37        }
38    }
39
40    pub(super) fn validate(&mut self) -> Result<(), CMError> {
41        for (i, flow) in &self.flows {
42            if flow.gas.in_flow != flow.gas.out_flow {
43                return Err(CMError::MassBalance(i.clone(), "gas".to_owned()));
44            }
45            if flow.liquid.in_flow != flow.liquid.out_flow {
46                return Err(CMError::MassBalance(i.clone(), "liquid".to_owned()));
47            }
48        }
49        self.validated = true;
50        Ok(())
51    }
52
53    pub(crate) fn update_flow(
54        &mut self,
55        id: &str,
56        phase: PhaseCM,
57        direction: FlowDirection,
58        vflow: f64,
59    ) {
60        self.validated = false;
61        if let Some(phase_flow) = self.flows.get_mut(id) {
62            let flow_data = match phase {
63                PhaseCM::Gas => &mut phase_flow.gas,
64                PhaseCM::Liquid => &mut phase_flow.liquid,
65            };
66
67            match direction {
68                FlowDirection::In => flow_data.in_flow += vflow,
69                FlowDirection::Out => flow_data.out_flow += vflow,
70            }
71        }
72    }
73    pub fn get_flow(&self, id: &str, phase: PhaseCM) -> Result<f64, CMError> {
74        if !self.validated {
75            return Err(CMError::Custom(
76                "Mass balance needs to be validated before being accessed".to_owned(),
77            ));
78        }
79
80        if let Some(phase_flow) = self.flows.get(id) {
81            return Ok(match phase {
82                PhaseCM::Gas => phase_flow.gas.in_flow,
83                PhaseCM::Liquid => phase_flow.liquid.in_flow,
84            });
85        }
86        Err(CMError::Custom(format!(
87            "Mass balance does not provide {} pfr",
88            id
89        )))
90    }
91}
92
93#[cfg(test)]
94mod test {
95    use super::*;
96
97    #[test]
98    fn test_pfr_mass_balance() {
99        let names = ["name1".to_owned(), "name2".to_owned()];
100        let mut mb = PfrGlobalMassBalance::new(&names);
101
102        let expected_ok = mb.validate(); //BEcause flow is null
103        assert!(expected_ok.is_ok());
104
105        mb.update_flow("name1", PhaseCM::Gas, FlowDirection::In, 4.);
106        let expected_err = mb.validate();
107        assert!(expected_err.is_err());
108
109        mb.update_flow("name1", PhaseCM::Gas, FlowDirection::Out, 2.);
110        mb.update_flow("name1", PhaseCM::Gas, FlowDirection::Out, 2.);
111
112        let expected_ok = mb.validate();
113        assert!(expected_ok.is_ok());
114
115        let pfr_flow = mb.get_flow("name1", PhaseCM::Gas).unwrap();
116        assert!(pfr_flow == 4.)
117    }
118}