diff --git a/example/pr-alcohols.json b/example/pr-alcohols.json new file mode 100644 index 0000000..2e16376 --- /dev/null +++ b/example/pr-alcohols.json @@ -0,0 +1,18 @@ +[ + { + "identifier": { + "cas": "67-56-1", + "name": "methanol", + "iupac_name": "methanol", + "smiles": "CO", + "inchi": "InChI=1/CH4O/c1-2/h2H,1H3", + "formula": "CH4O" + }, + "model_record": { + "tc": 512.60, + "pc": 8096000.0, + "acentric_factor": 0.559 + }, + "molarweight": 32.04 + } +] diff --git a/example/pr-alkanes.json b/example/pr-alkanes.json new file mode 100644 index 0000000..9aec553 --- /dev/null +++ b/example/pr-alkanes.json @@ -0,0 +1,34 @@ +[ + { + "identifier": { + "cas": "74-98-6", + "name": "propane", + "iupac_name": "propane", + "smiles": "CCC", + "inchi": "InChI=1/C3H8/c1-3-2/h3H2,1-2H3", + "formula": "C3H8" + }, + "model_record": { + "tc": 369.96, + "pc": 4250000.0, + "acentric_factor": 0.153 + }, + "molarweight": 44.0962 + }, + { + "identifier": { + "cas": "106-97-8", + "name": "butane", + "iupac_name": "butane", + "smiles": "CCCC", + "inchi": "InChI=1/C4H10/c1-3-4-2/h3-4H2,1-2H3", + "formula": "C4H10" + }, + "model_record": { + "tc": 425.2, + "pc": 3800000.0, + "acentric_factor": 0.199 + }, + "molarweight": 58.123 + } +] \ No newline at end of file diff --git a/src/cubic.rs b/src/cubic.rs index 6b67a2e..c9863c4 100644 --- a/src/cubic.rs +++ b/src/cubic.rs @@ -69,6 +69,15 @@ pub struct PengRobinsonParameters { joback_records: Option>, } +impl std::fmt::Display for PengRobinsonParameters { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.pure_records + .iter() + .try_for_each(|pr| writeln!(f, "{}", pr.to_string()))?; + writeln!(f, "\nk_ij:\n{}", self.k_ij) + } +} + impl PengRobinsonParameters { /// Build a simple parameter set without binary interaction parameters. pub fn new_simple( diff --git a/src/parameter/mod.rs b/src/parameter/mod.rs index 64e347f..db16c06 100644 --- a/src/parameter/mod.rs +++ b/src/parameter/mod.rs @@ -74,7 +74,7 @@ where /// Creates parameters from substance information stored in json files. fn from_json

( - substances: &[&str], + substances: Vec<&str>, file_pure: P, file_binary: Option

, search_option: IdentifierOption, @@ -82,24 +82,52 @@ where where P: AsRef, { - let queried: IndexSet = substances - .iter() - .map(|identifier| identifier.to_string()) - .collect(); - let file = File::open(file_pure)?; - let reader = BufReader::new(file); + Self::from_multiple_json(&[(substances, file_pure)], file_binary, search_option) + } - let pure_records: Vec> = - serde_json::from_reader(reader)?; - let mut record_map: HashMap<_, _> = pure_records - .into_iter() - .filter_map(|record| { - record - .identifier - .as_string(search_option) - .map(|i| (i, record)) - }) - .collect(); + /// Creates parameters from substance information stored in multiple json files. + fn from_multiple_json

( + input: &[(Vec<&str>, P)], + file_binary: Option

, + search_option: IdentifierOption, + ) -> Result + where + P: AsRef, + { + let mut queried: IndexSet = IndexSet::new(); + let mut record_map: HashMap> = + HashMap::new(); + + for (substances, file) in input { + substances.iter().try_for_each(|identifier| { + match queried.insert(identifier.to_string()) { + true => Ok(()), + false => Err(ParameterError::IncompatibleParameters(String::from( + format!( + "tried to add substance '{}' to system but it is already present.", + identifier.to_string() + ), + ))), + } + })?; + let f = File::open(file)?; + let reader = BufReader::new(f); + + let pure_records: Vec> = + serde_json::from_reader(reader)?; + + pure_records + .into_iter() + .filter_map(|record| { + record + .identifier + .as_string(search_option) + .map(|i| (i, record)) + }) + .for_each(|(i, r)| { + let _ = record_map.insert(i, r); + }); + } // Compare queried components and available components let available: IndexSet = record_map diff --git a/src/python/cubic.rs b/src/python/cubic.rs index 762ac20..de51648 100644 --- a/src/python/cubic.rs +++ b/src/python/cubic.rs @@ -14,7 +14,6 @@ use std::collections::HashMap; use std::convert::TryFrom; use std::rc::Rc; - /// A pure substance parameter for the Peng-Robinson equation of state. #[pyclass(name = "PengRobinsonRecord", unsendable)] #[derive(Clone)] @@ -63,6 +62,13 @@ pub struct PyPengRobinsonParameters(pub Rc); impl_parameter!(PengRobinsonParameters, PyPengRobinsonParameters); +#[pymethods] +impl PyPengRobinsonParameters { + fn __repr__(&self) -> PyResult { + Ok(self.0.to_string()) + } +} + /* EQUATION OF STATE */ /// A simple version of the Peng-Robinson equation of state. @@ -76,9 +82,7 @@ impl_parameter!(PengRobinsonParameters, PyPengRobinsonParameters); /// ------- /// PengRobinson #[pyclass(name = "PengRobinson", unsendable)] -#[pyo3( - text_signature = "(parameters)" -)] +#[pyo3(text_signature = "(parameters)")] #[derive(Clone)] pub struct PyPengRobinson(pub Rc); diff --git a/src/python/mod.rs b/src/python/mod.rs index 18ed0e2..d9482c0 100644 --- a/src/python/mod.rs +++ b/src/python/mod.rs @@ -108,7 +108,6 @@ pub fn feos_core(py: Python<'_>, m: &PyModule) -> PyResult<()> { import sys sys.modules['feos_core.si'] = quantity sys.modules['feos_core.user_defined'] = user_defined -sys.modules['feos_core.user_defined.num_dual'] = user_defined.num_dual sys.modules['feos_core.cubic'] = cubic ", None, diff --git a/src/python/parameter.rs b/src/python/parameter.rs index 30181ad..08554dd 100644 --- a/src/python/parameter.rs +++ b/src/python/parameter.rs @@ -596,12 +596,42 @@ macro_rules! impl_parameter { None => IdentifierOption::Name, }; Ok(Self(Rc::new(<$parameter>::from_json( - &substances, + substances, pure_path, binary_path, io, )?))) } + + /// Creates parameters from json files. + /// + /// Parameters + /// ---------- + /// input : List[Tuple[List[str], str]] + /// The substances to search and their respective parameter files. + /// E.g. [(["methane", "propane"], "parameters/alkanes.json"), (["methanol"], "parameters/alcohols.json")] + /// binary_path : str, optional + /// Path to file containing binary substance parameters. + /// search_option : str, optional, defaults to "Name" + /// Identifier that is used to search substance. + /// One of 'Name', 'Cas', 'Inchi', 'IupacName', 'Formula', 'Smiles' + #[staticmethod] + #[pyo3(text_signature = "(input, binary_path=None, search_option='Name')")] + fn from_multiple_json( + input: Vec<(Vec<&str>, &str)>, + binary_path: Option<&str>, + search_option: Option<&str>, + ) -> Result { + let io = match search_option { + Some(o) => IdentifierOption::try_from(o)?, + None => IdentifierOption::Name, + }; + Ok(Self(Rc::new(<$parameter>::from_multiple_json( + &input, + binary_path, + io, + )?))) + } } }; }