Skip to main content

cimstructs/
ControlArea.rs

1/// A control area is a grouping of generating units and/or loads and a cutset of tie lines (as terminals) which may be used for a variety of purposes including automatic generation control, power flow solution area interchange control specification, and input to load forecasting. All generation and load within the area defined by the terminals on the border are considered in the area interchange control. Note that any number of overlapping control area specifications can be superimposed on the physical model. The following general principles apply to ControlArea: 1. The control area orientation for net interchange is positive for an import, negative for an export. 2. The control area net interchange is determined by summing flows in Terminals. The Terminals are identified by creating a set of TieFlow objects associated with a ControlArea object. Each TieFlow object identifies one Terminal. 3. In a single network model, a tie between two control areas must be modelled in both control area specifications, such that the two representations of the tie flow sum to zero. 4. The normal orientation of Terminal flow is positive for flow into the conducting equipment that owns the Terminal. (i.e. flow from a bus into a device is positive.) However, the orientation of each flow in the control area specification must align with the control area convention, i.e. import is positive. If the orientation of the Terminal flow referenced by a TieFlow is positive into the control area, then this is confirmed by setting TieFlow.positiveFlowIn flag TRUE. If not, the orientation must be reversed by setting the TieFlow.positiveFlowIn flag FALSE.
2#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
3pub struct ControlArea {
4    #[serde(flatten)]
5    pub base: super::PowerSystemResource,
6    /// The energy area that is forecast from this control area specification.
7    #[serde(skip_serializing_if = "Option::is_none")]
8    pub energy_area: Option<super::base::MridRef>,
9    /// The specified positive net interchange into the control area, i.e. positive sign means flow into the area.
10    #[serde(skip_serializing_if = "Option::is_none")]
11    pub net_interchange: Option<f64>,
12    /// Active power net interchange tolerance. The attribute shall be a positive value or zero.
13    #[serde(skip_serializing_if = "Option::is_none")]
14    pub p_tolerance: Option<f64>,
15    /// The primary type of control area definition used to determine if this is used for automatic generation control, for planning interchange control, or other purposes. A control area specified with primary type of automatic generation control could still be forecast and used as an interchange area in power flow analysis.
16    #[serde(skip_serializing_if = "Option::is_none")]
17    pub type_: Option<super::base::UriRef>,
18}
19impl crate::base::CimElement for ControlArea {
20    fn mrid(&self) -> &str { &self.base.base.id }
21    fn type_name(&self) -> &'static str { "ControlArea" }
22    fn as_any(&self) -> &dyn std::any::Any { self }
23    fn to_json_value(&self) -> serde_json::Value {
24        serde_json::to_value(self).unwrap_or(serde_json::Value::Null)
25    }
26    fn to_block(&self) -> crate::base::RdfBlock {
27        let mut block = self.base.to_block();
28        block.type_name = "ControlArea".to_string();
29        if let Some(ref v) = self.energy_area {
30            block.fields.insert("ControlArea.EnergyArea".into(), crate::base::FieldValue::Resource(v.mrid.clone()));
31        }
32        if let Some(v) = self.net_interchange {
33            block.fields.insert("ControlArea.netInterchange".into(), crate::base::FieldValue::Text(v.to_string()));
34        }
35        if let Some(v) = self.p_tolerance {
36            block.fields.insert("ControlArea.pTolerance".into(), crate::base::FieldValue::Text(v.to_string()));
37        }
38        if let Some(ref v) = self.type_ {
39            block.fields.insert("ControlArea.type".into(), crate::base::FieldValue::Resource(v.uri.clone()));
40        }
41        block
42    }
43}
44
45impl ControlArea {
46    pub fn from_block(b: &crate::base::RdfBlock) -> Self {
47        let mut obj = Self::default();
48        obj.base.base.id.clone_from(&b.mrid);
49        for (key, val) in &b.fields {
50            match key.as_str() {
51                "ControlArea.EnergyArea" => {
52                    if let crate::base::FieldValue::Resource(sv) = val {
53                        obj.energy_area = Some(crate::base::MridRef { mrid: sv.clone() });
54                    }
55                }
56                "ControlArea.netInterchange" => {
57                    match val {
58                        crate::base::FieldValue::Text(sv) => { if let Ok(v) = sv.trim().parse() { obj.net_interchange = Some(v); } }
59                        crate::base::FieldValue::TextList(svs) => {
60                            if let Some(sv) = svs.last() { if let Ok(v) = sv.trim().parse() { obj.net_interchange = Some(v); } }
61                        }
62                        _ => {}
63                    }
64                }
65                "ControlArea.pTolerance" => {
66                    match val {
67                        crate::base::FieldValue::Text(sv) => { if let Ok(v) = sv.trim().parse() { obj.p_tolerance = Some(v); } }
68                        crate::base::FieldValue::TextList(svs) => {
69                            if let Some(sv) = svs.last() { if let Ok(v) = sv.trim().parse() { obj.p_tolerance = Some(v); } }
70                        }
71                        _ => {}
72                    }
73                }
74                "ControlArea.type" => {
75                    if let crate::base::FieldValue::Resource(sv) = val {
76                        obj.type_ = Some(crate::base::UriRef { uri: sv.clone() });
77                    }
78                }
79                "IdentifiedObject.description" => {
80                    match val {
81                        crate::base::FieldValue::Text(sv) => { obj.base.base.description = sv.clone(); }
82                        crate::base::FieldValue::TextList(svs) => {
83                            if let Some(sv) = svs.last() { obj.base.base.description = sv.clone(); }
84                        }
85                        _ => {}
86                    }
87                }
88                "IdentifiedObject.energyIdentCodeEic" => {
89                    match val {
90                        crate::base::FieldValue::Text(sv) => { obj.base.base.energy_ident_code_eic = sv.clone(); }
91                        crate::base::FieldValue::TextList(svs) => {
92                            if let Some(sv) = svs.last() { obj.base.base.energy_ident_code_eic = sv.clone(); }
93                        }
94                        _ => {}
95                    }
96                }
97                "IdentifiedObject.mRID" => {
98                    match val {
99                        crate::base::FieldValue::Text(sv) => { obj.base.base.m_rid = sv.clone(); }
100                        crate::base::FieldValue::TextList(svs) => {
101                            if let Some(sv) = svs.last() { obj.base.base.m_rid = sv.clone(); }
102                        }
103                        _ => {}
104                    }
105                }
106                "IdentifiedObject.name" => {
107                    match val {
108                        crate::base::FieldValue::Text(sv) => { obj.base.base.name = sv.clone(); }
109                        crate::base::FieldValue::TextList(svs) => {
110                            if let Some(sv) = svs.last() { obj.base.base.name = sv.clone(); }
111                        }
112                        _ => {}
113                    }
114                }
115                "IdentifiedObject.shortName" => {
116                    match val {
117                        crate::base::FieldValue::Text(sv) => { obj.base.base.short_name = sv.clone(); }
118                        crate::base::FieldValue::TextList(svs) => {
119                            if let Some(sv) = svs.last() { obj.base.base.short_name = sv.clone(); }
120                        }
121                        _ => {}
122                    }
123                }
124                _ => {}
125            }
126        }
127        obj
128    }
129}