11//! # Blocks
22//!
3- //! This file contains traits which describe the traits that will be
4- //! implemented by various structs to represent different unit operations.
3+ //! This file contains traits implemented by various structs to represent
4+ //! different unit operations.
55//!
66//! For example, if a block is a simple mixer, then it will implement the
77//! MassBalance trait but not the EnergyBalance.
8- //!
98
9+ use crate :: connector;
10+ use once_cell:: sync:: Lazy ;
11+ use uom:: si:: energy:: joule;
1012use uom:: si:: f64:: Energy ;
1113use uom:: si:: f64:: Mass ;
1214use uom:: si:: mass:: kilogram;
13- use uom:: si:: energy:: joule;
14- use crate :: connector;
15- use once_cell:: sync:: Lazy ;
1615
17- //Initiallizing a global variable for the tolerance for the energy balance
1816#[ allow( dead_code) ]
19- static TOLERENCE_ENERGY : Lazy < Energy > = Lazy :: new ( || Energy :: new :: < joule > ( 5.0 ) ) ;
17+ /// Minimum error allowed for energy difference. TODO: Change this to a
18+ /// relative scale instead of an absolute scale.
19+ pub static TOLERENCE_ENERGY : Lazy < Energy > =
20+ Lazy :: new ( || Energy :: new :: < joule > ( 5.0 ) ) ;
2021
21- //Initiallizing a global variable for the tolerance for the mass balance
2222#[ allow( dead_code) ]
23- static TOLERENCE_MASS : Lazy < Mass > = Lazy :: new ( || Mass :: new :: < kilogram > ( 5.0 ) ) ;
24-
25- //Initiallizing a global variable for the tolerance for the element balance
23+ /// Minimum error allowed for mass difference. TODO: Change this to a relative
24+ /// scale instead of an absolute scale.
25+ pub static TOLERENCE_MASS : Lazy < Mass > =
26+ Lazy :: new ( || Mass :: new :: < kilogram > ( 5.0 ) ) ;
2627
28+ #[ allow( dead_code) ]
2729/// Trait for ensuring the overall mass balance is maintained in a flowsheet.
2830///
29- /// This trait can be implemented by any block that needs to ensure mass conservation.
30- # [ allow ( dead_code ) ]
31+ /// This trait can be implemented by any block that needs to ensure mass
32+ /// conservation.
3133pub trait MassBalance {
32- // total mass in - total mass out < tolerance
33- fn mass_balance_check ( & self , mass_in : Mass , mass_out : Mass ) -> bool {
34+ /// Perform a mass balance check on object by comparing inlet and outlet
35+ /// mass. TODO: Compare mass flow rates, not mass and check for relative
36+ /// error instead of absolute, perhaps error should be less than 1e-6
37+ /// fraction of the total inlet mass. This can be an adjustable parameter.
38+ /// Smaller takes longer to converge, but is more
39+ fn mass_balance_check ( & self , mass_in : Mass , mass_out : Mass ) -> bool {
3440 let mass_in_kg = mass_in. get :: < kilogram > ( ) ;
3541 let mass_out_kg = mass_out. get :: < kilogram > ( ) ;
36-
3742 let mass_difference = mass_in_kg - mass_out_kg;
38-
3943 return mass_difference <= TOLERENCE_MASS . get :: < kilogram > ( ) ;
4044 }
4145}
4246
47+ #[ allow( dead_code) ]
4348/// # EnergyBalance
4449///
45- /// This trait ensures that blocks in the flowsheet adhere to energy conservation principles.
46- ///
47- /// This is useful for distinguishing between "dynamic" and "steady state" simulations.
48- #[ allow( dead_code) ]
50+ /// This trait ensures that blocks in the flowsheet adhere to energy
51+ /// conservation principles.
4952pub trait EnergyBalance {
50-
51- // total energy in - total energy out < tolerance
52- fn energy_balance_check ( & self , energy_in : Energy , energy_out : Energy ) -> bool {
53- // Convert both energy_in and energy_out to joules
53+ /// Perform an energy balance on a block. Checks all input and output
54+ /// streams and ensures that energy stays the same. TODO: Ensure that
55+ /// energy loss is accounted for. For example, a mixer may not be entirely
56+ /// adiabatic, and therefor some energy will be lost to the environment.
57+ /// Also implement changes in issue #19.
58+ fn energy_balance_check ( & self , energy_in : Energy , energy_out : Energy ) ->
59+ bool {
5460 let energy_in_joules = energy_in. get :: < joule > ( ) ;
5561 let energy_out_joules = energy_out. get :: < joule > ( ) ;
56-
57- // Calculate the difference between energy_in and energy_out in joules
5862 let energy_difference = energy_in_joules - energy_out_joules;
59-
60- // Check if the energy difference is less than the global threshold
61- let within_threshold = energy_difference <= TOLERENCE_ENERGY . get :: < joule > ( ) ;
62-
63+ let within_threshold = energy_difference <=
64+ TOLERENCE_ENERGY . get :: < joule > ( ) ;
6365 return within_threshold;
64-
6566 }
6667}
6768
68- /// # Mixer Block
69- ///
70- /// A block used for simple stream mixing operations.
71- ///
72- /// This struct requires the implementation of both EnergyBalance and MassBalance traits to ensure proper conservation principles are followed.
7369#[ allow( dead_code) ]
70+ /// # Mixer
71+ ///
72+ /// A block used for simple stream mixing operations.
7473pub struct Mixer {
75- pub block_id : String ,
76- pub x_cord : i32 ,
77- pub y_cord : i32 ,
78- pub input_streams_mass : Vec < connector:: Mconnector > ,
79- pub input_streams_energy : Vec < connector:: Econnector > ,
80- pub outlet_stream_energy : Option < connector:: Econnector > ,
74+ /// The ID of the block.
75+ pub block_id : String ,
76+ /// The x-coordiante on a flowsheet of the block.
77+ pub x_cord : i32 ,
78+ /// The y-coordinate on a flowsheet of the block.
79+ pub y_cord : i32 ,
80+ /// All mass input streams for the block.
81+ pub input_streams_mass : Vec < connector:: Mconnector > ,
82+ /// All energy input streams for the block.
83+ pub input_streams_energy : Vec < connector:: Econnector > ,
84+ /// All mass output streams for the block.
8185 pub outlet_stream_mass : Option < connector:: Mconnector > ,
82-
86+ /// All energy output streams for the block
87+ pub outlet_stream_energy : Option < connector:: Econnector > ,
8388}
8489
85- // Applying mass balance trait to Mixer Block
90+ /// Applying mass balance trait to Mixer Block
8691impl MassBalance for Mixer { }
8792
88- // Applying the energy balance trait to the Mixer Block
93+ /// Applying the energy balance trait to the Mixer Block
8994impl EnergyBalance for Mixer { }
9095
9196#[ allow( dead_code) ]
97+ /// Implementations of the mixer block.
9298impl Mixer {
93- pub fn new ( id : String , x_cord : i32 , y_cord : i32 , in_streams_mass : Vec < connector:: Mconnector > , in_streams_energy : Vec < connector:: Econnector > ) -> Mixer {
99+ /// Create a new mixer block.
100+ pub fn new (
101+ id : String ,
102+ x_cord : i32 ,
103+ y_cord : i32 ,
104+ in_streams_mass : Vec < connector:: Mconnector > ,
105+ in_streams_energy : Vec < connector:: Econnector > ,
106+ ) -> Mixer {
94107 return Mixer {
95- block_id : id,
108+ block_id : id,
96109 x_cord,
97110 y_cord,
98- input_streams_mass : in_streams_mass,
99- input_streams_energy : in_streams_energy,
100- outlet_stream_mass : None ,
101- outlet_stream_energy : None
111+ input_streams_mass : in_streams_mass,
112+ input_streams_energy : in_streams_energy,
113+ outlet_stream_mass : None ,
114+ outlet_stream_energy : None ,
102115 } ;
103116 }
104117
118+ /// Execute the mixer block (calculate balances, output streams, etc)
119+ /// TODO: This block should calculate the new state of external connectors.
105120 pub fn execute_block ( & mut self ) {
106-
107- // Calculating total Energy and Mass leaving the system (Assuming Steady State...)
108- self . outlet_stream_mass = Some ( connector:: Mconnector {
109- m_conn_id : String :: from ( "Mass_Outlet" ) ,
110- m_flow_total : self . compute_total_outlet_mass_flow ( ) . unwrap ( )
121+ self . outlet_stream_mass = Some ( connector:: Mconnector {
122+ m_conn_id : String :: from ( "Mass_Outlet" ) ,
123+ m_flow_total : self . compute_total_outlet_mass_flow ( ) . unwrap ( ) ,
124+ } ) ;
125+ self . outlet_stream_energy = Some ( connector:: Econnector {
126+ e_conn_id : String :: from ( "Energy Outlet" ) ,
127+ energy_flow_total : self . compute_outlet_energy_flows ( ) . unwrap ( ) ,
111128 } ) ;
112- self . outlet_stream_energy = Some ( connector:: Econnector { e_conn_id : String :: from ( "Energy Outlet" ) , energy_flow_total : self . compute_outlet_energy_flows ( ) . unwrap ( ) } ) ;
113129 }
114-
130+
115131 /// This private method will compute the outlet mass flows for the mixer block
116- ///
132+ ///
117133 /// # Returns
118- ///
134+ ///
119135 /// A Mass quantity (uom object) that holds the outlet mass flow
120136 fn compute_total_outlet_mass_flow ( & self ) -> Option < f64 > {
121- // TODO: steps to implement function:
137+ // TODO: steps to implement function:
122138 // Need to loop through each of the connector structures and add up the mass flows
123- // During this process, need to make sure that all the mass flows are in the same units
124- // Use the UOM package to help with this part...
125- let mut mass_flow_sum : f64 = 0.0 ;
126-
139+ // During this process, need to make sure that all the mass flows are in the same units
140+ // Use the UOM package to help with this part...
141+ let mut mass_flow_sum: f64 = 0.0 ;
142+
127143 for stream in & self . input_streams_mass {
128- mass_flow_sum = mass_flow_sum + stream. m_flow_total ;
129- }
144+ mass_flow_sum = mass_flow_sum + stream. m_flow_total ;
145+ }
130146 return Some ( mass_flow_sum) ;
131147 }
132148
133-
149+ /// Determines the total energy flowing through the block
134150 fn compute_outlet_energy_flows ( & self ) -> Option < f64 > {
151+ let mut energy_flow_sum: f64 = 0.0 ;
135152
136- let mut energy_flow_sum : f64 = 0.0 ;
137-
138153 for stream in & self . input_streams_energy {
139- energy_flow_sum = energy_flow_sum + stream. energy_flow_total ;
140- }
154+ energy_flow_sum = energy_flow_sum + stream. energy_flow_total ;
155+ }
141156 return Some ( energy_flow_sum) ;
142157 }
143158
144- fn compute_outlet_phase_fractions ( & self ) {
145-
146- }
147-
148- fn compute_outlet_temperature ( & self ) {
149-
150- }
151-
152- fn compute_outlet_pressure ( & self ) {
153-
154- }
159+ /// Determines the phase fractions of the output using thermodynamics.
160+ /// TODO: Implement this function
161+ fn compute_outlet_phase_fractions ( & self ) { }
155162
163+ /// Computes the outlet temperature of the mixer (assumes no chemical
164+ /// reactions) TODO: Implement this function
165+ fn compute_outlet_temperature ( & self ) { }
166+
167+ /// Computes the mixer outlet pressure.
168+ /// TODO: Implement this function
169+ fn compute_outlet_pressure ( & self ) { }
156170}
157171
158172#[ cfg( test) ]
159173mod block_tests {
160- use crate :: connector:: { Mconnector , Econnector } ;
174+ use crate :: connector:: { Econnector , Mconnector } ;
161175
162176 use super :: * ;
163- // use std::io;
164- use uom:: si:: f64:: Energy ;
165177 use uom:: si:: energy:: kilojoule;
178+ use uom:: si:: f64:: Energy ;
166179 use uom:: si:: mass:: pound;
167-
180+
168181 #[ test]
169182 fn test_mass_balance_check_steady_state_for_mixer ( ) {
170183 // here you will need to check that the mass into the mixer = mass out of mixer
171-
184+
172185 let mixer_test_obj = Mixer {
173- block_id : String :: from ( "Test Mixer" ) ,
174- x_cord : 0 ,
175- y_cord : 0 ,
176- input_streams_mass : Vec :: new ( ) ,
177- input_streams_energy : Vec :: new ( ) ,
178- outlet_stream_mass : None ,
179- outlet_stream_energy : None
186+ block_id : String :: from ( "Test Mixer" ) ,
187+ x_cord : 0 ,
188+ y_cord : 0 ,
189+ input_streams_mass : Vec :: new ( ) ,
190+ input_streams_energy : Vec :: new ( ) ,
191+ outlet_stream_mass : None ,
192+ outlet_stream_energy : None ,
180193 } ;
181194 let mass_in = Mass :: new :: < pound > ( 100.0 ) ;
182195 let mass_out = Mass :: new :: < pound > ( 95.0 ) ;
@@ -187,13 +200,13 @@ mod block_tests {
187200 fn test_energy_balance_check_steady_state_for_mixer ( ) {
188201 // energy into mixer = energy out of mixer
189202 let mixer_test_obj = Mixer {
190- block_id : String :: from ( "Test Mixer" ) ,
191- x_cord : 0 ,
192- y_cord : 0 ,
193- input_streams_mass : Vec :: new ( ) ,
194- input_streams_energy : Vec :: new ( ) ,
195- outlet_stream_mass : None ,
196- outlet_stream_energy : None
203+ block_id : String :: from ( "Test Mixer" ) ,
204+ x_cord : 0 ,
205+ y_cord : 0 ,
206+ input_streams_mass : Vec :: new ( ) ,
207+ input_streams_energy : Vec :: new ( ) ,
208+ outlet_stream_mass : None ,
209+ outlet_stream_energy : None ,
197210 } ;
198211 let energy_in = Energy :: new :: < kilojoule > ( 10.0 ) ;
199212 let energy_out = Energy :: new :: < kilojoule > ( 95.0 ) ;
@@ -203,36 +216,34 @@ mod block_tests {
203216 #[ test]
204217 fn test_compute_total_outlet_mass_flow ( ) {
205218 let in_streams_mass = vec ! [
206- Mconnector { m_conn_id: String :: from( "Mass1" ) , m_flow_total: 3.0 } ,
207- Mconnector { m_conn_id: String :: from( "Mass2" ) , m_flow_total: 7.0 } ,
219+ Mconnector {
220+ m_conn_id: String :: from( "Mass1" ) ,
221+ m_flow_total: 3.0 ,
222+ } ,
223+ Mconnector {
224+ m_conn_id: String :: from( "Mass2" ) ,
225+ m_flow_total: 7.0 ,
226+ } ,
208227 ] ;
209- let mixer = Mixer :: new (
210- String :: from ( "Mixer3" ) ,
211- 0 ,
212- 0 ,
213- in_streams_mass,
214- vec ! [ ] ,
215- ) ;
228+ let mixer = Mixer :: new ( String :: from ( "Mixer3" ) , 0 , 0 , in_streams_mass, vec ! [ ] ) ;
216229
217230 assert_eq ! ( mixer. compute_total_outlet_mass_flow( ) , Some ( 10.0 ) ) ;
218231 }
219232
220-
221233 #[ test]
222234 fn test_compute_outlet_energy_flows ( ) {
223235 let in_streams_energy = vec ! [
224- Econnector { e_conn_id: String :: from( "Energy1" ) , energy_flow_total: 100.0 } ,
225- Econnector { e_conn_id: String :: from( "Energy2" ) , energy_flow_total: 200.0 } ,
236+ Econnector {
237+ e_conn_id: String :: from( "Energy1" ) ,
238+ energy_flow_total: 100.0 ,
239+ } ,
240+ Econnector {
241+ e_conn_id: String :: from( "Energy2" ) ,
242+ energy_flow_total: 200.0 ,
243+ } ,
226244 ] ;
227- let mixer = Mixer :: new (
228- String :: from ( "Mixer5" ) ,
229- 0 ,
230- 0 ,
231- vec ! [ ] ,
232- in_streams_energy,
233- ) ;
245+ let mixer = Mixer :: new ( String :: from ( "Mixer5" ) , 0 , 0 , vec ! [ ] , in_streams_energy) ;
234246
235247 assert_eq ! ( mixer. compute_outlet_energy_flows( ) , Some ( 300.0 ) ) ;
236248 }
237-
238249}
0 commit comments