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}