diff --git a/.github/workflows/create-doc-pages.yml b/.github/workflows/create-doc-pages.yml new file mode 100644 index 0000000..d5ffed1 --- /dev/null +++ b/.github/workflows/create-doc-pages.yml @@ -0,0 +1,28 @@ +name: Generate and Deploy Rust Docs + +on: + pull_request: + branches: + - main + +jobs: + rust-docs: + name: Generate Rust Documentation + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Rust + uses: dtolnay/rust-toolchain@stable + + - name: Generate documentation + run: cargo doc --no-deps + + - name: Deploy to GitHub Pages + if: github.ref == 'refs/heads/main' + uses: peaceiris/actions-gh-pages@v4 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_dir: ./target/doc diff --git a/oscps-db/Cargo.toml b/oscps-db/Cargo.toml new file mode 100644 index 0000000..522b655 --- /dev/null +++ b/oscps-db/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "oscps-db" +version = "0.1.0" +authors = ["Nathaniel Thomas ", "Bhargav Akula "] +edition = "2021" + +[dependencies] diff --git a/oscps-db/src/lib.rs b/oscps-db/src/lib.rs new file mode 100644 index 0000000..d8f2f31 --- /dev/null +++ b/oscps-db/src/lib.rs @@ -0,0 +1,13 @@ +///#OSCPS-db +/// +///Main library folder for the OSCPS-db library crate +/// +///will hold the methods to pull information from the POSTGRES database and from relevant APIs +/// +///Will hold property information for chemcial property calculation +///Will hold information about the user's simulation + + +pub mod postgres_db; +pub mod properties_db; + diff --git a/oscps-db/src/postgres_db.rs b/oscps-db/src/postgres_db.rs new file mode 100644 index 0000000..7bdd500 --- /dev/null +++ b/oscps-db/src/postgres_db.rs @@ -0,0 +1,28 @@ +/// #PostgresDB +/// +/// Will provide methods to connect to a postgres database to pull relevant property and/or +/// simulation information +/// +/// properties: +/// 1. db_name +/// 2. query +/// 3. status +/// 4. connection_key + +use sqlx::PgPool; +use uuid::Uuid; + + +enum DBStatus { + Successful, + Failure, + InProgress +} + +pub struct PostgresDB { + pub db_name: String, + pub input_query: String, + pub request_status: DBStatus, + db_key: Uuid, + db_pool: PgPool, +} diff --git a/oscps-db/src/properties_db.rs b/oscps-db/src/properties_db.rs new file mode 100644 index 0000000..b011aa2 --- /dev/null +++ b/oscps-db/src/properties_db.rs @@ -0,0 +1,4 @@ +///# PropertiesDB +/// +///Will formulate the right queries required for 'DBConnector' +/// diff --git a/oscps-gui/Cargo.toml b/oscps-gui/Cargo.toml index ff6cb50..cf7081c 100644 --- a/oscps-gui/Cargo.toml +++ b/oscps-gui/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "oscps-gui" version = "0.1.0" -authors = ["Nathaniel Thomas ", "Bhargav Akula "] +authors = ["Nathaniel Thomas ", "Bhargav Akula "] edition = "2021" [dependencies] diff --git a/oscps-lib/Cargo.toml b/oscps-lib/Cargo.toml index a0326c6..aef0dad 100644 --- a/oscps-lib/Cargo.toml +++ b/oscps-lib/Cargo.toml @@ -1,14 +1,16 @@ [package] name = "oscps-lib" version = "0.1.0" +authors = ["Nathaniel Thomas ", "Bhargav Akula "] edition = "2021" [dependencies] -uom = "0.36.0" +uom = "0.37.0" once_cell = "1.17.1" pubchem = "0.1.1" -reqwest = { version = "0.11", features = ["json"] } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tokio = { version = "1", features = ["full"] } anyhow = "1.0" +autodiff = "0.7.0" +oscps-db = { path = "../oscps-db" } diff --git a/oscps-lib/src/component.rs b/oscps-lib/src/component.rs deleted file mode 100644 index a4581cd..0000000 --- a/oscps-lib/src/component.rs +++ /dev/null @@ -1,163 +0,0 @@ -//! # Component -//! -//! Contains chemical properties for components in the simulation. - -extern crate uom; - -extern crate pubchem; -use anyhow::Result; -use std::{thread,time::Duration}; - - -#[allow(dead_code)] -/// This will hold the list of chemicals used within the simulation -pub struct ChemicalList { - chemical_list: Vec, -} - -#[allow(dead_code)] -/// A struct to store information regarding the chemical properties of a -/// particular substance. The "Chemical" struct is a wrapper for the -/// pubchem::Compound object -pub struct Chemical { - /// The (PubChem)[] CID of a compound. - pub pubchem_obj: pubchem::Compound, - /// Physical properties of a compound. - pub properties: ChemicalProperties, -} - -#[allow(dead_code)] -/// Used by the "Chemical" struct to create the pubchem::Compound obj based on -/// either the chemical name or the pubchem id of the chemical -pub enum ChemicalIdentifier { - /// The PubChem ID of the component. - PubchemID(u32), - /// The actual name of the component. - CompoundName(String), -} - -#[allow(dead_code)] -/// Implementation of the chemical of interest. -impl Chemical { - /// Constructs a new chemical. - pub fn new(identifier: ChemicalIdentifier) -> Result { - let pubchem_chemical_object = match identifier { - ChemicalIdentifier::PubchemID(id) => pubchem::Compound::new(id), - ChemicalIdentifier::CompoundName(name) => pubchem::Compound::with_name(name.as_str()), - }; - let mut request_counter = 0; - let mut cid_vec = None; - while request_counter <= 10 { - match pubchem_chemical_object.cids(){ - Ok(cid_list) => { - cid_vec = Some(cid_list); - break; - }, - _ => { - request_counter += 1; - thread::sleep(Duration::from_secs(10)); - } - }; - } - - // let cid_vec = pubchem_chemical_object.cids().unwrap(); - let cid: i32 = cid_vec.unwrap()[0]; - let prop = ChemicalProperties::new(cid).unwrap(); - Ok(Chemical { - pubchem_obj: pubchem_chemical_object, - properties: prop, - }) - } - /// Returns the pubchem object for the compound. - pub fn get_pubchem_obj(&self) -> &pubchem::Compound { - &self.pubchem_obj - } - - /// Returns the "ChemicalProperties" object for the "Chemical" object. - pub fn get_properties(&self) -> &ChemicalProperties { - &self.properties - } -} - -#[allow(dead_code)] -/// Struct containing properties of a chemical -pub struct ChemicalProperties { - /// Contains the molar mass of a compound. - pub molar_mass: f64, // kg/mol - /// Critial temperature of a compoound. - pub critical_temp: f64, // K - /// The critical pressure of a compound. - pub critical_pressure: f64, // Pa - /// Acentric factor of a compound. - pub acentric_factor: f64, - ///Heat capacity Coefficient A - pub const_a: f64, - ///Heat capacity Coefficient B - pub const_b: f64, - ///Heat capacity Coefficient C - pub const_c: f64, - ///Heat capacity Coefficient D - pub const_d: f64 -} - -/// Implementation of the ChemicalProperties struct. -impl ChemicalProperties { - /// Constructor for the ChemicalProperties struct. - pub fn new(cid: i32) -> Result { - println!("Recieving information for compound/element {cid}"); - Ok(ChemicalProperties { - molar_mass: 0.0, // kg/mol - critical_temp: 0.0, // K - critical_pressure: 0.0, // Pa - acentric_factor: 0.0, - const_a: 0.0, - const_b: 0.0, - const_c: 0.0, - const_d: 0.0 - }) - } -} - -#[cfg(test)] -mod chemical_species_tests { - use crate::component::{Chemical, ChemicalIdentifier}; - use std::{thread,time::Duration}; - - #[test] - fn test_create_chemical_from_pubchem_id() { - // Using a known PubChem ID, e.g., 7732 (water) - let identifier = ChemicalIdentifier::PubchemID(7732); - - let chemical = Chemical::new(identifier); - thread::sleep(Duration::from_secs(10)); - - assert!( - chemical.is_ok(), - "Failed to create chemical from PubChem ID" - ); - let chemical = chemical.unwrap(); - - // Verify that the Chemical object contains the expected PubChem object - assert_eq!(chemical.get_pubchem_obj().cids().unwrap()[0], 7732); - - // Optionally, verify that the ChemicalProperties object has been initialized - // assert_eq!(chemical.get_properties().molar_mass, 0.0); // Example check for default values - } - - #[test] - fn test_create_chemical_from_name() { - let identifier = ChemicalIdentifier::CompoundName(String::from("Water")); - - let chemical = Chemical::new(identifier); - thread::sleep(Duration::from_secs(10)); - - - assert!(chemical.is_ok(), "Failed to create chemical from name"); - let chemical = chemical.unwrap(); - - // Verify that the Chemical object contains a valid name - assert_eq!(chemical.get_pubchem_obj().cids().unwrap()[0], 962); - assert_eq!(chemical.pubchem_obj.title().unwrap(), "Water"); - // assert_eq!(chemical.get_properties().molar_mass, 0.0); // Example check for default values - } -} diff --git a/oscps-lib/src/lib.rs b/oscps-lib/src/lib.rs index 9255cc1..7a42da1 100644 --- a/oscps-lib/src/lib.rs +++ b/oscps-lib/src/lib.rs @@ -5,6 +5,11 @@ #![warn(missing_docs)] +extern crate uom; +extern crate once_cell; +extern crate serde; +extern crate anyhow; + pub mod blocks; pub mod component; pub mod simulation; diff --git a/oscps-lib/src/properties.rs b/oscps-lib/src/properties.rs new file mode 100644 index 0000000..73b9720 --- /dev/null +++ b/oscps-lib/src/properties.rs @@ -0,0 +1,107 @@ +//! # Properties +//! +//! Contains chemical properties for species in the simulation. + +extern crate uom; +extern crate pubchem; +///Importing pure species properties +pub mod pure_species_properties; + +use anyhow::Result; +use uom::si::f64::*; +use std::{thread,time::Duration}; +use serde::{Serialize, Deserialize}; + +#[allow(dead_code)] +/// Used by the "Chemical" struct to create the pubchem::Compound obj based on +/// either the chemical name or the pubchem id of the chemical +pub enum ChemicalIdentifier { + /// The PubChem ID of the component. + PubchemID(u32), + /// The actual name of the component. + CompoundName(String), +} + + +#[allow(dead_code)] +/// A struct to store information regarding the chemical properties of a +/// particular substance. The "Chemical" struct is a wrapper for the +/// pubchem::Compound object +pub struct Chemical { + /// The (PubChem)[] CID of a compound. + pub pubchem_obj: pubchem::Compound, + /// Physical properties of a compound. + pub properties: ChemicalProperties, +} + +#[allow(dead_code)] +/// Implementation of the chemical of interest. +impl Chemical { + /// Constructs a new chemical. + pub fn new(identifier: ChemicalIdentifier) -> Result { + let pubchem_chemical_object = match identifier { + ChemicalIdentifier::PubchemID(id) => pubchem::Compound::new(id), + ChemicalIdentifier::CompoundName(name) => pubchem::Compound::with_name(name.as_str()), + }; + let mut request_counter = 0; + let mut cid_vec = None; + while request_counter <= 10 { + match pubchem_chemical_object.cids(){ + Ok(cid_list) => { + cid_vec = Some(cid_list); + break; + }, + _ => { + request_counter += 1; + thread::sleep(Duration::from_secs(10)); + } + }; + } + + // let cid_vec = pubchem_chemical_object.cids().unwrap(); + let cid: i32 = cid_vec.unwrap()[0]; + let prop = ChemicalProperties::new(cid).unwrap(); + Ok(Chemical { + pubchem_obj: pubchem_chemical_object, + properties: prop, + }) + } + /// Returns the pubchem object for the compound. + pub fn get_pubchem_obj(&self) -> &pubchem::Compound { + &self.pubchem_obj + } + + /// Returns the "ChemicalProperties" object for the "Chemical" object. + pub fn get_properties(&self) -> &ChemicalProperties { + &self.properties + } +} + +#[allow(dead_code)] +/// Struct containing properties of a chemical +pub struct ChemicalProperties { + /// Pure species properties + pub critical: Option, + + /// Heat capacity coefficients (optional, stored as an array) + pub heat_capacity: Option, + + /// Transport properties (optional, could include viscosity, etc.) + pub transport: Option, + + /// Additional chemical property categories + // Here we might add properties related to binary interactions, etc... + pub other_properties: Option>, +} + +/// Trait to group all property libraries +trait PropertyLibrary { + /// default function for connecting the database to pull relevant property information + fn oscps_db_connection(&self) -> &db_connection; +} + + + +#[cfg(test)] +mod chemical_species_tests { +} diff --git a/oscps-lib/src/properties/pure_species_properties.rs b/oscps-lib/src/properties/pure_species_properties.rs new file mode 100644 index 0000000..f9b4983 --- /dev/null +++ b/oscps-lib/src/properties/pure_species_properties.rs @@ -0,0 +1,32 @@ +///# Pure Species Properties +/// This sub-module will contain the information regarding the cheracteristic properties of pure +/// species. This would include the molar mass (molecular weight), accentric factor, critical +/// temperature, critical pressure, critical compressibility, critical molar volume, and normal +/// boiling point. + +#[warn(unused_imports)] +use crate::properties::*; +use uom::si::f64; +use std::sync::Arc; +// use oscps_db; + +///#PureSpeciesProperties +/// +///This will contain all the important properties for pure species +pub struct PureSpeciesProperties { + pub species_obj_id: Arc, + pub antoine_equation_constants: Vec, + pub critical_temperature: f64::ThermodynamicTemperature, + pub molar_mass: f64::MolarMass, + pub normal_boiling_point: f64::ThermodynamicTemperature, + pub critical_molar_volume: f64::Volume, + pub accentric_factor: f64::Ratio, + pub compressibility_factor: f64::Ratio +} + +///Functions to pull pure species properties from the database + // Database will need to handle API calls to external sources for information currently in the + // database. +impl PureSpeciesProperties { + +} diff --git a/oscps-lib/src/thermodynamics.rs b/oscps-lib/src/thermodynamics.rs index 47e969c..dce49bc 100644 --- a/oscps-lib/src/thermodynamics.rs +++ b/oscps-lib/src/thermodynamics.rs @@ -3,12 +3,13 @@ //! This module will hold all the functions related to calculating //! themrodynamic properties for the blocks and chemical species. -///Importing Ideal Gas Package -pub mod ideal_gas_package; -///Importing SRK Package -pub mod srk_package; -use crate::component::Chemical; +///Importing EOSModels +pub mod eos_models; +/// Importing chemical properties +use crate::properties::Chemical; + +///Importing External Packages use uom::si::f64::*; use uom::si::mass; use uom::si::pressure; @@ -16,8 +17,9 @@ use uom::si::thermodynamic_temperature; use uom::si::energy; use uom::si::amount_of_substance; - #[allow(dead_code)] +/// #ThermodynamicConstants +/// /// Struct for storing physical constants for thermodynamics. /// TODO: Reimplement the use of uom for dimensional analysis. pub enum ThermodynamicConstants { @@ -53,90 +55,22 @@ impl ThermodynamicConstants { } } -#[allow(dead_code)] -/// Species list -pub struct ComponentData { - /// Chemical species - pub chemical_species: Chemical, // will contain intrinsic properties of species - /// Mass quantity - pub mass_quantity: Mass, - /// Molar quantity - pub molar_quantity: AmountOfSubstance, - ///volumetric quantity - pub vol_quantity: Volume, - /// partial pressure - pub partial_pressure : Pressure, -} - -#[allow(dead_code)] -/// # ThermoState -/// Returns a thermodynamic state, including pressure, temperature, and -/// mole fractions. -/// This struct will be used for streams in the flow diagram -pub struct ThermoState { - /// Pressure of the state. - pub pressure: Option, // pressure - /// Temperature of the state. - pub temperature: Option, // temperature - /// List of mole fractions. - pub mass_list: Vec,//Information about each component within stream - /// Total Mass - pub total_mass : Option, // total mass in stream - /// Total Moles - pub total_mol : Option, // total moles in stream - /// Total Volume - pub total_volume : Option, // total volume in stream - ///Thermo Package - pub thermodynamic_package : Option> // thermodynamics package -} - - -#[allow(dead_code)] -/// Implementation of ThermoState -/// This struct holds the functionality to perform thermodynamic calculations for streams -impl ThermoState { - /// Constructor for creating a ThermoState - pub fn new() -> Self { - ThermoState { - pressure : None, - temperature : None, - mass_list : vec![], - total_mass : None, - total_mol : None, - total_volume : None, - thermodynamic_package : None - } - } - /// this function will return the total mass for an individual stream - fn calc_total_mass(&mut self) -> Mass { - let mut mass_sum = 0.0; - for chem in &self.mass_list { - mass_sum += chem.mass_quantity.get::(); - } - self.total_mass = Some(Mass::new::(mass_sum)); - - self.total_mass.unwrap() - } - /// this function will return the total moles for an individual stream - fn calc_total_moles(&mut self) -> AmountOfSubstance { - let mut mole_sum = 0.0; - for chem in &self.mass_list { - mole_sum += chem.molar_quantity.get::(); - } - self.total_mol = Some(AmountOfSubstance::new::(mole_sum)); - - self.total_mol.unwrap() - } -} - ///Thermodynamic Packages. /// -///#ThermoPackage -///Will be a common trait for all the thermodynamic packages -///Will include functions common to thermodynamic packages -///Will also enable to user to switch between thermodynamic packages within the ThermoState struct -///(the thermodynamic packages will be structs) -pub trait ThermoPackage{ +///#MaxwellRelations +/// +///Will be a common trait for all the thermodynamic packages and will include common functions. +///Will also enable to user to switch between thermodynamic packages within the StreamThermoState struct +/// +///The thermodynamic pacakges can be used by the blocks for any relevant calculations +/// +///For calculations, the thermodynamic packages will call upon the property struct for relevant +///info. +/// +///TODO: Currently the rust std::autodiff is still experimental. Need to wait for this release. In +///the meantime, we will either manually write out the derivatives or use a third party autdiff +///package (the third party is: https://crates.io/crates/autodiff) +pub trait MaxwellRelations{ ///Calculating the Enthalpy fn enthalpy(&self) -> MolarEnergy; ///Calculating the Entropy @@ -157,117 +91,5 @@ pub trait ThermoPackage{ fn gibbs_free_energy(&self) -> Energy; } - - - #[cfg(test)] -mod thermo_tests { - // use super::*; - // use crate::component::{Chemical, ChemicalProperties}; - // use uom::si::mass::kilogram; - // use uom::si::pressure::pascal; - // use uom::si::thermodynamic_temperature::kelvin; - // use std::{thread,time::Duration}; - - // #[test] - // ///Test case generates an instance of the 'ThermoState' struct - // fn test_create_thermo_state() { - // // Create some test data for ThermoMoleFrac (mole fractions) - // let water = Chemical { - // pubchem_obj: pubchem::Compound::new(962), - // properties: ChemicalProperties { - // molar_mass: 0.01801528, // kg/mol for water - // critical_temp: 647.1, // K - // critical_pressure: 2206.0, // Pa - // acentric_factor: 0.344, // example - // }, - // }; - // thread::sleep(Duration::from_secs(10)); - // let water_mass = Mass::new::(2.0); - // let water_species_pair = SpeciesQuantityPair { - // chemical_species: water, - // mass_quantity: water_mass, - // const_a: 1.0, - // const_b: 1.0, - // const_c: 1.0, - // const_d: 0.0 - // }; - - // // Create ThermoState - // let thermo_state = ThermoState::new( - // 101325.0, // pressure in Pascals (1 atm) - // 298.15, // temperature in Kelvin (25°C) - // vec![water_species_pair], // Example with one chemical - // ); - - // // Validate ThermoState - // assert_eq!(thermo_state.pressure.get::(), 101325.0); - // assert_eq!(thermo_state.temperature.get::(), 298.15); - // assert_eq!(thermo_state.mass_list.len(), 1); // Should contain one mole fraction entry - - // - - // // Check that the mole fraction's chemical is correctly set - // assert_eq!( - // thermo_state.mass_list[0] - // .chemical_species - // .get_pubchem_obj() - // .cids() - // .unwrap()[0], - // 962 - // ); - // } - - // #[test] - // ///Tests the mass fraction function within the 'ThermoState struct' - // fn test_mass_fraction_calculation() { - // let water = Chemical { - // pubchem_obj: pubchem::Compound::new(962), - // properties: ChemicalProperties { - // molar_mass: 0.01801528, // kg/mol for water - // critical_temp: 647.1, // K - // critical_pressure: 2206.0, // Pa - // acentric_factor: 0.344, // example - // }, - // }; - // thread::sleep(Duration::from_secs(10)); - - // let anisdine = Chemical { - // pubchem_obj: pubchem::Compound::new(7732), - // properties: ChemicalProperties { - // molar_mass: 123.155, // g/mol, converting to kg/mol = 123.155 / 1000 - // critical_temp: 592.0, // K (approximated) - // critical_pressure: 2.6e6, // Pa (approximated) - // acentric_factor: 0.24, // (approximated) - // }, - // }; - // thread::sleep(Duration::from_secs(10)); - // - // let water_mass = Mass::new::(2.0); - // let water_species_pair = SpeciesQuantityPair { - // chemical_species: water, - // mass_quantity: water_mass, - // }; - - // let anisidine_mass = Mass::new::(8.0); - // let anisidine_species_pair = SpeciesQuantityPair { - // chemical_species: anisdine, - // mass_quantity: anisidine_mass, - // }; - - // let therm_obj = ThermoState::new( - // 101325.0, - // 298.15, - // vec![water_species_pair, anisidine_species_pair], - // ); - - // let mass_fraction = therm_obj - // .mass_frac(&therm_obj.mass_list[0].chemical_species) - // .unwrap(); - - // assert!( - // (mass_fraction - 0.2).abs() < 1e-6, - // "Mole fraction calculation failed" - // ); // Should be 0.2 - // } -} +mod thermo_tests {} diff --git a/oscps-lib/src/thermodynamics/eos_models.rs b/oscps-lib/src/thermodynamics/eos_models.rs new file mode 100644 index 0000000..c9fcd38 --- /dev/null +++ b/oscps-lib/src/thermodynamics/eos_models.rs @@ -0,0 +1,23 @@ +///#EOSModel +/// +///This struct will represent the different thermodynamic equations of state + + +use crate::thermodynamics::*; +use std::sync::Arc; +use uom::si::f64::*; +use uom::si::molar_energy; +use uom::si::molar_heat_capacity; +use uom::si::pressure; +use uom::si::thermodynamic_temperature; +use uom::si::energy; +use uom::si::amount_of_substance; +use uom::si::volume; +use uom::si::ratio; + + +/// This struct will hold the chemical potential equation for each type of equation of state +/// Inspired by: https://github.com/ClapeyronThermo/Clapeyron.jl +pub struct EOSModel { + +} diff --git a/oscps-lib/src/thermodynamics/ideal_gas_package.rs b/oscps-lib/src/thermodynamics/ideal_gas_package.rs deleted file mode 100644 index d399335..0000000 --- a/oscps-lib/src/thermodynamics/ideal_gas_package.rs +++ /dev/null @@ -1,179 +0,0 @@ -///#IdealGasPackage -/// -///Will contain equations related to ideal gases - - -use crate::thermodynamics::*; -use std::sync::Arc; -use uom::si::f64::*; -use uom::si::molar_energy; -use uom::si::molar_heat_capacity; -use uom::si::pressure; -use uom::si::thermodynamic_temperature; -use uom::si::energy; -use uom::si::amount_of_substance; -use uom::si::volume; -use uom::si::ratio; - -///Creating the ideal gas thermodynamics package -pub struct IdealGasPackage { - ///Temperature - pub temperature : Arc, - /// Pressure - pub pressure : Arc, - ///List of Species - pub species_list : Vec>, - /// Mass - pub total_mass : Arc, - /// Volume - pub total_vol : Arc, - /// Moles - pub total_mol : Arc -} -///Implementing functions specific to the IdealGasPackage -impl IdealGasPackage { - ///Constructor - pub fn new( - temperature: Arc, - pressure : Arc, - species_list : Vec>, - total_mass : Arc, - total_vol : Arc, - total_mol : Arc) -> Self { - IdealGasPackage { - temperature, - pressure, - species_list, - total_mass, - total_vol, - total_mol - } - } -} -/// Implementing the ThermoPackage trait for the IdealGasPackage -impl ThermoPackage for IdealGasPackage { - ///Calculating enthalpy - // Need to run a for loop where I calculate the enthalpy of each species and then add it to - // the variable 'total_enthalpy' - // ASSUMPTIONS CURRENTLY MADE: - // No enthalpy from phase change - // when working with gases, assume that they are ideal gases - // Tref = 298 K & Pref = 101.325 kPa - // Href = 0 - fn enthalpy(&self) -> MolarEnergy { - let mut total_enthalpy = 0.0; - let t_ref = 298.15; //reference temperature - let h_ref = 0.0; //Reference enthalpy - let mut cp_ref; - let mut cp_t; - let r = ThermodynamicConstants::UniversalGasConstant.value().downcast::().unwrap(); - - for chem_object in &self.species_list { - let chem = &(*chem_object).chemical_species.properties; - if chem.const_c != 0.0 { - cp_ref = chem.const_a * t_ref + (1.0 / 2.0) * (chem.const_b / (10.0f64.powf(3.0))) * t_ref.powi(2); - cp_t = chem.const_a * self.temperature.get::() + (1.0 / 2.0) * (chem.const_b / (10.0f64.powf(3.0))) * self.temperature.get::().powf(2.0) + (1.0 / 3.0) * (chem.const_c / (10.0f64.powf(6.0))) * self.temperature.get::().powf(3.0); - } - else{ - cp_ref = chem.const_a * t_ref + (1.0 / 2.0) * (chem.const_b / (10.0f64.powf(3.0))) * t_ref.powi(2) + (-1.0) * (chem.const_d / (10.0f64.powf(-5.0))) * t_ref.powi(-1); - cp_t = chem.const_a * self.temperature.get::() + (1.0 / 2.0) * (chem.const_b / (10.0f64.powf(3.0))) * self.temperature.get::().powf(2.0) + (-1.0) * (chem.const_d / (10.0f64.powf(-5.0))) * self.temperature.get::().powf(-1.0); - } - let species_enthalpy = (chem_object.molar_quantity.get::()/self.total_mol.get::())*(h_ref + (cp_t - cp_ref)* r.get::()); - total_enthalpy += species_enthalpy; - } - - MolarEnergy::new::(total_enthalpy) - } - /// Determine ideal gas pressure - fn pressure(&self) -> Pressure { - let r = ThermodynamicConstants::UniversalGasConstant.value().downcast::().unwrap(); - let ideal_pressure = (self.total_mol.get::() * r.get::() * self.temperature.get::()) / (self.total_vol.get::()); - Pressure::new::(ideal_pressure) - } - ///Deterrmine entropy - // Will need to use equation (5.10) from the 'Introduction to Chemical Engineering - // Thermodynamics' - fn entropy(&self) -> MolarHeatCapacity { - let mut entropy_total = 0.0; - let t_ref = 298.15_f64; //reference temperature - let mut cp_ref; - let mut cp_t; - let r = ThermodynamicConstants::UniversalGasConstant.value().downcast::().unwrap(); - let p_o = 1.0_f64; // units atm - - for chem_object in &self.species_list { - let chem = &(*chem_object).chemical_species.properties; - if chem.const_c != 0.0 { - cp_ref = chem.const_a * t_ref.ln() + (chem.const_b / (10.0f64.powf(3.0))) * t_ref; - cp_t = chem.const_a * self.temperature.get::().ln() + (chem.const_b / (10.0f64.powf(3.0))) * self.temperature.get::() + (1.0 / 2.0) * (chem.const_c / (10.0f64.powf(6.0))) * self.temperature.get::().powf(2.0); - } - else{ - cp_ref = chem.const_a * t_ref.ln() + (chem.const_b / (10.0f64.powf(3.0))) * t_ref + (-1.0/2.0) * (chem.const_d / (10.0f64.powf(-5.0))) * t_ref.powi(-2); - cp_t = chem.const_a * self.temperature.get::().ln() + (chem.const_b / (10.0f64.powf(3.0))) * self.temperature.get::() + (-1.0/2.0) * (chem.const_d / (10.0f64.powf(-5.0))) * self.temperature.get::().powf(-2.0); - } - let integral_solve_species = cp_t - cp_ref; - let pressure_ratio = (*chem_object).partial_pressure.get::() / p_o; - - entropy_total += (chem_object.molar_quantity.get::()/self.total_mol.get::())*r.get::()*(integral_solve_species - pressure_ratio); - } - - MolarHeatCapacity::new::(entropy_total) - } - /// Determining vapor fraction - // In Ideal gas package, only will be used when components are all in gaseous state so - // vapor fraction will always be equal to 1 - fn vapor_fraction(&self) -> Ratio { - Ratio::new::(1.0) - } - /// Determining Cp (Heat capacity under constant pressure conditions) - fn heat_capacity_const_pressure(&self) -> MolarHeatCapacity { - let r = ThermodynamicConstants::UniversalGasConstant.value().downcast::().unwrap(); - let mut total_heat_capacity_const_pressure : f64 = 0.0; - let mut cp_t; - let t = self.temperature.get::(); - for chem_object in &self.species_list { - let chem = &(*chem_object).chemical_species.properties; - if chem.const_c != 0.0 { - cp_t = chem.const_a + (chem.const_b / (10.0f64.powf(3.0)))*t + (chem.const_c / (10.0f64.powf(6.0)))*t.powf(2.0); - } - else { - cp_t = chem.const_a + (chem.const_b / (10.0f64.powf(3.0)))*t + (chem.const_d / (10.0f64.powf(-5.0)))*t.powf(-2.0); - } - total_heat_capacity_const_pressure += cp_t* (chem_object.molar_quantity.get::()/self.total_mol.get::())*r.get::(); - } - MolarHeatCapacity::new::(total_heat_capacity_const_pressure) - } - ///Determining internal energy - //Need to figure out way to calculate Cv - fn internal_energy(&self) -> MolarEnergy { - MolarEnergy::new::(0.0) - } - ///Determining temperature - fn temperature(&self) -> ThermodynamicTemperature { - let r = ThermodynamicConstants::UniversalGasConstant.value().downcast::().unwrap().get::(); - //T = PV/nR - let p = self.pressure.get::(); - let v = self.total_vol.get::(); - let n = self.total_mol.get::(); - let ideal_temperature = (p*v)/(n*r); - ThermodynamicTemperature::new::(ideal_temperature) - } - ///Determining volume - fn volume(&self) -> Volume { - let r = ThermodynamicConstants::UniversalGasConstant.value().downcast::().unwrap().get::(); - // V = (nRT)/P - let n = self.total_mol.get::(); - let p = self.pressure.get::(); - let t = self.temperature.get::(); - let ideal_volume = (n*r*t)/(p); - Volume::new::(ideal_volume) - } - ///Determining the Gibbs free energy - fn gibbs_free_energy(&self) -> Energy { - let enthalpy = self.enthalpy().get::()*self.total_mol.get::(); - let entropy = self.entropy().get::()*self.total_mol.get::(); - let gibbs_free_energy_value = enthalpy - self.temperature.get::()*entropy; - Energy::new::(gibbs_free_energy_value) - } -} - diff --git a/oscps-lib/src/thermodynamics/srk_package.rs b/oscps-lib/src/thermodynamics/srk_package.rs deleted file mode 100644 index 312a815..0000000 --- a/oscps-lib/src/thermodynamics/srk_package.rs +++ /dev/null @@ -1,17 +0,0 @@ -// // NOTE: Commented out to prevent warnings. - -// ///#SRKPackage -// /// -// ///Will contain equations relating to the SRK Equation of state -// use crate::thermodynamics::*; -// use std::sync::Arc; -// use std::sync::{Arc, RwLock}; -// use uom::si::amount_of_substance; -// use uom::si::energy; -// use uom::si::f64::*; -// use uom::si::molar_energy; -// use uom::si::molar_heat_capacity; -// use uom::si::pressure; -// use uom::si::ratio; -// use uom::si::thermodynamic_temperature; -// use uom::si::volume;