feos_core/state/
builder.rs

1use super::{DensityInitialization, State};
2use crate::Total;
3use crate::equation_of_state::Residual;
4use crate::errors::FeosResult;
5use nalgebra::DVector;
6use quantity::*;
7
8/// A simple tool to construct [State]s with arbitrary input parameters.
9///
10/// # Examples
11/// ```
12/// # use feos_core::{FeosResult, StateBuilder};
13/// # use feos_core::cubic::{PengRobinson, PengRobinsonParameters};
14/// # use quantity::*;
15/// # use nalgebra::dvector;
16/// # use approx::assert_relative_eq;
17/// # use typenum::P3;
18/// # fn main() -> FeosResult<()> {
19/// // Create a state for given T,V,N
20/// let eos = &PengRobinson::new(PengRobinsonParameters::new_simple(&[369.8], &[41.9 * 1e5], &[0.15], &[15.0])?);
21/// let state = StateBuilder::new(&eos)
22///                 .temperature(300.0 * KELVIN)
23///                 .volume(12.5 * METER.powi::<P3>())
24///                 .moles(&(dvector![2.5] * MOL))
25///                 .build()?;
26/// assert_eq!(state.density, 0.2 * MOL / METER.powi::<P3>());
27///
28/// // For a pure component, the composition does not need to be specified.
29/// let eos = &PengRobinson::new(PengRobinsonParameters::new_simple(&[369.8], &[41.9 * 1e5], &[0.15], &[15.0])?);
30/// let state = StateBuilder::new(&eos)
31///                 .temperature(300.0 * KELVIN)
32///                 .volume(12.5 * METER.powi::<P3>())
33///                 .total_moles(2.5 * MOL)
34///                 .build()?;
35/// assert_eq!(state.density, 0.2 * MOL / METER.powi::<P3>());
36///
37/// // The state can be constructed without providing any extensive property.
38/// let eos = &PengRobinson::new(
39///     PengRobinsonParameters::new_simple(
40///         &[369.8, 305.4],
41///         &[41.9 * 1e5, 48.2 * 1e5],
42///         &[0.15, 0.10],
43///         &[15.0, 30.0]
44///     )?
45/// );
46/// let state = StateBuilder::new(&eos)
47///                 .temperature(300.0 * KELVIN)
48///                 .partial_density(&(dvector![0.2, 0.6] * MOL / METER.powi::<P3>()))
49///                 .build()?;
50/// assert_relative_eq!(state.molefracs, dvector![0.25, 0.75]);
51/// assert_relative_eq!(state.density, 0.8 * MOL / METER.powi::<P3>());
52/// # Ok(())
53/// # }
54/// ```
55#[derive(Clone)]
56pub struct StateBuilder<'a, E, const IG: bool> {
57    eos: &'a E,
58    temperature: Option<Temperature>,
59    volume: Option<Volume>,
60    density: Option<Density>,
61    partial_density: Option<&'a Density<DVector<f64>>>,
62    total_moles: Option<Moles>,
63    moles: Option<&'a Moles<DVector<f64>>>,
64    molefracs: Option<&'a DVector<f64>>,
65    pressure: Option<Pressure>,
66    molar_enthalpy: Option<MolarEnergy>,
67    molar_entropy: Option<MolarEntropy>,
68    molar_internal_energy: Option<MolarEnergy>,
69    density_initialization: Option<DensityInitialization>,
70    initial_temperature: Option<Temperature>,
71}
72
73impl<'a, E: Residual> StateBuilder<'a, E, false> {
74    /// Create a new `StateBuilder` for the given equation of state.
75    pub fn new(eos: &'a E) -> Self {
76        StateBuilder {
77            eos,
78            temperature: None,
79            volume: None,
80            density: None,
81            partial_density: None,
82            total_moles: None,
83            moles: None,
84            molefracs: None,
85            pressure: None,
86            molar_enthalpy: None,
87            molar_entropy: None,
88            molar_internal_energy: None,
89            density_initialization: None,
90            initial_temperature: None,
91        }
92    }
93}
94
95impl<'a, E: Residual, const IG: bool> StateBuilder<'a, E, IG> {
96    /// Provide the temperature for the new state.
97    pub fn temperature(mut self, temperature: Temperature) -> Self {
98        self.temperature = Some(temperature);
99        self
100    }
101
102    /// Provide the volume for the new state.
103    pub fn volume(mut self, volume: Volume) -> Self {
104        self.volume = Some(volume);
105        self
106    }
107
108    /// Provide the density for the new state.
109    pub fn density(mut self, density: Density) -> Self {
110        self.density = Some(density);
111        self
112    }
113
114    /// Provide partial densities for the new state.
115    pub fn partial_density(mut self, partial_density: &'a Density<DVector<f64>>) -> Self {
116        self.partial_density = Some(partial_density);
117        self
118    }
119
120    /// Provide the total moles for the new state.
121    pub fn total_moles(mut self, total_moles: Moles) -> Self {
122        self.total_moles = Some(total_moles);
123        self
124    }
125
126    /// Provide the moles for the new state.
127    pub fn moles(mut self, moles: &'a Moles<DVector<f64>>) -> Self {
128        self.moles = Some(moles);
129        self
130    }
131
132    /// Provide the molefracs for the new state.
133    pub fn molefracs(mut self, molefracs: &'a DVector<f64>) -> Self {
134        self.molefracs = Some(molefracs);
135        self
136    }
137
138    /// Provide the pressure for the new state.
139    pub fn pressure(mut self, pressure: Pressure) -> Self {
140        self.pressure = Some(pressure);
141        self
142    }
143
144    /// Specify a vapor state.
145    pub fn vapor(mut self) -> Self {
146        self.density_initialization = Some(DensityInitialization::Vapor);
147        self
148    }
149
150    /// Specify a liquid state.
151    pub fn liquid(mut self) -> Self {
152        self.density_initialization = Some(DensityInitialization::Liquid);
153        self
154    }
155
156    /// Provide an initial density used in density iterations.
157    pub fn initial_density(mut self, initial_density: Density) -> Self {
158        self.density_initialization = Some(DensityInitialization::InitialDensity(initial_density));
159        self
160    }
161}
162
163impl<'a, E: Total, const IG: bool> StateBuilder<'a, E, IG> {
164    /// Provide the molar enthalpy for the new state.
165    pub fn molar_enthalpy(mut self, molar_enthalpy: MolarEnergy) -> StateBuilder<'a, E, true> {
166        self.molar_enthalpy = Some(molar_enthalpy);
167        self.convert()
168    }
169
170    /// Provide the molar entropy for the new state.
171    pub fn molar_entropy(mut self, molar_entropy: MolarEntropy) -> StateBuilder<'a, E, true> {
172        self.molar_entropy = Some(molar_entropy);
173        self.convert()
174    }
175
176    /// Provide the molar internal energy for the new state.
177    pub fn molar_internal_energy(
178        mut self,
179        molar_internal_energy: MolarEnergy,
180    ) -> StateBuilder<'a, E, true> {
181        self.molar_internal_energy = Some(molar_internal_energy);
182        self.convert()
183    }
184
185    /// Provide an initial temperature used in the Newton solver.
186    pub fn initial_temperature(
187        mut self,
188        initial_temperature: Temperature,
189    ) -> StateBuilder<'a, E, true> {
190        self.initial_temperature = Some(initial_temperature);
191        self.convert()
192    }
193
194    fn convert(self) -> StateBuilder<'a, E, true> {
195        StateBuilder {
196            eos: self.eos,
197            temperature: self.temperature,
198            volume: self.volume,
199            density: self.density,
200            partial_density: self.partial_density,
201            total_moles: self.total_moles,
202            moles: self.moles,
203            molefracs: self.molefracs,
204            pressure: self.pressure,
205            molar_enthalpy: self.molar_enthalpy,
206            molar_entropy: self.molar_entropy,
207            molar_internal_energy: self.molar_internal_energy,
208            density_initialization: self.density_initialization,
209            initial_temperature: self.initial_temperature,
210        }
211    }
212}
213
214impl<E: Residual> StateBuilder<'_, E, false> {
215    /// Try to build the state with the given inputs.
216    pub fn build(self) -> FeosResult<State<E>> {
217        State::new(
218            self.eos,
219            self.temperature,
220            self.volume,
221            self.density,
222            self.partial_density,
223            self.total_moles,
224            self.moles,
225            self.molefracs,
226            self.pressure,
227            self.density_initialization,
228        )
229    }
230}
231
232impl<E: Total> StateBuilder<'_, E, true> {
233    /// Try to build the state with the given inputs.
234    pub fn build(self) -> FeosResult<State<E>> {
235        State::new_full(
236            self.eos,
237            self.temperature,
238            self.volume,
239            self.density,
240            self.partial_density,
241            self.total_moles,
242            self.moles,
243            self.molefracs,
244            self.pressure,
245            self.molar_enthalpy,
246            self.molar_entropy,
247            self.molar_internal_energy,
248            self.density_initialization,
249            self.initial_temperature,
250        )
251    }
252}