Skip to main content

cimstructs/
Measurement.rs

1/// A Measurement represents any measured, calculated or non-measured non-calculated quantity. Any piece of equipment may contain Measurements, e.g. a substation may have temperature measurements and door open indications, a transformer may have oil temperature and tank pressure measurements, a bay may contain a number of power flow measurements and a Breaker may contain a switch status measurement. The PSR - Measurement association is intended to capture this use of Measurement and is included in the naming hierarchy based on EquipmentContainer. The naming hierarchy typically has Measurements as leaves, e.g. Substation-VoltageLevel-Bay-Switch-Measurement. Some Measurements represent quantities related to a particular sensor location in the network, e.g. a voltage transformer (VT) or potential transformer (PT) at a busbar or a current transformer (CT) at the bar between a breaker and an isolator. The sensing position is not captured in the PSR - Measurement association. Instead it is captured by the Measurement - Terminal association that is used to define the sensing location in the network topology. The location is defined by the connection of the Terminal to ConductingEquipment. If both a Terminal and PSR are associated, and the PSR is of type ConductingEquipment, the associated Terminal should belong to that ConductingEquipment instance. When the sensor location is needed both Measurement-PSR and Measurement-Terminal are used. The Measurement-Terminal association is never used alone.
2#[derive(Debug, Default, Clone, serde::Serialize, serde::Deserialize)]
3pub struct Measurement {
4    #[serde(flatten)]
5    pub base: super::IdentifiedObject,
6    /// The power system resource that contains the measurement.
7    #[serde(skip_serializing_if = "Option::is_none")]
8    pub power_system_resource: Option<super::base::MridRef>,
9    /// One or more measurements may be associated with a terminal in the network.
10    #[serde(skip_serializing_if = "Option::is_none")]
11    pub terminal: Option<super::base::MridRef>,
12    /// Specifies the type of measurement. For example, this specifies if the measurement represents an indoor temperature, outdoor temperature, bus voltage, line flow, etc. When the measurementType is set to 'Specialization', the type of Measurement is defined in more detail by the specialized class which inherits from Measurement.
13    pub measurement_type: String,
14    /// Indicates to which phases the measurement applies and avoids the need to use 'measurementType' to also encode phase information (which would explode the types). The phase information in Measurement, along with 'measurementType' and 'phases' uniquely defines a Measurement for a device, based on normal network phase. Their meaning will not change when the computed energizing phasing is changed due to jumpers or other reasons. If the attribute is missing three phases (ABC) shall be assumed.
15    #[serde(skip_serializing_if = "Option::is_none")]
16    pub phases: Option<super::base::UriRef>,
17    /// The unit multiplier of the measured quantity.
18    #[serde(skip_serializing_if = "Option::is_none")]
19    pub unit_multiplier: Option<super::base::UriRef>,
20    /// The unit of measure of the measured quantity.
21    #[serde(skip_serializing_if = "Option::is_none")]
22    pub unit_symbol: Option<super::base::UriRef>,
23}
24impl crate::base::CimElement for Measurement {
25    fn mrid(&self) -> &str { &self.base.id }
26    fn type_name(&self) -> &'static str { "Measurement" }
27    fn as_any(&self) -> &dyn std::any::Any { self }
28    fn to_json_value(&self) -> serde_json::Value {
29        serde_json::to_value(self).unwrap_or(serde_json::Value::Null)
30    }
31    fn to_block(&self) -> crate::base::RdfBlock {
32        let mut block = self.base.to_block();
33        block.type_name = "Measurement".to_string();
34        if let Some(ref v) = self.power_system_resource {
35            block.fields.insert("Measurement.PowerSystemResource".into(), crate::base::FieldValue::Resource(v.mrid.clone()));
36        }
37        if let Some(ref v) = self.terminal {
38            block.fields.insert("Measurement.Terminal".into(), crate::base::FieldValue::Resource(v.mrid.clone()));
39        }
40        if !self.measurement_type.is_empty() {
41            block.fields.insert("Measurement.measurementType".into(), crate::base::FieldValue::Text(self.measurement_type.clone()));
42        }
43        if let Some(ref v) = self.phases {
44            block.fields.insert("Measurement.phases".into(), crate::base::FieldValue::Resource(v.uri.clone()));
45        }
46        if let Some(ref v) = self.unit_multiplier {
47            block.fields.insert("Measurement.unitMultiplier".into(), crate::base::FieldValue::Resource(v.uri.clone()));
48        }
49        if let Some(ref v) = self.unit_symbol {
50            block.fields.insert("Measurement.unitSymbol".into(), crate::base::FieldValue::Resource(v.uri.clone()));
51        }
52        block
53    }
54}
55
56impl Measurement {
57    pub fn from_block(b: &crate::base::RdfBlock) -> Self {
58        let mut obj = Self::default();
59        obj.base.id.clone_from(&b.mrid);
60        for (key, val) in &b.fields {
61            match key.as_str() {
62                "Measurement.PowerSystemResource" => {
63                    if let crate::base::FieldValue::Resource(sv) = val {
64                        obj.power_system_resource = Some(crate::base::MridRef { mrid: sv.clone() });
65                    }
66                }
67                "Measurement.Terminal" => {
68                    if let crate::base::FieldValue::Resource(sv) = val {
69                        obj.terminal = Some(crate::base::MridRef { mrid: sv.clone() });
70                    }
71                }
72                "Measurement.measurementType" => {
73                    match val {
74                        crate::base::FieldValue::Text(sv) => { obj.measurement_type = sv.clone(); }
75                        crate::base::FieldValue::TextList(svs) => {
76                            if let Some(sv) = svs.last() { obj.measurement_type = sv.clone(); }
77                        }
78                        _ => {}
79                    }
80                }
81                "Measurement.phases" => {
82                    if let crate::base::FieldValue::Resource(sv) = val {
83                        obj.phases = Some(crate::base::UriRef { uri: sv.clone() });
84                    }
85                }
86                "Measurement.unitMultiplier" => {
87                    if let crate::base::FieldValue::Resource(sv) = val {
88                        obj.unit_multiplier = Some(crate::base::UriRef { uri: sv.clone() });
89                    }
90                }
91                "Measurement.unitSymbol" => {
92                    if let crate::base::FieldValue::Resource(sv) = val {
93                        obj.unit_symbol = Some(crate::base::UriRef { uri: sv.clone() });
94                    }
95                }
96                "IdentifiedObject.description" => {
97                    match val {
98                        crate::base::FieldValue::Text(sv) => { obj.base.description = sv.clone(); }
99                        crate::base::FieldValue::TextList(svs) => {
100                            if let Some(sv) = svs.last() { obj.base.description = sv.clone(); }
101                        }
102                        _ => {}
103                    }
104                }
105                "IdentifiedObject.energyIdentCodeEic" => {
106                    match val {
107                        crate::base::FieldValue::Text(sv) => { obj.base.energy_ident_code_eic = sv.clone(); }
108                        crate::base::FieldValue::TextList(svs) => {
109                            if let Some(sv) = svs.last() { obj.base.energy_ident_code_eic = sv.clone(); }
110                        }
111                        _ => {}
112                    }
113                }
114                "IdentifiedObject.mRID" => {
115                    match val {
116                        crate::base::FieldValue::Text(sv) => { obj.base.m_rid = sv.clone(); }
117                        crate::base::FieldValue::TextList(svs) => {
118                            if let Some(sv) = svs.last() { obj.base.m_rid = sv.clone(); }
119                        }
120                        _ => {}
121                    }
122                }
123                "IdentifiedObject.name" => {
124                    match val {
125                        crate::base::FieldValue::Text(sv) => { obj.base.name = sv.clone(); }
126                        crate::base::FieldValue::TextList(svs) => {
127                            if let Some(sv) = svs.last() { obj.base.name = sv.clone(); }
128                        }
129                        _ => {}
130                    }
131                }
132                "IdentifiedObject.shortName" => {
133                    match val {
134                        crate::base::FieldValue::Text(sv) => { obj.base.short_name = sv.clone(); }
135                        crate::base::FieldValue::TextList(svs) => {
136                            if let Some(sv) = svs.last() { obj.base.short_name = sv.clone(); }
137                        }
138                        _ => {}
139                    }
140                }
141                _ => {}
142            }
143        }
144        obj
145    }
146}