twine_components/turbomachinery/
work.rs1use twine_core::constraint::{Constrained, ConstraintError, NonNegative};
11use twine_thermo::units::SpecificEnthalpy;
12
13#[derive(Debug, Clone, Copy, PartialEq)]
17pub struct CompressionWork(SpecificEnthalpy);
18
19impl CompressionWork {
20 #[must_use]
22 pub fn zero() -> Self {
23 Self::from_constrained(NonNegative::zero())
24 }
25
26 pub fn new(work: SpecificEnthalpy) -> Result<Self, ConstraintError> {
32 let work = NonNegative::new(work)?;
33 Ok(Self::from_constrained(work))
34 }
35
36 #[must_use]
38 pub fn from_constrained(work: Constrained<SpecificEnthalpy, NonNegative>) -> Self {
39 Self(work.into_inner())
40 }
41
42 #[must_use]
44 pub fn quantity(&self) -> SpecificEnthalpy {
45 self.0
46 }
47}
48
49#[derive(Debug, Clone, Copy, PartialEq)]
53pub struct ExpansionWork(SpecificEnthalpy);
54
55impl ExpansionWork {
56 #[must_use]
58 pub fn zero() -> Self {
59 Self::from_constrained(NonNegative::zero())
60 }
61
62 pub fn new(work: SpecificEnthalpy) -> Result<Self, ConstraintError> {
68 let work = NonNegative::new(work)?;
69 Ok(Self::from_constrained(work))
70 }
71
72 #[must_use]
74 pub fn from_constrained(work: Constrained<SpecificEnthalpy, NonNegative>) -> Self {
75 Self(work.into_inner())
76 }
77
78 #[must_use]
80 pub fn quantity(&self) -> SpecificEnthalpy {
81 self.0
82 }
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 use twine_core::constraint::NonNegative;
90
91 use crate::turbomachinery::test_utils::enth_si;
92
93 #[test]
94 fn compression_work_rejects_negative() {
95 let negative = enth_si(-1.0);
96 assert!(CompressionWork::new(negative).is_err());
97 }
98
99 #[test]
100 fn compression_work_from_constrained_quantity_roundtrip() {
101 let value = enth_si(42.0);
102 let constrained = NonNegative::new(value).unwrap();
103 let work = CompressionWork::from_constrained(constrained);
104 assert_eq!(work.quantity(), value);
105 }
106
107 #[test]
108 fn expansion_work_rejects_negative() {
109 let negative = enth_si(-1.0);
110 assert!(ExpansionWork::new(negative).is_err());
111 }
112
113 #[test]
114 fn expansion_work_from_constrained() {
115 let value = enth_si(5.0);
116 let constrained = NonNegative::new(value).unwrap();
117 let work = ExpansionWork::from_constrained(constrained);
118 assert_eq!(work.quantity(), value);
119 }
120}