diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml index 6eeef1c4f..35cce15f0 100644 --- a/.github/workflows/documentation.yml +++ b/.github/workflows/documentation.yml @@ -19,7 +19,7 @@ jobs: run: sudo apt-get install -y pandoc - name: Install python dependencies run: | - pip install sphinx nbsphinx ipython pygments sphinx_inline_tabs sphinx_design sphinx_copybutton myst_parser furo si-units + pip install sphinx nbsphinx ipython pygments sphinx_inline_tabs sphinx_design sphinx_copybutton myst_parser furo si-units numpy - name: Build Wheels uses: PyO3/maturin-action@v1 with: diff --git a/CHANGELOG.md b/CHANGELOG.md index 426fce86e..8b623570a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed +- Fixed off-by-one error for the convergence-check in `_density_iteration`. [#386](https://github.com/feos-org/feos/pull/386) +- Fixed erroneously transposed jacobian layout in binary association of `PcSaftBinary`. [#386](https://github.com/feos-org/feos/pull/386) ## [0.10.1] - 2026-07-24 ### Fixed diff --git a/crates/feos-core/src/density_iteration.rs b/crates/feos-core/src/density_iteration.rs index e27ca0fba..f3da0d2fc 100644 --- a/crates/feos-core/src/density_iteration.rs +++ b/crates/feos-core/src/density_iteration.rs @@ -119,9 +119,8 @@ where } let maxiter = 50; - let mut iterations = 0; + let mut converged = false; 'iteration: for k in 0..maxiter { - iterations += 1; let (_, mut p, mut dp_drho) = eos.p_dpdrho(temperature, rho, molefracs); // attempt to correct for poor initial density rho_init @@ -149,7 +148,7 @@ where let (_, _, d2pdrho2) = eos.p_dpdrho_d2pdrho2(temperature, rho, molefracs); if rho > 0.85 * maxdensity { - let (sp_p, sp_rho) = + let (sp_p, sp_rho, _) = _pressure_spinodal(eos, temperature, initial_density, molefracs)?; rho = sp_rho; error = sp_p - pressure; @@ -167,7 +166,7 @@ where rho = (rho * 1.1).min(maxdensity) } } else if error.is_sign_positive() && d2pdrho2.is_sign_positive() { - let (sp_p, sp_rho) = + let (sp_p, sp_rho, _) = _pressure_spinodal(eos, temperature, initial_density, molefracs)?; rho = sp_rho; error = sp_p - pressure; @@ -177,7 +176,7 @@ where rho = (rho * 1.1).min(maxdensity) } } else if error.is_sign_negative() && d2pdrho2.is_sign_negative() { - let (sp_p, sp_rho) = + let (sp_p, sp_rho, _) = _pressure_spinodal(eos, temperature, initial_density, molefracs)?; rho = sp_rho; error = sp_p - pressure; @@ -187,9 +186,9 @@ where rho *= 0.8 } } else if error.is_sign_negative() && d2pdrho2.is_sign_positive() { - let (_, rho_l) = _pressure_spinodal(eos, temperature, 0.8 * maxdensity, molefracs)?; + let (_, rho_l) = _pressure_spinodal_branch(eos, temperature, molefracs, Liquid)?; let (sp_v_p, rho_v) = - _pressure_spinodal(eos, temperature, 0.001 * maxdensity, molefracs)?; + _pressure_spinodal_branch(eos, temperature, molefracs, Vapor)?; error = sp_v_p - pressure; if error.is_sign_positive() && (initial_density - rho_v).abs() < (initial_density - rho_l).abs() @@ -199,9 +198,9 @@ where rho = (rho_l * 1.1).min(maxdensity) } } else if error.is_sign_positive() && d2pdrho2.is_sign_negative() { - let (_, rho_l) = _pressure_spinodal(eos, temperature, 0.8 * maxdensity, molefracs)?; + let (_, rho_l) = _pressure_spinodal_branch(eos, temperature, molefracs, Liquid)?; let (sp_v_p, rho_v) = - _pressure_spinodal(eos, temperature, 0.001 * maxdensity, molefracs)?; + _pressure_spinodal_branch(eos, temperature, molefracs, Vapor)?; error = sp_v_p - pressure; if error.is_sign_negative() && (initial_density - rho_v).abs() > (initial_density - rho_l).abs() @@ -221,27 +220,33 @@ where // Newton step rho += delta_rho; if error.abs() < f64::max(abstol, rho * reltol) { + converged = true; break 'iteration; } } - if iterations == maxiter + 1 { - Err(FeosError::NotConverged("density_iteration".to_owned())) - } else { + if converged { Ok(rho) + } else { + Err(FeosError::NotConverged("density_iteration".to_owned())) } } +/// Spinodal (dp/drho = 0) closest to `rho_init`. Returns `(p, rho)`. +/// +/// Which spinodal is found depends on the initial density. +/// If vapor/liquid branch is required, [`_pressure_spinodal_branch`] +/// can be used, which verifies the result. pub(crate) fn _pressure_spinodal, N: Dim>( eos: &E, temperature: f64, rho_init: f64, molefracs: &OVector, -) -> FeosResult<(f64, f64)> +) -> FeosResult<(f64, f64, f64)> where DefaultAllocator: Allocator, { let maxiter = 30; - let abstol = 1e-8; + let tol = 1e-8; let maxdensity = eos.compute_max_density(molefracs); let mut rho = rho_init; @@ -256,18 +261,57 @@ where for _ in 0..maxiter { let (p, dpdrho, d2pdrho2) = eos.p_dpdrho_d2pdrho2(temperature, rho, molefracs); - + if dpdrho.abs() < tol { + return Ok((p, rho, d2pdrho2)); + } let mut delta_rho = -dpdrho / d2pdrho2; + // Check failure mode: d2pdrho2 is zero which makes delta_rho infinite. + if !delta_rho.is_finite() { + return Err(FeosError::NotConverged("pressure_spinodal".to_owned())); + } if delta_rho.abs() > 0.05 * maxdensity { delta_rho = 0.05 * maxdensity * delta_rho.signum() } delta_rho = delta_rho.max(-rho * 0.95); // prevent stepping to rho < 0.0 delta_rho = delta_rho.min(maxdensity - rho); // prevent stepping to rho > maxdensity rho += delta_rho; + } + Err(FeosError::NotConverged("pressure_spinodal".to_owned())) +} - if dpdrho.abs() < abstol { - return Ok((p, rho)); +/// Spinodal of the requested branch (liquid or vapor). Returns `(p, rho)`. +/// +/// Errors if the iteration converged to the other branch. +pub(crate) fn _pressure_spinodal_branch, N: Dim>( + eos: &E, + temperature: f64, + molefracs: &OVector, + branch: DensityInitialization, +) -> FeosResult<(f64, f64)> +where + DefaultAllocator: Allocator, +{ + let maxdensity = eos.compute_max_density(molefracs); + let rho_init = match branch { + Liquid => 0.8 * maxdensity, + Vapor => 0.001 * maxdensity, + InitialDensity(_) => { + return Err(FeosError::Error(String::from( + "`_pressure_spinodal_branch`: branch must be Liquid or Vapor", + ))); } + }; + let (p, rho, d2pdrho2) = _pressure_spinodal(eos, temperature, rho_init, molefracs)?; + let (on_branch, name) = match branch { + Liquid => (d2pdrho2 > 0.0, "liquid"), + Vapor => (d2pdrho2 < 0.0, "vapor"), + InitialDensity(_) => unreachable!(), + }; + if on_branch { + Ok((p, rho)) + } else { + Err(FeosError::UndeterminedState(format!( + "pressure_spinodal: iteration converged to the wrong branch (requested {name} spinodal)" + ))) } - Err(FeosError::NotConverged("pressure_spinodal".to_owned())) } diff --git a/crates/feos-core/src/phase_equilibria/vle_pure.rs b/crates/feos-core/src/phase_equilibria/vle_pure.rs index f58fc6e21..4bbc5f004 100644 --- a/crates/feos-core/src/phase_equilibria/vle_pure.rs +++ b/crates/feos-core/src/phase_equilibria/vle_pure.rs @@ -1,5 +1,5 @@ use super::{PhaseEquilibrium, TRIVIAL_REL_DEVIATION}; -use crate::density_iteration::{_density_iteration, _pressure_spinodal}; +use crate::density_iteration::{_density_iteration, _pressure_spinodal_branch}; use crate::equation_of_state::{Residual, Subset}; use crate::errors::{FeosError, FeosResult}; use crate::state::{Contributions, DensityInitialization, State}; @@ -228,10 +228,9 @@ where DefaultAllocator: Allocator, { let x = E::pure_molefracs(); - let maxdensity = eos.compute_max_density(&x); let t = temperature.into_reduced(); - let (p_l, _) = _pressure_spinodal(eos, t, 0.8 * maxdensity, &x)?; - let (p_v, _) = _pressure_spinodal(eos, t, 0.001 * maxdensity, &x)?; + let (p_l, _) = _pressure_spinodal_branch(eos, t, &x, DensityInitialization::Liquid)?; + let (p_v, _) = _pressure_spinodal_branch(eos, t, &x, DensityInitialization::Vapor)?; let p = 0.5 * (0.0_f64.max(p_l) + p_v); let rho_l = _density_iteration(eos, t, p, &x, DensityInitialization::Liquid)?; let rho_v = _density_iteration(eos, t, p, &x, DensityInitialization::Vapor)?; diff --git a/crates/feos/src/pcsaft/eos/pcsaft_binary.rs b/crates/feos/src/pcsaft/eos/pcsaft_binary.rs index 160b3bd27..f6daae9c0 100644 --- a/crates/feos/src/pcsaft/eos/pcsaft_binary.rs +++ b/crates/feos/src/pcsaft/eos/pcsaft_binary.rs @@ -299,7 +299,7 @@ fn association + Copy>( ); let [g1, g2] = g.data.0[0]; - let [[j11, j12], [j21, j22]] = j.data.0; + let [[j11, j21], [j12, j22]] = j.data.0; let det = j11 * j22 - j12 * j21; let delta_xa1 = (j22 * g1 - j12 * g2) / det; @@ -526,9 +526,9 @@ pub mod test { }; use approx::assert_relative_eq; use feos_core::parameter::{AssociationRecord, PureRecord}; - use feos_core::{Contributions::Total, FeosResult, State}; + use feos_core::{Contributions::Total, DensityInitialization, FeosResult, State}; use nalgebra::{dvector, vector}; - use quantity::{KELVIN, KILO, METER, MOL}; + use quantity::{BAR, KELVIN, KILO, METER, MOL}; pub fn pcsaft_binary() -> FeosResult<(PcSaftBinary, PcSaft)> { let params = [ @@ -560,7 +560,7 @@ pub mod test { let (pcsaft, eos) = pcsaft_binary()?; let temperature = 300.0 * KELVIN; - let volume = 2.3 * METER * METER * METER; + let volume = 0.3 * METER * METER * METER; let moles = dvector![1.3, 2.5] * KILO * MOL; let state = State::new_nvt(&&eos, temperature, volume, &moles)?; @@ -589,6 +589,9 @@ pub mod test { println!("\nChemical potential:\n{}", mu_feos.get(0)); println!("{}", mu_ad.get(0)); assert_relative_eq!(mu_feos.get(0), mu_ad.get(0), max_relative = 1e-14); + println!("{}", mu_feos.get(1)); + println!("{}", mu_ad.get(1)); + assert_relative_eq!(mu_feos.get(1), mu_ad.get(1), max_relative = 1e-14); println!("\nPressure:\n{p_feos}"); println!("{p_ad}"); @@ -604,4 +607,205 @@ pub mod test { Ok(()) } + + /// Two identical associating components: the chemical potentials must be equal. + #[test] + fn test_pcsaft_binary_identical_assoc() -> FeosResult<()> { + // Pure parameters: parameters/pcsaft/esper2023.json + let methanol = [ + 2.25965, 2.83016, 183.58634, 0.0, 0.08716, 2465.13545, 1.0, 1.0, + ]; + let params = [methanol, methanol]; + let kij = 0.0; + let records = params.map(|p| { + PureRecord::with_association( + Default::default(), + 0.0, + PcSaftRecord::new(p[0], p[1], p[2], p[3], 0.0, None, None, None), + vec![AssociationRecord::new( + Some(PcSaftAssociationRecord::new(p[4], p[5])), + p[6], + p[7], + 0.0, + )], + ) + }); + let params_generic = + PcSaftParameters::new_binary(records, Some(PcSaftBinaryRecord::new(kij)), vec![])?; + let eos_generic = PcSaft::new(params_generic); + let eos_explicit = PcSaftBinary::new(params, kij); + + let temperature = 330.0 * KELVIN; + let volume = 1.0 / 24.0 * METER * METER * METER; + let x = [0.7, 0.3]; + + let state = State::new_nvt( + &&eos_generic, + temperature, + volume, + &dvector![x[0], x[1]] * KILO * MOL, + )?; + let mu_feos = state.residual_chemical_potential(); + let a_feos = state.residual_molar_helmholtz_energy(); + let state = State::new_nvt( + &eos_explicit, + temperature, + volume, + vector![x[0], x[1]] * KILO * MOL, + )?; + let mu_ad = state.residual_chemical_potential(); + let a_ad = state.residual_molar_helmholtz_energy(); + + println!("a generic {a_feos} specific {a_ad}"); + println!( + "mu[0] generic {} specific {}", + mu_feos.get(0), + mu_ad.get(0) + ); + println!( + "mu[1] generic {} specific {}", + mu_feos.get(1), + mu_ad.get(1) + ); + assert_relative_eq!(a_feos, a_ad, max_relative = 1e-12); + assert_relative_eq!(mu_feos.get(0), mu_feos.get(1), max_relative = 1e-12); + assert_relative_eq!(mu_ad.get(0), mu_ad.get(1), max_relative = 1e-12); + assert_relative_eq!(mu_feos.get(0), mu_ad.get(0), max_relative = 1e-12); + assert_relative_eq!(mu_feos.get(1), mu_ad.get(1), max_relative = 1e-12); + + // second derivatives (pressure derivatives) go through the association Newton too + let state_feos = State::new_nvt( + &&eos_generic, + temperature, + volume, + &dvector![x[0], x[1]] * KILO * MOL, + )?; + let p_feos = state_feos.pressure(Total); + let p_ad = state.pressure(Total); + println!("p generic {p_feos} specific {p_ad}"); + assert_relative_eq!(p_feos, p_ad, max_relative = 1e-12); + let dpdv_feos = state_feos.dp_dv(Total); + let dpdv_ad = state.dp_dv(Total); + println!("dp/dv generic {:?} specific {:?}", dpdv_feos, dpdv_ad); + assert_relative_eq!(dpdv_feos, dpdv_ad, max_relative = 1e-12); + let dmu_feos = state_feos.dmu_res_dt(); + let dmu_ad = state.dmu_res_dt(); + println!( + "dmu/dT generic {} {} specific {} {}", + dmu_feos.get(0), + dmu_feos.get(1), + dmu_ad.get(0), + dmu_ad.get(1) + ); + assert_relative_eq!(dmu_feos.get(0), dmu_ad.get(0), max_relative = 1e-12); + assert_relative_eq!(dmu_feos.get(1), dmu_ad.get(1), max_relative = 1e-12); + Ok(()) + } + + /// Two different, strongly associating components (methanol + water) with + /// a nonzero k_ij at liquid density, compared against the general PC-SAFT. + /// + /// Pure parameters: parameters/pcsaft/esper2023.json + /// Binary parameter: parameters/pcsaft/rehner2023_binary.json + #[test] + fn test_pcsaft_binary_methanol_water() -> FeosResult<()> { + let methanol = [ + 2.25965, 2.83016, 183.58634, 0.0, 0.08716, 2465.13545, 1.0, 1.0, + ]; + let water = [ + 2.36948, 2.15072, 230.71557, 0.0, 0.35319, 2195.10176, 1.0, 1.0, + ]; + let params = [methanol, water]; + let kij = -0.0159473671673194; + let records = params.map(|p| { + PureRecord::with_association( + Default::default(), + 0.0, + PcSaftRecord::new(p[0], p[1], p[2], p[3], 0.0, None, None, None), + vec![AssociationRecord::new( + Some(PcSaftAssociationRecord::new(p[4], p[5])), + p[6], + p[7], + 0.0, + )], + ) + }); + let params_generic = + PcSaftParameters::new_binary(records, Some(PcSaftBinaryRecord::new(kij)), vec![])?; + let generic = PcSaft::new(params_generic); + let specific = PcSaftBinary::new(params, kij); + + let temperature = 320.0 * KELVIN; + + for x1 in [0.1, 0.5, 0.9] { + let x = [x1, 1.0 - x1]; + // liquid at 1 bar according to the general PC-SAFT + let state_generic = State::new_npt( + &&generic, + temperature, + BAR, + &dvector![x[0], x[1]] * KILO * MOL, + Some(DensityInitialization::Liquid), + )?; + let volume = state_generic.volume()?; + let state_specific = State::new_nvt( + &specific, + temperature, + volume, + vector![x[0], x[1]] * KILO * MOL, + )?; + + let a_generic = state_generic.residual_molar_helmholtz_energy(); + let a_specific = state_specific.residual_molar_helmholtz_energy(); + let mu_generic = state_generic.residual_chemical_potential(); + let mu_specific = state_specific.residual_chemical_potential(); + let p_generic = state_generic.pressure(Total); + let p_specific = state_specific.pressure(Total); + let dpdv_generic = state_generic.dp_dv(Total); + let dpdv_specific = state_specific.dp_dv(Total); + let dmu_generic = state_generic.dmu_res_dt(); + let dmu_specific = state_specific.dmu_res_dt(); + + println!("x1 = {x1}"); + println!(" a generic {a_generic} specific {a_specific}"); + println!( + " mu[0] generic {} specific {}", + mu_generic.get(0), + mu_specific.get(0) + ); + println!( + " mu[1] generic {} specific {}", + mu_generic.get(1), + mu_specific.get(1) + ); + println!(" p generic {p_generic} specific {p_specific}"); + println!( + " dp/dv generic {:?} specific {:?}", + dpdv_generic, dpdv_specific + ); + println!( + " dmu/dT generic {} {} specific {} {}", + dmu_generic.get(0), + dmu_generic.get(1), + dmu_specific.get(0), + dmu_specific.get(1) + ); + assert_relative_eq!(a_generic, a_specific, max_relative = 1e-12); + assert_relative_eq!(mu_generic.get(0), mu_specific.get(0), max_relative = 1e-12); + assert_relative_eq!(mu_generic.get(1), mu_specific.get(1), max_relative = 1e-12); + assert_relative_eq!(p_generic, p_specific, max_relative = 1e-9); // requires small tol + assert_relative_eq!(dpdv_generic, dpdv_specific, max_relative = 1e-12); + assert_relative_eq!( + dmu_generic.get(0), + dmu_specific.get(0), + max_relative = 1e-12 + ); + assert_relative_eq!( + dmu_generic.get(1), + dmu_specific.get(1), + max_relative = 1e-12 + ); + } + Ok(()) + } } diff --git a/parameters/pcsaft/rehner2023_binary.json b/parameters/pcsaft/rehner2023_binary.json index 29042e967..1d2b658c1 100644 --- a/parameters/pcsaft/rehner2023_binary.json +++ b/parameters/pcsaft/rehner2023_binary.json @@ -30286,7 +30286,8 @@ "iupac_name": "propan-1-ol", "smiles": "CCCO", "inchi": "InChI=1S/C3H8O/c1-2-3-4/h4H,2-3H2,1H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -42813,7 +42814,8 @@ "iupac_name": "1,2-dimethoxyethane", "smiles": "COCCOC", "inchi": "InChI=1S/C4H10O2/c1-5-3-4-6-2/h3-4H2,1-2H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -44733,7 +44735,8 @@ "iupac_name": "1,2,3,4,5,6-hexadeuteriobenzene", "smiles": "[2H]c1c([2H])c([2H])c([2H])c([2H])c1[2H]", "inchi": "InChI=1S/C6H6/c1-2-4-6-5-3-1/h1-6H/i1D,2D,3D,4D,5D,6D" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -50341,7 +50344,8 @@ "iupac_name": "tetrafluoromethane", "smiles": "FC(F)(F)F", "inchi": "InChI=1S/CF4/c2-1(3,4)5" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -51751,7 +51755,8 @@ "iupac_name": "1-bromopropane", "smiles": "CCCBr", "inchi": "InChI=1S/C3H7Br/c1-2-3-4/h2-3H2,1H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -64001,7 +64006,8 @@ "iupac_name": "furan-2,5-dione", "smiles": "O=C1C=CC(=O)O1", "inchi": "InChI=1S/C4H2O3/c5-3-1-2-4(6)7-3/h1-2H" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -69098,7 +69104,8 @@ "iupac_name": "2-methyloxirane", "smiles": "CC1CO1", "inchi": "InChI=1S/C3H6O/c1-3-2-4-3/h3H,2H2,1H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -71153,7 +71160,8 @@ "iupac_name": "pentane-2,4-dione", "smiles": "CC(=O)CC(C)=O", "inchi": "InChI=1S/C5H8O2/c1-4(6)3-5(2)7/h3H2,1-2H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -71203,7 +71211,8 @@ "iupac_name": "2,2,2-trichloroacetaldehyde", "smiles": "O=CC(Cl)(Cl)Cl", "inchi": "InChI=1S/C2HCl3O/c3-2(4,5)1-6/h1H" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -72680,7 +72689,8 @@ "name": "carbon disulfide", "smiles": "S=C=S", "inchi": "InChI=1S/CS2/c2-1-3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -73818,7 +73828,8 @@ "iupac_name": "2-methylpent-2-ene", "smiles": "CCC=C(C)C", "inchi": "InChI=1S/C6H12/c1-4-5-6(2)3/h5H,4H2,1-3H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -81858,7 +81869,8 @@ "iupac_name": "3-methylbut-1-ene", "smiles": "C=CC(C)C", "inchi": "InChI=1S/C5H10/c1-4-5(2)3/h4-5H,1H2,2-3H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -86224,7 +86236,8 @@ "iupac_name": "2-methylhexane", "smiles": "CCCCC(C)C", "inchi": "InChI=1S/C7H16/c1-4-5-6-7(2)3/h7H,4-6H2,1-3H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -97322,7 +97335,8 @@ "iupac_name": "propanal", "smiles": "CCC=O", "inchi": "InChI=1S/C3H6O/c1-2-3-4/h3H,2H2,1H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -100931,7 +100945,8 @@ "iupac_name": "1,3-xylene", "smiles": "Cc1cccc(C)c1", "inchi": "InChI=1S/C8H10/c1-7-4-3-5-8(2)6-7/h3-6H,1-2H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -104976,7 +104991,8 @@ "iupac_name": "3-methylthiophene", "smiles": "Cc1ccsc1", "inchi": "InChI=1S/C5H6S/c1-5-2-3-6-4-5/h2-4H,1H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -105281,7 +105297,8 @@ "iupac_name": "cumene", "smiles": "CC(C)c1ccccc1", "inchi": "InChI=1S/C9H12/c1-8(2)9-6-4-3-5-7-9/h3-8H,1-2H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -106334,7 +106351,8 @@ "iupac_name": "triethyl phosphite", "smiles": "CCOP(OCC)OCC", "inchi": "InChI=1S/C6H15O3P/c1-4-7-10(8-5-2)9-6-3/h4-6H2,1-3H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -121361,7 +121379,8 @@ "iupac_name": "pentyl acetate", "smiles": "CCCCCOC(C)=O", "inchi": "InChI=1S/C7H14O2/c1-3-4-5-6-9-7(2)8/h3-6H2,1-2H3" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -137170,7 +137189,8 @@ "iupac_name": "2,3,3,3-tetrafluoroprop-1-ene", "smiles": "C=C(F)C(F)(F)F", "inchi": "InChI=1S/C3H2F4/c1-2(4)3(5,6)7/h1H2" - } + }, + "k_ij": 0.0 }, { "id1": { @@ -137492,7 +137512,8 @@ "iupac_name": "difluoromethoxy(trifluoro)methane", "smiles": "FC(F)OC(F)(F)F", "inchi": "InChI=1S/C2HF5O/c3-1(4)8-2(5,6)7/h1H" - } + }, + "k_ij": 0.0 }, { "id1": {