distillation_shortcut_unit/real_parameter.rs
1use crate::shared_unit_data::*;
2use crate::distillation_shortcut_unit::DistillationShortcutUnit;
3use cobia::*;
4
5/// The RealParameter class implements a CAPE-OPEN 1.2 real parameter.
6///
7/// Parameters must implement the ICapeIdentification and ICapeParameter interfaces.
8/// In addition, real parameters must implement the ICapeRealParameter interface.
9///
10/// This implementation can be used for both input and output parameters.
11/// Input parameters can be set by the user, while output parameters are set by the unit operation.
12///
13/// The parameter is allowed to have a missing value, but for input parameters this is considered invalid.
14///
15/// Any other invalid values (outside the bounds of the parameter) will raise an error when set.
16/// Therefore, any parameter for which the value is not missing, is valid.
17
18#[cape_object_implementation(
19 interfaces = {
20 cape_open_1_2::ICapeIdentification,
21 cape_open_1_2::ICapeParameter,
22 cape_open_1_2::ICapeRealParameter,
23 },
24 new_arguments = {
25 name,
26 description,
27 is_input,
28 shared_unit_data,
29 default_value,
30 minimum_value,
31 maximum_value,
32 dimensionality
33 }
34 )]
35pub struct RealParameter {
36 /// The name of the parameter
37 pub(crate) name: CapeStringImpl,
38 /// The description of the parameter
39 description: CapeStringImpl,
40 /// Indicates whether this parameter is an input (true) or an output (false)
41 is_input : bool,
42 /// Shared data for the unit, containing unit-specific information
43 shared_unit_data: SharedUnitDataRef,
44 /// The current value of the parameter
45 pub(crate) value : f64,
46 /// Default value of the parameter
47 default_value : f64,
48 /// Minimum value of the parameter
49 minimum_value : f64,
50 /// Maximum value of the parameter
51 maximum_value : f64,
52 /// Dimensionality of the parameter
53 dimensionality : Vec<f64>,
54}
55
56impl RealParameter {
57
58 fn new(
59 name: CapeStringImpl,
60 description: CapeStringImpl,
61 is_input: bool,
62 shared_unit_data: SharedUnitDataRef,
63 default_value: f64,
64 minimum_value: f64,
65 maximum_value: f64,
66 dimensionality: Vec<f64>,
67 ) -> Self {
68 Self {
69 name,
70 description,
71 is_input,
72 shared_unit_data,
73 value: default_value,
74 default_value,
75 minimum_value,
76 maximum_value,
77 dimensionality,
78 cobia_object_data:std::default::Default::default(), //field generated by the cape_object_implementation macro; can be set to default
79 }
80 }
81
82}
83
84impl std::fmt::Display for RealParameter {
85
86 /// Format the RealParameter as a string for display purposes.
87 ///
88 /// The std::fmt::Display interface is used when generating the
89 /// source name of the object that raises an error.
90 ///
91 /// # Arguments:
92 /// * `f` - A mutable reference to a `std::fmt::Formatter` where the formatted string will be written.
93 ///
94 /// # Returns:
95 /// * A `std::fmt::Result` indicating the success or failure of the formatting operation.
96
97 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
98 write!(f,"Parameter '{}' of {} unit '{}'",self.name, DistillationShortcutUnit::NAME, self.shared_unit_data.borrow().name)
99 }
100
101}
102
103impl cape_open_1_2::ICapeIdentification for RealParameter {
104
105 /// Get the name of the component.
106 ///
107 /// # Arguments:
108 /// * `name` - A mutable reference to a `CapeStringOut` where the name will be set.
109 ///
110 /// # Returns:
111 /// * A `Result` indicating success or failure. If successful, the name is set in `name`.
112
113 fn get_component_name(&mut self,name:&mut CapeStringOut) -> Result<(), COBIAError> {
114 name.set(&self.name)?;
115 Ok(())
116 }
117
118 /// Get the description of the component.
119 ///
120 /// # Arguments:
121 /// * `description` - A mutable reference to a `CapeStringOut` where the description will be set.
122 ///
123 /// # Returns:
124 /// * A `Result` indicating success or failure. If successful, the description is set in `description`.
125
126 fn get_component_description(&mut self,description:&mut CapeStringOut) -> Result<(), COBIAError> {
127 description.set(&self.description)?;
128 Ok(())
129 }
130
131 /// Set the name of the component.
132 ///
133 /// This method is not allowed for this parameter implementation and will return an error.
134
135 fn set_component_name(&mut self, _name: &CapeStringIn) -> Result<(), COBIAError> {
136 Err(cobia::COBIAError::Code(cobia::COBIAERR_DENIED))
137 }
138
139 /// Set the description of the component.
140 ///
141 /// This method is not allowed for this parameter implementation and will return an error.
142
143 fn set_component_description(&mut self, _desc: &CapeStringIn) -> Result<(), COBIAError> {
144 Err(cobia::COBIAError::Code(cobia::COBIAERR_DENIED))
145 }
146}
147
148impl cape_open_1_2::ICapeParameter for RealParameter {
149
150 /// Get the validation status of the parameter.
151 ///
152 /// As this parameter does not accept any values that are not valid,
153 /// the parameter is always valid if specified. However, an unspecified
154 /// input value is considered invalid.
155 ///
156 /// # Returns:
157 /// * A `Result` containing the validation status, which is always `CapeValid` for this implementation.
158
159 fn get_val_status(&mut self) -> Result<cape_open_1_2::CapeValidationStatus,COBIAError> {
160 if self.is_input && self.value.is_nan() {
161 Ok(cape_open_1_2::CapeValidationStatus::CapeInvalid)
162 } else {
163 Ok(cape_open_1_2::CapeValidationStatus::CapeValid)
164 }
165 }
166
167 /// Get the mode of the parameter.
168 ///
169 /// # Returns:
170 /// * A `Result` containing the mode of the parameter, which is either `CapeInput` or `CapeOutput` based on the `is_input` field.
171
172 fn get_mode(&mut self) -> Result<cape_open_1_2::CapeParamMode,COBIAError> {
173 if self.is_input {
174 Ok(cape_open_1_2::CapeParamMode::CapeInput)
175 } else {
176 Ok(cape_open_1_2::CapeParamMode::CapeOutput)
177 }
178 }
179
180 /// Get the type of the parameter.
181 ///
182 /// # Returns:
183 /// * A `Result` containing the type of the parameter, which is always `CapeParameterReal` for this implementation.
184
185 fn get_type(&mut self) -> Result<cape_open_1_2::CapeParamType,COBIAError> {
186 Ok(cape_open_1_2::CapeParamType::CapeParameterReal)
187 }
188
189 /// Validate the parameter.
190 ///
191 /// As this parameter does not accept any values that are not valid,
192 /// the parameter is always valid if specified. However, an unspecified
193 /// input value is considered invalid.
194 ///
195 /// # Arguments:
196 /// * `message` - A mutable reference to a `CapeStringOut` where any validation error messages will be set.
197 ///
198 /// # Returns:
199 /// * A `Result` containing a `CapeBoolean` indicating whether the parameter is valid or not. If the input value is not specified, it returns false and sets an error message.
200
201 fn validate(&mut self,message:&mut CapeStringOut) -> Result<CapeBoolean,COBIAError> {
202 if self.is_input && f64::is_nan(self.value) {
203 message.set_string("Value must be specified")?;
204 Ok(false as CapeBoolean)
205 } else {
206 Ok(true as CapeBoolean)
207 }
208 }
209
210 /// Reset the parameter to its default value.
211 ///
212 /// This method sets the value of the parameter back to its default value and marks the unit as dirty.
213 /// It also resets the validation status to `CapeNotValidated`.
214 ///
215 /// # Returns:
216 /// * A `Result` indicating success or failure. If successful, the value is reset to the default value.
217
218 fn reset(&mut self) -> Result<(),COBIAError> {
219 if self.value!=self.default_value {
220 self.value = self.default_value;
221 let mut shared=self.shared_unit_data.borrow_mut();
222 shared.dirty=true;
223 shared.validation_status=cape_open_1_2::CapeValidationStatus::CapeNotValidated;
224 }
225 Ok(())
226 }
227}
228
229impl cape_open_1_2::ICapeRealParameter for RealParameter {
230
231 /// Get the value of the parameter.
232 ///
233 /// This method retrieves the current value of the parameter.
234 ///
235 /// # Returns:
236 /// * A `Result` containing the current value of the parameter as `CapeReal`.
237
238 fn get_value(&mut self) -> Result<CapeReal,COBIAError> {
239 Ok(self.value)
240 }
241
242 /// Set the value of the parameter.
243 ///
244 /// This implementation accepts a blank value for the parameters, but
245 /// it does not allow an invalid value to be set.
246 ///
247 /// Only input parameters can be set.
248 ///
249 /// If the value is set, it marks the unit as dirty and not validated.
250 ///
251 /// # Arguments:
252 /// * `value` - The value to set for the parameter, which should be a `CapeReal`.
253 ///
254 /// # Returns:
255 /// * A `Result` indicating success or failure.
256
257 fn set_value(&mut self,value:CapeReal) -> Result<(),COBIAError> {
258 if !self.is_input {
259 return Err(COBIAError::Code(COBIAERR_DENIED));
260 }
261 if !f64::is_nan(value) {
262 if !f64::is_nan(self.minimum_value) && value < self.minimum_value {
263 return Err(COBIAError::Message(format!("Value of {} below minimum value of {}",value,self.minimum_value)));
264 }
265 if !f64::is_nan(self.maximum_value) && value > self.maximum_value {
266 return Err(COBIAError::Message(format!("Value of {} above maximum value of {}",value,self.maximum_value)));
267 }
268 }
269 if self.value != value {
270 self.value = value;
271 let mut shared=self.shared_unit_data.borrow_mut();
272 shared.dirty=true;
273 shared.validation_status=cape_open_1_2::CapeValidationStatus::CapeNotValidated;
274 }
275 Ok(())
276 }
277
278 /// Get the default value of the parameter.
279 ///
280 /// This method retrieves the default value of the parameter.
281 ///
282 /// If the default value is not available (NaN), it returns an error.
283 ///
284 /// # Returns:
285 /// * A `Result` containing the default value of the parameter as `CapeReal`, or an error.
286
287 fn get_default_value(&mut self) -> Result<CapeReal,COBIAError> {
288 if f64::is_nan(self.default_value) {
289 Err(COBIAError::Message("Default value not available".into()))
290 } else {
291 Ok(self.default_value)
292 }
293 }
294
295 /// Get the lower bound of the parameter.
296 ///
297 /// This method retrieves the lower bound of the parameter.
298 ///
299 /// If the lower bound is not available (NaN), it returns an error.
300 ///
301 /// # Returns:
302 /// * A `Result` containing the lower bound of the parameter as `CapeReal`, or an error.
303
304 fn get_lower_bound(&mut self) -> Result<CapeReal,COBIAError> {
305 if f64::is_nan(self.minimum_value) {
306 Err(COBIAError::Message("No lower bound available".into()))
307 } else {
308 Ok(self.default_value)
309 }
310 }
311
312 /// Get the upper bound of the parameter.
313 ///
314 /// This method retrieves the upper bound of the parameter.
315 ///
316 /// If the upper bound is not available (NaN), it returns an error.
317 ///
318 /// # Returns:
319 /// * A `Result` containing the upper bound of the parameter as `CapeReal`, or an error.
320
321 fn get_upper_bound(&mut self) -> Result<CapeReal,COBIAError> {
322 if f64::is_nan(self.maximum_value) {
323 Err(COBIAError::Message("No upper bound available".into()))
324 } else {
325 Ok(self.maximum_value)
326 }
327 }
328
329 /// Get the dimensionality of the parameter.
330 ///
331 /// This method retrieves the dimensionality of the parameter, as a vector
332 /// of coefficients to the SI units m, kg, S, A, K, mole, cd, rad.
333 ///
334 /// An additional relative flag is present at the end of the vector to indicate
335 /// whether the parameter is relative to a reference value (non-zero) or
336 /// absolute (zero); for example a pressure difference or temperature difference
337 /// is relative, and unit conversions should ignore the offset in the unit
338 /// conversion.
339 ///
340 /// A special case for the use of the relative flag is a dimensionless parameter
341 /// with the relative flag set to true, which indicates that the parameter is a
342 /// fraction or percentage, and should be treated as such in unit conversions.
343 ///
344 /// Any zero valued trailing coefficients may be omitted, so that the
345 /// dimensionality vector may have a size of between 0 and 9 elements.
346 ///
347 /// This implementation returns the dimensionality of the parameter as
348 /// passed to the construction of the parameter.
349 ///
350 /// # Arguments:
351 /// * `dimensionality` - A mutable reference to a `CapeArrayRealOut` where the dimensionality will be set.
352 ///
353 /// # Returns:
354 /// * A `Result` indicating success or failure. If successful, the dimensionality is set in `dimensionality`.
355
356 fn get_dimensionality(&mut self,dimensionality:&mut CapeArrayRealOut) -> Result<(),COBIAError> {
357 match dimensionality.put_array(&self.dimensionality) {
358 Ok(()) => Ok(()),
359 Err(e) => Err(e),
360 }
361 }
362
363 /// Validate whether a given value is valid for this parameter.
364 ///
365 /// This method checks if the provided value is within the bounds of the parameter and meets the dimensionality requirements.
366 ///
367 /// Note that a missing value (NaN) is considered invalid, but may be set nevertheless, which puts the parameter in an invalid state.
368 ///
369 /// Output parameters are not validated, as they are set by the unit operation and not by the user.
370 ///
371 /// # Arguments:
372 /// * `value` - The value to validate, which should be a `CapeReal`.
373 /// * `message` - A mutable reference to a `CapeStringOut` where any validation error messages will be set.
374 ///
375 /// # Returns:
376 /// * A `Result` containing a `CapeBoolean` indicating whether the value is valid or not. If the value is not valid, it sets an error message in `message`.
377
378 fn validate(&mut self,value:CapeReal,message:&mut CapeStringOut) -> Result<CapeBoolean,COBIAError> {
379 if !self.is_input {
380 return Err(COBIAError::Code(COBIAERR_DENIED));
381 }
382 if f64::is_nan(value) {
383 message.set_string("A value must be specified")?;
384 Ok(false as CapeBoolean)
385 } else if !f64::is_nan(self.minimum_value) && value < self.minimum_value {
386 message.set_string(format!("Value of {} below minimum value of {}",value,self.minimum_value))?;
387 Ok(false as CapeBoolean)
388 } else if !f64::is_nan(self.maximum_value) && value > self.maximum_value {
389 message.set_string(format!("Value of {} above maximum value of {}",value,self.maximum_value))?;
390 Ok(false as CapeBoolean)
391 } else {
392 Ok(true as CapeBoolean)
393 }
394 }
395}