'''Chemical Engineering Design Library (ChEDL). Utilities for process modeling.
Copyright (C) 2017, 2018, 2019, 2020, 2021, 2022
Caleb Bell <Caleb.Andrew.Bell@gmail.com>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
This module contains functions and classes related to the UNIFAC and its many
variants. The bulk of the code relates to calculating derivativies, or
is tables of data.
For reporting bugs, adding feature requests, or submitting pull requests,
please use the `GitHub issue tracker <https://github.com/CalebBell/thermo/>`_
or contact the author at Caleb.Andrew.Bell@gmail.com.
.. contents:: :local:
Main Model (Object-Oriented)
----------------------------
.. autoclass:: UNIFAC
:members:
Main Model (Functional)
-----------------------
.. autofunction:: UNIFAC_gammas
.. autofunction:: UNIFAC_psi
Misc Functions
--------------
.. autofunction:: UNIFAC_RQ
.. autofunction:: Van_der_Waals_volume
.. autofunction:: Van_der_Waals_area
.. autofunction:: chemgroups_to_matrix
.. autofunction:: UNIFAC_group_assignment_DDBST
Data for Original UNIFAC
------------------------
.. autodata:: UFSG
.. autodata:: UFMG
.. py:data:: UFIP
Interaction parameters for the original unifac model.
:type: dict[int: dict[int: float]]
Data for Dortmund UNIFAC
------------------------
.. autodata:: DOUFSG
.. autodata:: DOUFMG
.. py:data:: DOUFIP2016
Interaction parameters for the Dornmund unifac model.
:type: dict[int: dict[int: tuple(float, 3)]]
Data for NIST UNIFAC (2015)
---------------------------
.. autodata:: NISTUFSG
.. autodata:: NISTUFMG
.. py:data:: NISTUFIP
Interaction parameters for the NIST (2015) unifac model.
:type: dict[int: dict[int: tuple(float, 3)]]
Data for NIST KT UNIFAC (2011)
------------------------------
.. autodata:: NISTKTUFSG
.. autodata:: NISTKTUFMG
.. py:data:: NISTKTUFIP
Interaction parameters for the NIST KT UNIFAC (2011) model.
:type: dict[int: dict[int: tuple(float, 3)]]
Data for UNIFAC LLE
-------------------
.. autodata:: LLEUFSG
.. autodata:: LLEMG
.. py:data:: LLEUFIP
Interaction parameters for the LLE unifac model.
:type: dict[int: dict[int: float]]
Data for Lyngby UNIFAC
----------------------
.. autodata:: LUFSG
.. autodata:: LUFMG
.. py:data:: LUFIP
Interaction parameters for the Lyngby UNIFAC model.
:type: dict[int: dict[int: tuple(float, 3)]]
Data for PSRK UNIFAC
--------------------
.. autodata:: PSRKSG
.. autodata:: PSRKMG
.. py:data:: PSRKIP
Interaction parameters for the PSRKIP UNIFAC model.
:type: dict[int: dict[int: tuple(float, 3)]]
Data for VTPR UNIFAC
--------------------
.. autodata:: VTPRSG
.. autodata:: VTPRMG
.. py:data:: VTPRIP
Interaction parameters for the VTPRIP UNIFAC model.
:type: dict[int: dict[int: tuple(float, 3)]]
'''
__all__ = ['UNIFAC_gammas','UNIFAC', 'UNIFAC_psi', 'DOUFMG', 'DOUFSG', 'UFSG', 'UFMG',
'DDBST_UNIFAC_assignments',
'DDBST_MODIFIED_UNIFAC_assignments', 'DDBST_PSRK_assignments',
'UNIFAC_group_assignment_DDBST',
'UNIFAC_RQ', 'Van_der_Waals_volume', 'Van_der_Waals_area',
'load_group_assignments_DDBST',
'PSRKSG', 'LLEUFSG', 'LLEMG',
'LUFSG', 'NISTUFSG', 'NISTUFMG',
'VTPRSG', 'VTPRMG', 'NISTKTUFSG', 'NISTKTUFMG',
'LUFMG', 'PSRKMG',
'unifac_gammas_from_args']
import os
from chemicals.identifiers import CAS_to_int
from chemicals.utils import PY37, can_load_data
from fluids.constants import R
from fluids.numerics import exp, log
from fluids.numerics import numpy as np
from thermo.activity import GibbsExcess
from thermo.group_contribution.group_contribution_base import str_group_assignment_to_dict
try:
array, zeros, npexp, array_equal = np.array, np.zeros, np.exp, np.array_equal
except (ImportError, AttributeError):
pass
class UNIFAC_subgroup:
__slots__ = ['group_id', 'group', 'main_group_id', 'main_group', 'R', 'Q',
'smarts', 'smart_rdkit', 'hydrogen_from_smarts',
'priority', 'atoms', 'bonds']
def __repr__(self): # pragma: no cover
return '<%s>' %self.group
def __init__(self, group_id, group, main_group_id, main_group, R, Q, smarts=None,
priority=None, atoms=None, bonds=None, hydrogen_from_smarts=False):
self.group_id = group_id
self.group = group
self.main_group_id = main_group_id
self.main_group = main_group
self.R = R
self.Q = Q
self.smarts = smarts
self.priority = priority
self.atoms = atoms
self.bonds = bonds
self.smart_rdkit = None
self.hydrogen_from_smarts = hydrogen_from_smarts
# http://www.ddbst.com/published-parameters-unifac.html#ListOfMainGroups
#UFMG[No.] = ('Maingroup Name', subgroups)
UFMG = {}
UFMG[1] = ('CH2', [1, 2, 3, 4])
UFMG[2] = ('C=C', [5, 6, 7, 8, 70])
UFMG[3] = ('ACH', [9, 10])
UFMG[4] = ('ACCH2', [11, 12, 13])
UFMG[5] = ('OH', [14])
UFMG[6] = ('CH3OH', [15])
UFMG[7] = ('H2O', [16])
UFMG[8] = ('ACOH', [17])
UFMG[9] = ('CH2CO', [18, 19])
UFMG[10] = ('CHO', [20])
UFMG[11] = ('CCOO', [21, 22])
UFMG[12] = ('HCOO', [23])
UFMG[13] = ('CH2O', [24, 25, 26, 27])
UFMG[14] = ('CNH2', [28, 29, 30])
UFMG[15] = ('CNH', [31, 32, 33])
UFMG[16] = ('(C)3N', [34, 35])
UFMG[17] = ('ACNH2', [36])
UFMG[18] = ('PYRIDINE', [37, 38, 39])
UFMG[19] = ('CCN', [40, 41])
UFMG[20] = ('COOH', [42, 43])
UFMG[21] = ('CCL', [44, 45, 46])
UFMG[22] = ('CCL2', [47, 48, 49])
UFMG[23] = ('CCL3', [50, 51])
UFMG[24] = ('CCL4', [52])
UFMG[25] = ('ACCL', [53])
UFMG[26] = ('CNO2', [54, 55, 56])
UFMG[27] = ('ACNO2', [57])
UFMG[28] = ('CS2', [58])
UFMG[29] = ('CH3SH', [59, 60])
UFMG[30] = ('FURFURAL', [61])
UFMG[31] = ('DOH', [62])
UFMG[32] = ('I', [63])
UFMG[33] = ('BR', [64])
UFMG[34] = ('C=-C', [65, 66])
UFMG[35] = ('DMSO', [67])
UFMG[36] = ('ACRY', [68])
UFMG[37] = ('CLCC', [69])
UFMG[38] = ('ACF', [71])
UFMG[39] = ('DMF', [72, 73])
UFMG[40] = ('CF2', [74, 75, 76])
UFMG[41] = ('COO', [77])
UFMG[42] = ('SIH2', [78, 79, 80, 81])
UFMG[43] = ('SIO', [82, 83, 84])
UFMG[44] = ('NMP', [85])
UFMG[45] = ('CCLF', [86, 87, 88, 89, 90, 91, 92, 93])
UFMG[46] = ('CON(AM)', [94, 95, 96, 97, 98, 99])
UFMG[47] = ('OCCOH', [100, 101])
UFMG[48] = ('CH2S', [102, 103, 104])
UFMG[49] = ('MORPH', [105])
UFMG[50] = ('THIOPHEN', [106, 107, 108])
UFMG[51] = ('NCO', [109])
UFMG[55] = ('SULFONES', [118, 119])
UFMG[84] = ('IMIDAZOL', [178])
UFMG[85] = ('BTI', [179])
SINGLE_BOND = 'single'
DOUBLE_BOND = 'double'
TRIPLE_BOND = 'triple '
AROMATIC_BOND = 'aromatic'
def priority_from_atoms(atoms, bonds=None):
priority = 0
if 'H' in atoms:
priority += atoms['H']
if 'C' in atoms:
priority += atoms['C']*100
if 'O' in atoms:
priority += atoms['O']*150
if 'N' in atoms:
priority += atoms['N']*175
if 'Cl' in atoms:
priority += atoms['Cl']*300
if 'F' in atoms:
priority += atoms['F']*400
if 'Si' in atoms:
priority += atoms['Si']*200
if 'S' in atoms:
priority += atoms['S']*250
if bonds is not None:
priority += bonds.get(SINGLE_BOND, 0)*2
priority += bonds.get(DOUBLE_BOND, 0)*10
priority += bonds.get(TRIPLE_BOND, 0)*100
priority += bonds.get(AROMATIC_BOND, 0)*1000
return priority
"""Rules for bonds:
All groups that have any any atoms as part of any aromatic ring should have at least one aromatic bond.
"""
UFSG = {}
# UFSG[subgroup ID] = (subgroup formula, main group ID, subgroup R, subgroup Q)
# http://www.ddbst.com/published-parameters-unifac.html
# priority : (Manual priority (higher = takes prescedence), number of atoms, number of hydrogens)
UFSG[1] = UNIFAC_subgroup(1, 'CH3', 1, 'CH2', 0.9011, 0.848, smarts='[CX4;H3]', atoms={'C': 1, 'H': 3})
UFSG[2] = UNIFAC_subgroup(2, 'CH2', 1, 'CH2', 0.6744, 0.54, smarts='[CX4;H2]', atoms={'C': 1, 'H': 2})
UFSG[3] = UNIFAC_subgroup(3, 'CH', 1, 'CH2', 0.4469, 0.228, smarts='[CX4;H1]', atoms={'C': 1, 'H': 1})
UFSG[4] = UNIFAC_subgroup(4, 'C', 1, 'CH2', 0.2195, 0, smarts='[CX4;H0]', atoms={'C': 1, 'H': 0})
UFSG[5] = UNIFAC_subgroup(5, 'CH2=CH', 2, 'C=C', 1.3454, 1.176, smarts='[CX3;H2]=[CX3;H1]',
bonds={DOUBLE_BOND: 1}, atoms={'C': 2, 'H': 3})
UFSG[6] = UNIFAC_subgroup(6, 'CH=CH', 2, 'C=C', 1.1167, 0.867,
bonds={DOUBLE_BOND: 1}, atoms={'C': 2, 'H': 2},
smarts='[CX3;H1]=[CX3;H1]') # Could restrict the next connection from being H
UFSG[7] = UNIFAC_subgroup(7, 'CH2=C', 2, 'C=C', 1.1173, 0.988, bonds={DOUBLE_BOND: 1}, atoms={'C': 2, 'H': 2},
smarts='[CX3;H2]=[CX3;H0]')
UFSG[8] = UNIFAC_subgroup(8, 'CH=C', 2, 'C=C', 0.8886, 0.676, bonds={DOUBLE_BOND: 1}, atoms={'C': 2, 'H': 1},
smarts='[CX3;H1]=[CX3;H0]')
UFSG[9] = UNIFAC_subgroup(9, 'ACH', 3, 'ACH', 0.5313, 0.4, smarts='[cX3;H1]',
atoms={'C': 1, 'H': 1}, bonds={AROMATIC_BOND: 1})
UFSG[10] = UNIFAC_subgroup(10, 'AC', 3, 'ACH', 0.3652, 0.12, smarts='[cX3;H0]',
atoms={'C': 1}, bonds={AROMATIC_BOND: 1})
UFSG[11] = UNIFAC_subgroup(11, 'ACCH3', 4, 'ACCH2', 1.2663, 0.968, smarts='[cX3;H0][CX4;H3]',
atoms={'C': 2, 'H': 3}, bonds={AROMATIC_BOND: 1, SINGLE_BOND: 1})
UFSG[12] = UNIFAC_subgroup(12, 'ACCH2', 4, 'ACCH2', 1.0396, 0.66, smarts='[cX3;H0][CX4;H2]',
atoms={'C': 2, 'H': 2}, bonds={AROMATIC_BOND: 1, SINGLE_BOND: 1})
UFSG[13] = UNIFAC_subgroup(13, 'ACCH', 4, 'ACCH2', 0.8121, 0.348, smarts='[cX3;H0][CX4;H1]',
atoms={'C': 2, 'H': 1}, bonds={AROMATIC_BOND: 1, SINGLE_BOND: 1})
UFSG[14] = UNIFAC_subgroup(14, 'OH', 5, 'OH', 1, 1.2, smarts='[OX2;H1]', atoms={'O': 1, 'H': 1},)
UFSG[15] = UNIFAC_subgroup(15, 'CH3OH', 6, 'CH3OH', 1.4311, 1.432, smarts='[CX4;H3][OX2;H1]',
atoms={'C': 1, 'H': 4, 'O': 1}) # One extra radical; otherwise perfect, six matches
UFSG[16] = UNIFAC_subgroup(16, 'H2O', 7, 'H2O', 0.92, 1.4, smarts='[OH2]', atoms={'H': 2, 'O': 1})
UFSG[17] = UNIFAC_subgroup(17, 'ACOH', 8, 'ACOH', 0.8952, 0.68, smarts='[cX3;H0;R][OX2;H1]',
atoms={'C': 1, 'O': 1, 'H': 1}, bonds={AROMATIC_BOND: 1}) # pretty good 5 extra
UFSG[18] = UNIFAC_subgroup(18, 'CH3CO', 9, 'CH2CO', 1.6724, 1.488, smarts='[CX4;H3][CX3](=O)',
atoms={'C': 2, 'H': 3, 'O': 1}, bonds={DOUBLE_BOND: 1})
UFSG[19] = UNIFAC_subgroup(19, 'CH2CO', 9, 'CH2CO', 1.4457, 1.18,
atoms={'C': 2, 'H': 2, 'O': 1}, bonds={DOUBLE_BOND: 1},
smarts='[CX4;H2][CX3](=O)')
#'[CX4;H2;!$([CX4,CX3;H0,H1][CX3](=O)[CX4;H2][CX3](=O)[CX4,CX3;H0,H1])][CX3;!$([CX4,CX3;H0,H1][CX3](=O)[CX4;H2][CX3](=O)[CX4,CX3;H0,H1])](=O)[#6;!$([CX4;H3]);!$([CX4,CX3;H0,H1][CX3](=O)[CX4;H2][CX3](=O)[CX4,CX3;H0,H1])]') # '[CX4;H2][CX3](=O)'
UFSG[20] = UNIFAC_subgroup(20, 'CHO', 10, 'CHO', 0.998, 0.948, atoms={'C': 1, 'H': 1, 'O': 1}, bonds={DOUBLE_BOND: 1},
smarts='[CX3H1](=O)')
UFSG[21] = UNIFAC_subgroup(21, 'CH3COO', 11, 'CCOO', 1.9031, 1.728, atoms={'C': 2, 'H': 3, 'O': 2},
bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2},
smarts='[CH3][CX3;H0](=[O])[O]')
UFSG[22] = UNIFAC_subgroup(22, 'CH2COO', 11, 'CCOO', 1.6764, 1.42, smarts='[CX4;H2][CX3](=[OX1])[OX2]',
atoms={'C': 2, 'H': 2, 'O': 2},
bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2},) # Custom, lots of extra matches
UFSG[23] = UNIFAC_subgroup(23, 'HCOO', 12, 'HCOO', 1.242, 1.188, atoms={'C': 1, 'H': 1, 'O': 2},
bonds={DOUBLE_BOND: 1, SINGLE_BOND: 1},
smarts='[CX3;H1](=[OX1])[OX2]',#'[CX3;H1](=[OX1])[OX2][#6;!$([CX3]=[#8])]'
)
UFSG[24] = UNIFAC_subgroup(24, 'CH3O', 13, 'CH2O', 1.145, 1.088, smarts='[CH3][O]', atoms={'C': 1, 'H': 3, 'O': 1},
bonds={SINGLE_BOND: 1},)
UFSG[25] = UNIFAC_subgroup(25, 'CH2O', 13, 'CH2O', 0.9183, 0.78, smarts='[CH2][O]', atoms={'C': 1, 'H': 2, 'O': 1},
bonds={SINGLE_BOND: 1},)
UFSG[26] = UNIFAC_subgroup(26, 'CHO', 13, 'CH2O', 0.6908, 0.468, smarts='[C;H1][O]', atoms={'C': 1, 'H': 1, 'O': 1},
bonds={SINGLE_BOND: 1},)
UFSG[27] = UNIFAC_subgroup(27, 'THF', 13, 'CH2O', 0.9183, 1.1, smarts=['[CX4;H2;R][OX2;R]','[CX3;H1;R][OX2;R]'], #old smarts - '[CX4,CX3;H2,H1;R][OX2;R]',
bonds={SINGLE_BOND: 1}, atoms={'O': 1, 'C': 1, 'H': 2},
hydrogen_from_smarts=True) # CX3, H1 needed to allow 290-67-5 and 255-37-8 but adds a lot of false positives;
UFSG[28] = UNIFAC_subgroup(28, 'CH3NH2', 14, 'CNH2', 1.5959, 1.544, smarts='[CX4;H3][NX3;H2]',
bonds={SINGLE_BOND: 1}, atoms={'N': 1, 'C': 1, 'H': 5},) # Perfect
UFSG[29] = UNIFAC_subgroup(29, 'CH2NH2', 14, 'CNH2', 1.3692, 1.236, smarts='[CX4;H2][NX3;H2]',
bonds={SINGLE_BOND: 1}, atoms={'N': 1, 'C': 1, 'H': 4})
UFSG[30] = UNIFAC_subgroup(30, 'CHNH2', 14, 'CNH2', 1.1417, 0.924, smarts='[CX4;H1][NX3;H2]',
bonds={SINGLE_BOND: 1}, atoms={'N': 1, 'C': 1, 'H': 3})
UFSG[31] = UNIFAC_subgroup(31, 'CH3NH', 15, 'CNH', 1.4337, 1.244, smarts='[CX4;H3][NX3;H1]',
bonds={SINGLE_BOND: 1}, atoms={'N': 1, 'C': 1, 'H': 4})
UFSG[32] = UNIFAC_subgroup(32, 'CH2NH', 15, 'CNH', 1.207, 0.936, smarts='[CX4;H2][NX3;H1]',
bonds={SINGLE_BOND: 1}, atoms={'N': 1, 'C': 1, 'H': 3})
UFSG[33] = UNIFAC_subgroup(33, 'CHNH', 15, 'CNH', 0.9795, 0.624, smarts='[CX4;H1][NX3;H1]',
bonds={SINGLE_BOND: 1}, atoms={'N': 1, 'C': 1, 'H': 2})
UFSG[34] = UNIFAC_subgroup(34, 'CH3N', 16, '(C)3N', 1.1865, 0.94, smarts='[CX4;H3][NX3;H0]',
bonds={SINGLE_BOND: 1}, atoms={'N': 1, 'C': 1, 'H': 3})
UFSG[35] = UNIFAC_subgroup(35, 'CH2N', 16, '(C)3N', 0.9597, 0.632, smarts='[CX4;H2][NX3;H0]',
bonds={SINGLE_BOND: 1}, atoms={'N': 1, 'C': 1, 'H': 2})
UFSG[36] = UNIFAC_subgroup(36, 'ACNH2', 17, 'ACNH2', 1.06, 0.816, smarts='[c][NX3;H2]',
bonds={SINGLE_BOND: 1, AROMATIC_BOND: 1}, atoms={'N': 1, 'C': 1, 'H': 2})
UFSG[37] = UNIFAC_subgroup(37, 'C5H5N', 18, 'PYRIDINE', 2.9993, 2.113,
bonds={SINGLE_BOND: 0, AROMATIC_BOND: 6}, atoms={'N': 1, 'C': 5, 'H': 5},
smarts='[cX3;H1]1:[cX3;H1]:[cX3;H1]:[nX2;H0]:[cX3;H1]:[cX3;H1]:1')
# smarts='[cX3;H1][cX3;H1][cX3;H1][cX3;H1][nX2;H0][cX3;H1]') # There is another match from ddbst 3,4-Didehydropyridine but it is C5H3N and so wrong; only one real hit
UFSG[38] = UNIFAC_subgroup(38, 'C5H4N', 18, 'PYRIDINE', 2.8332, 1.833,
smarts=['[cX3;H0]1:[cX3;H1]:[cX3;H1]:[nX2;H0]:[cX3;H1]:[cX3;H1]:1',
'[cX3;H1]1:[cX3;H0]:[cX3;H1]:[nX2;H0]:[cX3;H1]:[cX3;H1]:1',
'[cX3;H1]1:[cX3;H1]:[cX3;H0]:[nX2;H0]:[cX3;H1]:[cX3;H1]:1',
'[cX3;H1]1:[cX3;H1]:[cX3;H1]:[nX2;H0]:[cX3;H0]:[cX3;H1]:1',
'[cX3;H1]1:[cX3;H1]:[cX3;H1]:[nX2;H0]:[cX3;H1]:[cX3;H0]:1'],
atoms={'C': 5, 'H': 4, 'N': 1}, bonds={AROMATIC_BOND: 6}) # Perfect hand made
UFSG[39] = UNIFAC_subgroup(39, 'C5H3N', 18, 'PYRIDINE', 2.667, 1.553,
atoms={'C': 5, 'H': 3, 'N': 1}, bonds={AROMATIC_BOND: 6},
smarts=['[cX3;H0]1:[cX3;H0]:[cX3;H1]:[nX2;H0]:[cX3;H1]:[cX3;H1]:1',
'[cX3;H0]1:[cX3;H1]:[cX3;H0]:[nX2;H0]:[cX3;H1]:[cX3;H1]:1',
'[cX3;H0]1:[cX3;H1]:[cX3;H1]:[nX2;H0]:[cX3;H0]:[cX3;H1]:1',
'[cX3;H0]1:[cX3;H1]:[cX3;H1]:[nX2;H0]:[cX3;H1]:[cX3;H0]:1',
'[cX3;H1]1:[cX3;H0]:[cX3;H0]:[nX2;H0]:[cX3;H1]:[cX3;H1]:1',
'[cX3;H1]1:[cX3;H0]:[cX3;H1]:[nX2;H0]:[cX3;H0]:[cX3;H1]:1',
'[cX3;H1]1:[cX3;H0]:[cX3;H1]:[nX2;H0]:[cX3;H1]:[cX3;H0]:1',
'[cX3;H1]1:[cX3;H1]:[cX3;H0]:[nX2;H0]:[cX3;H0]:[cX3;H1]:1',
'[cX3;H1]1:[cX3;H1]:[cX3;H0]:[nX2;H0]:[cX3;H1]:[cX3;H0]:1',
'[cX3;H1]1:[cX3;H1]:[cX3;H1]:[nX2;H0]:[cX3;H0]:[cX3;H0]:1']
)
UFSG[40] = UNIFAC_subgroup(40, 'CH3CN', 19, 'CCN', 1.8701, 1.724, atoms={'C': 2, 'H': 3, 'N': 1}, bonds={TRIPLE_BOND: 1, SINGLE_BOND: 1},
smarts='[CX4;H3][CX2]#[NX1]')
UFSG[41] = UNIFAC_subgroup(41, 'CH2CN', 19, 'CCN', 1.6434, 1.416, atoms={'C': 2, 'H': 2, 'N': 1}, bonds={TRIPLE_BOND: 1, SINGLE_BOND: 1},
smarts='[CX4;H2][CX2]#[NX1]')
UFSG[42] = UNIFAC_subgroup(42, 'COOH', 20, 'COOH', 1.3013, 1.224,
atoms={'C': 1, 'H': 1, 'O': 2}, bonds={DOUBLE_BOND: 1, SINGLE_BOND: 1},
smarts='[CX3](=[OX1])[O;H1]') # Tried '[C][CX3](=[OX1])[OH1]' at first but fails for a few hundred
UFSG[43] = UNIFAC_subgroup(43, 'HCOOH', 20, 'COOH', 1.528, 1.532,
atoms={'C': 1, 'H': 2, 'O': 2}, bonds={DOUBLE_BOND: 1, SINGLE_BOND: 1},
smarts='[CX3;H1](=[OX1])[OX2;H1]') # effortlessly web - missing one hit
UFSG[44] = UNIFAC_subgroup(44, 'CH2CL', 21, 'CCL', 1.4654, 1.264,
smarts='[CX4;H2;!$(C(Cl)(Cl))](Cl)',
atoms={'Cl': 1, 'H': 2, 'C': 1}, bonds={SINGLE_BOND: 1}) # Matches perfectly effortlessly web
UFSG[45] = UNIFAC_subgroup(45, 'CHCL', 21, 'CCL', 1.238, 0.952,
atoms={'Cl': 1, 'H': 1, 'C': 1}, bonds={SINGLE_BOND: 1},
smarts='[CX4;H1;!$(C(Cl)(Cl))](Cl)') # effortlessly web
UFSG[46] = UNIFAC_subgroup(46, 'CCL', 21, 'CCL', 1.0106, 0.724,
atoms={'Cl': 1, 'H': 0, 'C': 1}, bonds={SINGLE_BOND: 1},
smarts='[CX4;H0](Cl)') # effortlessly web
UFSG[47] = UNIFAC_subgroup(47, 'CH2CL2', 22, 'CCL2', 2.2564, 1.988,
atoms={'Cl': 2, 'H': 2, 'C': 1}, bonds={SINGLE_BOND: 2},
smarts='[CX4;H2;!$(C(Cl)(Cl)(Cl))](Cl)(Cl)') # effortlessly web
UFSG[48] = UNIFAC_subgroup(48, 'CHCL2', 22, 'CCL2', 2.0606, 1.684,
atoms={'Cl': 2, 'H': 1, 'C': 1}, bonds={SINGLE_BOND: 2},
smarts='[CX4;H1;!$(C(Cl)(Cl)(Cl))](Cl)(Cl)') # effortlessly web
UFSG[49] = UNIFAC_subgroup(49, 'CCL2', 22, 'CCL2', 1.8016, 1.448,
atoms={'Cl': 2, 'H': 0, 'C': 1}, bonds={SINGLE_BOND: 2},
smarts='[CX4;H0;!$(C(Cl)(Cl)(Cl))](Cl)(Cl)') # effortlessly web
UFSG[50] = UNIFAC_subgroup(50, 'CHCL3', 23, 'CCL3', 2.87, 2.41,
atoms={'Cl': 3, 'H': 1, 'C': 1}, bonds={SINGLE_BOND: 3},
smarts='[CX4;H1;!$([CX4;H0](Cl)(Cl)(Cl)(Cl))](Cl)(Cl)(Cl)') # effortlessly web
UFSG[51] = UNIFAC_subgroup(51, 'CCL3', 23, 'CCL3', 2.6401, 2.184,
atoms={'Cl': 3, 'H': 0, 'C': 1}, bonds={SINGLE_BOND: 3},
smarts='[CX4;H0;!$([CX4;H0](Cl)(Cl)(Cl)(Cl))](Cl)(Cl)(Cl)') # effortlessly web
UFSG[52] = UNIFAC_subgroup(52, 'CCL4', 24, 'CCL4', 3.39, 2.91,
atoms={'Cl': 4, 'H': 0, 'C': 1}, bonds={SINGLE_BOND: 4},
smarts='[CX4;H0]([Cl])([Cl])([Cl])([Cl])')
UFSG[53] = UNIFAC_subgroup(53, 'ACCL', 25, 'ACCL', 1.1562, 0.844,
atoms={'Cl': 1, 'H': 0, 'C': 1}, bonds={AROMATIC_BOND: 1},
smarts='[c][Cl]') # Does take up one of the carbon spaces on the ring
UFSG[54] = UNIFAC_subgroup(54, 'CH3NO2', 26, 'CNO2', 2.0086, 1.868,
atoms={'N': 1, 'H': 3, 'O': 2, 'C': 1}, bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2},
smarts='[CX4;H3][NX3](=[OX1])([OX1])')
UFSG[55] = UNIFAC_subgroup(55, 'CH2NO2', 26, 'CNO2', 1.7818, 1.56,
atoms={'N': 1, 'H': 2, 'O': 2, 'C': 1}, bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2},
smarts='[CX4;H2][NX3](=[OX1])([OX1])')
UFSG[56] = UNIFAC_subgroup(56, 'CHNO2', 26, 'CNO2', 1.5544, 1.248,
atoms={'N': 1, 'H': 1, 'O': 2, 'C': 1}, bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2},
smarts='[CX4;H1][NX3](=[OX1])([OX1])')
UFSG[57] = UNIFAC_subgroup(57, 'ACNO2', 27, 'ACNO2', 1.4199, 1.104,
atoms={'N': 1, 'O': 2, 'C': 1}, bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2, AROMATIC_BOND: 1},
smarts='[cX3][NX3](=[OX1])([OX1])')
UFSG[58] = UNIFAC_subgroup(58, 'CS2', 28, 'CS2', 2.057, 1.65,
atoms={'C': 1, 'S': 2}, bonds={DOUBLE_BOND: 2},
smarts='C(=S)=S') # Easy, compount smarts
UFSG[59] = UNIFAC_subgroup(59, 'CH3SH', 29, 'CH3SH', 1.877, 1.676,
atoms={'C': 1, 'S': 1, 'H': 4}, bonds={SINGLE_BOND: 1},
smarts='[SX2H][CX4;H3]') # perfect match
UFSG[60] = UNIFAC_subgroup(60, 'CH2SH', 29, 'CH3SH', 1.651, 1.368,
atoms={'C': 1, 'S': 1, 'H': 3}, bonds={SINGLE_BOND: 1},
smarts='[SX2H][CX4;H2]')
UFSG[61] = UNIFAC_subgroup(61, 'FURFURAL', 30, 'FURFURAL', 3.168, 2.484,
atoms={'C': 5, 'H': 4, 'O': 2}, bonds={AROMATIC_BOND: 3, SINGLE_BOND: 3, DOUBLE_BOND: 1},
smarts='c1cc(oc1)C=O') # Easy, compound smarts, 1 hit only
UFSG[62] = UNIFAC_subgroup(62, 'DOH', 31, 'DOH', 2.4088, 2.248,
atoms={'C': 2, 'H': 6, 'O': 2}, bonds={SINGLE_BOND: 3},
smarts='[OX2;H1][CX4;H2][CX4;H2][OX2;H1]') # Probably going to cause problems, match too much
UFSG[63] = UNIFAC_subgroup(63, 'I', 32, 'I', 1.264, 0.992, smarts='[I]',
atoms={'I': 1}, bonds={SINGLE_BOND: 1},
)
UFSG[64] = UNIFAC_subgroup(64, 'BR', 33, 'BR', 0.9492, 0.832,
atoms={'Br': 1}, bonds={SINGLE_BOND: 1},
smarts='[Br]')
UFSG[65] = UNIFAC_subgroup(65, 'CH=-C', 34, 'C=-C', 1.292, 1.088,
atoms={'C': 2, 'H': 1}, bonds={TRIPLE_BOND: 1},
smarts='[CX2;H1]#[CX2;H0]')
UFSG[66] = UNIFAC_subgroup(66, 'C=-C', 34, 'C=-C', 1.0613, 0.784,
atoms={'C': 2, 'H': 0}, bonds={TRIPLE_BOND: 1},
smarts='[CX2;H0]#[CX2;H0]')
UFSG[67] = UNIFAC_subgroup(67, 'DMSO', 35, 'DMSO', 2.8266, 2.472,
atoms={'C': 2, 'H': 6, 'O': 1, 'S': 1}, bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2},
smarts='[SX3H0](=[OX1])([CX4;H3])[CX4;H3]') # Compound smarts
UFSG[68] = UNIFAC_subgroup(68, 'ACRY', 36, 'ACRY', 2.3144, 2.052,
atoms={'C': 3, 'H': 3, 'N': 1}, bonds={DOUBLE_BOND: 1, SINGLE_BOND: 1, TRIPLE_BOND: 1},
smarts='[CX3;H2]=[CX3;H1][CX2;H0]#[NX1;H0]') # Easy, compount smarts
UFSG[69] = UNIFAC_subgroup(69, 'CL-(C=C)', 37, 'CLCC', 0.791, 0.724,
# This group is just the Cl, but it HAS to be attatched to a C that is part of C=C
atoms={'Cl': 1}, bonds={SINGLE_BOND: 1},
# smarts='Cl[CX3]=[CX3]')
smarts='[$([Cl;H0]([C]=[C]))]')
UFSG[70] = UNIFAC_subgroup(70, 'C=C', 2, 'C=C', 0.6605, 0.485,
atoms={'C': 2}, bonds={DOUBLE_BOND: 1},
smarts='[CX3;H0]=[CX3;H0]') # ddbst matches some of these into rings incorrectly
UFSG[71] = UNIFAC_subgroup(71, 'ACF', 38, 'ACF', 0.6948, 0.524,
atoms={'C': 1, 'F': 1}, bonds={AROMATIC_BOND: 1, SINGLE_BOND:1},
smarts='[cX3][F]') # Perfect for many, except 71671-89-1
UFSG[72] = UNIFAC_subgroup(72, 'DMF', 39, 'DMF', 3.0856, 2.736,
atoms={'C': 3, 'O': 1, 'N': 1, 'H': 7}, bonds={SINGLE_BOND: 3, DOUBLE_BOND:1},
smarts='[CX4;H3][N]([CX4;H3])[CX3;H1]=[O]')
UFSG[73] = UNIFAC_subgroup(73, 'HCON(CH2)2', 39, 'DMF', 2.6322, 2.12,
atoms={'C': 3, 'O': 1, 'N': 1, 'H': 5}, bonds={SINGLE_BOND: 3, DOUBLE_BOND:1},
smarts='[NX3]([CX4;H2])([CX4;H2])[CX3;H1](=[OX1])')
UFSG[74] = UNIFAC_subgroup(74, 'CF3', 40, 'CF2', 1.406, 1.38,
atoms={'C': 1, 'F': 3}, bonds={SINGLE_BOND: 3},
smarts='C(F)(F)F')
UFSG[75] = UNIFAC_subgroup(75, 'CF2', 40, 'CF2', 1.0105, 0.92,
atoms={'C': 1, 'F': 2}, bonds={SINGLE_BOND: 2},
smarts='C(F)F')
UFSG[76] = UNIFAC_subgroup(76, 'CF', 40, 'CF2', 0.615, 0.46,
atoms={'C': 1, 'F': 1}, bonds={SINGLE_BOND: 1},
smarts='C(F)')
UFSG[77] = UNIFAC_subgroup(77, 'COO', 41, 'COO', 1.38, 1.2,
atoms={'C': 1, 'O': 2}, bonds={SINGLE_BOND: 1, DOUBLE_BOND:1},
smarts='[CX3,cX3](=[OX1])[OX2,oX2]') # ddbst wants match into rings, thus the cX3, oX2
UFSG[78] = UNIFAC_subgroup(78, 'SIH3', 42, 'SIH2', 1.6035, 1.2632,
atoms={'Si': 1, 'H': 3}, bonds={},
smarts='[SiX4,SiX3,SiX5;H3]') # some db smiles compounds missing Hs, not matched not due to smarts
UFSG[79] = UNIFAC_subgroup(79, 'SIH2', 42, 'SIH2', 1.4443, 1.0063,
atoms={'Si': 1, 'H': 2}, bonds={},
smarts='[SiX4,SiX3,SiX5,SiX2;H2]') # some db smiles compounds missing Hs, not matched not due to smarts
UFSG[80] = UNIFAC_subgroup(80, 'SIH', 42, 'SIH2', 1.2853, 0.7494,
atoms={'Si': 1, 'H': 1}, bonds={},
smarts='[SiX4,SiX3,SiX5,SiX2,SiX1;H1]') # some db smiles compounds missing Hs, not matched not due to smarts
UFSG[81] = UNIFAC_subgroup(81, 'SI', 42, 'SIH2', 1.047, 0.4099,
atoms={'Si': 1, 'H': 0}, bonds={},
smarts='[Si]')
UFSG[82] = UNIFAC_subgroup(82, 'SIH2O', 43, 'SIO', 1.4838, 1.0621,
smarts='[SiH2][O]',
atoms={'Si': 1, 'H': 2, 'O': 1}, bonds={SINGLE_BOND: 1})
UFSG[83] = UNIFAC_subgroup(83, 'SIHO', 43, 'SIO', 1.303, 0.7639,
smarts='[SiH1][O]',
atoms={'Si': 1, 'H': 1, 'O': 1}, bonds={SINGLE_BOND: 1})
UFSG[84] = UNIFAC_subgroup(84, 'SIO', 43, 'SIO', 1.1044, 0.4657, smarts='[SiH0][O]',
atoms={'Si': 1, 'H': 0, 'O': 1}, bonds={SINGLE_BOND: 1})
UFSG[85] = UNIFAC_subgroup(85, 'NMP', 44, 'NMP', 3.981, 3.2,
atoms={'C': 5, 'H': 9, 'O': 1, 'N': 1}, bonds={SINGLE_BOND: 6, DOUBLE_BOND: 1},
smarts='[CX4;H3][NX3;H0]1[CX4;H2][CX4;H2][CX4;H2][CX3;H0]1=[OX1;H0]')
UFSG[86] = UNIFAC_subgroup(86, 'CCL3F', 45, 'CCLF', 3.0356, 2.644,
bonds={SINGLE_BOND: 4}, atoms={'C': 1, 'Cl': 3, 'F': 1},
smarts='[CX4;H0]([F])([Cl])([Cl])[Cl]') # pure compound?
UFSG[87] = UNIFAC_subgroup(87, 'CCL2F', 45, 'CCLF', 2.2287, 1.916,
bonds={SINGLE_BOND: 3}, atoms={'C': 1, 'Cl': 2, 'F': 1},
smarts='C(F)(Cl)Cl')
UFSG[88] = UNIFAC_subgroup(88, 'HCCL2F', 45, 'CCLF', 2.406, 2.116,
bonds={SINGLE_BOND: 3}, atoms={'C': 1, 'H': 1, 'Cl': 2, 'F': 1},
smarts='ClC(Cl)F')
UFSG[89] = UNIFAC_subgroup(89, 'HCCLF', 45, 'CCLF', 1.6493, 1.416,
bonds={SINGLE_BOND: 2}, atoms={'C': 1, 'H': 1, 'Cl': 1, 'F': 1},
smarts='C(Cl)F')
UFSG[90] = UNIFAC_subgroup(90, 'CCLF2', 45, 'CCLF', 1.8174, 1.648,
bonds={SINGLE_BOND: 3}, atoms={'C': 1, 'Cl': 1, 'F': 2},
smarts='Cl[CX4;H0](F)(F)')
UFSG[91] = UNIFAC_subgroup(91, 'HCCLF2', 45, 'CCLF', 1.967, 1.828,
bonds={SINGLE_BOND: 3}, atoms={'H': 1, 'C': 1, 'Cl': 1, 'F': 2},
smarts='Cl[CX4;H1](F)F')
UFSG[92] = UNIFAC_subgroup(92, 'CCLF3', 45, 'CCLF', 2.1721, 2.1,
bonds={SINGLE_BOND: 4}, atoms={'C': 1, 'Cl': 1, 'F': 3},
smarts='ClC(F)(F)F') # perfect
UFSG[93] = UNIFAC_subgroup(93, 'CCL2F2', 45, 'CCLF', 2.6243, 2.376,
bonds={SINGLE_BOND: 4}, atoms={'C': 1, 'Cl': 2, 'F': 2},
smarts='ClC(Cl)(F)F') # perfect
UFSG[94] = UNIFAC_subgroup(94, 'AMH2', 46, 'CON(AM)', 1.4515, 1.248,
bonds={SINGLE_BOND: 1, DOUBLE_BOND: 1}, atoms={'C': 1, 'O': 1, 'N': 1, 'H': 2},
smarts='[CX3;H0](=[OX1])[NX3;H2]')
UFSG[95] = UNIFAC_subgroup(95, 'AMHCH3', 46, 'CON(AM)', 2.1905, 1.796,
# CONHCH3
bonds={SINGLE_BOND: 2, DOUBLE_BOND: 1}, atoms={'C': 2, 'O': 1, 'N': 1, 'H': 4},
smarts='[CX3;H0](=[OX1])[NX3;H1][CX4;H3]') # 3 extra hits, effortlessly web
UFSG[96] = UNIFAC_subgroup(96, 'AMHCH2', 46, 'CON(AM)', 1.9637, 1.488,
bonds={SINGLE_BOND: 2, DOUBLE_BOND: 1}, atoms={'C': 2, 'O': 1, 'N': 1, 'H': 3},
smarts='[CX3;H0](=[OX1])[NX3;H1][CX4;H2]') # 4 extra hits, effortlessly web
UFSG[97] = UNIFAC_subgroup(97, 'AM(CH3)2', 46, 'CON(AM)', 2.8589, 2.428,
bonds={SINGLE_BOND: 3, DOUBLE_BOND: 1}, atoms={'C': 3, 'O': 1, 'N': 1, 'H': 6},
smarts='[CX3;H0](=[OX1])[NX3;H0]([CX4;H3])[CX4;H3]') # effortlessly web
UFSG[98] = UNIFAC_subgroup(98, 'AMCH3CH2', 46, 'CON(AM)', 2.6322, 2.12,
bonds={SINGLE_BOND: 3, DOUBLE_BOND: 1}, atoms={'C': 3, 'O': 1, 'N': 1, 'H': 5},
smarts='[CX3;H0](=[OX1])[NX3;H0]([CX4;H3])[CX4;H2]') # 1 extra hits, effortlessly web
UFSG[99] = UNIFAC_subgroup(99, 'AM(CH2)2', 46, 'CON(AM)', 2.4054, 1.812,
bonds={SINGLE_BOND: 3, DOUBLE_BOND: 1}, atoms={'C': 3, 'O': 1, 'N': 1, 'H': 4},
smarts='[CX3;H0](=[OX1])[NX3;H0]([CX4;H2])[CX4;H2]') # 2 extra hits, effortlessly web
UFSG[100] = UNIFAC_subgroup(100, 'C2H5O2', 47, 'OCCOH', 2.1226, 1.904,
bonds={SINGLE_BOND: 3}, atoms={'C': 2, 'H': 5, 'O': 2},
smarts='[CX4;H2]([OX2;H1])[CX4;H2][OX2;H0]') # Matches all; 53 extra hits
UFSG[101] = UNIFAC_subgroup(101, 'C2H4O2', 47, 'OCCOH', 1.8952, 1.592,
bonds={SINGLE_BOND: 3}, atoms={'C': 2, 'H': 4, 'O': 2},
smarts=['[CX4;H1]([OX2;H1])[CX4;H2][OX2;H0]', '[CX4;H2]([OX2;H1])[CX4;H1][OX2;H0]']) # custom expression
UFSG[102] = UNIFAC_subgroup(102, 'CH3S', 48, 'CH2S', 1.613, 1.368,
bonds={SINGLE_BOND: 1}, atoms={'C': 1, 'H': 3, 'S': 1},
smarts='[CX4;H3][SX2]')
UFSG[103] = UNIFAC_subgroup(103, 'CH2S', 48, 'CH2S', 1.3863, 1.06,
bonds={SINGLE_BOND: 1}, atoms={'C': 1, 'H': 2, 'S': 1},
smarts='[CX4;H2][SX2]')
UFSG[104] = UNIFAC_subgroup(104, 'CHS', 48, 'CH2S', 1.1589, 0.748,
bonds={SINGLE_BOND: 1}, atoms={'C': 1, 'H': 1, 'S': 1},
smarts='[CX4,CX3,CX2;H1][S]') # S bond might need to be more restricted; C bond might need to be more restricted
UFSG[105] = UNIFAC_subgroup(105, 'MORPH', 49, 'MORPH', 3.474, 2.796,
bonds={SINGLE_BOND: 6}, atoms={'C': 4, 'H': 9, 'O': 1, 'N': 1},
smarts='[CX4;H2]1[CX4;H2][OX2;H0][CX4;H2][CX4;H2][NX3;H1]1')
UFSG[106] = UNIFAC_subgroup(106, 'C4H4S', 50, 'THIOPHEN', 2.8569, 2.14,
bonds={AROMATIC_BOND: 5}, atoms={'C': 4, 'H': 4, 'S': 1},
smarts='[cX3;H1]1[cX3;H1][cX3;H1][sX2;H0][cX3;H1]1')
# Custom tuned - matches perfectly no extras, might need to be more slack in the future
UFSG[107] = UNIFAC_subgroup(107, 'C4H3S', 50, 'THIOPHEN', 2.6908, 1.86,
bonds={AROMATIC_BOND: 5}, atoms={'C': 4, 'H': 3, 'S': 1},
smarts=['[cX3;H1]1[cX3;H1][cX3;H1][sX2;H0][cX3;H0]1',
'[cX3;H1]1[cX3;H0][cX3;H1][sX2;H0][cX3;H1]1']) # 1 extra - custom tuned
UFSG[108] = UNIFAC_subgroup(108, 'C4H2S', 50, 'THIOPHEN', 2.5247, 1.58,
bonds={AROMATIC_BOND: 5}, atoms={'C': 4, 'H': 2, 'S': 1},
smarts=['[cX3;H0]1[cX3;H0][cX3;H1][sX2;H0][cX3;H1]1',
'[cX3;H0]1[cX3;H1][cX3;H0][sX2;H0][cX3;H1]1',
'[cX3;H0]1[cX3;H1][cX3;H1][sX2;H0][cX3;H0]1',
'[cX3;H1]1[cX3;H0][cX3;H0][sX2;H0][cX3;H1]1',
'[cX3;H1]1[cX3;H0][cX3;H1][sX2;H0][cX3;H0]1',
'[cX3;H1]1[cX3;H1][cX3;H0][sX2;H0][cX3;H0]1']) # Not sure if this is right - probably not!!!
UFSG[109] = UNIFAC_subgroup(109, 'NCO', 51, 'NCO', 1.0567, 0.732,
atoms={'C': 1, 'N': 1, 'O': 1}, bonds={DOUBLE_BOND: 2},
smarts='[NX2H0]=[CX2H0]=[OX1H0]') # Bonds might need to be different - but this smarts matches them all so far
UFSG[118] = UNIFAC_subgroup(118, '(CH2)2SU', 55, 'SULFONES', 2.6869, 2.12,
atoms={'S': 1, 'O': 2, 'H': 4, 'C': 2}, bonds={SINGLE_BOND: 2, DOUBLE_BOND: 2},
smarts='[CX4;H2][SX4](=O)(=O)[CX4;H2]') # TYPO on their part; Makes no sense for there to be CH3 groups
UFSG[119] = UNIFAC_subgroup(119, 'CH2CHSU', 55, 'SULFONES', 2.4595, 1.808,
atoms={'S': 1, 'O': 2, 'H': 3, 'C': 2}, bonds={SINGLE_BOND: 2, DOUBLE_BOND: 2},
smarts='[CX4;H2][SX4](=O)(=O)[CX4;H1]') # 3 missing of 6
UFSG[178] = UNIFAC_subgroup(178, 'IMIDAZOL', 84, 'IMIDAZOL', 2.026, 0.868,
atoms={'C': 3, 'N': 2, 'H': 3}, bonds={AROMATIC_BOND: 5},
smarts='[c]1:[c]:[n]:[c]:[n]:1') # DDBST fragmentation indicates N cannot have a hydrogen attatched
UFSG[179] = UNIFAC_subgroup(179, 'BTI', 85, 'BTI', 5.774, 4.932,
bonds={DOUBLE_BOND: 4, SINGLE_BOND: 4},
atoms={'C':2, 'O': 4, 'F': 6, 'S': 2, 'N': 1},
smarts='C(F)(F)(F)S(=O)(=O)[N-]S(=O)(=O)C(F)(F)F')
# http://www.ddbst.com/PublishedParametersUNIFACDO.html#ListOfSubGroupsAndTheirGroupSurfacesAndVolumes
# subgroup = (subgroup, #maingroup, maingroup, R, Q)
DOUFSG = {}
DOUFSG[1] = UNIFAC_subgroup(1, 'CH3', 1, 'CH2', 0.6325, 1.0608,
atoms=UFSG[1].atoms, bonds=UFSG[1].bonds, smarts=UFSG[1].smarts)
DOUFSG[2] = UNIFAC_subgroup(2, 'CH2', 1, 'CH2', 0.6325, 0.7081,
atoms=UFSG[2].atoms, bonds=UFSG[2].bonds, smarts=UFSG[2].smarts)
DOUFSG[3] = UNIFAC_subgroup(3, 'CH', 1, 'CH2', 0.6325, 0.3554,
atoms=UFSG[3].atoms, bonds=UFSG[3].bonds, smarts=UFSG[3].smarts)
DOUFSG[4] = UNIFAC_subgroup(4, 'C', 1, 'CH2', 0.6325, 0,
atoms=UFSG[4].atoms, bonds=UFSG[4].bonds, smarts=UFSG[4].smarts)
DOUFSG[5] = UNIFAC_subgroup(5, 'CH2=CH', 2, 'C=C', 1.2832, 1.6016,
atoms=UFSG[5].atoms, bonds=UFSG[5].bonds, smarts=UFSG[5].smarts)
DOUFSG[6] = UNIFAC_subgroup(6, 'CH=CH', 2, 'C=C', 1.2832, 1.2489,
atoms=UFSG[6].atoms, bonds=UFSG[6].bonds, smarts=UFSG[6].smarts)
DOUFSG[7] = UNIFAC_subgroup(7, 'CH2=C', 2, 'C=C', 1.2832, 1.2489,
atoms=UFSG[7].atoms, bonds=UFSG[7].bonds, smarts=UFSG[7].smarts)
DOUFSG[8] = UNIFAC_subgroup(8, 'CH=C', 2, 'C=C', 1.2832, 0.8962,
atoms=UFSG[8].atoms, bonds=UFSG[8].bonds, smarts=UFSG[8].smarts)
DOUFSG[9] = UNIFAC_subgroup(9, 'ACH', 3, 'ACH', 0.3763, 0.4321,
atoms=UFSG[9].atoms, bonds=UFSG[9].bonds, smarts=UFSG[9].smarts)
DOUFSG[10] = UNIFAC_subgroup(10, 'AC', 3, 'ACH', 0.3763, 0.2113,
atoms=UFSG[10].atoms, bonds=UFSG[10].bonds, smarts=UFSG[10].smarts)
DOUFSG[11] = UNIFAC_subgroup(11, 'ACCH3', 4, 'ACCH2', 0.91, 0.949,
atoms=UFSG[11].atoms, bonds=UFSG[11].bonds, smarts=UFSG[11].smarts)
DOUFSG[12] = UNIFAC_subgroup(12, 'ACCH2', 4, 'ACCH2', 0.91, 0.7962,
atoms=UFSG[12].atoms, bonds=UFSG[12].bonds, smarts=UFSG[12].smarts)
DOUFSG[13] = UNIFAC_subgroup(13, 'ACCH', 4, 'ACCH2', 0.91, 0.3769,
atoms=UFSG[13].atoms, bonds=UFSG[13].bonds, smarts=UFSG[13].smarts)
DOUFSG[14] = UNIFAC_subgroup(14, 'OH(P)', 5, 'OH', 1.2302, 0.8927,
atoms={'O': 1, 'H': 1}, bonds={}, smarts='[OH1;$([OH1][CX4H2])]')
# OH bonded to a primary carbon, OH(S) and OH(T) are secondary and tertiary
DOUFSG[15] = UNIFAC_subgroup(15, 'CH3OH', 6, 'CH3OH', 0.8585, 0.9938,
atoms=UFSG[15].atoms, bonds=UFSG[15].bonds, smarts=UFSG[15].smarts)
DOUFSG[16] = UNIFAC_subgroup(16, 'H2O', 7, 'H2O', 1.7334, 2.4561,
atoms=UFSG[16].atoms, bonds=UFSG[16].bonds, smarts=UFSG[16].smarts)
DOUFSG[17] = UNIFAC_subgroup(17, 'ACOH', 8, 'ACOH', 1.08, 0.975,
atoms=UFSG[17].atoms, bonds=UFSG[17].bonds, smarts=UFSG[17].smarts)
DOUFSG[18] = UNIFAC_subgroup(18, 'CH3CO', 9, 'CH2CO', 1.7048, 1.67,
atoms=UFSG[18].atoms, bonds=UFSG[18].bonds, smarts=UFSG[18].smarts)
DOUFSG[19] = UNIFAC_subgroup(19, 'CH2CO', 9, 'CH2CO', 1.7048, 1.5542,
atoms=UFSG[19].atoms, bonds=UFSG[19].bonds, smarts=UFSG[19].smarts)
DOUFSG[20] = UNIFAC_subgroup(20, 'CHO', 10, 'CHO', 0.7173, 0.771,
atoms=UFSG[20].atoms, bonds=UFSG[20].bonds, smarts=UFSG[20].smarts)
DOUFSG[21] = UNIFAC_subgroup(21, 'CH3COO', 11, 'CCOO', 1.27, 1.6286,
atoms=UFSG[21].atoms, bonds=UFSG[21].bonds, smarts=UFSG[21].smarts)
DOUFSG[22] = UNIFAC_subgroup(22, 'CH2COO', 11, 'CCOO', 1.27, 1.4228,
atoms=UFSG[22].atoms, bonds=UFSG[22].bonds, smarts=UFSG[22].smarts)
DOUFSG[23] = UNIFAC_subgroup(23, 'HCOO', 12, 'HCOO', 1.9, 1.8,
atoms=UFSG[23].atoms, bonds=UFSG[23].bonds, smarts=UFSG[23].smarts)
DOUFSG[24] = UNIFAC_subgroup(24, 'CH3O', 13, 'CH2O', 1.1434, 1.6022,
atoms=UFSG[24].atoms, bonds=UFSG[24].bonds, smarts=UFSG[24].smarts)
DOUFSG[25] = UNIFAC_subgroup(25, 'CH2O', 13, 'CH2O', 1.1434, 1.2495,
atoms=UFSG[25].atoms, bonds=UFSG[25].bonds, smarts=UFSG[25].smarts)
DOUFSG[26] = UNIFAC_subgroup(26, 'CHO', 13, 'CH2O', 1.1434, 0.8968,
atoms=UFSG[26].atoms, bonds=UFSG[26].bonds, smarts=UFSG[26].smarts)
DOUFSG[27] = UNIFAC_subgroup(27, 'THF', 43, 'CY-CH2O', 1.7023, 1.8784,
atoms=UFSG[27].atoms, bonds=UFSG[27].bonds, smarts=UFSG[27].smarts)
DOUFSG[28] = UNIFAC_subgroup(28, 'CH3NH2', 14, 'CH2NH2', 1.6607, 1.6904,
atoms=UFSG[28].atoms, bonds=UFSG[28].bonds, smarts=UFSG[28].smarts)
DOUFSG[29] = UNIFAC_subgroup(29, 'CH2NH2', 14, 'CH2NH2', 1.6607, 1.3377,
atoms=UFSG[29].atoms, bonds=UFSG[29].bonds, smarts=UFSG[29].smarts)
DOUFSG[30] = UNIFAC_subgroup(30, 'CHNH2', 14, 'CH2NH2', 1.6607, 0.985,
atoms=UFSG[30].atoms, bonds=UFSG[30].bonds, smarts=UFSG[30].smarts)
DOUFSG[31] = UNIFAC_subgroup(31, 'CH3NH', 15, 'CH2NH', 1.368, 1.4332,
atoms=UFSG[31].atoms, bonds=UFSG[31].bonds, smarts=UFSG[31].smarts)
DOUFSG[32] = UNIFAC_subgroup(32, 'CH2NH', 15, 'CH2NH', 1.368, 1.0805,
atoms=UFSG[32].atoms, bonds=UFSG[32].bonds, smarts=UFSG[32].smarts)
DOUFSG[33] = UNIFAC_subgroup(33, 'CHNH', 15, 'CH2NH', 1.368, 0.7278,
atoms=UFSG[33].atoms, bonds=UFSG[33].bonds, smarts=UFSG[33].smarts)
DOUFSG[34] = UNIFAC_subgroup(34, 'CH3N', 16, '(C)3N', 1.0746, 1.176,
atoms=UFSG[34].atoms, bonds=UFSG[34].bonds, smarts=UFSG[34].smarts)
DOUFSG[35] = UNIFAC_subgroup(35, 'CH2N', 16, '(C)3N', 1.0746, 0.824,
atoms=UFSG[35].atoms, bonds=UFSG[35].bonds, smarts=UFSG[35].smarts)
DOUFSG[36] = UNIFAC_subgroup(36, 'ACNH2', 17, 'ACNH2', 1.1849, 0.8067,
atoms=UFSG[36].atoms, bonds=UFSG[36].bonds, smarts=UFSG[36].smarts)
DOUFSG[37] = UNIFAC_subgroup(37, 'AC2H2N', 18, 'PYRIDINE', 1.4578, 0.9022,
atoms={'C': 2, 'H': 2, 'N': 1}, bonds={AROMATIC_BOND: 2}, smarts='[cX3H1][n][cX3H1]')
DOUFSG[38] = UNIFAC_subgroup(38, 'AC2HN', 18, 'PYRIDINE', 1.2393, 0.633,
atoms={'C': 2, 'H': 1, 'N': 1}, bonds={AROMATIC_BOND: 2}, smarts='[cX3H0][n][cX3H1]')
DOUFSG[39] = UNIFAC_subgroup(39, 'AC2N', 18, 'PYRIDINE', 1.0731, 0.353,
atoms={'C': 2, 'N': 1}, bonds={AROMATIC_BOND: 2}, smarts='[cX3H0][n][cX3H0]')
DOUFSG[40] = UNIFAC_subgroup(40, 'CH3CN', 19, 'CH2CN', 1.5575, 1.5193,
atoms=UFSG[40].atoms, bonds=UFSG[40].bonds, smarts=UFSG[40].smarts)
DOUFSG[41] = UNIFAC_subgroup(41, 'CH2CN', 19, 'CH2CN', 1.5575, 1.1666,
atoms=UFSG[41].atoms, bonds=UFSG[41].bonds, smarts=UFSG[41].smarts)
DOUFSG[42] = UNIFAC_subgroup(42, 'COOH', 20, 'COOH', 0.8, 0.9215,
atoms=UFSG[42].atoms, bonds=UFSG[42].bonds, smarts=UFSG[42].smarts)
DOUFSG[43] = UNIFAC_subgroup(43, 'HCOOH', 44, 'HCOOH', 0.8, 1.2742,
atoms=UFSG[43].atoms, bonds=UFSG[43].bonds, smarts=UFSG[43].smarts)
DOUFSG[44] = UNIFAC_subgroup(44, 'CH2CL', 21, 'CCL', 0.9919, 1.3654,
atoms=UFSG[44].atoms, bonds=UFSG[44].bonds, smarts=UFSG[44].smarts)
DOUFSG[45] = UNIFAC_subgroup(45, 'CHCL', 21, 'CCL', 0.9919, 1.0127,
atoms=UFSG[45].atoms, bonds=UFSG[45].bonds, smarts=UFSG[45].smarts)
DOUFSG[46] = UNIFAC_subgroup(46, 'CCL', 21, 'CCL', 0.9919, 0.66,
atoms=UFSG[46].atoms, bonds=UFSG[46].bonds, smarts=UFSG[46].smarts)
DOUFSG[47] = UNIFAC_subgroup(47, 'CH2CL2', 22, 'CCL2', 1.8, 2.5,
atoms=UFSG[47].atoms, bonds=UFSG[47].bonds, smarts=UFSG[47].smarts)
DOUFSG[48] = UNIFAC_subgroup(48, 'CHCL2', 22, 'CCL2', 1.8, 2.1473,
atoms=UFSG[48].atoms, bonds=UFSG[48].bonds, smarts=UFSG[48].smarts)
DOUFSG[49] = UNIFAC_subgroup(49, 'CCL2', 22, 'CCL2', 1.8, 1.7946,
atoms=UFSG[49].atoms, bonds=UFSG[49].bonds, smarts=UFSG[49].smarts)
DOUFSG[50] = UNIFAC_subgroup(50, 'CHCL3', 45, 'CHCL3', 2.45, 2.8912,
atoms=UFSG[50].atoms, bonds=UFSG[50].bonds, smarts=UFSG[50].smarts)
DOUFSG[51] = UNIFAC_subgroup(51, 'CCL3', 23, 'CCL3', 2.65, 2.3778,
atoms=UFSG[51].atoms, bonds=UFSG[51].bonds, smarts=UFSG[51].smarts)
DOUFSG[52] = UNIFAC_subgroup(52, 'CCL4', 24, 'CCL4', 2.618, 3.1836,
atoms=UFSG[52].atoms, bonds=UFSG[52].bonds, smarts=UFSG[52].smarts)
DOUFSG[53] = UNIFAC_subgroup(53, 'ACCL', 25, 'ACCL', 0.5365, 0.3177,
atoms=UFSG[53].atoms, bonds=UFSG[53].bonds, smarts=UFSG[53].smarts)
DOUFSG[54] = UNIFAC_subgroup(54, 'CH3NO2', 26, 'CNO2', 2.644, 2.5,
atoms=UFSG[54].atoms, bonds=UFSG[54].bonds, smarts=UFSG[54].smarts)
DOUFSG[55] = UNIFAC_subgroup(55, 'CH2NO2', 26, 'CNO2', 2.5, 2.304,
atoms=UFSG[55].atoms, bonds=UFSG[55].bonds, smarts=UFSG[55].smarts)
DOUFSG[56] = UNIFAC_subgroup(56, 'CHNO2', 26, 'CNO2', 2.887, 2.241,
atoms=UFSG[56].atoms, bonds=UFSG[56].bonds, smarts=UFSG[56].smarts)
DOUFSG[57] = UNIFAC_subgroup(57, 'ACNO2', 27, 'ACNO2', 0.4656, 0.3589,
atoms=UFSG[57].atoms, bonds=UFSG[57].bonds, smarts=UFSG[57].smarts)
DOUFSG[58] = UNIFAC_subgroup(58, 'CS2', 28, 'CS2', 1.24, 1.068,
atoms=UFSG[58].atoms, bonds=UFSG[58].bonds, smarts=UFSG[58].smarts)
DOUFSG[59] = UNIFAC_subgroup(59, 'CH3SH', 29, 'CH3SH', 1.289, 1.762,
atoms=UFSG[59].atoms, bonds=UFSG[59].bonds, smarts=UFSG[59].smarts)
DOUFSG[60] = UNIFAC_subgroup(60, 'CH2SH', 29, 'CH3SH', 1.535, 1.316,
atoms=UFSG[60].atoms, bonds=UFSG[60].bonds, smarts=UFSG[60].smarts)
DOUFSG[61] = UNIFAC_subgroup(61, 'FURFURAL', 30, 'FURFURAL', 1.299, 1.289,
atoms=UFSG[61].atoms, bonds=UFSG[61].bonds, smarts=UFSG[61].smarts)
DOUFSG[62] = UNIFAC_subgroup(62, 'DOH', 31, 'DOH', 2.088, 2.4,
atoms=UFSG[62].atoms, bonds=UFSG[62].bonds, smarts=UFSG[62].smarts)
DOUFSG[63] = UNIFAC_subgroup(63, 'I', 32, 'I', 1.076, 0.9169,
atoms=UFSG[63].atoms, bonds=UFSG[63].bonds, smarts=UFSG[63].smarts)
DOUFSG[64] = UNIFAC_subgroup(64, 'BR', 33, 'BR', 1.209, 1.4,
atoms=UFSG[64].atoms, bonds=UFSG[64].bonds, smarts=UFSG[64].smarts)
DOUFSG[65] = UNIFAC_subgroup(65, 'CH=-C', 34, 'C=-C', 0.9214, 1.3,
atoms=UFSG[65].atoms, bonds=UFSG[65].bonds, smarts=UFSG[65].smarts)
DOUFSG[66] = UNIFAC_subgroup(66, 'C=-C', 34, 'C=-C', 1.303, 1.132,
atoms=UFSG[66].atoms, bonds=UFSG[66].bonds, smarts=UFSG[66].smarts)
DOUFSG[67] = UNIFAC_subgroup(67, 'DMSO', 35, 'DMSO', 3.6, 2.692,
atoms=UFSG[67].atoms, bonds=UFSG[67].bonds, smarts=UFSG[67].smarts)
DOUFSG[68] = UNIFAC_subgroup(68, 'ACRY', 36, 'ACRY', 1, 0.92,
atoms=UFSG[68].atoms, bonds=UFSG[68].bonds, smarts=UFSG[68].smarts)
DOUFSG[69] = UNIFAC_subgroup(69, 'CL-(C=C)', 37, 'CLCC', 0.5229, 0.7391,
atoms=UFSG[69].atoms, bonds=UFSG[69].bonds, smarts=UFSG[69].smarts)
DOUFSG[70] = UNIFAC_subgroup(70, 'C=C', 2, 'C=C', 1.2832, 0.4582,
atoms=UFSG[70].atoms, bonds=UFSG[70].bonds, smarts=UFSG[70].smarts)
DOUFSG[71] = UNIFAC_subgroup(71, 'ACF', 38, 'ACF', 0.8814, 0.7269,
atoms=UFSG[71].atoms, bonds=UFSG[71].bonds, smarts=UFSG[71].smarts)
DOUFSG[72] = UNIFAC_subgroup(72, 'DMF', 39, 'DMF', 2, 2.093,
atoms=UFSG[72].atoms, bonds=UFSG[72].bonds, smarts=UFSG[72].smarts)
DOUFSG[73] = UNIFAC_subgroup(73, 'HCON(CH2)2', 39, 'DMF', 2.381, 1.522,
atoms=UFSG[73].atoms, bonds=UFSG[73].bonds, smarts=UFSG[73].smarts)
DOUFSG[74] = UNIFAC_subgroup(74, 'CF3', 40, 'CF2', 1.284, 1.266,
atoms=UFSG[74].atoms, bonds=UFSG[74].bonds, smarts=UFSG[74].smarts)
DOUFSG[75] = UNIFAC_subgroup(75, 'CF2', 40, 'CF2', 1.284, 1.098,
atoms=UFSG[75].atoms, bonds=UFSG[75].bonds, smarts=UFSG[75].smarts)
DOUFSG[76] = UNIFAC_subgroup(76, 'CF', 40, 'CF2', 0.8215, 0.5135,
atoms=UFSG[76].atoms, bonds=UFSG[76].bonds, smarts=UFSG[76].smarts)
DOUFSG[77] = UNIFAC_subgroup(77, 'COO', 41, 'COO', 1.6, 0.9,
atoms=UFSG[77].atoms, bonds=UFSG[77].bonds, smarts=UFSG[77].smarts)
# TODO revise
DOUFSG[78] = UNIFAC_subgroup(78, 'CY-CH2', 42, 'CY-CH2', 0.7136, 0.8635,
atoms={'C': 1, 'H': 2}, bonds={}, smarts='[CH2;R]')
DOUFSG[79] = UNIFAC_subgroup(79, 'CY-CH', 42, 'CY-CH2', 0.3479, 0.1071,
atoms={'C': 1, 'H': 1}, bonds={}, smarts='[CH1;R]')
DOUFSG[80] = UNIFAC_subgroup(80, 'CY-C', 42, 'CY-CH2', 0.347, 0,
atoms={'C': 1}, bonds={}, smarts='[CH0;R]')
DOUFSG[81] = UNIFAC_subgroup(81, 'OH(S)', 5, 'OH', 1.063, 0.8663,
atoms={'O': 1, 'H': 1}, bonds={}, smarts='[OH1;$([OH1][CX4H1])]')
DOUFSG[82] = UNIFAC_subgroup(82, 'OH(T)', 5, 'OH', 0.6895, 0.8345,
atoms={'O': 1, 'H': 1}, bonds={}, smarts='[OH1;$([OH1][CX4H0])]')
# Not positive of this one, 1,2,4-Trioxane mol uploaded matches this but with two carbon groups
DOUFSG[83] = UNIFAC_subgroup(83, 'CY-CH2O', 43, 'CY-CH2O', 1.4046, 1.4,
atoms={'C': 1, 'H': 2, 'O': 1}, bonds={SINGLE_BOND: 1},
smarts='[CX4H2;R][OX2;R]', hydrogen_from_smarts=True)
# 2,4,6-Trimethyl-1,3,5-trioxane matches this one with one hydrogen per carbon
# metaldehyde matches this one with one hydrogen per carbon (ring of 8 atoms)
# 1,3,5-Trioxane matches this one with two hydrogens
# Diprogulic acid is a weird one, has 1 of 84 and 1 of 83 but I can't tell the difference
# The 84 has no hydrogens
# https://www.chemspider.com/Chemical-Structure.79694.html?rid=4adfb45d-9e81-4676-8988-0715e0991550
# This one appears to only match two atoms
# There is NO INFORMATION to determine these groups
DOUFSG[84] = UNIFAC_subgroup(84, 'TRIOXAN', 43, 'CY-CH2O', 1.0413, 1.0116,
atoms={'C': 1, 'H': 2, 'O': 1}, bonds={SINGLE_BOND: 1},
smarts='[CX4H2;R][OX2;R]', hydrogen_from_smarts=True)
DOUFSG[85] = UNIFAC_subgroup(85, 'CNH2', 14, 'CH2NH2', 1.6607, 0.985,
atoms={'C': 1, 'H': 2, 'N': 1}, bonds={SINGLE_BOND: 1}, smarts='[CX4H0][NH2]')
DOUFSG[86] = UNIFAC_subgroup(86, 'NMP', 46, 'CY-CONC', 3.981, 3.2,
atoms={'O': 1, 'N': 1, 'C': 2, 'H': 3}, bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2}, smarts='[OX1H0]=[C;R][NX3H0;R][CH3]')
DOUFSG[87] = UNIFAC_subgroup(87, 'NEP', 46, 'CY-CONC', 3.7543, 2.892,
atoms={'O': 1, 'C': 2, 'N': 1, 'H': 2}, bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2},
smarts='[OX1H0]=[CH0X3;R][H0;R][CH2]')
DOUFSG[88] = UNIFAC_subgroup(88, 'NIPP', 46, 'CY-CONC', 3.5268, 2.58,
atoms={'O': 1, 'N': 1, 'H': 1, 'C': 2},
bonds={DOUBLE_BOND: 1, SINGLE_BOND: 1},priority=1000000000,
smarts='[OX1H0;!R]=[CX3H0;R][NX3H0;R][C;!R]')
DOUFSG[89] = UNIFAC_subgroup(89, 'NTBP', 46, 'CY-CONC', 3.2994, 2.352,
atoms={'C': 2, 'N': 1, 'O': 1, 'H': 0},
bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2},
smarts='[OX1H0;!R]=[CH0X3;R][NX3H0;R][CH0;!R]')
# Is 90 missing?
DOUFSG[91] = UNIFAC_subgroup(91, 'CONH2', 47, 'CONR', 1.4515, 1.248,
atoms={'O': 1, 'N': 1, 'C': 1, 'H': 2}, bonds={DOUBLE_BOND: 1, SINGLE_BOND: 1},
smarts='[CX3H0](=[OX1H0])[NX3H2]')
DOUFSG[92] = UNIFAC_subgroup(92, 'CONHCH3', 47, 'CONR', 1.5, 1.08,
atoms={'O' :1, 'N': 1, 'H': 3, 'C': 2},
bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2},
smarts= '[OX1H0;!R]=[CX3H0;!R][NH1X3;!R][CH3;!R]')
# 93, 98, 99 missing but inteaction parameters are available.
DOUFSG[100] = UNIFAC_subgroup(100, 'CONHCH2', 47, 'CONR', 1.5, 1.08,
atoms={'C': 2, 'N': 1, 'O': 1, 'H': 3},
bonds={DOUBLE_BOND: 1, SINGLE_BOND: 2},
smarts='[CH2X4;!R][NH1X3;!R][CX3H0;!R]=[OX1H0;!R]')
DOUFSG[101] = UNIFAC_subgroup(101, 'AM(CH3)2', 48, 'CONR2', 2.4748, 1.9643)
DOUFSG[102] = UNIFAC_subgroup(102, 'AMCH3CH2', 48, 'CONR2', 2.2739, 1.5754)
DOUFSG[103] = UNIFAC_subgroup(103, 'AM(CH2)2', 48, 'CONR2', 2.0767, 1.1866)
DOUFSG[104] = UNIFAC_subgroup(104, 'AC2H2S', 52, 'ACS', 1.7943, 1.34)
DOUFSG[105] = UNIFAC_subgroup(105, 'AC2HS', 52, 'ACS', 1.6282, 1.06)
DOUFSG[106] = UNIFAC_subgroup(106, 'AC2S', 52, 'ACS', 1.4621, 0.78)
DOUFSG[107] = UNIFAC_subgroup(107, 'H2COCH', 53, 'EPOXIDES', 1.3601, 1.8031)
DOUFSG[108] = UNIFAC_subgroup(108, 'COCH', 53, 'EPOXIDES', 0.683, 0.3418)
DOUFSG[109] = UNIFAC_subgroup(109, 'HCOCH', 53, 'EPOXIDES', 0.9104, 0.6538)
DOUFSG[110] = UNIFAC_subgroup(110, '(CH2)2SU', 56, 'SULFONE', 2.687, 2.12)
DOUFSG[111] = UNIFAC_subgroup(111, 'CH2SUCH', 56, 'SULFONE', 2.46, 1.808)
DOUFSG[112] = UNIFAC_subgroup(112, '(CH3)2CB', 55, 'CARBONAT', 2.42, 2.4976)
DOUFSG[113] = UNIFAC_subgroup(113, '(CH2)2CB', 55, 'CARBONAT', 2.42, 2.0018)
DOUFSG[114] = UNIFAC_subgroup(114, 'CH2CH3CB', 55, 'CARBONAT', 2.42, 2.2497)
DOUFSG[119] = UNIFAC_subgroup(119, 'H2COCH2', 53, 'EPOXIDES', 1.063, 1.123)
DOUFSG[153] = UNIFAC_subgroup(153, 'H2COC', 53, 'EPOXIDES', 0.9104, 0.6538)
DOUFSG[178] = UNIFAC_subgroup(178, 'C3H2N2+', 84, 'IMIDAZOL', 1.7989, 0.64)
DOUFSG[179] = UNIFAC_subgroup(179, 'BTI-', 85, 'BTI', 5.8504, 5.7513,
atoms=UFSG[179].atoms, bonds=UFSG[179].bonds, smarts=UFSG[179].smarts)
DOUFSG[184] = UNIFAC_subgroup(184, 'C3H3N2+', 84, 'IMIDAZOL', 2.411, 2.409)
DOUFSG[189] = UNIFAC_subgroup(189, 'C4H8N+', 87, 'PYRROL', 2.7986, 2.7744)
DOUFSG[195] = UNIFAC_subgroup(195, 'BF4-', 89, 'BF4', 4.62, 1.1707)
DOUFSG[196] = UNIFAC_subgroup(196, 'C5H5N+', 90, 'PYRIDIN', 2.4878, 2.474)
DOUFSG[197] = UNIFAC_subgroup(197, 'OTF-', 91, 'OTF', 3.3854, 2.009)
# 122, 123, 124, 201 Added Rev. 6
DOUFSG[122] = UNIFAC_subgroup(122, 'CH3S', 61, 'SULFIDES', 1.6130, 1.3680,
atoms=UFSG[102].atoms, bonds=UFSG[102].bonds, smarts=UFSG[102].smarts)
DOUFSG[123] = UNIFAC_subgroup(123, 'CH2S', 61, 'SULFIDES', 1.3863, 1.0600,
atoms=UFSG[103].atoms, bonds=UFSG[103].bonds, smarts=UFSG[103].smarts)
DOUFSG[124] = UNIFAC_subgroup(124, 'CHS', 61, 'SULFIDES', 1.1589, 0.7480,
atoms=UFSG[104].atoms, bonds=UFSG[104].bonds, smarts=UFSG[104].smarts)
DOUFSG[201] = UNIFAC_subgroup(201, '-S-S-', 93, 'DISULFIDES', 1.0678, 2.2440)
# subgroup = (group, (subgroup ids))
# http://www.ddbst.com/PublishedParametersUNIFACDO.html#ListOfMainGroups
DOUFMG = {}
DOUFMG[1] = ('CH2', [1, 2, 3, 4])
DOUFMG[2] = ('C=C', [5, 6, 7, 8, 70])
DOUFMG[3] = ('ACH', [9, 10])
DOUFMG[4] = ('ACCH2', [11, 12, 13])
DOUFMG[5] = ('OH', [14, 81, 82])
DOUFMG[6] = ('CH3OH', [15])
DOUFMG[7] = ('H2O', [16])
DOUFMG[8] = ('ACOH', [17])
DOUFMG[9] = ('CH2CO', [18, 19])
DOUFMG[10] = ('CHO', [20])
DOUFMG[11] = ('CCOO', [21, 22])
DOUFMG[12] = ('HCOO', [23])
DOUFMG[13] = ('CH2O', [24, 25, 26])
DOUFMG[14] = ('CH2NH2', [28, 29, 30, 85])
DOUFMG[15] = ('CH2NH', [31, 32, 33])
DOUFMG[16] = ('(C)3N', [34, 35])
DOUFMG[17] = ('ACNH2', [36])
DOUFMG[18] = ('PYRIDINE', [37, 38, 39])
DOUFMG[19] = ('CH2CN', [40, 41])
DOUFMG[20] = ('COOH', [42])
DOUFMG[21] = ('CCL', [44, 45, 46])
DOUFMG[22] = ('CCL2', [47, 48, 49])
DOUFMG[23] = ('CCL3', [51])
DOUFMG[24] = ('CCL4', [52])
DOUFMG[25] = ('ACCL', [53])
DOUFMG[26] = ('CNO2', [54, 55, 56])
DOUFMG[27] = ('ACNO2', [57])
DOUFMG[28] = ('CS2', [58])
DOUFMG[29] = ('CH3SH', [59, 60])
DOUFMG[30] = ('FURFURAL', [61])
DOUFMG[31] = ('DOH', [62])
DOUFMG[32] = ('I', [63])
DOUFMG[33] = ('BR', [64])
DOUFMG[34] = ('C=-C', [65, 66])
DOUFMG[35] = ('DMSO', [67])
DOUFMG[36] = ('ACRY', [68])
DOUFMG[37] = ('CLCC', [69])
DOUFMG[38] = ('ACF', [71])
DOUFMG[39] = ('DMF', [72, 73])
DOUFMG[40] = ('CF2', [74, 75, 76])
DOUFMG[41] = ('COO', [77])
DOUFMG[42] = ('CY-CH2', [78, 79, 80])
DOUFMG[43] = ('CY-CH2O', [27, 83, 84])
DOUFMG[44] = ('HCOOH', [43])
DOUFMG[45] = ('CHCL3', [50])
DOUFMG[46] = ('CY-CONC', [86, 87, 88, 89])
DOUFMG[47] = ('CONR', [91, 92, 100])
DOUFMG[48] = ('CONR2', [101, 102, 103])
DOUFMG[49] = ('HCONR', [93, 94]) # Added in Further Development of Modified UNIFAC (Dortmund):  Revision and Extension 5
DOUFMG[52] = ('ACS', [104, 105, 106])
DOUFMG[53] = ('EPOXIDES', [107, 108, 109, 119, 153])
DOUFMG[55] = ('CARBONAT', [112, 113, 114])
DOUFMG[56] = ('SULFONE', [110, 111])
DOUFMG[84] = ('IMIDAZOL', [178, 184])
DOUFMG[85] = ('BTI', [179])
DOUFMG[87] = ('PYRROL', [189])
DOUFMG[89] = ('BF4', [195])
DOUFMG[90] = ('PYRIDIN', [196])
DOUFMG[91] = ('OTF', [197])
# Added Rev 6
DOUFMG[61] = ('SULFIDES', [122, 123, 124])
DOUFMG[93] = ('DISULFIDES', [201])
# subgroup = (subgroup, #maingroup, maingroup, R, Q)
VTPRSG = {}
VTPRSG[1] = UNIFAC_subgroup(1, 'CH3', 1, 'CH2', None, 1.2958, smarts=DOUFSG[1].smarts)
VTPRSG[2] = UNIFAC_subgroup(2, 'CH2', 1, 'CH2', None, 0.9471, smarts=DOUFSG[2].smarts)
VTPRSG[3] = UNIFAC_subgroup(3, 'CH', 1, 'CH2', None, 0.2629, smarts=DOUFSG[3].smarts)
VTPRSG[4] = UNIFAC_subgroup(4, 'C', 1, 'CH2', None, 0, smarts=DOUFSG[4].smarts)
VTPRSG[5] = UNIFAC_subgroup(5, 'CH2=CH', 2, 'C=C', None, 1.1507, smarts=DOUFSG[5].smarts)
VTPRSG[6] = UNIFAC_subgroup(6, 'CH=CH', 2, 'C=C', None, 1.3221, smarts=DOUFSG[6].smarts)
VTPRSG[7] = UNIFAC_subgroup(7, 'CH2=C', 2, 'C=C', None, 0.9889, smarts=DOUFSG[7].smarts)
VTPRSG[8] = UNIFAC_subgroup(8, 'CH=C', 2, 'C=C', None, 0.6760, smarts=DOUFSG[8].smarts)
VTPRSG[70] = UNIFAC_subgroup(70, 'C=C', 2, 'C=C', None, 0.4850, smarts=DOUFSG[70].smarts)
VTPRSG[97] = UNIFAC_subgroup(97, 'Allene', 2, 'Allene', None, 1.1287, smarts=None)
VTPRSG[98] = UNIFAC_subgroup(98, '=CHCH=', 2, '=CHCH=', None, 1.7345, smarts=None)
VTPRSG[99] = UNIFAC_subgroup(99, '=CCH=', 2, '=CCH=', None, 3.5331, smarts=None)
VTPRSG[250] = UNIFAC_subgroup(250, 'H2C=CH2', 2, 'H2C=CH2', None, 0.6758, smarts=None)
VTPRSG[9] = UNIFAC_subgroup(9, 'ACH', 3, 'ACH', None, 0.4972, smarts=DOUFSG[9].smarts)
VTPRSG[10] = UNIFAC_subgroup(10, 'AC', 3, 'ACH', None, 0.1885, smarts=DOUFSG[10].smarts)
VTPRSG[11] = UNIFAC_subgroup(11, 'ACCH3', 4, 'ACCH2', None, 1.4843, smarts=DOUFSG[11].smarts)
VTPRSG[12] = UNIFAC_subgroup(12, 'ACCH2', 4, 'ACCH2', None, 1.1356, smarts=DOUFSG[12].smarts)
VTPRSG[13] = UNIFAC_subgroup(13, 'ACCH', 4, 'ACCH2', None, 0.4514, smarts=DOUFSG[13].smarts)
VTPRSG[14] = UNIFAC_subgroup(14, 'OH(P)', 5, 'OH', None, 1.0189, smarts=DOUFSG[14].smarts)
VTPRSG[81] = UNIFAC_subgroup(81, 'OH(S)', 5, 'OH', None, 0.9326, smarts=DOUFSG[81].smarts)
VTPRSG[82] = UNIFAC_subgroup(82, 'OH(T)', 5, 'OH', None, 0.8727, smarts=DOUFSG[82].smarts)
VTPRSG[15] = UNIFAC_subgroup(15, 'CH3OH', 6, 'CH3OH', None, 0.8779, smarts=DOUFSG[15].smarts)
VTPRSG[16] = UNIFAC_subgroup(16, 'H2O', 7, 'H2O', None, 1.5576, smarts=DOUFSG[16].smarts)
VTPRSG[17] = UNIFAC_subgroup(17, 'ACOH', 8, 'ACOH', None, 0.9013, smarts=DOUFSG[17].smarts)
VTPRSG[18] = UNIFAC_subgroup(18, 'CH3CO', 9, 'CH2CO', None, 1.448, smarts=DOUFSG[18].smarts)
VTPRSG[19] = UNIFAC_subgroup(19, 'CH2CO', 9, 'CH2CO', None, 1.18, smarts=DOUFSG[19].smarts)
VTPRSG[20] = UNIFAC_subgroup(20, 'CHO', 10, 'CHO', None, 0.948, smarts=DOUFSG[20].smarts)
VTPRSG[21] = UNIFAC_subgroup(21, 'CH3COO', 11, 'CCOO', None, 1.728, smarts=DOUFSG[21].smarts)
VTPRSG[22] = UNIFAC_subgroup(22, 'CH2COO', 11, 'CCOO', None, 1.42, smarts=DOUFSG[22].smarts)
VTPRSG[129] = UNIFAC_subgroup(129, 'CHCOO', 11, 'CCOO', None, 1.221, smarts=None)
VTPRSG[180] = UNIFAC_subgroup(180, 'CHCOO', 11, 'CCOO', None, 0.88, smarts=None)
VTPRSG[23] = UNIFAC_subgroup(23, 'HCOO', 12, 'HCOO', None, 1.1880, smarts=DOUFSG[23].smarts)
VTPRSG[24] = UNIFAC_subgroup(24, 'CH3O', 13, 'CH2O', None, 1.088, smarts=DOUFSG[24].smarts)
VTPRSG[25] = UNIFAC_subgroup(25, 'CH2O', 13, 'CH2O', None, 0.78, smarts=DOUFSG[25].smarts)
VTPRSG[26] = UNIFAC_subgroup(26, 'CHO', 13, 'CH2O', None, 0.468, smarts=DOUFSG[26].smarts)
VTPRSG[28] = UNIFAC_subgroup(28, 'CH3NH2', 14, 'CH2NH2', None, 1.2260, smarts=DOUFSG[28].smarts)
VTPRSG[29] = UNIFAC_subgroup(29, 'CH2NH2', 14, 'CH2NH2', None, 1.2360, smarts=DOUFSG[29].smarts)
VTPRSG[30] = UNIFAC_subgroup(30, 'CHNH2', 14, 'CH2NH2', None, 1.1868, smarts=DOUFSG[30].smarts)
VTPRSG[85] = UNIFAC_subgroup(85, 'CNH2', 14, 'CH2NH2', None, 1.1527, smarts=DOUFSG[85].smarts)
VTPRSG[31] = UNIFAC_subgroup(31, 'CH3NH', 15, 'CH2NH', None, 1.2440, smarts=DOUFSG[31].smarts)
VTPRSG[32] = UNIFAC_subgroup(32, 'CH2NH', 15, 'CH2NH', None, 0.936, smarts=DOUFSG[32].smarts)
VTPRSG[33] = UNIFAC_subgroup(33, 'CHNH', 15, 'CH2NH', None, 0.6240, smarts=DOUFSG[33].smarts)
VTPRSG[34] = UNIFAC_subgroup(34, 'CH3N', 16, '(C)3N', None, 0.94, smarts=DOUFSG[34].smarts)
VTPRSG[35] = UNIFAC_subgroup(35, 'CH2N', 16, '(C)3N', None, 0.632, smarts=DOUFSG[35].smarts)
VTPRSG[36] = UNIFAC_subgroup(36, 'ACNH2', 17, 'ACNH2', None, 0.8160, smarts=DOUFSG[36].smarts)
VTPRSG[40] = UNIFAC_subgroup(40, 'CH3CN', 19, 'CH2CN', None, 1.5302, smarts=DOUFSG[40].smarts)
VTPRSG[41] = UNIFAC_subgroup(41, 'CH2CN', 19, 'CH2CN', None, 1.4492, smarts=DOUFSG[41].smarts)
VTPRSG[44] = UNIFAC_subgroup(44, 'CH2CL', 21, 'CCL', None, 1.264, smarts=DOUFSG[44].smarts)
VTPRSG[45] = UNIFAC_subgroup(45, 'CHCL', 21, 'CCL', None, 0.952, smarts=DOUFSG[45].smarts)
VTPRSG[46] = UNIFAC_subgroup(46, 'CCL', 21, 'CCL', None, 0.724, smarts=DOUFSG[46].smarts)
VTPRSG[47] = UNIFAC_subgroup(47, 'CH2CL2', 22, 'CCL2', None, 1.9880, smarts=DOUFSG[47].smarts)
VTPRSG[48] = UNIFAC_subgroup(48, 'CHCL2', 22, 'CCL2', None, 1.6840, smarts=DOUFSG[48].smarts)
VTPRSG[49] = UNIFAC_subgroup(49, 'CCL2', 22, 'CCL2', None, 1.4480, smarts=DOUFSG[49].smarts)
VTPRSG[51] = UNIFAC_subgroup(51, 'CCL3', 23, 'CCL3', None, 2.1840, smarts=DOUFSG[51].smarts)
VTPRSG[52] = UNIFAC_subgroup(52, 'CCL4', 24, 'CCL4', None, 3.1836, smarts=DOUFSG[52].smarts)
VTPRSG[53] = UNIFAC_subgroup(53, 'ACCL', 25, 'ACCL', None, 0.3177, smarts=DOUFSG[53].smarts) # Q not verified - from DO, not listed, in 2016 paper
VTPRSG[59] = UNIFAC_subgroup(59, 'CH3SH', 29, 'CH3SH', None, 1.762, smarts=DOUFSG[59].smarts)# Q not verified - from DO, not listed, in 2016 paper
VTPRSG[60] = UNIFAC_subgroup(60, 'CH2SH', 29, 'CH3SH', None, 1.316, smarts=DOUFSG[60].smarts)# Q not verified - from DO, not listed, in 2016 paper
VTPRSG[58] = UNIFAC_subgroup(58, 'CS2', 28, 'CS2', None, 1.65, smarts=DOUFSG[58].smarts)
VTPRSG[61] = UNIFAC_subgroup(61, 'FURFURAL', 30, 'FURFURAL', None, 2.0363, smarts=DOUFSG[61].smarts)
VTPRSG[62] = UNIFAC_subgroup(62, 'DOH', 31, 'DOH', None, 2.2480, smarts=DOUFSG[62].smarts)
VTPRSG[63] = UNIFAC_subgroup(63, 'I', 32, 'I', None, 0.9920, smarts=DOUFSG[63].smarts)
VTPRSG[64] = UNIFAC_subgroup(64, 'BR', 33, 'BR', None, 0.8320, smarts=DOUFSG[64].smarts)
VTPRSG[67] = UNIFAC_subgroup(67, 'DMSO', 35, 'DMSO', None, 2.4720, smarts=DOUFSG[67].smarts)
VTPRSG[72] = UNIFAC_subgroup(72, 'DMF', 39, 'DMF', None, 2.7360, smarts=DOUFSG[72].smarts)
VTPRSG[73] = UNIFAC_subgroup(73, 'HCON(..', 39, 'DMF', None, 2.1200, smarts=DOUFSG[73].smarts)
VTPRSG[78] = UNIFAC_subgroup(78, 'CY-CH2', 42, 'CY-CH2', None, 0.8635, smarts=DOUFSG[78].smarts)
VTPRSG[79] = UNIFAC_subgroup(79, 'CY-CH', 42, 'CY-CH2', None, 0.1071, smarts=DOUFSG[79].smarts)
VTPRSG[80] = UNIFAC_subgroup(80, 'CY-C', 42, 'CY-CH2', None, 0, smarts=DOUFSG[80].smarts)
VTPRSG[27] = UNIFAC_subgroup(27, 'THF', 43, 'CY-CH2O', None, 2.3637, smarts=DOUFSG[27].smarts)
VTPRSG[83] = UNIFAC_subgroup(83, 'CY-CH2O', 43, 'CY-CH2O', None, 1.4, smarts=DOUFSG[83].smarts)
VTPRSG[84] = UNIFAC_subgroup(84, 'TRIOXAN', 43, 'CY-CH2O', None, 1.0116, smarts=DOUFSG[84].smarts)
VTPRSG[50] = UNIFAC_subgroup(50, 'CHCL3', 45, 'CHCL3', None, 2.4100, smarts=DOUFSG[50].smarts)
VTPRSG[86] = UNIFAC_subgroup(86, 'NMP', 46, 'CY-CONC', None, 3.2, smarts=DOUFSG[86].smarts)
VTPRSG[87] = UNIFAC_subgroup(87, 'NEP', 46, 'CY-CONC', None, 2.892, smarts=DOUFSG[87].smarts)
VTPRSG[88] = UNIFAC_subgroup(88, 'NIPP', 46, 'CY-CONC', None, 2.58, smarts=DOUFSG[88].smarts)
VTPRSG[89] = UNIFAC_subgroup(89, 'NTBP', 46, 'CY-CONC', None, 2.352, smarts=DOUFSG[89].smarts)
VTPRSG[107] = UNIFAC_subgroup(107, 'H2COCH', 53, 'EPOXIDES', None, 1.8031, smarts=DOUFSG[107].smarts)
VTPRSG[108] = UNIFAC_subgroup(108, 'COCH', 53, 'EPOXIDES', None, 0.3418, smarts=DOUFSG[108].smarts)
VTPRSG[109] = UNIFAC_subgroup(109, 'HCOCH', 53, 'EPOXIDES', None, 0.6538, smarts=DOUFSG[109].smarts)
VTPRSG[119] = UNIFAC_subgroup(119, 'H2COCH2', 53, 'EPOXIDES', None, 1.123, smarts=DOUFSG[119].smarts)
VTPRSG[153] = UNIFAC_subgroup(153, 'H2COC', 53, 'EPOXIDES', None, 0.6538, smarts=DOUFSG[153].smarts)
VTPRSG[116] = UNIFAC_subgroup(116, 'AC-CHO', 57, 'AC-CHO', None, 1.0, smarts=None)
VTPRSG[139] = UNIFAC_subgroup(139, 'CF2H', 68, 'CF2H', None, 1.6643, smarts=None)
VTPRSG[140] = UNIFAC_subgroup(140, 'CF2H2', 68, 'CF2H', None, 1.3304, smarts=None)
VTPRSG[142] = UNIFAC_subgroup(142, 'CF2Cl', 70, 'CF2Cl2', None, 1.8506, smarts=None)
VTPRSG[143] = UNIFAC_subgroup(143, 'CF2Cl2', 70, 'CF2Cl2', None, 2.5974, smarts=None)
VTPRSG[148] = UNIFAC_subgroup(148, 'CF3Br', 70, 'CF2Cl2', None, 2.5104, smarts=None)
VTPRSG[146] = UNIFAC_subgroup(146, 'CF4', 73, 'CF4', None, 1.8400, smarts=None)
VTPRSG[300] = UNIFAC_subgroup(300, 'NH3', 150, 'NH3', None, 0.7780, smarts=None)
VTPRSG[306] = UNIFAC_subgroup(306, 'CO2', 151, 'CO2', None, 0.982, smarts=None)
VTPRSG[307] = UNIFAC_subgroup(307, 'CH4', 152, 'CH4', None, 1.124, smarts=None)
VTPRSG[308] = UNIFAC_subgroup(308, 'O2', 153, 'O2', None, 0.849, smarts=None)
VTPRSG[305] = UNIFAC_subgroup(305, 'Ar', 154, 'Ar', None, 1.116, smarts=None)
VTPRSG[304] = UNIFAC_subgroup(304, 'N2', 155, 'N2', None, 0.93, smarts=None)
VTPRSG[303] = UNIFAC_subgroup(303, 'H2S', 156, 'H2S', None, 1.202, smarts=None)
VTPRSG[302] = UNIFAC_subgroup(302, 'H2', 157, 'H2', None, 0.571, smarts=None)
VTPRSG[309] = UNIFAC_subgroup(309, 'D2', 157, 'D2', None, 0.527, smarts=None)
VTPRSG[301] = UNIFAC_subgroup(301, 'CO', 158, 'CO', None, 0.8280, smarts=None)
VTPRSG[310] = UNIFAC_subgroup(310, 'SO2', 160, 'SO2', None, 1.1640, smarts=None)
VTPRSG[312] = UNIFAC_subgroup(312, 'N2O', 162, 'N2O', None, 0.8880, smarts=None)
VTPRSG[314] = UNIFAC_subgroup(314, 'He', 164, 'He', None, 0.9850, smarts=None)
VTPRSG[315] = UNIFAC_subgroup(315, 'Ne', 165, 'Ne', None, 0.9860, smarts=None)
VTPRSG[319] = UNIFAC_subgroup(319, 'HCl', 169, 'HCl', None, 1.2560, smarts=None)
VTPRSG[345] = UNIFAC_subgroup(345, 'Hg', 185, 'Hg', None, 7.9616, smarts=None)
# From Present Status of the Group Contribution Equation of State VTPR and Typical Applications for Process Development
VTPRSG[54] = UNIFAC_subgroup(54, 'CH3NO2', 26, 'CNO2', None, 1.8285, smarts=DOUFSG[54].smarts)
VTPRSG[55] = UNIFAC_subgroup(55, 'CH2NO2', 26, 'CNO2', None, 1.56, smarts=DOUFSG[55].smarts)
VTPRSG[56] = UNIFAC_subgroup(56, 'CHNO2', 26, 'CNO2', None, 1.248, smarts=DOUFSG[56].smarts)
VTPRMG = {1: ("CH2", [1, 2, 3, 4]),
2: ("H2C=CH2", [5, 6, 7, 8, 70, 97, 98, 99, 250]),
3: ("ACH", [9, 10]),
4: ("ACCH2", [11, 12, 13]),
5: ("OH", [14, 81, 82]),
6: ("CH3OH", [15]),
7: ("H2O", [16]),
8: ("ACOH", [17]),
9: ("CH2CO", [18, 19]),
10: ("CHO", [20]),
11: ("CCOO", [21, 22, 129, 180]),
12: ("HCOO", [23]),
13: ("CH2O", [24, 25, 26]),
14: ("CH2NH2", [28, 29, 30, 85]),
15: ("CH2NH", [31, 32, 33]),
16: ("(C)3N", [34, 35]),
17: ("ACNH2", [36]),
19: ("CH2CN", [40, 41]),
21: ("CCL", [44, 45, 46]),
22: ("CCL2", [47, 48, 49]),
23: ("CCL3", [51]),
24: ("CCL4", [52]),
25: ("ACCL", [53]),
26: ("CNO2", [54, 55, 56]),
28: ("CS2", [58]),
29: ("CH3SH", [59, 60]),
30: ("FURFURAL", [61]),
31: ("DOH", [62]),
32: ("I", [63]),
33: ("BR", [64]),
35: ("DMSO", [67]),
39: ("DMF", [72, 73]),
42: ("CY-CH2", [78, 79, 80]),
43: ("CY-CH2O", [27, 83, 84]),
45: ("CHCL3", [50]),
46: ("CY-CONC", [86, 87, 88, 89]),
53: ("EPOXIDES", [107, 108, 109, 119, 153]),
57: ("AC-CHO", [116]),
68: ("CF2H", [139, 140]),
70: ("CF2Cl2", [142, 143, 148]),
73: ("CF4", [146]),
150: ("NH3", [300]),
151: ("CO2", [306]),
152: ("CH4", [307]),
153: ("O2", [308]),
154: ("Ar", [305]),
155: ("N2", [304]),
156: ("H2S", [303]),
157: ("D2", [302, 309]),
158: ("CO", [301]),
160: ("SO2", [310]),
162: ("N2O", [312]),
164: ("He", [314]),
165: ("Ne", [315]),
169: ("HCl", [319]),
185: ("Hg", [345]),
}
NISTUFMG = {}
# From Kang and Diky and Chirico and Magee and Muzny and Abdulagatov and Kazakov and Frenkel - 2011 - A new method for evaluation of UNIFAC interaction parameters
# + Some information extracted from below
NISTUFMG[1] = ('CH2', [1, 2, 3, 4], 'Alkyl chains')
NISTUFMG[2] = ('C=C', [5, 6, 7, 8, 9], 'Double bonded alkyl chains')
NISTUFMG[3] = ('ACH', [15, 16, 17], 'Aromatic carbon')
NISTUFMG[4] = ('ACCH2', [18, 19, 20, 21], 'Aromatic carbon plus alkyl chain')
NISTUFMG[5] = ('OH', [34, 204, 205], 'Alcohols')
NISTUFMG[6] = ('CH3OH', [35], 'Methanol')
NISTUFMG[7] = ('H2O', [36], 'Water')
NISTUFMG[8] = ('ACOH', [37], 'Phenolic –OH groups ')
NISTUFMG[9] = ('CH2CO', [42, 43, 44, 45], 'Ketones')
NISTUFMG[10] = ('CHO', [48], 'Aldehydes')
NISTUFMG[11] = ('CCOO', [51, 52, 53, 54], 'Esters')
NISTUFMG[12] = ('HCOO', [55], 'Formates')
NISTUFMG[13] = ('CH2O', [59, 60, 61, 62, 63], 'Ethers')
NISTUFMG[14] = ('CNH2', [66, 67, 68, 69], 'Amines with 1-alkyl group')
NISTUFMG[15] = ('(C)2NH', [71, 72, 73], 'Amines with 2-alkyl groups')
NISTUFMG[16] = ('(C)3N', [74, 75], 'Amines with 3-alkyl groups')
NISTUFMG[17] = ('ACNH2', [79, 80, 81], 'Anilines')
NISTUFMG[18] = ('PYRIDINE', [76, 77, 78], 'Pyridines')
NISTUFMG[19] = ('CCN', [85, 86, 87, 88], 'Nitriles')
NISTUFMG[20] = ('COOH', [94, 95], 'Acids')
NISTUFMG[21] = ('CCl', [99, 100, 101], 'Chlorocarbons')
NISTUFMG[22] = ('CCl2', [102, 103, 104], 'Dichlorocarbons')
NISTUFMG[23] = ('CCl3', [105, 106], 'Trichlorocarbons')
NISTUFMG[24] = ('CCl4', [107], 'Tetrachlorocarbons')
NISTUFMG[25] = ('ACCl', [109], 'Chloroaromatics')
NISTUFMG[26] = ('CNO2', [132, 133, 134, 135], 'Nitro alkanes')
NISTUFMG[27] = ('ACNO2', [136], 'Nitroaromatics')
NISTUFMG[28] = ('CS2', [146], 'Carbon disulfide')
NISTUFMG[29] = ('CH3SH', [138, 139, 140, 141], 'Mercaptans')
NISTUFMG[30] = ('FURFURAL', [50], 'Furfural')
NISTUFMG[31] = ('DOH', [38], 'Ethylene Glycol')
NISTUFMG[32] = ('I', [128], 'Iodides')
NISTUFMG[33] = ('BR', [130], 'Bromides')
NISTUFMG[34] = ('C≡C', [13, 14], 'Triplebonded alkyl chains')
NISTUFMG[35] = ('DMSO', [153], 'Dimethylsulfoxide')
NISTUFMG[36] = ('ACRY', [90], 'Acrylic')
NISTUFMG[37] = ('ClC=C', [108], 'Chlorine attached to double bonded alkyl chain')
NISTUFMG[38] = ('ACF', [118], 'Fluoroaromatics')
NISTUFMG[39] = ('DMF', [161, 162, 163, 164, 165], 'Amides')
NISTUFMG[40] = ('CF2', [111, 112, 113, 114, 115, 116, 117], 'Fluorines')
NISTUFMG[41] = ('COO', [58], 'Esters')
NISTUFMG[42] = ('SiH2', [197, 198, 199, 200], 'Silanes')
NISTUFMG[43] = ('SiO', [201, 202, 203], 'Siloxanes')
NISTUFMG[44] = ('NMP', [195], 'N-Methyl-2-pyrrolidone')
NISTUFMG[45] = ('CClF', [120, 121, 122, 123, 124, 125, 126, 127], 'Chloro-Fluorides')
NISTUFMG[46] = ('CONCH2', [166, 167, 168, 169], 'Amides')
NISTUFMG[47] = ('OCCOH', [39, 40, 41], 'Oxygenated Alcohols')
NISTUFMG[48] = ('CH2S', [142, 143, 144, 145], 'Sulfides')
NISTUFMG[49] = ('MORPHOLIN', [196], 'Morpholine')
NISTUFMG[50] = ('THIOPHENE', [147, 148, 149], 'Thiophene')
NISTUFMG[51] = ('CH2(cy)', [27, 28, 29], 'Cyclic hydrocarbon chains')
NISTUFMG[52] = ('C=C(cy)', [30, 31, 32], 'Cyclic unsaturated hydrocarbon chains')
# Added
NISTUFSG = {}
NISTUFSG[1] = UNIFAC_subgroup(1, 'CH3', 1, 'CH2', 0.6325, 1.0608)
NISTUFSG[2] = UNIFAC_subgroup(2, 'CH2', 1, 'CH2', 0.6325, 0.7081)
NISTUFSG[3] = UNIFAC_subgroup(3, 'CH', 1, 'CH2', 0.6325, 0.3554)
NISTUFSG[4] = UNIFAC_subgroup(4, 'C', 1, 'CH2', 0.6325, 0)
NISTUFSG[5] = UNIFAC_subgroup(5, 'CH2=CH', 2, 'C=C', 1.2832, 1.6016)
NISTUFSG[6] = UNIFAC_subgroup(6, 'CH=CH', 2, 'C=C', 1.2832, 1.2489)
NISTUFSG[7] = UNIFAC_subgroup(7, 'CH2=C', 2, 'C=C', 1.2832, 1.2489)
NISTUFSG[8] = UNIFAC_subgroup(8, 'CH=C', 2, 'C=C', 1.2832, 0.8962)
NISTUFSG[70] = UNIFAC_subgroup(70, 'C=C', 2, 'C=C', 1.2832, 0.4582)
NISTUFSG[9] = UNIFAC_subgroup(9, 'ACH', 3, 'ACH', 0.3763, 0.4321)
NISTUFSG[10] = UNIFAC_subgroup(10, 'AC', 3, 'ACH', 0.3763, 0.2113)
NISTUFSG[11] = UNIFAC_subgroup(11, 'ACCH3', 4, 'ACCH2', 0.91, 0.949)
NISTUFSG[12] = UNIFAC_subgroup(12, 'ACCH2', 4, 'ACCH2', 0.91, 0.7962)
NISTUFSG[13] = UNIFAC_subgroup(13, 'ACCH', 4, 'ACCH2', 0.91, 0.3769)
NISTUFSG[195] = UNIFAC_subgroup(195, 'ACC', 4, 'ACCH2', 0.5847, 0.12)
NISTUFSG[14] = UNIFAC_subgroup(14, 'OH prim', 5, 'OH', 1.2302, 0.8927)
NISTUFSG[81] = UNIFAC_subgroup(81, 'OH sec', 5, 'OH', 1.063, 0.8663)
NISTUFSG[82] = UNIFAC_subgroup(82, 'OH tert', 5, 'OH', 0.6895, 0.8345)
NISTUFSG[15] = UNIFAC_subgroup(15, 'CH3OH', 6, 'CH3OH', 0.8585, 0.9938)
NISTUFSG[16] = UNIFAC_subgroup(16, 'H2O', 7, 'H2O', 1.7334, 2.4561)
NISTUFSG[17] = UNIFAC_subgroup(17, 'ACOH', 8, 'ACOH', 1.08, 0.975)
NISTUFSG[18] = UNIFAC_subgroup(18, 'CH3CO', 9, 'CH2CO', 1.7048, 1.67)
NISTUFSG[19] = UNIFAC_subgroup(19, 'CH2CO', 9, 'CH2CO', 1.7048, 1.5542)
NISTUFSG[301] = UNIFAC_subgroup(301, 'CHCO', 9, 'CH2CO', 1.7048, 1.5542)
NISTUFSG[302] = UNIFAC_subgroup(302, 'CCO', 9, 'CH2CO', 1.7048, 1.5542)
NISTUFSG[20] = UNIFAC_subgroup(20, 'CHO', 10, 'CHO', 0.7173, 0.771)
NISTUFSG[308] = UNIFAC_subgroup(308, 'HCHO', 10, 'CHO', 0.7173, 0.771)
NISTUFSG[21] = UNIFAC_subgroup(21, 'CH3COO', 11, 'CCOO', 1.27, 1.6286)
NISTUFSG[22] = UNIFAC_subgroup(22, 'CH2COO', 11, 'CCOO', 1.27, 1.4228)
NISTUFSG[23] = UNIFAC_subgroup(23, 'HCOO', 12, 'HCOO', 1.9, 1.8)
NISTUFSG[24] = UNIFAC_subgroup(24, 'CH3O', 13, 'CH2O', 1.1434, 1.6022)
NISTUFSG[25] = UNIFAC_subgroup(25, 'CH2O', 13, 'CH2O', 1.1434, 1.2495)
NISTUFSG[26] = UNIFAC_subgroup(26, 'CHO', 13, 'CH2O', 1.1434, 0.8968)
NISTUFSG[28] = UNIFAC_subgroup(28, 'CH3NH2', 14, 'CNH2', 1.6607, 1.6904)
NISTUFSG[29] = UNIFAC_subgroup(29, 'CH2NH2', 14, 'CNH2', 1.6607, 1.3377)
NISTUFSG[30] = UNIFAC_subgroup(30, 'CHNH2', 14, 'CNH2', 1.6607, 0.985)
NISTUFSG[85] = UNIFAC_subgroup(85, 'CNH2', 14, 'CNH2', 1.6607, 0.985)
NISTUFSG[31] = UNIFAC_subgroup(31, 'CH3NH', 15, 'CNH', 1.368, 1.4332)
NISTUFSG[32] = UNIFAC_subgroup(32, 'CH2NH', 15, 'CNH', 1.368, 1.0805)
NISTUFSG[33] = UNIFAC_subgroup(33, 'CHNH', 15, 'CNH', 1.368, 0.7278)
NISTUFSG[34] = UNIFAC_subgroup(34, 'CH3N', 16, '(C)3N', 1.0746, 1.176)
NISTUFSG[35] = UNIFAC_subgroup(35, 'CH2N', 16, '(C)3N', 1.0746, 0.824)
NISTUFSG[36] = UNIFAC_subgroup(36, 'ACNH2', 17, 'ACNH2', 1.1849, 0.8067)
NISTUFSG[306] = UNIFAC_subgroup(306, 'ACNH', 17, 'ACNH2', 1.1849, 0.732)
NISTUFSG[307] = UNIFAC_subgroup(307, 'ACN', 17, 'ACNH2', 1.1849, 0.61)
NISTUFSG[37] = UNIFAC_subgroup(37, 'AC2H2N', 18, 'Pyridine', 1.4578, 0.9022)
NISTUFSG[38] = UNIFAC_subgroup(38, 'AC2HN', 18, 'Pyridine', 1.2393, 0.633)
NISTUFSG[39] = UNIFAC_subgroup(39, 'AC2N', 18, 'Pyridine', 1.0731, 0.353)
NISTUFSG[196] = UNIFAC_subgroup(196, 'AC2H2NH', 94, 'Pyrrole', 1.325, 0.752)
NISTUFSG[197] = UNIFAC_subgroup(197, 'AC2HNH', 94, 'Pyrrole', 1.0976, 0.44)
NISTUFSG[198] = UNIFAC_subgroup(198, 'AC2NH', 94, 'Pyrrole', 0.8701, 0.212)
NISTUFSG[40] = UNIFAC_subgroup(40, 'CH3CN', 19, 'CCN', 1.5575, 1.5193)
NISTUFSG[41] = UNIFAC_subgroup(41, 'CH2CN', 19, 'CCN', 1.5575, 1.1666)
NISTUFSG[303] = UNIFAC_subgroup(303, 'CHCN', 19, 'CCN', 1.5575, 1.1666)
NISTUFSG[304] = UNIFAC_subgroup(304, 'CCN', 19, 'CCN', 1.5575, 1.1666)
NISTUFSG[42] = UNIFAC_subgroup(42, 'COOH', 20, 'COOH', 0.8, 0.9215)
NISTUFSG[44] = UNIFAC_subgroup(44, 'CH2Cl', 21, 'CCl', 0.9919, 1.3654)
NISTUFSG[45] = UNIFAC_subgroup(45, 'CHCl', 21, 'CCl', 0.9919, 1.0127)
NISTUFSG[46] = UNIFAC_subgroup(46, 'CCl', 21, 'CCl', 0.9919, 0.66)
NISTUFSG[47] = UNIFAC_subgroup(47, 'CH2Cl2', 22, 'CCl2', 1.8, 2.5)
NISTUFSG[48] = UNIFAC_subgroup(48, 'CHCl2', 22, 'CCl2', 1.8, 2.1473)
NISTUFSG[49] = UNIFAC_subgroup(49, 'CCl2', 22, 'CCl2', 1.8, 1.7946)
NISTUFSG[51] = UNIFAC_subgroup(51, 'CCl3', 23, 'CCl3', 2.65, 2.3778)
NISTUFSG[52] = UNIFAC_subgroup(52, 'CCl4', 52, 'CCl4', 2.618, 3.1863)
NISTUFSG[53] = UNIFAC_subgroup(53, 'ACCl', 53, 'ACCl', 0.5365, 0.3177)
NISTUFSG[54] = UNIFAC_subgroup(54, 'CH3NO2', 26, 'CNO2', 2.644, 2.5)
NISTUFSG[55] = UNIFAC_subgroup(55, 'CH2NO2', 26, 'CNO2', 2.5, 2.304)
NISTUFSG[56] = UNIFAC_subgroup(56, 'CHNO2', 26, 'CNO2', 2.887, 2.241)
NISTUFSG[305] = UNIFAC_subgroup(305, 'CNO2', 26, 'CNO2', 2.887, 2.241)
NISTUFSG[57] = UNIFAC_subgroup(57, 'ACNO2', 27, 'ACNO2', 0.4656, 0.3589)
NISTUFSG[58] = UNIFAC_subgroup(58, 'CS2', 28, 'CS2', 1.24, 1.068)
NISTUFSG[59] = UNIFAC_subgroup(59, 'CH3SH', 29, 'CH2SH', 1.289, 1.762)
NISTUFSG[60] = UNIFAC_subgroup(60, 'CH2SH', 29, 'CH2SH', 1.535, 1.316)
NISTUFSG[192] = UNIFAC_subgroup(192, 'CHSH', 29, 'CH2SH', 1.4232, 1.21)
NISTUFSG[193] = UNIFAC_subgroup(193, 'CSH', 29, 'CH2SH', 1.1958, 1.1401)
NISTUFSG[194] = UNIFAC_subgroup(194, 'ACSH', 29, 'CH2SH', 1.2887, 1.2)
NISTUFSG[61] = UNIFAC_subgroup(61, 'Furfural', 30, 'Furfural', 1.299, 1.289)
NISTUFSG[62] = UNIFAC_subgroup(62, 'CH2(OH)-CH2(OH)', 31, 'DOH', 3.7374, 3.2016)
NISTUFSG[205] = UNIFAC_subgroup(205, '-CH(OH)-CH2(OH)', 31, 'DOH', 3.5642, 2.8225)
NISTUFSG[206] = UNIFAC_subgroup(206, '-CH(OH)-CH(OH)-', 31, 'DOH', 3.391, 2.4434)
NISTUFSG[207] = UNIFAC_subgroup(207, '>C(OH)-CH2(OH)', 31, 'DOH', 3.1847, 2.1144)
NISTUFSG[208] = UNIFAC_subgroup(208, '>C(OH)-CH(OH)-', 31, 'DOH', 3.0175, 2.0562)
NISTUFSG[209] = UNIFAC_subgroup(209, '>C(OH)-C(OH)<', 31, 'DOH', 2.644, 1.669)
NISTUFSG[63] = UNIFAC_subgroup(63, 'I', 32, 'I', 1.076, 0.9169)
NISTUFSG[64] = UNIFAC_subgroup(64, 'Br', 33, 'Br', 1.209, 1.4)
NISTUFSG[65] = UNIFAC_subgroup(65, 'CH#C', 34, 'C#C', 0.9214, 1.3)
NISTUFSG[66] = UNIFAC_subgroup(66, 'C#C', 34, 'C#C', 1.303, 1.132)
NISTUFSG[67] = UNIFAC_subgroup(67, 'DMSO', 35, 'DMSO', 3.6, 2.692)
NISTUFSG[68] = UNIFAC_subgroup(68, 'Acrylonitrile', 36, 'Acrylonitrile', 1, 0.92)
NISTUFSG[69] = UNIFAC_subgroup(69, 'Cl-(C=C)', 37, 'Cl-(C=C)', 0.5229, 0.7391)
NISTUFSG[71] = UNIFAC_subgroup(71, 'ACF', 38, 'ACF', 0.8814, 0.7269)
NISTUFSG[72] = UNIFAC_subgroup(72, 'DMF', 39, 'DMF', 2, 2.093)
NISTUFSG[73] = UNIFAC_subgroup(73, 'HCON(CH2)2', 39, 'DMF', 2.381, 1.522)
NISTUFSG[74] = UNIFAC_subgroup(74, 'CF3', 40, 'CF2', 2.7489, 2.7769)
NISTUFSG[75] = UNIFAC_subgroup(75, 'CF2', 40, 'CF2', 1.4778, 1.4738)
NISTUFSG[76] = UNIFAC_subgroup(76, 'CF', 40, 'CF2', 0.8215, 0.5135)
NISTUFSG[77] = UNIFAC_subgroup(77, 'COO', 41, 'COO', 1.6, 0.9)
NISTUFSG[78] = UNIFAC_subgroup(78, 'c-CH2', 42, 'c-CH2', 0.7136, 0.8635)
NISTUFSG[79] = UNIFAC_subgroup(79, 'c-CH', 42, 'c-CH2', 0.3479, 0.1071)
NISTUFSG[80] = UNIFAC_subgroup(80, 'c-C', 42, 'c-CH2', 0.347, 0)
NISTUFSG[27] = UNIFAC_subgroup(27, 'CH2-O-CH2', 43, 'c-CH2O', 1.7023, 1.8784)
NISTUFSG[83] = UNIFAC_subgroup(83, 'CH2-O-[CH2-O]1/2', 43, 'c-CH2O', 1.4046, 1.4)
NISTUFSG[84] = UNIFAC_subgroup(84, '[O-CH2]1/2-O-[CH2-O]1/2', 43, 'c-CH2O', 1.0413, 1.0116)
NISTUFSG[43] = UNIFAC_subgroup(43, 'HCOOH', 44, 'HCOOH', 0.8, 1.2742)
NISTUFSG[50] = UNIFAC_subgroup(50, 'CHCl3', 45, 'CHCl3', 2.45, 2.8912)
NISTUFSG[86] = UNIFAC_subgroup(86, 'c-CON-CH3', 46, 'c-CONC', 3.981, 3.2)
NISTUFSG[87] = UNIFAC_subgroup(87, 'c-CON-CH2', 46, 'c-CONC', 3.7543, 2.892)
NISTUFSG[88] = UNIFAC_subgroup(88, 'c-CON-CH', 46, 'c-CONC', 3.5268, 2.58)
NISTUFSG[89] = UNIFAC_subgroup(89, 'c-CON-C', 46, 'c-CONC', 3.2994, 2.352)
NISTUFSG[92] = UNIFAC_subgroup(92, 'CONHCH3', 47, 'CONR', 1.5, 1.08)
NISTUFSG[100] = UNIFAC_subgroup(100, 'CONHCH2', 47, 'CONR', 1.5, 1.08)
NISTUFSG[101] = UNIFAC_subgroup(101, 'CON(CH3)2', 48, 'CONR2', 2.4748, 1.9643)
NISTUFSG[102] = UNIFAC_subgroup(102, 'CON(CH3)CH2', 48, 'CONR2', 2.2739, 1.5754)
NISTUFSG[103] = UNIFAC_subgroup(103, 'CON(CH2)2', 48, 'CONR2', 2.0767, 1.1866)
NISTUFSG[93] = UNIFAC_subgroup(93, 'HCONHCH3', 49, 'HCONR', 2.4617, 2.192)
NISTUFSG[94] = UNIFAC_subgroup(94, 'HCONHCH2', 49, 'HCONR', 2.4617, 1.842)
NISTUFSG[116] = UNIFAC_subgroup(116, 'ACCN', 50, 'ACCN', 1.2815, 0.96)
NISTUFSG[117] = UNIFAC_subgroup(117, 'CH3NCO', 51, 'NCO', 1.9578, 1.58)
NISTUFSG[118] = UNIFAC_subgroup(118, 'CH2NCO', 51, 'NCO', 1.731, 1.272)
NISTUFSG[119] = UNIFAC_subgroup(119, 'CHNCO', 51, 'NCO', 1.5036, 0.96)
NISTUFSG[120] = UNIFAC_subgroup(120, 'ACNCO', 51, 'NCO', 1.4219, 0.852)
NISTUFSG[104] = UNIFAC_subgroup(104, 'AC2H2S', 52, 'ACS', 1.7943, 1.34)
NISTUFSG[105] = UNIFAC_subgroup(105, 'AC2HS', 52, 'ACS', 1.6282, 1.06)
NISTUFSG[106] = UNIFAC_subgroup(106, 'AC2S', 52, 'ACS', 1.4621, 0.78)
NISTUFSG[107] = UNIFAC_subgroup(107, 'H2COCH', 53, 'Epoxy', 1.3601, 1.8031)
NISTUFSG[109] = UNIFAC_subgroup(109, 'HCOCH', 53, 'Epoxy', 0.9104, 0.6538)
NISTUFSG[121] = UNIFAC_subgroup(121, 'COOCO', 54, 'Anhydride', 1.7732, 1.52)
NISTUFSG[112] = UNIFAC_subgroup(112, '(CH3O)2CO', 55, 'Carbonate', 3.0613, 2.816)
NISTUFSG[113] = UNIFAC_subgroup(113, '(CH2O)2CO', 55, 'Carbonate', 2.6078, 2.2)
NISTUFSG[114] = UNIFAC_subgroup(114, '(CH3O)COOCH2', 55, 'Carbonate', 2.8214, 2.508)
NISTUFSG[199] = UNIFAC_subgroup(199, '(ACO)COOCH2', 55, 'Carbonate', 2.2854, 1.78)
NISTUFSG[200] = UNIFAC_subgroup(200, '(ACO)CO(OAC)', 55, 'Carbonate', 1.9895, 1.36)
NISTUFSG[110] = UNIFAC_subgroup(110, 'CH2SuCH2', 56, 'Sulfone', 2.687, 2.12)
NISTUFSG[111] = UNIFAC_subgroup(111, 'CH2SuCH ', 56, 'Sulfone', 2.46, 1.808)
NISTUFSG[122] = UNIFAC_subgroup(122, 'ACSO2', 56, 'Sulfone', 1.7034, 1.16)
NISTUFSG[123] = UNIFAC_subgroup(123, 'ACCHO', 57, 'ACCHO', 1.3632, 1.068)
NISTUFSG[124] = UNIFAC_subgroup(124, 'ACCOOH', 58, 'ACCOOH', 1.6664, 1.344)
NISTUFSG[127] = UNIFAC_subgroup(127, 'AC-O-CO-CH3 ', 59, 'AC-O-CO', 2.2815, 1.848)
NISTUFSG[128] = UNIFAC_subgroup(128, 'AC-O-CO-CH2', 59, 'AC-O-CO', 2.0547, 1.54)
NISTUFSG[129] = UNIFAC_subgroup(129, 'AC-O-CO-CH', 59, 'AC-O-CO', 1.8273, 1.228)
NISTUFSG[130] = UNIFAC_subgroup(130, 'AC-O-CO-C', 59, 'AC-O-CO', 1.5999, 1)
NISTUFSG[131] = UNIFAC_subgroup(131, '-O-CH2-CH2-OH', 60, 'OCCOH', 2.1226, 1.904)
NISTUFSG[132] = UNIFAC_subgroup(132, '-O-CH-CH2-OH', 60, 'OCCOH', 1.8952, 1.592)
NISTUFSG[133] = UNIFAC_subgroup(133, '-O-CH2-CH-OH', 60, 'OCCOH', 1.8952, 1.592)
NISTUFSG[134] = UNIFAC_subgroup(134, 'CH3-S-', 61, 'CH2S', 1.6131, 1.368)
NISTUFSG[135] = UNIFAC_subgroup(135, '-CH2-S-', 61, 'CH2S', 1.3863, 1.06)
NISTUFSG[136] = UNIFAC_subgroup(136, '>CH-S-', 61, 'CH2S', 1.1589, 0.748)
NISTUFSG[137] = UNIFAC_subgroup(137, '->C-S-', 61, 'CH2S', 0.9314, 0.52)
NISTUFSG[187] = UNIFAC_subgroup(187, 'ACS', 61, 'CH2S', 1.0771, 0.64)
NISTUFSG[125] = UNIFAC_subgroup(125, 'c-CO-NH', 62, 'Lactam', 1.3039, 1.036)
NISTUFSG[126] = UNIFAC_subgroup(126, 'c-CO-O', 63, 'Lactone', 1.0152, 0.88)
NISTUFSG[138] = UNIFAC_subgroup(138, 'CH3O-(O)', 64, 'Peroxide', 1.3889, 1.328)
NISTUFSG[139] = UNIFAC_subgroup(139, 'CH2O-(O)', 64, 'Peroxide', 1.1622, 1.02)
NISTUFSG[140] = UNIFAC_subgroup(140, 'CHO-(O)', 64, 'Peroxide', 0.9347, 0.708)
NISTUFSG[141] = UNIFAC_subgroup(141, 'CO-(O)', 64, 'Peroxide', 1.0152, 0.88)
NISTUFSG[142] = UNIFAC_subgroup(142, 'ACO-(O)', 64, 'Peroxide', 0.853, 0.6)
NISTUFSG[143] = UNIFAC_subgroup(143, 'CFH', 65, 'CFH', 0.5966, 0.44)
NISTUFSG[144] = UNIFAC_subgroup(144, 'CFCl', 66, 'CFCl', 1.4034, 1.168)
NISTUFSG[145] = UNIFAC_subgroup(145, 'CFCl2', 67, 'CFCl2', 2.2103, 1.896)
NISTUFSG[146] = UNIFAC_subgroup(146, 'CF2H', 68, 'CF2H', 0.9736, 0.88)
NISTUFSG[147] = UNIFAC_subgroup(147, 'CF2ClH', 69, 'CF2ClH', 1.7396, 1.6)
NISTUFSG[148] = UNIFAC_subgroup(148, 'CF2Cl2', 70, 'CF2Cl2', 2.5873, 2.336)
NISTUFSG[149] = UNIFAC_subgroup(149, 'CF3H', 71, 'CF3H', 1.3507, 1.32)
NISTUFSG[150] = UNIFAC_subgroup(150, 'CF3Cl', 72, 'CF3Cl', 2.1575, 2.048)
NISTUFSG[151] = UNIFAC_subgroup(151, 'CF4', 73, 'CF4', 1.7278, 1.76)
NISTUFSG[152] = UNIFAC_subgroup(152, 'C(O)2', 74, 'Acetal', 0.7073, 0.48)
NISTUFSG[186] = UNIFAC_subgroup(186, 'CH(O)2', 74, 'Acetal', 0.9347, 0.708)
NISTUFSG[309] = UNIFAC_subgroup(309, 'CH2(O)2', 74, 'Acetal', 0.9347, 0.708)
NISTUFSG[153] = UNIFAC_subgroup(153, 'ACN(CH3)2', 75, 'ACNR2', 2.4529, 1.908)
NISTUFSG[154] = UNIFAC_subgroup(154, 'ACN(CH3)CH2', 75, 'ACNR2', 2.2261, 1.6)
NISTUFSG[155] = UNIFAC_subgroup(155, 'ACN(CH2)2', 75, 'ACNR2', 1.9993, 1.292)
NISTUFSG[156] = UNIFAC_subgroup(156, 'ACNHCH3', 76, 'ACNR', 1.7989, 1.364)
NISTUFSG[157] = UNIFAC_subgroup(157, 'ACNHCH2', 76, 'ACNR', 1.5722, 1.056)
NISTUFSG[158] = UNIFAC_subgroup(158, 'ACNHCH', 76, 'ACNR', 1.3448, 0.744)
NISTUFSG[159] = UNIFAC_subgroup(159, 'AC2H2O', 77, 'Furan', 1.3065, 1.04)
NISTUFSG[160] = UNIFAC_subgroup(160, 'AC2HO', 77, 'Furan', 1.1404, 0.76)
NISTUFSG[161] = UNIFAC_subgroup(161, 'AC2O', 77, 'Furan', 0.9743, 0.48)
NISTUFSG[188] = UNIFAC_subgroup(188, 'c-CH2-NH', 78, 'c-CNH', 1.207, 0.936)
NISTUFSG[162] = UNIFAC_subgroup(162, 'c-CH-NH', 78, 'c-CNH', 0.9796, 0.624)
NISTUFSG[163] = UNIFAC_subgroup(163, 'c-C-NH', 78, 'c-CNH', 0.7521, 0.396)
NISTUFSG[189] = UNIFAC_subgroup(189, 'c-CH2-NCH3', 79, 'c-CNR', 1.8609, 1.48)
NISTUFSG[190] = UNIFAC_subgroup(190, 'c-CH2-NCH2', 79, 'c-CNR', 1.6341, 1.172)
NISTUFSG[191] = UNIFAC_subgroup(191, 'c-CH2-NCH', 79, 'c-CNR', 1.4067, 0.86)
NISTUFSG[164] = UNIFAC_subgroup(164, 'c-CH-NCH3', 79, 'c-CNR', 1.6335, 1.168)
NISTUFSG[165] = UNIFAC_subgroup(165, 'c-CH-NCH2', 79, 'c-CNR', 1.4067, 0.86)
NISTUFSG[166] = UNIFAC_subgroup(166, 'c-CH-NCH', 79, 'c-CNR', 1.1793, 0.548)
NISTUFSG[170] = UNIFAC_subgroup(170, 'SiH3-', 80, 'SiH', 1.6035, 1.263)
NISTUFSG[171] = UNIFAC_subgroup(171, '-SiH2-', 80, 'SiH', 1.4443, 1.006)
NISTUFSG[172] = UNIFAC_subgroup(172, '>SiH-', 80, 'SiH', 1.2853, 0.749)
NISTUFSG[173] = UNIFAC_subgroup(173, '>Si<', 80, 'SiH', 1.047, 0.41)
NISTUFSG[174] = UNIFAC_subgroup(174, '-SiH2-O-', 81, 'SiO', 1.4838, 1.062)
NISTUFSG[175] = UNIFAC_subgroup(175, '>SiH-O-', 81, 'SiO', 1.303, 0.764)
NISTUFSG[176] = UNIFAC_subgroup(176, '->Si-O-', 81, 'SiO', 1.1044, 0.466)
NISTUFSG[309] = UNIFAC_subgroup(309, 'CH=NOH', 82, 'Oxime', 1.499, 1.46)
NISTUFSG[177] = UNIFAC_subgroup(177, 'C=NOH', 82, 'Oxime', 1.499, 1.46)
NISTUFSG[178] = UNIFAC_subgroup(178, 'ACCO', 83, 'ACCO', 1.1365, 0.76)
NISTUFSG[179] = UNIFAC_subgroup(179, 'C2Cl4', 86, 'C2Cl4', 3.381, 3.5845)
NISTUFSG[180] = UNIFAC_subgroup(180, 'c-CHH2', 92, 'c-CHNH2', 1.2261, 1.096)
NISTUFSG[201] = UNIFAC_subgroup(201, 'c-CH=CH', 95, 'c-C=C', 1.0897, 0.832)
NISTUFSG[202] = UNIFAC_subgroup(202, 'c-CH=C', 95, 'c-C=C', 0.8616, 0.644)
NISTUFSG[203] = UNIFAC_subgroup(203, 'c-C=C', 95, 'c-C=C', 0.5498, 0.244)
NISTUFSG[204] = UNIFAC_subgroup(204, 'Glycerol', 96, 'Glycerol', 5.4209, 4.4227)
PSRKSG = {}
PSRKSG[1] = UNIFAC_subgroup(1, 'CH3', 1, 'CH2', 0.9011, 0.8480,
atoms=UFSG[1].atoms, bonds=UFSG[1].bonds, smarts=UFSG[1].smarts)
PSRKSG[2] = UNIFAC_subgroup(2, 'CH2', 1, 'CH2', 0.6744, 0.5400,
atoms=UFSG[2].atoms, bonds=UFSG[2].bonds, smarts=UFSG[2].smarts)
PSRKSG[3] = UNIFAC_subgroup(3, 'CH', 1, 'CH2', 0.4469, 0.2280,
atoms=UFSG[3].atoms, bonds=UFSG[3].bonds, smarts=UFSG[3].smarts)
PSRKSG[4] = UNIFAC_subgroup(4, 'C', 1, 'CH2', 0.2195, 0.0000,
atoms=UFSG[4].atoms, bonds=UFSG[4].bonds, smarts=UFSG[4].smarts)
PSRKSG[5] = UNIFAC_subgroup(5, 'CH2=CH', 2, 'C=C', 1.3454, 1.1760,
atoms=UFSG[5].atoms, bonds=UFSG[5].bonds, smarts=UFSG[5].smarts)
PSRKSG[6] = UNIFAC_subgroup(6, 'CH=CH', 2, 'C=C', 1.1167, 0.8670,
atoms=UFSG[6].atoms, bonds=UFSG[6].bonds, smarts=UFSG[6].smarts)
PSRKSG[7] = UNIFAC_subgroup(7, 'CH2=C', 2, 'C=C', 1.1173, 0.9880,
atoms=UFSG[7].atoms, bonds=UFSG[7].bonds, smarts=UFSG[7].smarts)
PSRKSG[8] = UNIFAC_subgroup(8, 'CH=C', 2, 'C=C', 0.8886, 0.6760,
atoms=UFSG[8].atoms, bonds=UFSG[8].bonds, smarts=UFSG[8].smarts)
PSRKSG[9] = UNIFAC_subgroup(9, 'ACH', 3, 'ACH', 0.5313, 0.4000,
atoms=UFSG[9].atoms, bonds=UFSG[9].bonds, smarts=UFSG[9].smarts)
PSRKSG[10] = UNIFAC_subgroup(10, 'AC', 3, 'ACH', 0.3652, 0.1200,
atoms=UFSG[10].atoms, bonds=UFSG[10].bonds, smarts=UFSG[10].smarts)
PSRKSG[11] = UNIFAC_subgroup(11, 'ACCH3', 4, 'ACCH2', 1.2663, 0.9680,
atoms=UFSG[11].atoms, bonds=UFSG[11].bonds, smarts=UFSG[11].smarts)
PSRKSG[12] = UNIFAC_subgroup(12, 'ACCH2', 4, 'ACCH2', 1.0396, 0.6600,
atoms=UFSG[12].atoms, bonds=UFSG[12].bonds, smarts=UFSG[12].smarts)
PSRKSG[13] = UNIFAC_subgroup(13, 'ACCH', 4, 'ACCH2', 0.8121, 0.3480,
atoms=UFSG[13].atoms, bonds=UFSG[13].bonds, smarts=UFSG[13].smarts)
PSRKSG[14] = UNIFAC_subgroup(14, 'OH', 5, 'OH', 1.0000, 1.2000,
atoms=UFSG[14].atoms, bonds=UFSG[14].bonds, smarts=UFSG[14].smarts)
PSRKSG[15] = UNIFAC_subgroup(15, 'CH3OH', 6, 'CH3OH', 1.4311, 1.4320,
atoms=UFSG[15].atoms, bonds=UFSG[15].bonds, smarts=UFSG[15].smarts)
PSRKSG[16] = UNIFAC_subgroup(16, 'H2O', 7, 'H2O', 0.9200, 1.4000,
atoms=UFSG[16].atoms, bonds=UFSG[16].bonds, smarts=UFSG[16].smarts)
PSRKSG[17] = UNIFAC_subgroup(17, 'ACOH', 8, 'ACOH', 0.8952, 0.6800,
atoms=UFSG[17].atoms, bonds=UFSG[17].bonds, smarts=UFSG[17].smarts)
PSRKSG[18] = UNIFAC_subgroup(18, 'CH3CO', 9, 'CH2CO', 1.6724, 1.4880,
atoms=UFSG[18].atoms, bonds=UFSG[18].bonds, smarts=UFSG[18].smarts)
PSRKSG[19] = UNIFAC_subgroup(19, 'CH2CO', 9, 'CH2CO', 1.4457, 1.1800,
atoms=UFSG[19].atoms, bonds=UFSG[19].bonds, smarts=UFSG[19].smarts)
PSRKSG[20] = UNIFAC_subgroup(20, 'CHO', 10, 'CHO', 0.9980, 0.9480,
atoms=UFSG[20].atoms, bonds=UFSG[20].bonds, smarts=UFSG[20].smarts)
PSRKSG[21] = UNIFAC_subgroup(21, 'CH3COO', 11, 'CCOO', 1.9031, 1.7280,
atoms=UFSG[21].atoms, bonds=UFSG[21].bonds, smarts=UFSG[21].smarts)
PSRKSG[22] = UNIFAC_subgroup(22, 'CH2COO', 11, 'CCOO', 1.6764, 1.4200,
atoms=UFSG[22].atoms, bonds=UFSG[22].bonds, smarts=UFSG[22].smarts)
PSRKSG[23] = UNIFAC_subgroup(23, 'HCOO', 12, 'HCOO', 1.2420, 1.1880,
atoms=UFSG[23].atoms, bonds=UFSG[23].bonds, smarts=UFSG[23].smarts)
PSRKSG[24] = UNIFAC_subgroup(24, 'CH3O', 13, 'CH2O', 1.1450, 1.0880,
atoms=UFSG[24].atoms, bonds=UFSG[24].bonds, smarts=UFSG[24].smarts)
PSRKSG[25] = UNIFAC_subgroup(25, 'CH2O', 13, 'CH2O', 0.9183, 0.7800,
atoms=UFSG[25].atoms, bonds=UFSG[25].bonds, smarts=UFSG[25].smarts)
PSRKSG[26] = UNIFAC_subgroup(26, 'CHO', 13, 'CH2O', 0.6908, 0.4680,
atoms=UFSG[26].atoms, bonds=UFSG[26].bonds, smarts=UFSG[26].smarts)
PSRKSG[27] = UNIFAC_subgroup(27, 'THF', 13, 'CH2O', 0.9183, 1.1000,
atoms=UFSG[27].atoms, bonds=UFSG[27].bonds, smarts=UFSG[27].smarts)
PSRKSG[28] = UNIFAC_subgroup(28, 'CH3NH2', 14, 'CNH2', 1.5959, 1.5440,
atoms=UFSG[28].atoms, bonds=UFSG[28].bonds, smarts=UFSG[28].smarts)
PSRKSG[29] = UNIFAC_subgroup(29, 'CH2NH2', 14, 'CNH2', 1.3692, 1.2360,
atoms=UFSG[29].atoms, bonds=UFSG[29].bonds, smarts=UFSG[29].smarts)
PSRKSG[30] = UNIFAC_subgroup(30, 'CHNH2', 14, 'CNH2', 1.1417, 0.9240,
atoms=UFSG[30].atoms, bonds=UFSG[30].bonds, smarts=UFSG[30].smarts)
PSRKSG[31] = UNIFAC_subgroup(31, 'CH3NH', 15, 'CNH', 1.4337, 1.2440,
atoms=UFSG[31].atoms, bonds=UFSG[31].bonds, smarts=UFSG[31].smarts)
PSRKSG[32] = UNIFAC_subgroup(32, 'CH2NH', 15, 'CNH', 1.2070, 0.9360,
atoms=UFSG[32].atoms, bonds=UFSG[32].bonds, smarts=UFSG[32].smarts)
PSRKSG[33] = UNIFAC_subgroup(33, 'CHNH', 15, 'CNH', 0.9795, 0.6240,
atoms=UFSG[33].atoms, bonds=UFSG[33].bonds, smarts=UFSG[33].smarts)
PSRKSG[34] = UNIFAC_subgroup(34, 'CH3N', 16, '(C)3N', 1.1865, 0.9400,
atoms=UFSG[34].atoms, bonds=UFSG[34].bonds, smarts=UFSG[34].smarts)
PSRKSG[35] = UNIFAC_subgroup(35, 'CH2N', 16, '(C)3N', 0.9597, 0.6320,
atoms=UFSG[35].atoms, bonds=UFSG[35].bonds, smarts=UFSG[35].smarts)
PSRKSG[36] = UNIFAC_subgroup(36, 'ACNH2', 17, 'ACNH2', 1.0600, 0.8160,
atoms=UFSG[36].atoms, bonds=UFSG[36].bonds, smarts=UFSG[36].smarts)
PSRKSG[37] = UNIFAC_subgroup(37, 'C5H5N', 18, 'PYRIDINE', 2.9993, 2.1130,
atoms=UFSG[37].atoms, bonds=UFSG[37].bonds, smarts=UFSG[37].smarts)
PSRKSG[38] = UNIFAC_subgroup(38, 'C5H4N', 18, 'PYRIDINE', 2.8332, 1.8330,
atoms=UFSG[38].atoms, bonds=UFSG[38].bonds, smarts=UFSG[38].smarts)
PSRKSG[39] = UNIFAC_subgroup(39, 'C5H3N', 18, 'PYRIDINE', 2.6670, 1.5530,
atoms=UFSG[39].atoms, bonds=UFSG[39].bonds, smarts=UFSG[39].smarts)
PSRKSG[40] = UNIFAC_subgroup(40, 'CH3CN', 19, 'CCN', 1.8701, 1.7240,
atoms=UFSG[40].atoms, bonds=UFSG[40].bonds, smarts=UFSG[40].smarts)
PSRKSG[41] = UNIFAC_subgroup(41, 'CH2CN', 19, 'CCN', 1.6434, 1.4160,
atoms=UFSG[41].atoms, bonds=UFSG[41].bonds, smarts=UFSG[41].smarts)
PSRKSG[42] = UNIFAC_subgroup(42, 'COOH', 20, 'COOH', 1.3013, 1.2240,
atoms=UFSG[42].atoms, bonds=UFSG[42].bonds, smarts=UFSG[42].smarts)
PSRKSG[43] = UNIFAC_subgroup(43, 'HCOOH', 20, 'COOH', 1.5280, 1.5320,
atoms=UFSG[43].atoms, bonds=UFSG[43].bonds, smarts=UFSG[43].smarts)
PSRKSG[44] = UNIFAC_subgroup(44, 'CH2CL', 21, 'CCL', 1.4654, 1.2640,
atoms=UFSG[44].atoms, bonds=UFSG[44].bonds, smarts=UFSG[44].smarts)
PSRKSG[45] = UNIFAC_subgroup(45, 'CHCL', 21, 'CCL', 1.2380, 0.9520,
atoms=UFSG[45].atoms, bonds=UFSG[45].bonds, smarts=UFSG[45].smarts)
PSRKSG[46] = UNIFAC_subgroup(46, 'CCL', 21, 'CCL', 1.0106, 0.7240,
atoms=UFSG[46].atoms, bonds=UFSG[46].bonds, smarts=UFSG[46].smarts)
PSRKSG[47] = UNIFAC_subgroup(47, 'CH2CL2', 22, 'CCL2', 2.2564, 1.9880,
atoms=UFSG[47].atoms, bonds=UFSG[47].bonds, smarts=UFSG[47].smarts)
PSRKSG[48] = UNIFAC_subgroup(48, 'CHCL2', 22, 'CCL2', 2.0606, 1.6840,
atoms=UFSG[48].atoms, bonds=UFSG[48].bonds, smarts=UFSG[48].smarts)
PSRKSG[49] = UNIFAC_subgroup(49, 'CCL2', 22, 'CCL2', 1.8016, 1.4480,
atoms=UFSG[49].atoms, bonds=UFSG[49].bonds, smarts=UFSG[49].smarts)
PSRKSG[50] = UNIFAC_subgroup(50, 'CHCL3', 23, 'CCL3', 2.8700, 2.4100,
atoms=UFSG[50].atoms, bonds=UFSG[50].bonds, smarts=UFSG[50].smarts)
PSRKSG[51] = UNIFAC_subgroup(51, 'CCL3', 23, 'CCL3', 2.6401, 2.1840,
atoms=UFSG[51].atoms, bonds=UFSG[51].bonds, smarts=UFSG[51].smarts)
PSRKSG[52] = UNIFAC_subgroup(52, 'CCL4', 24, 'CCL4', 3.3900, 2.9100,
atoms=UFSG[52].atoms, bonds=UFSG[52].bonds, smarts=UFSG[52].smarts)
PSRKSG[53] = UNIFAC_subgroup(53, 'ACCL', 25, 'ACCL', 1.1562, 0.8440,
atoms=UFSG[53].atoms, bonds=UFSG[53].bonds, smarts=UFSG[53].smarts)
PSRKSG[54] = UNIFAC_subgroup(54, 'CH3NO2', 26, 'CNO2', 2.0086, 1.8680,
atoms=UFSG[54].atoms, bonds=UFSG[54].bonds, smarts=UFSG[54].smarts)
PSRKSG[55] = UNIFAC_subgroup(55, 'CH2NO2', 26, 'CNO2', 1.7818, 1.5600,
atoms=UFSG[55].atoms, bonds=UFSG[55].bonds, smarts=UFSG[55].smarts)
PSRKSG[56] = UNIFAC_subgroup(56, 'CHNO2', 26, 'CNO2', 1.5544, 1.2480,
atoms=UFSG[56].atoms, bonds=UFSG[56].bonds, smarts=UFSG[56].smarts)
PSRKSG[57] = UNIFAC_subgroup(57, 'ACNO2', 27, 'ACNO2', 1.4199, 1.1040,
atoms=UFSG[57].atoms, bonds=UFSG[57].bonds, smarts=UFSG[57].smarts)
PSRKSG[58] = UNIFAC_subgroup(58, 'CS2', 28, 'CS2', 2.0570, 1.6500,
atoms=UFSG[58].atoms, bonds=UFSG[58].bonds, smarts=UFSG[58].smarts)
PSRKSG[59] = UNIFAC_subgroup(59, 'CH3SH', 29, 'CH3SH', 1.8770, 1.6760,
atoms=UFSG[59].atoms, bonds=UFSG[59].bonds, smarts=UFSG[59].smarts)
PSRKSG[60] = UNIFAC_subgroup(60, 'CH2SH', 29, 'CH3SH', 1.6510, 1.3680,
atoms=UFSG[60].atoms, bonds=UFSG[60].bonds, smarts=UFSG[60].smarts)
PSRKSG[61] = UNIFAC_subgroup(61, 'FURFURAL', 30, 'FURFURAL', 3.1680, 2.4840,
atoms=UFSG[61].atoms, bonds=UFSG[61].bonds, smarts=UFSG[61].smarts)
PSRKSG[62] = UNIFAC_subgroup(62, 'DOH', 31, 'DOH', 2.4088, 2.2480,
atoms=UFSG[62].atoms, bonds=UFSG[62].bonds, smarts=UFSG[62].smarts)
PSRKSG[63] = UNIFAC_subgroup(63, 'I', 32, 'I', 1.2640, 0.9920,
atoms=UFSG[63].atoms, bonds=UFSG[63].bonds, smarts=UFSG[63].smarts)
PSRKSG[64] = UNIFAC_subgroup(64, 'BR', 33, 'BR', 0.9492, 0.8320,
atoms=UFSG[64].atoms, bonds=UFSG[64].bonds, smarts=UFSG[64].smarts)
PSRKSG[65] = UNIFAC_subgroup(65, 'CH=-C', 34, 'C=-C', 1.2920, 1.0880,
atoms=UFSG[65].atoms, bonds=UFSG[65].bonds, smarts=UFSG[65].smarts)
PSRKSG[66] = UNIFAC_subgroup(66, 'C=-C', 34, 'C=-C', 1.0613, 0.7840,
atoms=UFSG[66].atoms, bonds=UFSG[66].bonds, smarts=UFSG[66].smarts)
PSRKSG[67] = UNIFAC_subgroup(67, 'DMSO', 35, 'DMSO', 2.8266, 2.4720,
atoms=UFSG[67].atoms, bonds=UFSG[67].bonds, smarts=UFSG[67].smarts)
PSRKSG[68] = UNIFAC_subgroup(68, 'ACRY', 36, 'ACRY', 2.3144, 2.0520,
atoms=UFSG[68].atoms, bonds=UFSG[68].bonds, smarts=UFSG[68].smarts)
PSRKSG[69] = UNIFAC_subgroup(69, 'CL-(C=C)', 37, 'CLCC', 0.7910, 0.7240,
atoms=UFSG[69].atoms, bonds=UFSG[69].bonds, smarts=UFSG[69].smarts)
PSRKSG[70] = UNIFAC_subgroup(70, 'C=C', 2, 'C=C', 0.6605, 0.4850,
atoms=UFSG[70].atoms, bonds=UFSG[70].bonds, smarts=UFSG[70].smarts)
PSRKSG[71] = UNIFAC_subgroup(71, 'ACF', 38, 'ACF', 0.6948, 0.5240,
atoms=UFSG[71].atoms, bonds=UFSG[71].bonds, smarts=UFSG[71].smarts)
PSRKSG[72] = UNIFAC_subgroup(72, 'DMF', 39, 'DMF', 3.0856, 2.7360,
atoms=UFSG[72].atoms, bonds=UFSG[72].bonds, smarts=UFSG[72].smarts)
PSRKSG[73] = UNIFAC_subgroup(73, 'HCON(CH2)2', 39, 'DMF', 2.6322, 2.1200,
atoms=UFSG[73].atoms, bonds=UFSG[73].bonds, smarts=UFSG[73].smarts)
PSRKSG[74] = UNIFAC_subgroup(74, 'CF3', 40, 'CF2', 1.4060, 1.3800,
atoms=UFSG[74].atoms, bonds=UFSG[74].bonds, smarts=UFSG[74].smarts)
PSRKSG[75] = UNIFAC_subgroup(75, 'CF2', 40, 'CF2', 1.0105, 0.9200,
atoms=UFSG[75].atoms, bonds=UFSG[75].bonds, smarts=UFSG[75].smarts)
PSRKSG[76] = UNIFAC_subgroup(76, 'CF', 40, 'CF2', 0.6150, 0.4600,
atoms=UFSG[76].atoms, bonds=UFSG[76].bonds, smarts=UFSG[76].smarts)
PSRKSG[77] = UNIFAC_subgroup(77, 'COO', 41, 'COO', 1.3800, 1.2000,
atoms=UFSG[77].atoms, bonds=UFSG[77].bonds, smarts=UFSG[77].smarts)
PSRKSG[78] = UNIFAC_subgroup(78, 'SIH3', 42, 'SIH2', 1.6035, 1.2632,
atoms=UFSG[78].atoms, bonds=UFSG[78].bonds, smarts=UFSG[78].smarts)
PSRKSG[79] = UNIFAC_subgroup(79, 'SIH2', 42, 'SIH2', 1.4443, 1.0063,
atoms=UFSG[79].atoms, bonds=UFSG[79].bonds, smarts=UFSG[79].smarts)
PSRKSG[80] = UNIFAC_subgroup(80, 'SIH', 42, 'SIH2', 1.2853, 0.7494,
atoms=UFSG[80].atoms, bonds=UFSG[80].bonds, smarts=UFSG[80].smarts)
PSRKSG[81] = UNIFAC_subgroup(81, 'SI', 42, 'SIH2', 1.0470, 0.4099,
atoms=UFSG[81].atoms, bonds=UFSG[81].bonds, smarts=UFSG[81].smarts)
PSRKSG[82] = UNIFAC_subgroup(82, 'SIH2O', 43, 'SIO', 1.4838, 1.0621,
atoms=UFSG[82].atoms, bonds=UFSG[82].bonds, smarts=UFSG[82].smarts)
PSRKSG[83] = UNIFAC_subgroup(83, 'SIHO', 43, 'SIO', 1.3030, 0.7639,
atoms=UFSG[83].atoms, bonds=UFSG[83].bonds, smarts=UFSG[83].smarts)
PSRKSG[84] = UNIFAC_subgroup(84, 'SIO', 43, 'SIO', 1.1044, 0.4657,
atoms=UFSG[84].atoms, bonds=UFSG[84].bonds, smarts=UFSG[84].smarts)
PSRKSG[85] = UNIFAC_subgroup(85, 'NMP', 44, 'NMP', 3.9810, 3.2000,
atoms=UFSG[85].atoms, bonds=UFSG[85].bonds, smarts=UFSG[85].smarts)
PSRKSG[86] = UNIFAC_subgroup(86, 'CCL3F', 45, 'CCLF', 3.0356, 2.6440,
atoms=UFSG[86].atoms, bonds=UFSG[86].bonds, smarts=UFSG[86].smarts)
PSRKSG[87] = UNIFAC_subgroup(87, 'CCL2F', 45, 'CCLF', 2.2287, 1.9160,
atoms=UFSG[87].atoms, bonds=UFSG[87].bonds, smarts=UFSG[87].smarts)
PSRKSG[88] = UNIFAC_subgroup(88, 'HCCL2F', 45, 'CCLF', 2.4060, 2.1160,
atoms=UFSG[88].atoms, bonds=UFSG[88].bonds, smarts=UFSG[88].smarts)
PSRKSG[89] = UNIFAC_subgroup(89, 'HCCLF', 45, 'CCLF', 1.6493, 1.4160,
atoms=UFSG[89].atoms, bonds=UFSG[89].bonds, smarts=UFSG[89].smarts)
PSRKSG[90] = UNIFAC_subgroup(90, 'CCLF2', 45, 'CCLF', 1.8174, 1.6480,
atoms=UFSG[90].atoms, bonds=UFSG[90].bonds, smarts=UFSG[90].smarts)
PSRKSG[91] = UNIFAC_subgroup(91, 'HCCLF2', 45, 'CCLF', 1.9670, 1.8280,
atoms=UFSG[91].atoms, bonds=UFSG[91].bonds, smarts=UFSG[91].smarts)
PSRKSG[92] = UNIFAC_subgroup(92, 'CCLF3', 45, 'CCLF', 2.1721, 2.1000,
atoms=UFSG[92].atoms, bonds=UFSG[92].bonds, smarts=UFSG[92].smarts)
PSRKSG[93] = UNIFAC_subgroup(93, 'CCL2F2', 45, 'CCLF', 2.6243, 2.3760,
atoms=UFSG[93].atoms, bonds=UFSG[93].bonds, smarts=UFSG[93].smarts)
PSRKSG[94] = UNIFAC_subgroup(94, 'AMH2', 46, 'CON (AM)', 1.4515, 1.2480,
atoms=UFSG[94].atoms, bonds=UFSG[94].bonds, smarts=UFSG[94].smarts)
PSRKSG[95] = UNIFAC_subgroup(95, 'AMHCH3', 46, 'CON (AM)', 2.1905, 1.7960,
atoms=UFSG[95].atoms, bonds=UFSG[95].bonds, smarts=UFSG[95].smarts)
PSRKSG[96] = UNIFAC_subgroup(96, 'AMHCH2', 46, 'CON (AM)', 1.9637, 1.4880,
atoms=UFSG[96].atoms, bonds=UFSG[96].bonds, smarts=UFSG[96].smarts)
PSRKSG[97] = UNIFAC_subgroup(97, 'AM(CH3)2', 46, 'CON (AM)', 2.8589, 2.4280,
atoms=UFSG[97].atoms, bonds=UFSG[97].bonds, smarts=UFSG[97].smarts)
PSRKSG[98] = UNIFAC_subgroup(98, 'AMCH3CH2', 46, 'CON (AM)', 2.6322, 2.1200,
atoms=UFSG[98].atoms, bonds=UFSG[98].bonds, smarts=UFSG[98].smarts)
PSRKSG[99] = UNIFAC_subgroup(99, 'AM(CH2)2', 46, 'CON (AM)', 2.4054, 1.8120,
atoms=UFSG[99].atoms, bonds=UFSG[99].bonds, smarts=UFSG[99].smarts)
PSRKSG[100] = UNIFAC_subgroup(100, 'C2H5O2', 47, 'OCCOH', 2.1226, 1.9040,
atoms=UFSG[100].atoms, bonds=UFSG[100].bonds, smarts=UFSG[100].smarts)
PSRKSG[101] = UNIFAC_subgroup(101, 'C2H4O2', 47, 'OCCOH', 1.8952, 1.5920,
atoms=UFSG[101].atoms, bonds=UFSG[101].bonds, smarts=UFSG[101].smarts)
PSRKSG[102] = UNIFAC_subgroup(102, 'CH3S', 48, 'CH2S', 1.6130, 1.3680,
atoms=UFSG[102].atoms, bonds=UFSG[102].bonds, smarts=UFSG[102].smarts)
PSRKSG[103] = UNIFAC_subgroup(103, 'CH2S', 48, 'CH2S', 1.3863, 1.0600,
atoms=UFSG[103].atoms, bonds=UFSG[103].bonds, smarts=UFSG[103].smarts)
PSRKSG[104] = UNIFAC_subgroup(104, 'CHS', 48, 'CH2S', 1.1589, 0.7480,
atoms=UFSG[104].atoms, bonds=UFSG[104].bonds, smarts=UFSG[104].smarts)
PSRKSG[105] = UNIFAC_subgroup(105, 'MORPH', 49, 'MORPH', 3.4740, 2.7960,
atoms=UFSG[105].atoms, bonds=UFSG[105].bonds, smarts=UFSG[105].smarts)
PSRKSG[106] = UNIFAC_subgroup(106, 'C4H4S', 50, 'THIOPHEN', 2.8569, 2.1400,
atoms=UFSG[106].atoms, bonds=UFSG[106].bonds, smarts=UFSG[106].smarts)
PSRKSG[107] = UNIFAC_subgroup(107, 'C4H3S', 50, 'THIOPHEN', 2.6908, 1.8600,
atoms=UFSG[107].atoms, bonds=UFSG[107].bonds, smarts=UFSG[107].smarts)
PSRKSG[108] = UNIFAC_subgroup(108, 'C4H2S', 50, 'THIOPHEN', 2.5247, 1.5800,
atoms=UFSG[108].atoms, bonds=UFSG[108].bonds, smarts=UFSG[108].smarts)
PSRKSG[109] = UNIFAC_subgroup(109, 'H2C=CH2', 2, 'C=C', 1.3564, 1.3098,
atoms={'H': 4, 'C': 2}, bonds={DOUBLE_BOND: 1}, smarts='[CX3H2]=[CX3H2]') # ethylene
PSRKSG[110] = UNIFAC_subgroup(110, 'CH=-CH', 34, 'C=-C', 0.7910, 0.7200,
atoms={'C': 2, 'H': 2}, bonds={TRIPLE_BOND: 1},
smarts='[CX2;H1]#[CX2;H1]') # ethyne
PSRKSG[111] = UNIFAC_subgroup(111, 'NH3', 55, 'NH3', 0.8510, 0.7780,
atoms={'N': 1, 'H': 3}, bonds={SINGLE_BOND: 3}, smarts='[NX3H3]')
PSRKSG[112] = UNIFAC_subgroup(112, 'CO', 63, 'CO', 0.7110, 0.8280,
atoms={'C': 1, 'O': 1}, bonds={TRIPLE_BOND: 1}, smarts='[C-]#[O+]')
PSRKSG[113] = UNIFAC_subgroup(113, 'H2', 62, 'H2', 0.4160, 0.5710,
atoms={'H': 2}, bonds={SINGLE_BOND: 1}, smarts='[HH]', priority=1000000000) # TODO
PSRKSG[114] = UNIFAC_subgroup(114, 'H2S', 61, 'H2S', 1.2350, 1.2020,
atoms={'S': 1, 'H': 2}, bonds={}, smarts='[SH2]')
PSRKSG[115] = UNIFAC_subgroup(115, 'N2', 60, 'N2', 0.8560, 0.9300,
atoms={'N': 2}, bonds={TRIPLE_BOND: 1}, smarts='N#N')
PSRKSG[116] = UNIFAC_subgroup(116, 'AR', 59, 'AR', 1.1770, 1.1160,
atoms={'Ar': 1}, bonds={}, smarts='[ArX0]')
PSRKSG[117] = UNIFAC_subgroup(117, 'CO2', 56, 'CO2', 1.3000, 0.9820,
atoms={'C': 1, 'O': 2}, bonds={DOUBLE_BOND: 2}, smarts='[CX2H0](=[OX1H0])=[OX1H0]')
PSRKSG[118] = UNIFAC_subgroup(118, 'CH4', 57, 'CH4', 1.1292, 1.1240,
atoms={'C': 1, 'H': 4}, bonds={SINGLE_BOND: 1}, smarts='[CX4H4]')
PSRKSG[119] = UNIFAC_subgroup(119, 'O2', 58, 'O2', 0.7330, 0.8490,
atoms={'O': 2}, bonds={DOUBLE_BOND: 1}, smarts='[OX1H0]=[OX1H0]')
PSRKSG[120] = UNIFAC_subgroup(120, 'D2', 62, 'H2', 0.3700, 0.5270,
atoms={'H': 2}, bonds={}, smarts='[2H][2H]')
PSRKSG[121] = UNIFAC_subgroup(121, 'SO2', 65, 'SO2', 1.3430, 1.1640,
atoms={'S': 1, 'O': 2}, bonds={DOUBLE_BOND: 2}, smarts='[OX1H0]=[SX2H0]=[OX1H0]')
PSRKSG[122] = UNIFAC_subgroup(122, 'NO', 66, 'NO', 0.7160, 0.6200,
atoms={'N': 1, 'O': 1}, bonds={DOUBLE_BOND: 1}, smarts='[NX1H0]=[OX1H0]')
PSRKSG[123] = UNIFAC_subgroup(123, 'N2O', 67, 'N2O', 0.9800, 0.8880,
atoms={'N': 2, 'O': 1}, bonds={DOUBLE_BOND: 2}, smarts='[NX1H0]#[N+X2H0][O-X1H0]')
PSRKSG[124] = UNIFAC_subgroup(124, 'SF6', 68, 'SF6', 2.3740, 2.0560,
atoms={'S': 1, 'F': 6}, bonds={SINGLE_BOND: 6}, smarts='[FX1H0][SX6H0]([FX1H0])([FX1H0])([FX1H0])([FX1H0])[FX1H0]')
PSRKSG[125] = UNIFAC_subgroup(125, 'HE', 69, 'HE', 0.8850, 0.9850,
atoms={'He': 1}, bonds={}, smarts='[HeX0H0]')
PSRKSG[126] = UNIFAC_subgroup(126, 'NE', 70, 'NE', 0.8860, 0.9860,
atoms={'Ne': 1}, bonds={}, smarts='[NeX0]')
PSRKSG[127] = UNIFAC_subgroup(127, 'KR', 71, 'KR', 1.1200, 1.1200,
atoms={'Kr': 1}, bonds={}, smarts='[KrX0]')
PSRKSG[128] = UNIFAC_subgroup(128, 'XE', 72, 'XE', 1.1300, 1.1300,
atoms={'Xe': 1}, bonds={}, smarts='[XeX0]')
PSRKSG[129] = UNIFAC_subgroup(129, 'HF', 73, 'HF', 1.0160, 1.2160,
atoms={'H': 1, 'F': 1}, bonds={},smarts='[FX1H1]')
PSRKSG[130] = UNIFAC_subgroup(130, 'HCL', 74, 'HCL', 1.0560, 1.2560,
atoms={'H': 1, 'Cl': 1}, bonds={}, smarts='[ClX1H1]')
PSRKSG[131] = UNIFAC_subgroup(131, 'HBR', 75, 'HBR', 1.0580, 1.2580,
atoms={'H': 1, 'Br': 1}, bonds={}, smarts='[BrX1H1]')
PSRKSG[132] = UNIFAC_subgroup(132, 'HI', 76, 'HI', 1.3930, 1.2080,
atoms={'H': 1, 'I': 1}, bonds={}, smarts='[IX1H1]')
PSRKSG[133] = UNIFAC_subgroup(133, 'COS', 77, 'COS', 1.6785, 1.3160,
atoms={'C': 1, 'O': 1, 'S': 1}, bonds={}, smarts='[CX2H0](=[OX1H0])=[SX1H0]')
PSRKSG[134] = UNIFAC_subgroup(134, 'CHSH', 29, 'CH3SH', 1.4250, 1.0600,
atoms={'C': 1, 'H': 2, 'S': 1}, bonds={SINGLE_BOND: 1},
smarts='[CX4H1][SX2H1]', priority=100000000)
PSRKSG[135] = UNIFAC_subgroup(135, 'CSH', 29, 'CH3SH', 1.1990, 0.7520,
atoms={'C': 1, 'S': 1, 'H': 1}, bonds={SINGLE_BOND: 1}, smarts='[CX4H0][SX2H1]', priority=1000000)
PSRKSG[136] = UNIFAC_subgroup(136, 'H2COCH', 51, 'EPOXY', 1.3652, 1.0080,
atoms={'H': 3, 'C': 2, 'O': 1}, bonds={SINGLE_BOND: 3}, smarts='[CX4H2]1[CX4H1][OX2H0]1')
PSRKSG[137] = UNIFAC_subgroup(137, 'HCOCH', 51, 'EPOXY', 1.1378, 0.6960,
atoms={'C': 2, 'O': 1, 'H': 2}, bonds={SINGLE_BOND: 3}, smarts='[CX4H1]1[CX4H1][OX2H0]1')
PSRKSG[138] = UNIFAC_subgroup(138, 'HCOC', 51, 'EPOXY', 0.9104, 0.4680,
atoms={'C': 2, 'O': 1, 'H': 1}, bonds={SINGLE_BOND: 3}, smarts='[CX4H1]1[CX4H0][OX2H0]1')
PSRKSG[139] = UNIFAC_subgroup(139, 'H2COCH2', 51, 'EPOXY', 1.5926, 1.3200,
atoms={'C': 2, 'H': 4, 'O': 1}, bonds={SINGLE_BOND: 3}, smarts='[CX4H2]1[CX4H2][OX2H0]1')
PSRKSG[140] = UNIFAC_subgroup(140, 'H2COC', 51, 'EPOXY', 1.1378, 0.7800,
atoms={'C': 2, 'O': 1, 'H': 2}, bonds={SINGLE_BOND: 3}, smarts='[CX4H2]1[CX4H0][OX2H0]1')
PSRKSG[141] = UNIFAC_subgroup(141, 'COC', 51, 'EPOXY', 0.6829, 0.2400,
atoms={'C': 2, 'O': 1}, bonds={SINGLE_BOND: 3}, smarts='[CX4H0]1[CX4H0][OX2H0]1')
# These are structural groups but also believed to be individual gases
PSRKSG[142] = UNIFAC_subgroup(142, 'F2', 78, 'F2', 0.7500, 0.8800,
atoms={'F': 2}, bonds={SINGLE_BOND: 1}, smarts='[F][F]')
PSRKSG[143] = UNIFAC_subgroup(143, 'CL2', 79, 'CL2', 1.5300, 1.4400,
atoms={'Cl': 2}, bonds={SINGLE_BOND: 1}, smarts='[Cl][Cl]')
PSRKSG[144] = UNIFAC_subgroup(144, 'BR2', 80, 'BR2', 1.9000, 1.6600,
atoms={'Br': 2}, bonds={SINGLE_BOND: 1}, smarts='[Br][Br]')
PSRKSG[145] = UNIFAC_subgroup(145, 'HCN', 81, 'HCN', 1.2000, 1.1900,
atoms={'H': 1, 'C': 1, 'N': 1}, bonds={TRIPLE_BOND: 1}, smarts='[CX2H1]#[NX1H0]')
PSRKSG[146] = UNIFAC_subgroup(146, 'NO2', 82, 'NO2', 1.0000, 1.1000,
atoms={'N': 1, 'O': 2}, bonds={SINGLE_BOND: 1, DOUBLE_BOND: 1}, smarts='[OX1H0][NX2H0]=[OX1H0]')
PSRKSG[147] = UNIFAC_subgroup(147, 'CF4', 83, 'CF4', 1.7800, 1.8200,
atoms={'C': 1, 'F': 4}, bonds={SINGLE_BOND: 4}, smarts='[CX4H0]([FX1])([FX1])([FX1])[FX1]')
PSRKSG[148] = UNIFAC_subgroup(148, 'O3', 84, 'O3', 1.1000, 1.2700,
atoms={'O': 3}, bonds={SINGLE_BOND: 1, DOUBLE_BOND: 1}, smarts='[O-X1H0][O+X2H0]=[OX1H0]')
PSRKSG[149] = UNIFAC_subgroup(149, 'CLNO', 85, 'CLNO', 1.4800, 1.3400,
atoms={'Cl': 1, 'N': 1, 'O': 1}, bonds={SINGLE_BOND: 1, DOUBLE_BOND: 1}, smarts='[NX2H0](=[OX1H0])[ClX1H0]')
# Can't figure out what 152 is supposed to match!
PSRKSG[152] = UNIFAC_subgroup(152, 'CNH2', 14, 'CNH2', 0.9147, 0.6140,
# atoms={'C': 1, 'N': 1, 'H': 2}, bonds={DOUBLE_BOND: 1}
)
PSRKMG = {1: ("CH2", [1, 2, 3, 4]),
2: ("C=C", [5, 6, 7, 8, 70, 109]),
3: ("ACH", [9, 10]),
4: ("ACCH2", [11, 12, 13]),
5: ("OH", [14]),
6: ("CH3OH", [15]),
7: ("H2O", [16]),
8: ("ACOH", [17]),
9: ("CH2CO", [18, 19]),
10: ("CHO", [20]),
11: ("CCOO", [21, 22]),
12: ("HCOO", [23]),
13: ("CH2O", [24, 25, 26, 27]),
14: ("CNH2", [28, 29, 30, 152]),
15: ("CNH", [31, 32, 33]),
16: ("(C)3N", [34, 35]),
17: ("ACNH2", [36]),
18: ("PYRIDINE", [37, 38, 39]),
19: ("CCN", [40, 41]),
20: ("COOH", [42, 43]),
21: ("CCL", [44, 45, 46]),
22: ("CCL2", [47, 48, 49]),
23: ("CCL3", [50, 51]),
24: ("CCL4", [52]),
25: ("ACCL", [53]),
26: ("CNO2", [54, 55, 56]),
27: ("ACNO2", [57]),
28: ("CS2", [58]),
29: ("CH3SH", [59, 60, 134, 135]),
30: ("FURFURAL", [61]),
31: ("DOH", [62]),
32: ("I", [63]),
33: ("BR", [64]),
34: ("C=-C", [65, 66, 110]),
35: ("DMSO", [67]),
36: ("ACRY", [68]),
37: ("CLCC", [69]),
38: ("ACF", [71]),
39: ("DMF", [72, 73]),
40: ("CF2", [74, 75, 76]),
41: ("COO", [77]),
42: ("SIH2", [78, 79, 80, 81]),
43: ("SIO", [82, 83, 84]),
44: ("NMP", [85]),
45: ("CCLF", [86, 87, 88, 89, 90, 91, 92, 93]),
46: ("CON (AM)", [94, 95, 96, 97, 98, 99]),
47: ("OCCOH", [100, 101]),
48: ("CH2S", [102, 103, 104]),
49: ("MORPH", [105]),
50: ("THIOPHEN", [106, 107, 108]),
51: ("EPOXY", [136, 137, 138, 139, 140, 141]),
55: ("NH3", [111]),
56: ("CO2", [117]),
57: ("CH4", [118]),
58: ("O2", [119]),
59: ("AR", [116]),
60: ("N2", [115]),
61: ("H2S", [114]),
62: ("H2", [113, 120]),
63: ("CO", [112]),
65: ("SO2", [121]),
66: ("NO", [122]),
67: ("N2O", [123]),
68: ("SF6", [124]),
69: ("HE", [125]),
70: ("NE", [126]),
71: ("KR", [127]),
72: ("XE", [128]),
73: ("HF", [129]),
74: ("HCL", [130]),
75: ("HBR", [131]),
76: ("HI", [132]),
77: ("COS", [133]),
78: ("F2", [142]),
79: ("CL2", [143]),
80: ("BR2", [144]),
81: ("HCN", [145]),
82: ("NO2", [146]),
83: ("CF4", [147]),
84: ("O3", [148]),
85: ("CLNO", [149]),
}
"""
Magnussen, Thomas, Peter Rasmussen, and Aage Fredenslund. "UNIFAC Parameter Table for Prediction of Liquid-Liquid Equilibriums."
Industrial & Engineering Chemistry Process Design and Development 20, no. 2 (April 1, 1981): 331-39. https://doi.org/10.1021/i200013a024.
"""
LLEUFSG = {}
# LLEUFSG[subgroup ID] = (subgroup formula, main group ID, subgroup R, subgroup Q)
LLEUFSG[1] = UNIFAC_subgroup(1, 'CH3', 1, 'CH2', 0.9011, 0.848,
bonds=UFSG[1].bonds, atoms=UFSG[1].atoms,
smarts=UFSG[1].smarts)
LLEUFSG[2] = UNIFAC_subgroup(2, 'CH2', 1, 'CH2', 0.6744, 0.54,
bonds=UFSG[2].bonds, atoms=UFSG[2].atoms,
smarts=UFSG[2].smarts)
LLEUFSG[3] = UNIFAC_subgroup(3, 'CH', 1, 'CH2', 0.4469, 0.228,
bonds=UFSG[3].bonds, atoms=UFSG[3].atoms,
smarts=UFSG[3].smarts)
LLEUFSG[4] = UNIFAC_subgroup(4, 'C', 1, 'CH2', 0.2195, 0,
bonds=UFSG[4].bonds, atoms=UFSG[4].atoms,
smarts=UFSG[4].smarts)
LLEUFSG[5] = UNIFAC_subgroup(5, 'CH2=CH', 2, 'C=C', 1.3454, 1.176,
bonds=UFSG[5].bonds, atoms=UFSG[5].atoms,
smarts=UFSG[5].smarts)
LLEUFSG[6] = UNIFAC_subgroup(6, 'CH=CH', 2, 'C=C', 1.1167, 0.867,
bonds=UFSG[6].bonds, atoms=UFSG[6].atoms,
smarts=UFSG[6].smarts)
LLEUFSG[7] = UNIFAC_subgroup(7, 'CH=C', 2, 'C=C', 0.8886, 0.676,
bonds=UFSG[8].bonds, atoms=UFSG[8].atoms,
smarts=UFSG[8].smarts) # 7, 8 diff order than UFSG
LLEUFSG[8] = UNIFAC_subgroup(8, 'CH2=C', 2, 'C=C', 1.1173, 0.988,
bonds=UFSG[7].bonds, atoms=UFSG[7].atoms,
smarts=UFSG[7].smarts)
LLEUFSG[9] = UNIFAC_subgroup(9, 'ACH', 3, 'ACH', 0.5313, 0.4,
bonds=UFSG[9].bonds, atoms=UFSG[9].atoms,
smarts=UFSG[9].smarts)
LLEUFSG[10] = UNIFAC_subgroup(10, 'AC', 3, 'ACH', 0.3652, 0.12,
bonds=UFSG[10].bonds, atoms=UFSG[10].atoms,
smarts=UFSG[10].smarts)
LLEUFSG[11] = UNIFAC_subgroup(11, 'ACCH3', 4, 'ACCH2', 1.2663, 0.968,
bonds=UFSG[11].bonds, atoms=UFSG[11].atoms,
smarts=UFSG[11].smarts)
LLEUFSG[12] = UNIFAC_subgroup(12, 'ACCH2', 4, 'ACCH2', 1.0396, 0.66,
bonds=UFSG[12].bonds, atoms=UFSG[12].atoms,
smarts=UFSG[12].smarts)
LLEUFSG[13] = UNIFAC_subgroup(13, 'ACCH', 4, 'ACCH2', 0.8121, 0.348,
bonds=UFSG[13].bonds, atoms=UFSG[13].atoms,
smarts=UFSG[13].smarts)
LLEUFSG[14] = UNIFAC_subgroup(14, 'OH', 5, 'OH', 1, 1.2,
bonds=UFSG[14].bonds, atoms=UFSG[14].atoms,
smarts=UFSG[14].smarts)
LLEUFSG[15] = UNIFAC_subgroup(15, 'P1', 6, 'P1', 3.2499, 3.128,
bonds={SINGLE_BOND: 3}, atoms={'C': 3, 'H': 8, 'O': 1}, priority=10000000,
smarts='[CX4H3][CX4H2][CX4H2][OX2H1]') # 1-propanol ONLY specific chemical
LLEUFSG[16] = UNIFAC_subgroup(16, 'P2', 7, 'P2', 3.2491, 3.124,
bonds={SINGLE_BOND: 3}, atoms={'C': 3, 'H': 8, 'O': 1},
smarts='[CX4H3][CX4H1]([CX4H3])[OX2H1]') # 2-propanol ONLY specific chemical
LLEUFSG[17] = UNIFAC_subgroup(17, 'H2O', 8, 'H2O', 0.92, 1.4,
bonds=UFSG[16].bonds, atoms=UFSG[16].atoms,
smarts=UFSG[16].smarts)
LLEUFSG[18] = UNIFAC_subgroup(18, 'ACOH', 9, 'ACOH', 0.8952, 0.68,
bonds=UFSG[17].bonds, atoms=UFSG[17].atoms,
smarts=UFSG[17].smarts)
LLEUFSG[19] = UNIFAC_subgroup(19, 'CH3CO', 10, 'CH2CO', 1.6724, 1.488,
bonds=UFSG[18].bonds, atoms=UFSG[18].atoms,
smarts=UFSG[18].smarts)
LLEUFSG[20] = UNIFAC_subgroup(20, 'CH2CO', 10, 'CH2CO', 1.4457, 1.18,
bonds=UFSG[19].bonds, atoms=UFSG[19].atoms,
smarts=UFSG[19].smarts)
LLEUFSG[21] = UNIFAC_subgroup(21, 'CHO', 11, 'CHO', 0.998, 0.948,
bonds=UFSG[20].bonds, atoms=UFSG[20].atoms,
smarts=UFSG[20].smarts)
LLEUFSG[22] = UNIFAC_subgroup(22, 'Furfural', 12, 'Furfural', 3.168, 2.484,
bonds=UFSG[61].bonds, atoms=UFSG[61].atoms,
smarts=UFSG[61].smarts)
LLEUFSG[23] = UNIFAC_subgroup(23, 'COOH', 13, 'COOH', 1.3013, 1.224,
bonds=UFSG[42].bonds, atoms=UFSG[42].atoms,
smarts=UFSG[42].smarts)
LLEUFSG[24] = UNIFAC_subgroup(24, 'HCOOH', 13, 'COOH', 1.528, 1.532,
bonds=UFSG[43].bonds, atoms=UFSG[43].atoms,
smarts=UFSG[43].smarts)
LLEUFSG[25] = UNIFAC_subgroup(25, 'CH3COO', 14, 'CCOO', 1.9031, 1.728,
bonds=UFSG[21].bonds, atoms=UFSG[21].atoms,
smarts=UFSG[21].smarts)
LLEUFSG[26] = UNIFAC_subgroup(26, 'CH2COO', 14, 'CCOO', 1.6764, 1.42,
bonds=UFSG[22].bonds, atoms=UFSG[22].atoms,
smarts=UFSG[22].smarts)
LLEUFSG[27] = UNIFAC_subgroup(27, 'CH3O', 15, 'CH2O', 1.145, 1.088,
bonds=UFSG[24].bonds, atoms=UFSG[24].atoms,
smarts=UFSG[24].smarts)
LLEUFSG[28] = UNIFAC_subgroup(28, 'CH2O', 15, 'CH2O', 0.9183, 0.78,
bonds=UFSG[25].bonds, atoms=UFSG[25].atoms,
smarts=UFSG[25].smarts)
LLEUFSG[29] = UNIFAC_subgroup(29, 'CHO', 15, 'CH2O', 0.6908, 0.468,
bonds=UFSG[26].bonds, atoms=UFSG[26].atoms,
smarts=UFSG[26].smarts)
LLEUFSG[30] = UNIFAC_subgroup(30, 'FCH2O', 15, 'CH2O', 9183, 1.1,
bonds=UFSG[27].bonds, atoms=UFSG[27].atoms,
smarts=UFSG[27].smarts) # THF in original and others, FCH2O here
LLEUFSG[31] = UNIFAC_subgroup(31, 'CH2CL', 16, 'CCL', 1.4654, 1.264,
bonds=UFSG[44].bonds, atoms=UFSG[44].atoms,
smarts=UFSG[44].smarts)
LLEUFSG[32] = UNIFAC_subgroup(32, 'CHCL', 16, 'CCL', 1.238, 0.952,
bonds=UFSG[45].bonds, atoms=UFSG[45].atoms,
smarts=UFSG[45].smarts)
LLEUFSG[33] = UNIFAC_subgroup(33, 'CCL', 16, 'CCL', 1.0106, 0.724,
bonds=UFSG[46].bonds, atoms=UFSG[46].atoms,
smarts=UFSG[46].smarts)
LLEUFSG[34] = UNIFAC_subgroup(34, 'CH2CL2', 17, 'CCL2', 2.2564, 1.988,
bonds=UFSG[47].bonds, atoms=UFSG[47].atoms,
smarts=UFSG[47].smarts)
LLEUFSG[35] = UNIFAC_subgroup(35, 'CHCL2', 17, 'CCL2', 2.0606, 1.684,
bonds=UFSG[48].bonds, atoms=UFSG[48].atoms,
smarts=UFSG[48].smarts)
LLEUFSG[36] = UNIFAC_subgroup(36, 'CCL2', 17, 'CCL2', 1.8016, 1.448,
bonds=UFSG[49].bonds, atoms=UFSG[49].atoms,
smarts=UFSG[49].smarts)
LLEUFSG[37] = UNIFAC_subgroup(37, 'CHCL3', 18, 'CCL3', 2.87, 2.41,
bonds=UFSG[50].bonds, atoms=UFSG[50].atoms,
smarts=UFSG[50].smarts)
LLEUFSG[38] = UNIFAC_subgroup(38, 'CCL3', 18, 'CCL3', 2.6401, 2.184,
bonds=UFSG[51].bonds, atoms=UFSG[51].atoms,
smarts=UFSG[51].smarts)
LLEUFSG[39] = UNIFAC_subgroup(39, 'CCL4', 19, 'CCL4', 3.39, 2.91,
bonds=UFSG[52].bonds, atoms=UFSG[52].atoms,
smarts=UFSG[52].smarts)
LLEUFSG[40] = UNIFAC_subgroup(40, 'ACCL', 20, 'ACCL', 1.1562, 0.844,
bonds=UFSG[53].bonds, atoms=UFSG[53].atoms,
smarts=UFSG[53].smarts)
LLEUFSG[41] = UNIFAC_subgroup(41, 'CH3CN', 21, 'CCN', 1.8701, 1.724,
bonds=UFSG[40].bonds, atoms=UFSG[40].atoms,
smarts=UFSG[40].smarts)
LLEUFSG[42] = UNIFAC_subgroup(42, 'CH2CN', 21, 'CCN', 1.6434, 1.416,
bonds=UFSG[41].bonds, atoms=UFSG[41].atoms,
smarts=UFSG[41].smarts)
LLEUFSG[43] = UNIFAC_subgroup(43, 'ACNH2', 22, 'ACNH2', 1.06, 0.816,
bonds=UFSG[36].bonds, atoms=UFSG[36].atoms,
smarts=UFSG[36].smarts)
LLEUFSG[44] = UNIFAC_subgroup(44, 'CH3NO2', 23, 'CNO2', 2.0086, 1.868,
bonds=UFSG[54].bonds, atoms=UFSG[54].atoms,
smarts=UFSG[54].smarts)
LLEUFSG[45] = UNIFAC_subgroup(45, 'CH2NO2', 23, 'CNO2', 1.7818, 1.56,
bonds=UFSG[55].bonds, atoms=UFSG[55].atoms,
smarts=UFSG[55].smarts)
LLEUFSG[46] = UNIFAC_subgroup(46, 'CHNO2', 23, 'CNO2', 1.5544, 1.248,
bonds=UFSG[56].bonds, atoms=UFSG[56].atoms,
smarts=UFSG[56].smarts)
LLEUFSG[47] = UNIFAC_subgroup(47, 'ACNO2', 24, 'ACNO2', 1.4199, 1.104,
bonds=UFSG[57].bonds, atoms=UFSG[57].atoms,
smarts=UFSG[57].smarts)
LLEUFSG[48] = UNIFAC_subgroup(48, 'DOH', 25, 'DOH', 2.4088, 2.248,
bonds=UFSG[62].bonds, atoms=UFSG[62].atoms,
smarts=UFSG[62].smarts)
LLEUFSG[49] = UNIFAC_subgroup(49, '(HOCH2CH2)2O', 26, 'DEOH', 4.0013, 3.568,
bonds={SINGLE_BOND: 6}, atoms={'C': 4, 'H': 10, 'O': 3},
smarts='C(COCCO)O') # diethylene glycol
LLEUFSG[50] = UNIFAC_subgroup(50, 'C5H5N', 27, 'PYRIDINE', 2.9993, 2.113,
bonds=UFSG[37].bonds, atoms=UFSG[37].atoms,
smarts=UFSG[37].smarts)
LLEUFSG[51] = UNIFAC_subgroup(51, 'C5H4N', 27, 'PYRIDINE', 2.8332, 1.833,
bonds=UFSG[38].bonds, atoms=UFSG[38].atoms,
smarts=UFSG[38].smarts)
LLEUFSG[52] = UNIFAC_subgroup(52, 'C5H3N', 27, 'PYRIDINE', 2.667, 1.553,
bonds=UFSG[39].bonds, atoms=UFSG[39].atoms,
smarts=UFSG[39].smarts)
LLEUFSG[53] = UNIFAC_subgroup(53, 'CCl2=CHCl', 28, 'TCE', 3.3092, 2.860,
bonds={SINGLE_BOND: 3, DOUBLE_BOND: 1}, atoms={'C': 2, 'H': 1, 'Cl': 3},
smarts='C(=C(Cl)Cl)Cl') # trichloroethylene
LLEUFSG[54] = UNIFAC_subgroup(54, 'HCONHCH3', 29, 'MFA', 2.4317, 2.192,
bonds={SINGLE_BOND: 2, DOUBLE_BOND: 1}, atoms={'C': 2, 'H': 5, 'N': 1, 'O': 1},
smarts='CNC=O') # methylformamide
LLEUFSG[55] = UNIFAC_subgroup(55, 'DMF', 30, 'DMFA', 3.0856, 2.736,
bonds=UFSG[72].bonds, atoms=UFSG[72].atoms,
smarts=UFSG[72].smarts) # DMFA is same as DMF - dimethylformamide
LLEUFSG[56] = UNIFAC_subgroup(56, '(CH2)4SO2', 31, 'TMS', 4.0358, 3.20,
bonds={SINGLE_BOND: 5, DOUBLE_BOND: 2}, atoms={'C': 4, 'H': 8, 'O': 2, 'S': 1},
smarts='C1CCS(=O)(=O)C1') # tetramethylene sulfone
LLEUFSG[57] = UNIFAC_subgroup(57, 'DMSO', 32, 'DMSO', 2.8266, 2.472,
bonds=UFSG[67].bonds, atoms=UFSG[67].atoms,
smarts=UFSG[67].smarts)
# Generated with the following:
"""
t = 'LLEMG = {'
for main_key in range(1, 33):
main_group = None
hits = []
for subgroup_key, o in LLEUFSG.items():
if o.main_group_id == main_key:
main_group = o.main_group
hits.append(subgroup_key)
t += '%d: ("%s", %s),\n' %(main_key, main_group, list(sorted(hits)))
t += '}'
"""
LLEMG = { 1: ("CH2", [1, 2, 3, 4]),
2: ("C=C", [5, 6, 7, 8]),
3: ("ACH", [9, 10]),
4: ("ACCH2", [11, 12, 13]),
5: ("OH", [14]),
6: ("P1", [15]),
7: ("P2", [16]),
8: ("H2O", [17]),
9: ("ACOH", [18]),
10: ("CH2CO", [19, 20]),
11: ("CHO", [21]),
12: ("Furfural", [22]),
13: ("COOH", [23, 24]),
14: ("CCOO", [25, 26]),
15: ("CH2O", [27, 28, 29, 30]),
16: ("CCL", [31, 32, 33]),
17: ("CCL2", [34, 35, 36]),
18: ("CCL3", [37, 38]),
19: ("CCL4", [39]),
20: ("ACCL", [40]),
21: ("CCN", [41, 42]),
22: ("ACNH2", [43]),
23: ("CNO2", [44, 45, 46]),
24: ("ACNO2", [47]),
25: ("DOH", [48]),
26: ("DEOH", [49]),
27: ("PYRIDINE", [50, 51, 52]),
28: ("TCE", [53]),
29: ("MFA", [54]),
30: ("DMFA", [55]),
31: ("TMS", [56]),
32: ("DMSO", [57]),
}
"""
Larsen, Bent L., Peter Rasmussen, and Aage Fredenslund. "A Modified UNIFAC
Group-Contribution Model for Prediction of Phase Equilibria and Heats of Mixing."
Industrial & Engineering Chemistry Research 26, no. 11 (November 1, 1987):
2274-86. https://doi.org/10.1021/ie00071a018.
"""
LUFSG = {}
LUFSG[1] = UNIFAC_subgroup(1, 'CH3', 1, 'CH2', 0.9011, 0.848,
atoms=UFSG[1].atoms, bonds=UFSG[1].bonds, smarts=UFSG[1].smarts)
LUFSG[2] = UNIFAC_subgroup(2, 'CH2', 1, 'CH2', 0.6744, 0.54,
atoms=UFSG[2].atoms, bonds=UFSG[2].bonds, smarts=UFSG[2].smarts)
LUFSG[3] = UNIFAC_subgroup(3, 'CH', 1, 'CH2', 0.4469, 0.228,
atoms=UFSG[3].atoms, bonds=UFSG[3].bonds, smarts=UFSG[3].smarts)
LUFSG[4] = UNIFAC_subgroup(4, 'C', 1, 'CH2', 0.2195, 0,
atoms=UFSG[4].atoms, bonds=UFSG[4].bonds, smarts=UFSG[4].smarts)
LUFSG[5] = UNIFAC_subgroup(5, 'CH2=CH', 2, 'C=C', 1.3454, 1.176,
atoms=UFSG[5].atoms, bonds=UFSG[5].bonds, smarts=UFSG[5].smarts)
LUFSG[6] = UNIFAC_subgroup(6, 'CH=CH', 2, 'C=C', 1.1167, 0.867,
atoms=UFSG[6].atoms, bonds=UFSG[6].bonds, smarts=UFSG[6].smarts)
LUFSG[7] = UNIFAC_subgroup(7, 'CH2=C', 2, 'C=C', 1.1173, 0.988,
atoms=UFSG[7].atoms, bonds=UFSG[7].bonds, smarts=UFSG[7].smarts)
LUFSG[8] = UNIFAC_subgroup(8, 'CH=C', 2, 'C=C', 0.8886, 0.676,
atoms=UFSG[8].atoms, bonds=UFSG[8].bonds, smarts=UFSG[8].smarts)
LUFSG[9] = UNIFAC_subgroup(9, 'C=C', 2, 'C=C', 0.6605, 0.485,
atoms=UFSG[70].atoms, bonds=UFSG[70].bonds, smarts=UFSG[70].smarts)
LUFSG[10] = UNIFAC_subgroup(10, 'ACH', 3, 'ACH', 0.5313, 0.4,
atoms=UFSG[9].atoms, bonds=UFSG[9].bonds, smarts=UFSG[9].smarts)
LUFSG[11] = UNIFAC_subgroup(11, 'AC', 3, 'ACH', 0.3652, 0.12,
atoms=UFSG[10].atoms, bonds=UFSG[10].bonds, smarts=UFSG[10].smarts)
LUFSG[12] = UNIFAC_subgroup(12, 'OH', 4, 'OH', 1, 1.2,
atoms=UFSG[14].atoms, bonds=UFSG[14].bonds, smarts=UFSG[14].smarts)
LUFSG[13] = UNIFAC_subgroup(13, 'CH3OH', 5, 'CH3OH', 1.0, 1.0,
atoms=UFSG[15].atoms, bonds=UFSG[15].bonds, smarts=UFSG[15].smarts)
LUFSG[14] = UNIFAC_subgroup(14, 'H2O', 6, 'H2O', 0.92, 1.4,
atoms=UFSG[16].atoms, bonds=UFSG[16].bonds, smarts=UFSG[16].smarts)
LUFSG[15] = UNIFAC_subgroup(15, 'CH3CO', 7, 'CH2CO', 1.6724, 1.488,
atoms=UFSG[18].atoms, bonds=UFSG[18].bonds, smarts=UFSG[18].smarts)
LUFSG[16] = UNIFAC_subgroup(16, 'CH2CO', 7, 'CH2CO', 1.4457, 1.488,
atoms=UFSG[19].atoms, bonds=UFSG[19].bonds, smarts=UFSG[19].smarts)
LUFSG[17] = UNIFAC_subgroup(17, 'CHO', 8, 'CHO', 0.998, 0.948,
atoms=UFSG[20].atoms, bonds=UFSG[20].bonds, smarts=UFSG[20].smarts)
LUFSG[18] = UNIFAC_subgroup(18, 'CH3COO', 9, 'CCOO', 1.9031, 1.728,
atoms=UFSG[21].atoms, bonds=UFSG[21].bonds, smarts=UFSG[21].smarts)
LUFSG[19] = UNIFAC_subgroup(19, 'CH2COO', 9, 'CCOO', 1.6764, 1.42,
atoms=UFSG[22].atoms, bonds=UFSG[22].bonds, smarts=UFSG[22].smarts)
LUFSG[20] = UNIFAC_subgroup(20, 'CH3O', 10, 'CH2O', 1.145, 0.9,
atoms=UFSG[24].atoms, bonds=UFSG[24].bonds, smarts=UFSG[24].smarts)
LUFSG[21] = UNIFAC_subgroup(21, 'CH2O', 10, 'CH2O', 0.9183, 0.78,
atoms=UFSG[25].atoms, bonds=UFSG[25].bonds, smarts=UFSG[25].smarts)
LUFSG[22] = UNIFAC_subgroup(22, 'CHO', 10, 'CH2O', 0.6908, 0.65,
atoms=UFSG[26].atoms, bonds=UFSG[26].bonds, smarts=UFSG[26].smarts)
LUFSG[23] = UNIFAC_subgroup(23, 'THF', 10, 'CH2O', 0.9183, 1.1,
atoms=UFSG[27].atoms, bonds=UFSG[27].bonds, smarts=UFSG[27].smarts)
LUFSG[24] = UNIFAC_subgroup(24, 'NH2', 11, 'NH2', 0.6948, 1.150,
atoms={'H': 2, 'N': 1}, bonds={}, smarts='[NH2]')
LUFSG[25] = UNIFAC_subgroup(25, 'CH3NH', 12, 'CNH2NG', 1.4337, 1.050,
atoms=UFSG[31].atoms, bonds=UFSG[31].bonds, smarts=UFSG[31].smarts)
LUFSG[26] = UNIFAC_subgroup(26, 'CH2NH', 12, 'CNH2NG', 1.207, 0.936,
atoms=UFSG[32].atoms, bonds=UFSG[32].bonds, smarts=UFSG[32].smarts)
LUFSG[27] = UNIFAC_subgroup(27, 'CHNH', 12, 'CNH2NG', 0.9795, 0.624,
atoms=UFSG[33].atoms, bonds=UFSG[33].bonds, smarts=UFSG[33].smarts)
LUFSG[28] = UNIFAC_subgroup(28, 'CH3N', 13, 'CH2N', 1.1865, 0.94,
atoms=UFSG[34].atoms, bonds=UFSG[34].bonds, smarts=UFSG[34].smarts)
LUFSG[29] = UNIFAC_subgroup(29, 'CH2N', 13, 'CH2N', 0.9597, 0.632,
atoms=UFSG[35].atoms, bonds=UFSG[35].bonds, smarts=UFSG[35].smarts)
LUFSG[30] = UNIFAC_subgroup(30, 'ANH2', 14, 'ANH2', 0.6948, 1.4,
atoms={'H': 2, 'N': 1}, bonds={}, smarts='[nH2]') # NH2 attached to aromatic ring
LUFSG[31] = UNIFAC_subgroup(31, 'C5H5N', 15, 'PYRIDINE', 2.9993, 2.113,
atoms=UFSG[37].atoms, bonds=UFSG[37].bonds, smarts=UFSG[37].smarts)
LUFSG[32] = UNIFAC_subgroup(32, 'C5H4N', 15, 'PYRIDINE', 2.8332, 1.833,
atoms=UFSG[38].atoms, bonds=UFSG[38].bonds, smarts=UFSG[38].smarts)
LUFSG[33] = UNIFAC_subgroup(33, 'C5H3N', 15, 'PYRIDINE', 2.667, 1.553,
atoms=UFSG[39].atoms, bonds=UFSG[39].bonds, smarts=UFSG[39].smarts)
LUFSG[34] = UNIFAC_subgroup(34, 'CH3CN', 16, 'CCN', 1.8701, 1.724,
atoms=UFSG[40].atoms, bonds=UFSG[40].bonds, smarts=UFSG[40].smarts)
LUFSG[35] = UNIFAC_subgroup(35, 'CH2CN', 16, 'CCN', 1.6434, 1.416,
atoms=UFSG[41].atoms, bonds=UFSG[41].bonds, smarts=UFSG[41].smarts)
LUFSG[36] = UNIFAC_subgroup(36, 'COOH', 17, 'COOH', 1.3013, 1.224,
atoms=UFSG[42].atoms, bonds=UFSG[42].bonds, smarts=UFSG[42].smarts)
LUFSG[37] = UNIFAC_subgroup(37, 'CH2CL', 18, 'CCL', 1.4654, 1.264,
atoms=UFSG[44].atoms, bonds=UFSG[44].bonds, smarts=UFSG[44].smarts)
LUFSG[38] = UNIFAC_subgroup(38, 'CHCL', 18, 'CCL', 1.238, 0.952,
atoms=UFSG[45].atoms, bonds=UFSG[45].bonds, smarts=UFSG[45].smarts)
LUFSG[39] = UNIFAC_subgroup(39, 'CCL', 18, 'CCL', 1.0106, 0.724,
atoms=UFSG[46].atoms, bonds=UFSG[46].bonds, smarts=UFSG[46].smarts)
LUFSG[40] = UNIFAC_subgroup(40, 'CH2CL2', 19, 'CCL2', 2.2564, 1.988,
atoms=UFSG[47].atoms, bonds=UFSG[47].bonds, smarts=UFSG[47].smarts)
LUFSG[41] = UNIFAC_subgroup(41, 'CHCL2', 19, 'CCL2', 2.0606, 1.684,
atoms=UFSG[48].atoms, bonds=UFSG[48].bonds, smarts=UFSG[48].smarts)
LUFSG[42] = UNIFAC_subgroup(42, 'CCL2', 19, 'CCL2', 1.8016, 1.448,
atoms=UFSG[49].atoms, bonds=UFSG[49].bonds, smarts=UFSG[49].smarts)
LUFSG[43] = UNIFAC_subgroup(43, 'CHCL3', 20, 'CCL3', 2.87, 2.41,
atoms=UFSG[50].atoms, bonds=UFSG[50].bonds, smarts=UFSG[50].smarts)
LUFSG[44] = UNIFAC_subgroup(44, 'CCL3', 20, 'CCL3', 2.6401, 2.184,
atoms=UFSG[51].atoms, bonds=UFSG[51].bonds, smarts=UFSG[51].smarts)
LUFSG[45] = UNIFAC_subgroup(45, 'CCL4', 21, 'CCL4', 3.39, 2.91,
atoms=UFSG[52].atoms, bonds=UFSG[52].bonds, smarts=UFSG[52].smarts)
LUFMG = {1: ("CH2", [1, 2, 3, 4]),
2: ("C=C", [5, 6, 7, 8, 9]),
3: ("ACH", [10, 11]),
4: ("OH", [12]),
5: ("CH3OH", [13]),
6: ("H2O", [14]),
7: ("CH2CO", [15, 16]),
8: ("CHO", [17]),
9: ("CCOO", [18, 19]),
10: ("CH2O", [20, 21, 22, 23]),
11: ("NH2", [24]),
12: ("CNH2NG", [25, 26, 27]),
13: ("CH2N", [28, 29]),
14: ("ANH2", [30]),
15: ("PYRIDINE", [31, 32, 33]),
16: ("CCN", [34, 35]),
17: ("COOH", [36]),
18: ("CCL", [37, 38, 39]),
19: ("CCL2", [40, 41, 42]),
20: ("CCL3", [43, 44]),
21: ("CCL4", [45]),
}
NISTKTUFSG = {}
NISTKTUFSG[1] = UNIFAC_subgroup(1, "CH3-", 1, 'C', 0.9011, 0.848)
NISTKTUFSG[2] = UNIFAC_subgroup(2, "-CH2-", 1, 'C', 0.6744, 0.54)
NISTKTUFSG[3] = UNIFAC_subgroup(3, "-CH<", 1, 'C', 0.4469, 0.228)
NISTKTUFSG[4] = UNIFAC_subgroup(4, ">C<", 1, 'C', 0.2195, 0)
NISTKTUFSG[5] = UNIFAC_subgroup(5, "CH2=CH-", 2, 'C=C', 1.3454, 1.176)
NISTKTUFSG[6] = UNIFAC_subgroup(6, "-CH=CH-", 2, 'C=C', 1.1167, 0.867)
NISTKTUFSG[7] = UNIFAC_subgroup(7, "CH2=C<", 2, 'C=C', 1.1173, 0.988)
NISTKTUFSG[8] = UNIFAC_subgroup(8, "-CH=C<", 2, 'C=C', 0.8886, 0.676)
NISTKTUFSG[9] = UNIFAC_subgroup(9, ">C=C<", 2, 'C=C', 0.6605, 0.485)
NISTKTUFSG[15] = UNIFAC_subgroup(15, "-ACH-", 3, 'ACH', 0.5313, 0.4)
NISTKTUFSG[16] = UNIFAC_subgroup(16, ">AC- (link)", 3, 'ACH', 0.3652, 0.12)
NISTKTUFSG[17] = UNIFAC_subgroup(17, ">AC- (cond)", 3, 'ACH', 0.3125, 0.084)
NISTKTUFSG[18] = UNIFAC_subgroup(18, ">AC-CH3", 4, 'ACCH2', 1.2663, 0.968)
NISTKTUFSG[19] = UNIFAC_subgroup(19, ">AC-CH2-", 4, 'ACCH2', 1.0396, 0.66)
NISTKTUFSG[20] = UNIFAC_subgroup(20, ">AC-CH<", 4, 'ACCH2', 0.8121, 0.348)
NISTKTUFSG[21] = UNIFAC_subgroup(21, ">AC-C<-", 4, 'ACCH2', 0.5847, 0.084)
NISTKTUFSG[34] = UNIFAC_subgroup(34, "-OH(primary)", 5, 'OH', 1, 1.2)
NISTKTUFSG[204] = UNIFAC_subgroup(204, "-OH(secondary)", 5, 'OH', 1, 1.2)
NISTKTUFSG[205] = UNIFAC_subgroup(205, "-OH(tertiary)", 5, 'OH', 1, 1.2)
NISTKTUFSG[35] = UNIFAC_subgroup(35, "CH3OH", 6, 'CH2OH', 1.4311, 1.432)
NISTKTUFSG[36] = UNIFAC_subgroup(36, "H2O", 7, 'H2O', 0.92, 1.4)
NISTKTUFSG[37] = UNIFAC_subgroup(37, ">AC-OH", 8, 'ACOH', 0.8952, 0.68)
NISTKTUFSG[42] = UNIFAC_subgroup(42, "CH3-CO-", 9, 'CH2CO', 1.6724, 1.488)
NISTKTUFSG[43] = UNIFAC_subgroup(43, "-CH2-CO-", 9, 'CH2CO', 1.4457, 1.18)
NISTKTUFSG[44] = UNIFAC_subgroup(44, ">CH-CO-", 9, 'CH2CO', 1.2182, 0.868)
NISTKTUFSG[45] = UNIFAC_subgroup(45, "->C-CO-", 9, 'CH2CO', 0.9908, 0.64)
NISTKTUFSG[48] = UNIFAC_subgroup(48, "-CHO", 10, 'CHO', 0.998, 0.948)
NISTKTUFSG[51] = UNIFAC_subgroup(51, "CH3-COO-", 11, 'CCOO', 1.9031, 1.728)
NISTKTUFSG[52] = UNIFAC_subgroup(52, "-CH2-COO-", 11, 'CCOO', 1.6764, 1.42)
NISTKTUFSG[53] = UNIFAC_subgroup(53, ">CH-COO-", 11, 'CCOO', 1.4489, 1.108)
NISTKTUFSG[54] = UNIFAC_subgroup(54, "->C-COO-", 11, 'CCOO', 1.2215, 0.88)
NISTKTUFSG[55] = UNIFAC_subgroup(55, "HCOO-", 12, 'HCOO', 1.242, 1.188)
NISTKTUFSG[59] = UNIFAC_subgroup(59, "CH3-O-", 13, 'CH2O', 1.145, 1.088)
NISTKTUFSG[60] = UNIFAC_subgroup(60, "-CH2-O-", 13, 'CH2O', 0.9183, 0.78)
NISTKTUFSG[61] = UNIFAC_subgroup(61, ">CH-O-", 13, 'CH2O', 0.6908, 0.468)
NISTKTUFSG[62] = UNIFAC_subgroup(62, "->CO-", 13, 'CH2O', 0.9183, 0.24)
NISTKTUFSG[63] = UNIFAC_subgroup(63, "-CH2-O- (cy)", 'CH2O', None, 0.9183, 1.1)
NISTKTUFSG[66] = UNIFAC_subgroup(66, "CH3-NH2", 14, 'CNH2', 1.5959, 1.544)
NISTKTUFSG[67] = UNIFAC_subgroup(67, "-CH2-NH2", 14, 'CNH2', 1.3692, 1.236)
NISTKTUFSG[68] = UNIFAC_subgroup(68, ">CH-NH2", 14, 'CNH2', 1.1417, 0.924)
NISTKTUFSG[69] = UNIFAC_subgroup(69, "->C-NH2", 14, 'CNH2', 0.9275, 0.696)
NISTKTUFSG[71] = UNIFAC_subgroup(71, "CH3-NH-", 15, '(C)2NH', 1.4337, 1.244)
NISTKTUFSG[72] = UNIFAC_subgroup(72, "-CH2-NH-", 15, '(C)2NH', 1.207, 0.936)
NISTKTUFSG[73] = UNIFAC_subgroup(73, ">CH-NH-", 15, '(C)2NH', 0.9795, 0.624)
NISTKTUFSG[74] = UNIFAC_subgroup(74, "CH3-N<", 16, '(C)3N', 1.1865, 0.94)
NISTKTUFSG[75] = UNIFAC_subgroup(75, "-CH2-N<", 16, '(C)3N', 0.9597, 0.632)
NISTKTUFSG[79] = UNIFAC_subgroup(79, ">AC-NH2", 17, 'ACNH2', 1.06, 0.816)
NISTKTUFSG[80] = UNIFAC_subgroup(80, ">AC-NH-", 17, 'ACNH2', 0.8978, 0.516)
NISTKTUFSG[81] = UNIFAC_subgroup(81, ">AC-N<", 17, 'ACNH2', 0.6506, 0.212)
NISTKTUFSG[76] = UNIFAC_subgroup(76, "C5H5N", 18, 'Pyridine', 2.9993, 2.113)
NISTKTUFSG[77] = UNIFAC_subgroup(77, "C5H4N-", 18, 'Pyridine', 2.8332, 1.833)
NISTKTUFSG[78] = UNIFAC_subgroup(78, "C5H3N<", 18, 'Pyridine', 2.667, 1.553)
NISTKTUFSG[85] = UNIFAC_subgroup(85, "CH3-CN", 19, 'CCN', 1.8701, 1.724)
NISTKTUFSG[86] = UNIFAC_subgroup(86, "-CH2-CN", 19, 'CCN', 1.6434, 1.416)
NISTKTUFSG[87] = UNIFAC_subgroup(87, ">CH-CN", 19, 'CCN', 1.416, 1.104)
NISTKTUFSG[88] = UNIFAC_subgroup(88, "->C-CN", 19, 'CCN', 1.1885, 0.876)
NISTKTUFSG[94] = UNIFAC_subgroup(94, "-COOH", 20, 'COOH', 1.3013, 1.224)
NISTKTUFSG[95] = UNIFAC_subgroup(95, "HCOOH", 20, 'COOH', 1.528, 1.532)
NISTKTUFSG[99] = UNIFAC_subgroup(99, "-CH2-Cl", 21, 'CCl', 1.4654, 1.264)
NISTKTUFSG[100] = UNIFAC_subgroup(100, ">CH-Cl", 21, 'CCl', 1.238, 0.952)
NISTKTUFSG[101] = UNIFAC_subgroup(101, "->CCl", 21, 'CCl', 1.0106, 0.724)
NISTKTUFSG[102] = UNIFAC_subgroup(102, "CH2Cl2", 22, 'CCl2', 2.2564, 1.988)
NISTKTUFSG[103] = UNIFAC_subgroup(103, "-CHCl2", 22, 'CCl2', 2.0606, 1.684)
NISTKTUFSG[104] = UNIFAC_subgroup(104, ">CCl2", 22, 'CCl2', 1.8016, 1.448)
NISTKTUFSG[105] = UNIFAC_subgroup(105, "CHCl3", 23, 'CCl3', 2.87, 2.41)
NISTKTUFSG[106] = UNIFAC_subgroup(106, "-CCl3", 23, 'CCl3', 2.6401, 2.184)
NISTKTUFSG[107] = UNIFAC_subgroup(107, "CCl4", 24, 'CCl4', 3.39, 2.91)
NISTKTUFSG[109] = UNIFAC_subgroup(109, ">AC-Cl", 25, 'ACCl', 1.1562, 0.844)
NISTKTUFSG[132] = UNIFAC_subgroup(132, "CH3-NO2", 26, 'CNO2', 2.0086, 1.868)
NISTKTUFSG[133] = UNIFAC_subgroup(133, "-CH2-NO2", 26, 'CNO2', 1.7818, 1.56)
NISTKTUFSG[134] = UNIFAC_subgroup(134, ">CH-NO2", 26, 'CNO2', 1.5544, 1.248)
NISTKTUFSG[135] = UNIFAC_subgroup(135, "->C-NO2", 26, 'CNO2', 1.327, 1.02)
NISTKTUFSG[136] = UNIFAC_subgroup(136, ">AC-NO2", 27, 'ACNO2', 1.4199, 1.104)
NISTKTUFSG[146] = UNIFAC_subgroup(146, "CS2", 28, 'CS2', 2.057, 1.65)
NISTKTUFSG[138] = UNIFAC_subgroup(138, "CH3-SH", 29, 'CH3SH', 1.877, 1.676)
NISTKTUFSG[139] = UNIFAC_subgroup(139, "-CH2-SH", 29, 'CH3SH', 1.651, 1.368)
NISTKTUFSG[140] = UNIFAC_subgroup(140, ">CH-SH", 29, 'CH3SH', 1.4232, 0.228)
NISTKTUFSG[141] = UNIFAC_subgroup(141, "->C-SH", 29, 'CH3SH', 1.1958, 0)
NISTKTUFSG[50] = UNIFAC_subgroup(50, "C5H4O2", 30, 'Furfural', 3.168, 2.484)
NISTKTUFSG[38] = UNIFAC_subgroup(38, "(CH2OH)2", 31, 'DOH', 2.4088, 2.248)
NISTKTUFSG[128] = UNIFAC_subgroup(128, "-I", 32, 'I', 1.264, 0.992)
NISTKTUFSG[130] = UNIFAC_subgroup(130, "-Br", 33, 'Br', 0.9492, 0.832)
NISTKTUFSG[13] = UNIFAC_subgroup(13, "CH≡C-", 34, 'C=-C', 1.292, 1.088)
NISTKTUFSG[14] = UNIFAC_subgroup(14, "-C≡C-", 34, 'C=-C', 1.0613, 0.784)
NISTKTUFSG[153] = UNIFAC_subgroup(153, "DMSO", 35, 'DMSO', 2.8266, 2.472)
NISTKTUFSG[90] = UNIFAC_subgroup(90, "CH2=CH-CN", 36, 'ACRY', 2.3144, 2.052)
NISTKTUFSG[108] = UNIFAC_subgroup(108, "Cl(C=C)", 37, 'Cl(C=C)', 0.791, 0.724)
NISTKTUFSG[118] = UNIFAC_subgroup(118, ">AC-F", 38, 'ACF', 0.6948, 0.524)
NISTKTUFSG[161] = UNIFAC_subgroup(161, "DMF", 39, 'DMF', 3.0856, 2.736)
NISTKTUFSG[162] = UNIFAC_subgroup(162, "-CON(CH3)2", 39, 'DMF', 2.8589, 2.428)
NISTKTUFSG[163] = UNIFAC_subgroup(163, "-CON(CH2)(CH3)-", 39, 'DMF', 2.6322, 2.12)
NISTKTUFSG[164] = UNIFAC_subgroup(164, "HCON(CH2)2<", 39, 'DMF', 2.6322, 2.12)
NISTKTUFSG[165] = UNIFAC_subgroup(165, "-CON(CH2)2<", 39, 'DMF', 2.4054, 1.812)
NISTKTUFSG[111] = UNIFAC_subgroup(111, "CHF3", 40, 'CF2', 1.5781, 1.548)
NISTKTUFSG[112] = UNIFAC_subgroup(112, "-CF3", 40, 'CF2', 1.406, 1.38)
NISTKTUFSG[113] = UNIFAC_subgroup(113, "-CHF2", 40, 'CF2', 1.2011, 1.108)
NISTKTUFSG[114] = UNIFAC_subgroup(114, ">CF2", 40, 'CF2', 1.0105, 0.92)
NISTKTUFSG[115] = UNIFAC_subgroup(115, "-CH2F", 40, 'CF2', 1.0514, 0.98)
NISTKTUFSG[116] = UNIFAC_subgroup(116, ">CH-F", 40, 'CF2', 0.824, 0.668)
NISTKTUFSG[117] = UNIFAC_subgroup(117, "->CF", 40, 'CF2', 0.615, 0.46)
NISTKTUFSG[58] = UNIFAC_subgroup(58, "-COO-", 41, 'COO', 1.38, 1.2)
NISTKTUFSG[197] = UNIFAC_subgroup(197, "SiH3-", 42, 'SiH2', 1.6035, 1.263)
NISTKTUFSG[198] = UNIFAC_subgroup(198, "-SiH2-", 42, 'SiH2', 1.4443, 1.006)
NISTKTUFSG[199] = UNIFAC_subgroup(199, ">SiH-", 42, 'SiH2', 1.2853, 0.749)
NISTKTUFSG[200] = UNIFAC_subgroup(200, ">Si<", 42, 'SiH2', 1.047, 0.41)
NISTKTUFSG[201] = UNIFAC_subgroup(201, "-SiH2-O-", 43, 'SiO', 1.4838, 1.062)
NISTKTUFSG[202] = UNIFAC_subgroup(202, ">SiH-O-", 43, 'SiO', 1.303, 0.764)
NISTKTUFSG[203] = UNIFAC_subgroup(203, "->Si-O-", 43, 'SiO', 1.1044, 0.466)
NISTKTUFSG[195] = UNIFAC_subgroup(195, "NMP", 44, 'NMP', 3.981, 3.2)
NISTKTUFSG[120] = UNIFAC_subgroup(120, "CCl3F", 45, 'CClF', 3.0356, 2.644)
NISTKTUFSG[121] = UNIFAC_subgroup(121, "-CCl2F", 45, 'CClF', 2.2287, 1.916)
NISTKTUFSG[122] = UNIFAC_subgroup(122, "HCCl2F", 45, 'CClF', 2.406, 2.116)
NISTKTUFSG[123] = UNIFAC_subgroup(123, "-HCClF", 45, 'CClF', 1.6493, 1.416)
NISTKTUFSG[124] = UNIFAC_subgroup(124, "-CClF2", 45, 'CClF', 1.8174, 1.648)
NISTKTUFSG[125] = UNIFAC_subgroup(125, "HCClF2", 45, 'CClF', 1.967, 1.828)
NISTKTUFSG[126] = UNIFAC_subgroup(126, "CClF3", 45, 'CClF', 2.1721, 2.1)
NISTKTUFSG[127] = UNIFAC_subgroup(127, "CCl2F2", 45, 'CClF', 2.6243, 2.376)
NISTKTUFSG[166] = UNIFAC_subgroup(166, "-CONH(CH3)", 46, 'CONCH2', 2.205, 1.884)
NISTKTUFSG[167] = UNIFAC_subgroup(167, "HCONH(CH2)-", 46, 'CONCH2', 2.205, 1.884)
NISTKTUFSG[168] = UNIFAC_subgroup(168, "-CONH(CH2)-", 46, 'CONCH2', 1.9782, 1.576)
NISTKTUFSG[169] = UNIFAC_subgroup(169, "-CONH2", 46, 'CONCH2', 1.4661, 1.336)
NISTKTUFSG[39] = UNIFAC_subgroup(39, "-O-CH2-CH2-OH", 47, 'OCCOH', 2.1226, 1.904)
NISTKTUFSG[40] = UNIFAC_subgroup(40, "-O-CH-CH2-OH", 47, 'OCCOH', 1.8952, 1.592)
NISTKTUFSG[41] = UNIFAC_subgroup(41, "-O-CH2-CH-OH", 47, 'OCCOH', 1.8952, 1.592)
NISTKTUFSG[142] = UNIFAC_subgroup(142, "CH3-S-", 48, 'CH2S', 1.613, 1.368)
NISTKTUFSG[143] = UNIFAC_subgroup(143, "-CH2-S-", 48, 'CH2S', 1.3863, 1.06)
NISTKTUFSG[144] = UNIFAC_subgroup(144, ">CH-S-", 48, 'CH2S', 1.1589, 0.748)
NISTKTUFSG[145] = UNIFAC_subgroup(145, "->C-S-", 48, 'CH2S', 0.9314, 0.52)
NISTKTUFSG[196] = UNIFAC_subgroup(196, "MORPHOLIN", 49, 'Morpholin', 3.474, 2.796)
NISTKTUFSG[147] = UNIFAC_subgroup(147, "THIOPHENE", 50, 'THIOPHENE', 2.8569, 2.14)
NISTKTUFSG[148] = UNIFAC_subgroup(148, "C4H3S-", 50, 'THIOPHENE', 2.6908, 1.86)
NISTKTUFSG[149] = UNIFAC_subgroup(149, "C4H2S<", 50, 'THIOPHENE', 2.5247, 1.58)
NISTKTUFSG[27] = UNIFAC_subgroup(27, "-CH2- (cy)", 51, 'CH2(cyc)', 0.6744, 0.54)
NISTKTUFSG[28] = UNIFAC_subgroup(28, ">CH- (cy)", 51, 'CH2(cyc)', 0.4469, 0.228)
NISTKTUFSG[29] = UNIFAC_subgroup(29, ">C< (cy)", 51, 'CH2(cyc)', 0.2195, 0)
NISTKTUFSG[30] = UNIFAC_subgroup(30, "-CH=CH- (cy)", 52, 'C=C(cyc)', 1.1167, 0.867)
NISTKTUFSG[31] = UNIFAC_subgroup(31, "CH2=C< (cy)", 52, 'C=C(cyc)', 1.1173, 0.988)
NISTKTUFSG[32] = UNIFAC_subgroup(32, "-CH=C< (cy)", 52, 'C=C(cyc)', 0.8886, 0.676)
NISTKTUFMG = {1: ("C", [1, 2, 3, 4]),
2: ("C=C", [5, 6, 7, 8, 9]),
3: ("ACH", [15, 16, 17]),
4: ("ACCH2", [18, 19, 20, 21]),
5: ("OH", [34, 204, 205]),
6: ("CH2OH", [35]),
7: ("H2O", [36]),
8: ("ACOH", [37]),
9: ("CH2CO", [42, 43, 44, 45]),
10: ("CHO", [48]),
11: ("CCOO", [51, 52, 53, 54]),
12: ("HCOO", [55]),
13: ("CH2O", [59, 60, 61, 62]),
14: ("CNH2", [66, 67, 68, 69]),
15: ("(C)2NH", [71, 72, 73]),
16: ("(C)3N", [74, 75]),
17: ("ACNH2", [79, 80, 81]),
18: ("Pyridine", [76, 77, 78]),
19: ("CCN", [85, 86, 87, 88]),
20: ("COOH", [94, 95]),
21: ("CCl", [99, 100, 101]),
22: ("CCl2", [102, 103, 104]),
23: ("CCl3", [105, 106]),
24: ("CCl4", [107]),
25: ("ACCl", [109]),
26: ("CNO2", [132, 133, 134, 135]),
27: ("ACNO2", [136]),
28: ("CS2", [146]),
29: ("CH3SH", [138, 139, 140, 141]),
30: ("Furfural", [50]),
31: ("DOH", [38]),
32: ("I", [128]),
33: ("Br", [130]),
34: ("C=-C", [13, 14]),
35: ("DMSO", [153]),
36: ("ACRY", [90]),
37: ("Cl(C=C)", [108]),
38: ("ACF", [118]),
39: ("DMF", [161, 162, 163, 164, 165]),
40: ("CF2", [111, 112, 113, 114, 115, 116, 117]),
41: ("COO", [58]),
42: ("SiH2", [197, 198, 199, 200]),
43: ("SiO", [201, 202, 203]),
44: ("NMP", [195]),
45: ("CClF", [120, 121, 122, 123, 124, 125, 126, 127]),
46: ("CONCH2", [166, 167, 168, 169]),
47: ("OCCOH", [39, 40, 41]),
48: ("CH2S", [142, 143, 144, 145]),
49: ("Morpholin", [196]),
50: ("THIOPHENE", [147, 148, 149]),
51: ("CH2(cyc)", [27, 28, 29]),
52: ("C=C(cyc)", [30, 31, 32]),
}
"""Compared to storing the values in dict[(int1, int2)] = (values),
the dict-in-dict structure is found emperically to take 111608 bytes vs.
79096 bytes, or 30% less memory.
"""
for d in (UFSG, DOUFSG, NISTUFSG, NISTKTUFSG, LLEUFSG, LUFSG, PSRKSG, VTPRSG):
for group in d.values():
if group.priority is None:
if group.atoms is not None:
group.priority = priority_from_atoms(group.atoms, group.bonds)
global _unifac_ip_loaded
_unifac_ip_loaded = False
def load_unifac_ip():
global _unifac_ip_loaded, UFIP, LLEUFIP, LUFIP, DOUFIP2006, DOUFIP2016, NISTUFIP, NISTKTUFIP, PSRKIP, VTPRIP
folder = os.path.join(os.path.dirname(__file__), 'Phase Change')
UFIP = {i: {} for i in list(range(1, 52)) + [55, 84, 85]}
with open(os.path.join(folder, 'UNIFAC original interaction parameters.tsv')) as f:
for line in f:
maingroup1, maingroup2, interaction_parameter = line.strip('\n').split('\t')
# Index by both int, order maters, to only one parameter.
UFIP[int(maingroup1)][int(maingroup2)] = float(interaction_parameter)
LLEUFIP = {i: {} for i in list(range(1, 33))}
with open(os.path.join(folder, 'UNIFAC LLE interaction parameters.tsv')) as f:
for line in f:
maingroup1, maingroup2, interaction_parameter = line.strip('\n').split('\t')
LLEUFIP[int(maingroup1)][int(maingroup2)] = float(interaction_parameter)
LUFIP = {i: {} for i in list(range(1, 22))}
with open(os.path.join(folder, 'UNIFAC Lyngby interaction parameters.tsv')) as f:
for line in f:
maingroup1, maingroup2, a, b, c = line.strip('\n').split('\t')
LUFIP[int(maingroup1)][int(maingroup2)] = (float(a), float(b), float(c))
DOUFIP2006 = {i: {} for i in DOUFMG.keys()}
with open(os.path.join(folder, 'UNIFAC modified Dortmund interaction parameters 2006.tsv')) as f:
for line in f:
maingroup1, maingroup2, a, b, c = line.strip('\n').split('\t')
DOUFIP2006[int(maingroup1)][int(maingroup2)] = (float(a), float(b), float(c))
DOUFIP2016 = {i: {} for i in list(DOUFMG.keys())+[50, 77, 98, 99]}
# Some of the groups have no public parameters unfortunately
with open(os.path.join(folder, 'UNIFAC modified Dortmund interaction parameters.tsv')) as f:
for line in f:
maingroup1, maingroup2, a, b, c = line.strip('\n').split('\t')
DOUFIP2016[int(maingroup1)][int(maingroup2)] = (float(a), float(b), float(c))
#NISTUFIP = {i: {} for i in list(NISTUFMG.keys())}
NISTUFIP = {i: {} for i in list(range(87)) + [92, 94, 95, 96] }
with open(os.path.join(folder, 'UNIFAC modified NIST 2015 interaction parameters.tsv')) as f:
for line in f:
maingroup1, maingroup2, a, b, c, Tmin, Tmax = line.strip('\n').split('\t')
NISTUFIP[int(maingroup1)][int(maingroup2)] = (float(a), float(b), float(c))
NISTKTUFIP = {i: {} for i in range(1, 53) }
with open(os.path.join(folder, 'NIST KT 2011 interaction parameters.tsv')) as f:
for line in f:
maingroup1, maingroup2, a, b, c = line.strip('\n').split('\t')
NISTKTUFIP[int(maingroup1)][int(maingroup2)] = (float(a), float(b), float(c))
PSRKIP = {i: {} for i in range(1, 86)}
with open(os.path.join(folder, 'PSRK interaction parameters.tsv')) as f:
for line in f:
maingroup1, maingroup2, a, b, c = line.strip('\n').split('\t')
PSRKIP[int(maingroup1)][int(maingroup2)] = (float(a), float(b), float(c))
VTPRIP = {i: {} for i in range(1, 200)}
# Three existing documents
for name in ('VTPR 2012 interaction parameters.tsv', 'VTPR 2014 interaction parameters.tsv', 'VTPR 2016 interaction parameters.tsv'):
with open(os.path.join(folder, name)) as f:
for line in f:
maingroup1, maingroup2, a, b, c = line.strip('\n').split('\t')
VTPRIP[int(maingroup1)][int(maingroup2)] = (float(a), float(b), float(c))
_unifac_ip_loaded = True
if PY37:
def __getattr__(name):
if name in ('UFIP', 'LLEUFIP', 'LUFIP', 'DOUFIP2006', 'DOUFIP2016',
'NISTUFIP', 'NISTKTUFIP', 'PSRKIP', 'VTPRIP'):
load_unifac_ip()
return globals()[name]
raise AttributeError(f"module {__name__} has no attribute {name}")
else:
if can_load_data:
load_unifac_ip()
DDBST_UNIFAC_assignments = {}
DDBST_MODIFIED_UNIFAC_assignments = {}
DDBST_PSRK_assignments = {}
def load_group_assignments_DDBST():
'''Data is stored in the format
InChI key\tbool bool bool \tsubgroup count ...\tsubgroup count \tsubgroup count...
where the bools refer to whether or not the original UNIFAC, modified
UNIFAC, and PSRK group assignments were completed correctly.
The subgroups and their count have an indefinite length.
'''
# Do not allow running multiple times
if DDBST_UNIFAC_assignments:
return None
folder = os.path.join(os.path.dirname(__file__), 'Phase Change')
with open(os.path.join(folder, 'DDBST UNIFAC assignments.tsv')) as f:
_group_assignments = [DDBST_UNIFAC_assignments, DDBST_MODIFIED_UNIFAC_assignments, DDBST_PSRK_assignments]
for line in f.readlines():
key, valids, original, modified, PSRK = line.split('\t')
# list of whether or not each method was correctly identified or not
valids = [i == '1' for i in valids.split(' ')]
for groups, storage, valid in zip([original, modified, PSRK], _group_assignments, valids):
if valid:
groups = groups.rstrip().split(' ')
d_data = {}
for i in range(int(len(groups)/2)):
d_data[int(groups[i*2])] = int(groups[i*2+1])
storage[key] = d_data
## Database lookup
UNIFAC_DDBST_ASSIGNMENT_CURSOR = None
def init_ddbst_UNIFAC_db():
global UNIFAC_DDBST_ASSIGNMENT_CURSOR
import sqlite3
conn = sqlite3.connect(
os.path.join(os.path.dirname(__file__), 'Phase Change', 'DDBST_UNIFAC_assignments.sqlite'),
check_same_thread=False,
)
UNIFAC_DDBST_ASSIGNMENT_CURSOR = conn.cursor()
[docs]def UNIFAC_group_assignment_DDBST(CAS, model):
r'''Lookup the group assignment of a compound in either the 'UNIFAC'
the 'MODIFIED_UNIFAC', or the 'PSRK' model. These values are read from a
sqlite database on demand.
Parameters
----------
CAS : str
CAS number, [-]
model : str
One of 'UNIFAC', 'MODIFIED_UNIFAC', or 'PSRK', [-]
Returns
-------
asssignments : dict
The group assignments and their counts; note that an empty dictionary
indicates the fragmentation is not available, [-]
Notes
-----
Examples
--------
>>> UNIFAC_group_assignment_DDBST('50-14-6', 'UNIFAC')
{1: 5, 2: 8, 3: 6, 4: 1, 6: 1, 7: 1, 8: 2, 14: 1}
'''
if UNIFAC_DDBST_ASSIGNMENT_CURSOR is None:
init_ddbst_UNIFAC_db()
CASi = CAS_to_int(CAS)
UNIFAC_DDBST_ASSIGNMENT_CURSOR.execute("SELECT * FROM DDBST WHERE `index`=?", (str(CASi),))
result = UNIFAC_DDBST_ASSIGNMENT_CURSOR.fetchone()
if result is None:
return {}
if model == 'UNIFAC':
assignment = result[1]
elif model == 'MODIFIED_UNIFAC':
assignment = result[2]
elif model == 'PSRK':
assignment = result[3]
else:
raise ValueError("Allowed models are 'UNIFAC', 'PSRK', 'MODIFIED_UNIFAC' ")
return str_group_assignment_to_dict(assignment)
[docs]def UNIFAC_RQ(groups, subgroup_data=None):
r'''Calculates UNIFAC parameters R and Q for a chemical, given a dictionary
of its groups, as shown in [1]_. Most UNIFAC methods use the same subgroup
values; however, a dictionary of `UNIFAC_subgroup` instances may be
specified as an optional second parameter.
.. math::
r_i = \sum_{k=1}^{n} \nu_k R_k
.. math::
q_i = \sum_{k=1}^{n}\nu_k Q_k
Parameters
----------
groups : dict[count]
Dictionary of numeric subgroup IDs : their counts
subgroup_data : None or dict[UNIFAC_subgroup]
Optional replacement for standard subgroups; leave as None to use the
original UNIFAC subgroup r and q values.
Returns
-------
R : float
R UNIFAC parameter (normalized Van der Waals Volume) [-]
Q : float
Q UNIFAC parameter (normalized Van der Waals Area) [-]
Notes
-----
These parameters have some predictive value for other chemical properties.
Examples
--------
Hexane
>>> UNIFAC_RQ({1:2, 2:4})
(4.4998000000000005, 3.856)
References
----------
.. [1] Gmehling, Jurgen. Chemical Thermodynamics: For Process Simulation.
Weinheim, Germany: Wiley-VCH, 2012.
'''
if subgroup_data is not None:
subgroups = subgroup_data
else:
subgroups = UFSG
ri = 0.
qi = 0.
for group, count in groups.items():
ri += subgroups[group].R*count
qi += subgroups[group].Q*count
return ri, qi
[docs]def Van_der_Waals_volume(R):
r'''Calculates a species Van der Waals molar volume with the UNIFAC method,
given a species's R parameter.
.. math::
V_{wk} = 15.17R_k
Parameters
----------
R : float
R UNIFAC parameter (normalized Van der Waals Volume) [-]
Returns
-------
V_vdw : float
Unnormalized Van der Waals volume, [m^3/mol]
Notes
-----
The volume was originally given in cm^3/mol, but is converted to SI here.
Examples
--------
>>> Van_der_Waals_volume(4.4998)
6.826196599999999e-05
References
----------
.. [1] Wei, James, Morton M. Denn, John H. Seinfeld, Arup Chakraborty,
Jackie Ying, Nicholas Peppas, and George Stephanopoulos. Molecular
Modeling and Theory in Chemical Engineering. Academic Press, 2001.
'''
return R*1.517e-05
[docs]def Van_der_Waals_area(Q):
r'''Calculates a species Van der Waals molar surface area with the UNIFAC
method, given a species's Q parameter.
.. math::
A_{wk} = 2.5\times 10^9 Q_k
Parameters
----------
Q : float
Q UNIFAC parameter (normalized Van der Waals Area) [-]
Returns
-------
A_vdw : float
Unnormalized Van der Waals surface area, [m^2/mol]
Notes
-----
The volume was originally given in cm^2/mol, but is converted to SI here.
Examples
--------
>>> Van_der_Waals_area(3.856)
964000.0
References
----------
.. [1] Wei, James, Morton M. Denn, John H. Seinfeld, Arup Chakraborty,
Jackie Ying, Nicholas Peppas, and George Stephanopoulos. Molecular
Modeling and Theory in Chemical Engineering. Academic Press, 2001.
'''
return Q*250000.0
[docs]def UNIFAC_psi(T, subgroup1, subgroup2, subgroup_data, interaction_data,
modified=False):
r'''Calculates the interaction parameter psi(m, n) for two UNIFAC
subgroups, given the system temperature, the UNIFAC subgroups considered
for the variant of UNIFAC used, the interaction parameters for the
variant of UNIFAC used, and whether or not the temperature dependence is
modified from the original form, as shown below.
Original temperature dependence:
.. math::
\Psi_{mn} = \exp\left(\frac{-a_{mn}}{T}\right)
Modified temperature dependence:
.. math::
\Psi_{mn} = \exp\left(\frac{-a_{mn} - b_{mn}T - c_{mn}T^2}{T}\right)
Parameters
----------
T : float
Temperature of the system, [K]
subgroup1 : int
First UNIFAC subgroup for identifier, [-]
subgroup2 : int
Second UNIFAC subgroup for identifier, [-]
subgroup_data : dict[UNIFAC_subgroup]
Normally provided as inputs to `UNIFAC`.
interaction_data : dict[dict[tuple(a_mn, b_mn, c_mn)]]
Normally provided as inputs to `UNIFAC`.
modified : bool
True if the modified temperature dependence is used by the interaction
parameters, otherwise False
Returns
-------
psi : float
UNIFAC interaction parameter term, [-]
Notes
-----
UNIFAC interaction parameters are asymmetric. No warning is raised if an
interaction parameter is missing.
Examples
--------
>>> from thermo.unifac import UFSG, UFIP, DOUFSG, DOUFIP2006
>>> UNIFAC_psi(307, 18, 1, UFSG, UFIP)
0.9165248264184787
>>> UNIFAC_psi(373.15, 9, 78, DOUFSG, DOUFIP2006, modified=True)
1.3703140538273264
References
----------
.. [1] Gmehling, Jurgen. Chemical Thermodynamics: For Process Simulation.
Weinheim, Germany: Wiley-VCH, 2012.
.. [2] Fredenslund, Aage, Russell L. Jones, and John M. Prausnitz. "Group
Contribution Estimation of Activity Coefficients in Nonideal Liquid
Mixtures." AIChE Journal 21, no. 6 (November 1, 1975): 1086-99.
doi:10.1002/aic.690210607.
'''
main1 = subgroup_data[subgroup1].main_group_id
main2 = subgroup_data[subgroup2].main_group_id
if modified:
try:
a, b, c = interaction_data[main1][main2]
except:
return 1.
return exp(-a/T -b - c*T)
else:
try:
return exp(-interaction_data[main1][main2]/T)
except:
return 1.
[docs]def UNIFAC_gammas(T, xs, chemgroups, cached=None, subgroup_data=None,
interaction_data=None, modified=False):
r'''Calculates activity coefficients using the UNIFAC model (optionally
modified), given a mixture's temperature, liquid mole fractions,
and optionally the subgroup data and interaction parameter data of your
choice. The default is to use the original UNIFAC model, with the latest
parameters published by DDBST. The model supports modified forms (Dortmund,
NIST) when the `modified` parameter is True.
Parameters
----------
T : float
Temperature of the system, [K]
xs : list[float]
Mole fractions of all species in the system in the liquid phase, [-]
chemgroups : list[dict]
List of dictionaries of subgroup IDs and their counts for all species
in the mixture, [-]
subgroup_data : dict[UNIFAC_subgroup]
UNIFAC subgroup data; available dictionaries in this module are UFSG
(original), DOUFSG (Dortmund), or NISTUFSG ([4]_).
interaction_data : dict[dict[tuple(a_mn, b_mn, c_mn)]]
UNIFAC interaction parameter data; available dictionaries in this
module are UFIP (original), DOUFIP2006 (Dortmund parameters as
published by 2006), DOUFIP2016 (Dortmund parameters as published by
2016), and NISTUFIP ([4]_).
modified : bool
True if using the modified form and temperature dependence, otherwise
False.
Returns
-------
gammas : list[float]
Activity coefficients of all species in the mixture, [-]
Notes
-----
The actual implementation of UNIFAC is formulated slightly different than
the formulas above for computational efficiency. DDBST switched to using
the more efficient forms in their publication, but the numerical results
are identical.
The model is as follows:
.. math::
\ln \gamma_i = \ln \gamma_i^c + \ln \gamma_i^r
**Combinatorial component**
.. math::
\ln \gamma_i^c = \ln \frac{\phi_i}{x_i} + \frac{z}{2} q_i
\ln\frac{\theta_i}{\phi_i} + L_i - \frac{\phi_i}{x_i}
\sum_{j=1}^{n} x_j L_j
.. math::
\theta_i = \frac{x_i q_i}{\sum_{j=1}^{n} x_j q_j}
.. math::
\phi_i = \frac{x_i r_i}{\sum_{j=1}^{n} x_j r_j}
.. math::
L_i = 5(r_i - q_i)-(r_i-1)
**Residual component**
.. math::
\ln \gamma_i^r = \sum_{k}^n \nu_k^{(i)} \left[ \ln \Gamma_k
- \ln \Gamma_k^{(i)} \right]
.. math::
\ln \Gamma_k = Q_k \left[1 - \ln \sum_m \Theta_m \Psi_{mk} - \sum_m
\frac{\Theta_m \Psi_{km}}{\sum_n \Theta_n \Psi_{nm}}\right]
.. math::
\Theta_m = \frac{Q_m X_m}{\sum_{n} Q_n X_n}
.. math::
X_m = \frac{ \sum_j \nu^j_m x_j}{\sum_j \sum_n \nu_n^j x_j}
**R and Q**
.. math::
r_i = \sum_{k=1}^{n} \nu_k R_k
.. math::
q_i = \sum_{k=1}^{n}\nu_k Q_k
The newer forms of UNIFAC (Dortmund, NIST) calculate the combinatorial
part slightly differently:
.. math::
\ln \gamma_i^c = 1 - {V'}_i + \ln({V'}_i) - 5q_i \left(1
- \frac{V_i}{F_i}+ \ln\left(\frac{V_i}{F_i}\right)\right)
.. math::
V'_i = \frac{r_i^{3/4}}{\sum_j r_j^{3/4}x_j}
.. math::
V_i = \frac{r_i}{\sum_j r_j x_j}
.. math::
F_i = \frac{q_i}{\sum_j q_j x_j}
Although this form looks substantially different than the original, it
infact reverts to the original form if only :math:`V'_i` is replaced by
:math:`V_i`. This is more clear when looking at the full rearranged form as
in [3]_.
In some publications such as [5]_, the nomenclature is such that
:math:`\theta_i` and :math:`\phi` do not contain the top :math:`x_i`,
making :math:`\theta_i = F_i` and :math:`\phi_i = V_i`. [5]_ is also
notable for having supporting information containing very nice sets of
analytical derivatives.
UNIFAC LLE uses the original formulation of UNIFAC, and otherwise only
different interaction parameters.
Examples
--------
>>> UNIFAC_gammas(T=333.15, xs=[0.5, 0.5], chemgroups=[{1:2, 2:4}, {1:1, 2:1, 18:1}])
[1.427602583562, 1.364654501010]
>>> from thermo.unifac import DOUFIP2006
>>> UNIFAC_gammas(373.15, [0.2, 0.3, 0.2, 0.2],
... [{9:6}, {78:6}, {1:1, 18:1}, {1:1, 2:1, 14:1}],
... subgroup_data=DOUFSG, interaction_data=DOUFIP2006, modified=True)
[1.1864311137, 1.44028013391, 1.20447983349, 1.972070609029]
References
----------
.. [1] Gmehling, Jurgen. Chemical Thermodynamics: For Process Simulation.
Weinheim, Germany: Wiley-VCH, 2012.
.. [2] Fredenslund, Aage, Russell L. Jones, and John M. Prausnitz. "Group
Contribution Estimation of Activity Coefficients in Nonideal Liquid
Mixtures." AIChE Journal 21, no. 6 (November 1, 1975): 1086-99.
doi:10.1002/aic.690210607.
.. [3] Jakob, Antje, Hans Grensemann, Jürgen Lohmann, and Jürgen Gmehling.
"Further Development of Modified UNIFAC (Dortmund): Revision and
Extension 5." Industrial & Engineering Chemistry Research 45, no. 23
(November 1, 2006): 7924-33. doi:10.1021/ie060355c.
.. [4] Kang, Jeong Won, Vladimir Diky, and Michael Frenkel. "New Modified
UNIFAC Parameters Using Critically Evaluated Phase Equilibrium Data."
Fluid Phase Equilibria 388 (February 25, 2015): 128-41.
doi:10.1016/j.fluid.2014.12.042.
.. [5] Jäger, Andreas, Ian H. Bell, and Cornelia Breitkopf. "A
Theoretically Based Departure Function for Multi-Fluid Mixture Models."
Fluid Phase Equilibria 469 (August 15, 2018): 56-69.
https://doi.org/10.1016/j.fluid.2018.04.015.
'''
cmps = range(len(xs))
if subgroup_data is None:
subgroups = UFSG
else:
subgroups = subgroup_data
if interaction_data is None:
if not _unifac_ip_loaded: load_unifac_ip()
interactions = UFIP
else:
interactions = interaction_data
# Obtain r and q values using the subgroup values
if not cached:
rs = []
qs = []
for groups in chemgroups:
ri = 0.
qi = 0.
for group, count in groups.items():
ri += subgroups[group].R*count
qi += subgroups[group].Q*count
rs.append(ri)
qs.append(qi)
group_counts = {}
for groups in chemgroups:
for group, count in groups.items():
if group in group_counts:
group_counts[group] += count
else:
group_counts[group] = count
else:
rs, qs, group_counts = cached
# Sum the denominator for calculating Xs
group_sum = sum(count*xs[i] for i in cmps for count in chemgroups[i].values())
# Caclulate each numerator for calculating Xs
# Xms stored in group_count_xs, length number of independent groups
group_count_xs = {}
for group in group_counts:
tot_numerator = sum(chemgroups[i][group]*xs[i] for i in cmps if group in chemgroups[i])
group_count_xs[group] = tot_numerator/group_sum
# print(group_count_xs, 'group_count_xs')
rsxs = sum([rs[i]*xs[i] for i in cmps])
Vis = [rs[i]/rsxs for i in cmps]
qsxs = sum([qs[i]*xs[i] for i in cmps])
Fis = [qs[i]/qsxs for i in cmps]
if modified:
rsxs2 = sum([rs[i]**0.75*xs[i] for i in cmps])
Vis2 = [rs[i]**0.75/rsxs2 for i in cmps]
loggammacs = [1. - Vis2[i] + log(Vis2[i]) - 5.*qs[i]*(1. - Vis[i]/Fis[i]
+ log(Vis[i]/Fis[i])) for i in cmps]
else:
loggammacs = [1. - Vis[i] + log(Vis[i]) - 5.*qs[i]*(1. - Vis[i]/Fis[i]
+ log(Vis[i]/Fis[i])) for i in cmps]
# print(loggammacs)
Q_sum_term = sum([subgroups[group].Q*group_count_xs[group] for group in group_counts])
# theta(m) for an overall mixture composition
area_fractions = {group: subgroups[group].Q*group_count_xs[group]/Q_sum_term
for group in group_counts.keys()}
# print('theta(m) for an overall mixture ', area_fractions)
# This needs to not be a dictionary
UNIFAC_psis = {k: {m:(UNIFAC_psi(T, m, k, subgroups, interactions, modified=modified))
for m in group_counts} for k in group_counts}
loggamma_groups = {}
# This is for the total mixture bit of the residual
for k in group_counts:
sum1, sum2 = 0., 0.
for m in group_counts:
sum1 += area_fractions[m]*UNIFAC_psis[k][m]
# This term can be pre-calculated
sum3 = sum(area_fractions[n]*UNIFAC_psis[m][n] for n in group_counts)
sum2 -= area_fractions[m]*UNIFAC_psis[m][k]/sum3
loggamma_groups[k] = subgroups[k].Q*(1. - log(sum1) + sum2)
loggammars = []
for groups in chemgroups:
# Most of this is for the pure-component bit of the residual
chem_loggamma_groups = {}
chem_group_sum = sum(groups.values())
# Xm = chem_group_count_xs
chem_group_count_xs = {group: count/chem_group_sum for group, count in groups.items()}
# print('Xm', chem_group_count_xs)
# denominator of term used to compute Theta(m)
Q_sum_term = sum([subgroups[group].Q*chem_group_count_xs[group] for group in groups])
# Theta(m) = chem_area_fractions (dict indexed by main group)
chem_area_fractions = {group: subgroups[group].Q*chem_group_count_xs[group]/Q_sum_term
for group in groups.keys()}
# print('Theta(m)', chem_area_fractions)
for k in groups:
sum1, sum2 = 0., 0.
for m in groups:
sum1 += chem_area_fractions[m]*UNIFAC_psis[k][m]
# sum3 should be cached
sum3 = sum(chem_area_fractions[n]*UNIFAC_psis[m][n] for n in groups)
sum2 -= chem_area_fractions[m]*UNIFAC_psis[m][k]/sum3
chem_loggamma_groups[k] = subgroups[k].Q*(1. - log(sum1) + sum2)
tot = sum([count*(loggamma_groups[group] - chem_loggamma_groups[group])
for group, count in groups.items()])
loggammars.append(tot)
return [exp(loggammacs[i]+loggammars[i]) for i in cmps]
[docs]def chemgroups_to_matrix(chemgroups):
r'''
Index by [group index][compound index]
>>> chemgroups_to_matrix([{9: 6}, {2: 6}, {1: 1, 18: 1}, {1: 1, 2: 1, 14: 1}])
[[0, 0, 1, 1], [0, 6, 0, 1], [6, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0]]
'''
matrix = []
keys = []
all_keys = set()
[all_keys.update(i.keys()) for i in chemgroups]
for k in sorted(list(all_keys)):
matrix.append([l[k] if k in l else 0 for l in chemgroups])
# matrix.append([float(l[k]) if k in l else 0.0 for l in chemgroups]) # Cannot notice performance improvement
return matrix
def unifac_psis(T, N_groups, version, psi_a, psi_b, psi_c, psis=None):
if psis is None:
psis = [[0.0]*N_groups for _ in range(N_groups)] # numba: delete
# psis = zeros((N_groups, N_groups)) # numba: uncomment
mT_inv = -1.0/T
if version == 4 or version == 5:
T0 = 298.15
TmT0 = T - T0
B = T*log(T0/T) + T - T0
for i in range(N_groups):
a_row, b_row, c_row = psi_a[i], psi_b[i], psi_c[i]
psisi = psis[i]
for j in range(N_groups):
psisi[j] = exp(mT_inv*(a_row[j] + b_row[j]*TmT0 + c_row[j]*B))
else:
for i in range(N_groups):
a_row, b_row, c_row = psi_a[i], psi_b[i], psi_c[i]
psisi = psis[i]
for j in range(N_groups):
psisi[j] = exp(a_row[j]*mT_inv - b_row[j] - c_row[j]*T)
return psis
def unifac_dpsis_dT(T, N_groups, version, psi_a, psi_b, psi_c, psis, dpsis_dT=None):
if dpsis_dT is None:
dpsis_dT = [[0.0]*N_groups for _ in range(N_groups)] # numba: delete
# dpsis_dT = zeros((N_groups, N_groups)) # numba: uncomment
T2_inv = 1.0/(T*T)
if version == 4 or version == 5:
T0 = 298.15
mT_inv = -1.0/T
T2_inv = mT_inv*mT_inv
TmT0 = T - T0
x0 = log(T0/T)
B = T*x0 + T - T0
x1 = mT_inv + TmT0*T2_inv
x2 = x0*mT_inv + B*T2_inv
for i in range(N_groups):
a_row, b_row, c_row, psis_row = psi_a[i], psi_b[i], psi_c[i], psis[i]
dpsis_dTi = dpsis_dT[i]
for j in range(N_groups):
dpsis_dTi[j] = psis_row[j]*(x1*b_row[j] + c_row[j]*x2 + a_row[j]*T2_inv)
else:
for i in range(N_groups):
a_row, c_row, psis_row = psi_a[i], psi_c[i], psis[i]
dpsis_dTi = dpsis_dT[i]
for j in range(N_groups):
dpsis_dTi[j] = psis_row[j]*(a_row[j]*T2_inv - c_row[j])
return dpsis_dT
def unifac_d2psis_dT2(T, N_groups, version, psi_a, psi_b, psi_c, psis, d2psis_dT2=None):
if d2psis_dT2 is None:
d2psis_dT2 = [[0.0]*N_groups for _ in range(N_groups)] # numba: delete
# d2psis_dT2 = zeros((N_groups, N_groups)) # numba: uncomment
if version == 4 or version == 5:
T0 = 298.15
T_inv = 1.0/T
T2_inv = T_inv*T_inv
x0 = log(T0/T)
for i in range(N_groups):
psis_row, a_row, b_row, c_row = psis[i], psi_a[i], psi_b[i], psi_c[i]
row = d2psis_dT2[i]
for j in range(N_groups):
a1, a2, a3 = a_row[j], b_row[j], c_row[j]
tf2 = a1 + a2*(T - T0) + a3*(T*log(T0/T) + T - T0)
tf3 = a2 + a3*x0
x1 = (tf3 - tf2*T_inv)
v = T2_inv*psis_row[j]*(a3 + 2.0*tf3 + x1*x1 - 2.0*tf2*T_inv)
row[j] = v
else:
mT2_inv = -1.0/(T*T)
T3_inv_m2 = -2.0/(T*T*T)
for i in range(N_groups):
a_row, c_row, psis_row = psi_a[i], psi_c[i], psis[i]
d2psis_dT2i = d2psis_dT2[i]
for j in range(N_groups):
x0 = c_row[j] + mT2_inv*a_row[j]
d2psis_dT2i[j] = (x0*x0 + T3_inv_m2*a_row[j])*psis_row[j]
return d2psis_dT2
def unifac_d3psis_dT3(T, N_groups, version, psi_a, psi_b, psi_c, psis, d3psis_dT3=None):
if d3psis_dT3 is None:
d3psis_dT3 = [[0.0]*N_groups for _ in range(N_groups)] # numba: delete
# d3psis_dT3 = zeros((N_groups, N_groups)) # numba: uncomment
if version == 4 or version == 5:
T0 = 298.15
T_inv = 1.0/T
nT3_inv = -T_inv*T_inv*T_inv
TmT0 = T - T0
x0 = log(T0/T)
B = T*x0 + T - T0
for i in range(N_groups):
psis_row, a_row, b_row, c_row = psis[i], psi_a[i], psi_b[i], psi_c[i]
row = d3psis_dT3[i]
for j in range(N_groups):
a1, a2, a3 = a_row[j], b_row[j], c_row[j]
tf2 = a1 + a2*TmT0 + a3*B
tf3 = a2 + a3*x0
x6 = tf2*T_inv
x5 = (tf3 - x6)
v = nT3_inv*psis_row[j]*(4.0*a3 + 6.0*tf3 + x5*x5*x5
+ 3.0*(x5)*(a3 + tf3 + tf3 - 2.0*x6)
- 6.0*x6)
row[j] = v
else:
nT2_inv = -1.0/(T*T)
T3_inv_6 = 6.0/(T*T*T)
T4_inv_6 = 6.0/(T*T*T*T)
for i in range(N_groups):
psis_row, a_row, c_row = psis[i], psi_a[i], psi_c[i]
row = d3psis_dT3[i]
for j in range(N_groups):
x0 = c_row[j] + nT2_inv*a_row[j]
row[j] = (x0*(T3_inv_6*a_row[j] - x0*x0) + T4_inv_6*a_row[j])*psis_row[j]
return d3psis_dT3
def unifac_Vis(rs, xs, N, Vis=None):
if Vis is None:
Vis = [0.0]*N
rx_sum_inv = 0.0
for i in range(N):
rx_sum_inv += rs[i]*xs[i]
rx_sum_inv = 1.0/rx_sum_inv # actually inverse it
for i in range(N):
Vis[i] = rs[i]*rx_sum_inv
return Vis, rx_sum_inv
def unifac_dVis_dxs(rs, rx_sum_inv, N, dVis_dxs=None):
if dVis_dxs is None:
dVis_dxs = [[0.0]*N for _ in range(N)] # numba: delete
# dVis_dxs = zeros((N, N)) # numba: uncomment
mrx_sum_inv2 = -rx_sum_inv*rx_sum_inv
for i in range(N):
v = rs[i]*mrx_sum_inv2
dVijs = dVis_dxs[i]
for j in range(N):
dVijs[j] = v*rs[j]
return dVis_dxs
def unifac_d2Vis_dxixjs(rs, rx_sum_inv, N, d2Vis_dxixjs=None):
if d2Vis_dxixjs is None:
d2Vis_dxixjs = [[[0.0]*N for _ in range(N)] for _ in range(N)] # numba: delete
# d2Vis_dxixjs = zeros((N, N, N)) # numba: uncomment
rx_sum_inv3_2 = 2.0*rx_sum_inv*rx_sum_inv*rx_sum_inv
for i in range(N):
mat = d2Vis_dxixjs[i]
x0 = rs[i]*rx_sum_inv3_2
for j in range(N):
row = mat[j]
x1 = x0*rs[j]
for k in range(N):
row[k] = x1*rs[k]
return d2Vis_dxixjs
def unifac_d3Vis_dxixjxks(rs, rx_sum_inv, N, d3Vis_dxixjxks=None):
if d3Vis_dxixjxks is None:
d3Vis_dxixjxks = [[[[0.0]*N for _ in range(N)] for _ in range(N)] for _ in range(N)] # numba: delete
# d3Vis_dxixjxks = zeros((N, N, N, N)) # numba: uncomment
mrx_sum_inv4_6 = -6.0*rx_sum_inv*rx_sum_inv*rx_sum_inv*rx_sum_inv
for i in range(N):
cube = d3Vis_dxixjxks[i]
x0 = rs[i]*mrx_sum_inv4_6
for j in range(N):
mat = cube[j]
x1 = x0*rs[j]
for k in range(N):
row = mat[k]
x2 = x1*rs[k]
for l in range(N):
row[l] = x2*rs[l]
return d3Vis_dxixjxks
def unifac_Xs(N, N_groups, xs, vs, Xs=None):
if Xs is None:
Xs = [0.0]*N_groups
Xs_sum_inv = 0.0
for i in range(N_groups):
tot = 0.0
vsi = vs[i]
for j in range(N):
tot += vsi[j]*xs[j]
Xs[i] = tot
Xs_sum_inv += tot
Xs_sum_inv = 1.0/Xs_sum_inv
for i in range(N_groups):
Xs[i] *= Xs_sum_inv
return Xs, Xs_sum_inv
def unifac_Thetas(N_groups, Xs, Qs, Thetas=None):
if Thetas is None:
Thetas = [0.0]*N_groups
Thetas_sum_inv = 0.0
for i in range(N_groups):
Thetas_sum_inv += Xs[i]*Qs[i]
Thetas_sum_inv = 1.0/Thetas_sum_inv
for i in range(N_groups):
Thetas[i] = Qs[i]*Xs[i]*Thetas_sum_inv
return Thetas, Thetas_sum_inv
def unifac_dThetas_dxs(N_groups, N, Qs, vs, VS, VSXS, F, G, dThetas_dxs=None, vec0=None):
if dThetas_dxs is None:
dThetas_dxs = [[0.0]*N for _ in range(N_groups)] # numba: delete
# dThetas_dxs = zeros((N_groups, N)) # numba: uncomment
if vec0 is None:
vec0 = [0.0]*N
tot0 = 0.0
for k in range(N_groups):
tot0 += Qs[k]*VSXS[k]
tot0*= F
for j in range(N):
tot1 = 0.0
for k in range(N_groups):
tot1 -= Qs[k]*vs[k][j]
vec0[j] = F*(G*(tot0*VS[j] + tot1) - VS[j])
FG = F*G
for i in range(N_groups):
c = FG*Qs[i]
row = dThetas_dxs[i]
for j in range(N):
row[j] = c*(VSXS[i]*vec0[j] + vs[i][j])
return dThetas_dxs
def unifac_d2Thetas_dxixjs(N_groups, N, Qs, vs, VS, VSXS, F, G, d2Thetas_dxixjs=None, vec0=None):
if d2Thetas_dxixjs is None:
d2Thetas_dxixjs = [[[0.0]*N_groups for _ in range(N)] for _ in range(N)] # numba: delete
# d2Thetas_dxixjs = zeros((N, N, N_groups)) # numba: uncomment
if vec0 is None:
vec0 = [0.0]*N
QsVSXS = 0.0
for i in range(N_groups):
QsVSXS += Qs[i]*VSXS[i]
QsVSXS_sum_inv = 1.0/QsVSXS
for j in range(N):
nffVSj = -F*VS[j]
v = 0.0
for n in range(N_groups):
v += Qs[n]*(nffVSj*VSXS[n] + vs[n][j])
vec0[j] = v
n2F = -2.0*F
F2_2 = 2.0*F*F
QsVSXS_sum_inv2 = 2.0*QsVSXS_sum_inv
for j in range(N):
matrix = d2Thetas_dxixjs[j]
for k in range(N):
row = matrix[k]
n2FVsK = n2F*VS[k]
tot0 = 0.0
for n in range(N_groups):
tot0 += Qs[n]*(VS[j]*(n2FVsK*VSXS[n] + vs[n][k]) + VS[k]*vs[n][j])
tot0 = tot0*F*QsVSXS_sum_inv
for i in range(N_groups):
# tot0, tot1, tot2 = 0.0, 0.0, 0.0
# for n in range(N_groups):
# # dep on k, j only; some sep
# tot0 += -2.0*F*Qs[n]*VS[j]*VS[k]*VSXS[n] + Qs[n]*VS[j]*vs[n][k] + Qs[n]*VS[k]*vs[n][j]
# These are each used in three places
# tot1 += -F*Qs[n]*VS[j]*VSXS[n] + Qs[n]*vs[n][j]
# tot2 += -F*Qs[n]*VS[k]*VSXS[n] + Qs[n]*vs[n][k]
v = -F*(VS[j]*vs[i][k] + VS[k]*vs[i][j]) + VSXS[i]*tot0 + F2_2*VS[j]*VS[k]*VSXS[i]
# v = -F*VS[j]*vs[i][k] - F*VS[k]*vs[i][j]
# v += F2_2*VS[j]*VS[k]*VSXS[i]
# v += VSXS[i]*tot0
#
# v += QsVSXS_sum_inv2*VSXS[i]*vec0[j]*vec0[k]*QsVSXS_sum_inv
#
# # For both of these duplicate terms, j goes with k; k with j
# v -= vs[i][j]*vec0[k]*QsVSXS_sum_inv
# v -= vs[i][k]*vec0[j]*QsVSXS_sum_inv
#
# v += F*VS[j]*VSXS[i]*vec0[k]*QsVSXS_sum_inv
# v += F*VS[k]*VSXS[i]*vec0[j]*QsVSXS_sum_inv
v += QsVSXS_sum_inv*(QsVSXS_sum_inv2*VSXS[i]*vec0[j]*vec0[k]
- vs[i][j]*vec0[k] - vs[i][k]*vec0[j]
+ F*VSXS[i]*(VS[j]*vec0[k] + VS[k]*vec0[j]))
row[i] = v*Qs[i]*QsVSXS_sum_inv
return d2Thetas_dxixjs
def unifac_VSXS(N, N_groups, vs, xs, VSXS=None):
if VSXS is None:
VSXS = [0.0]*N_groups
for i in range(N_groups):
v = 0.0
for j in range(N):
v += vs[i][j]*xs[j]
VSXS[i] = v
return VSXS
def unifac_Theta_Psi_sums(N_groups, Thetas, psis, Theta_Psi_sums=None):
if Theta_Psi_sums is None:
Theta_Psi_sums = [0.0]*N_groups
for k in range(N_groups):
tot = 0.0
for m in range(N_groups):
tot += Thetas[m]*psis[m][k]
Theta_Psi_sums[k] = tot
return Theta_Psi_sums
def unifac_ws(N, N_groups, psis, dThetas_dxs, Ws=None):
if Ws is None:
Ws = [[0.0]*N for _ in range(N_groups)] # numba: delete
# Ws = zeros((N_groups, N)) # numba: uncomment
for k in range(N_groups):
row0 = Ws[k]
for i in range(N):
tot0 = 0.0
for m in range(N_groups):
tot0 += psis[m][k]*dThetas_dxs[m][i]
row0[i] = tot0
return Ws
def unifac_Theta_pure_Psi_sums(N, N_groups, psis, Thetas_pure, Theta_pure_Psi_sums=None):
if Theta_pure_Psi_sums is None:
Theta_pure_Psi_sums = [[0.0]*N_groups for _ in range(N)] # numba: delete
# Theta_pure_Psi_sums = zeros((N, N_groups)) # numba: uncomment
for i in range(N):
row = Theta_pure_Psi_sums[i]
Thetas_pure_i = Thetas_pure[i]
for k in range(N_groups):
tot = 0.0
for m in range(N_groups):
tot += Thetas_pure_i[m]*psis[m][k]
row[k] = (tot)
return Theta_pure_Psi_sums
def unifac_lnGammas_subgroups(N_groups, Qs, psis, Thetas, Theta_Psi_sums, Theta_Psi_sum_invs, lnGammas_subgroups=None):
if lnGammas_subgroups is None:
lnGammas_subgroups = [0.0]*N_groups
for k in range(N_groups):
psisk = psis[k]
last = 1.0
for m in range(N_groups):
last -= Thetas[m]*Theta_Psi_sum_invs[m]*psisk[m]
lnGammas_subgroups[k] = Qs[k]*(last - log(Theta_Psi_sums[k]))
return lnGammas_subgroups
def unifac_dlnGammas_subgroups_dxs(N, N_groups, Qs, Ws, psis, Thetas, Theta_Psi_sum_invs,
dThetas_dxs, dlnGammas_subgroups_dxs=None):
if dlnGammas_subgroups_dxs is None:
dlnGammas_subgroups_dxs = [[0.0]*N for _ in range(N_groups)] # numba : delete
# dlnGammas_subgroups_dxs = zeros((N_groups, N)) # numba : uncomment
for k in range(N_groups):
row = dlnGammas_subgroups_dxs[k]
for i in range(N):
tot = -Ws[k][i]*Theta_Psi_sum_invs[k]
for m in range(N_groups):
tot -= psis[k][m]*Theta_Psi_sum_invs[m]*(dThetas_dxs[m][i]
- Ws[m][i]*Theta_Psi_sum_invs[m]*Thetas[m])
row[i] = tot*Qs[k]
return dlnGammas_subgroups_dxs
def unifac_d2lnGammas_subgroups_dTdxs(N, N_groups, Qs, Fs, Zs, Ws, psis, dpsis_dT, Thetas, dThetas_dxs, d2lnGammas_subgroups_dTdxs=None, vec0=None, vec1=None, mat0=None):
if d2lnGammas_subgroups_dTdxs is None:
d2lnGammas_subgroups_dTdxs = [[0.0]*N for _ in range(N_groups)] # numba : delete
# d2lnGammas_subgroups_dTdxs = zeros((N_groups, N)) # numba : uncomment
if mat0 is None:
mat0 = [[0.0]*N for _ in range(N_groups)] # numba : delete
# mat0 = zeros((N_groups, N)) # numba : uncomment
if vec0 is None:
vec0 = [0.0]*N_groups
if vec1 is None:
vec1 = [0.0]*N_groups
# Could save this matrix but it is not used anywhere else
for k in range(N_groups):
row = mat0[k]
for j in range(N):
tot = 0.0
for m in range(N_groups):
tot += dThetas_dxs[m][j]*dpsis_dT[m][k]
row[j] = tot
for i in range(N_groups):
vec0[i] = Zs[i]*Zs[i]
for m in range(N_groups):
vec1[m] = 2.0*Fs[m]*vec0[m]*Zs[m]*Thetas[m]
for k in range(N_groups):
row = d2lnGammas_subgroups_dTdxs[k]
for i in range(N):
v = Zs[k]*(mat0[k][i] - Fs[k]*Ws[k][i]*Zs[k])
for m in range(N_groups):
v += dThetas_dxs[m][i]*Zs[m]*(dpsis_dT[k][m] - Fs[m]*Zs[m]*psis[k][m])
v -= vec0[m]*Thetas[m]*(mat0[m][i]*psis[k][m] + Ws[m][i]*dpsis_dT[k][m])
v += vec1[m]*Ws[m][i]*psis[k][m]
row[i] = -v*Qs[k]
return d2lnGammas_subgroups_dTdxs
def unifac_d2lnGammas_subgroups_dxixjs(N, N_groups, Qs, Zs, Ws, psis, Thetas,
dThetas_dxs, d2Thetas_dxixjs,
d2lnGammas_subgroups_dxixjs=None, vec0=None):
if d2lnGammas_subgroups_dxixjs is None:
d2lnGammas_subgroups_dxixjs = [[[0.0]*N_groups for _ in range(N)] for _ in range(N)] # numba : delete
# d2lnGammas_subgroups_dxixjs = zeros((N, N, N_groups)) # numba : uncomment
if vec0 is None:
vec0 = [0.0]*N_groups
for i in range(N):
matrix = d2lnGammas_subgroups_dxixjs[i]
for j in range(N):
d2Thetas_dxixjs_ij = d2Thetas_dxixjs[i][j]
row = matrix[j]
for k in range(N_groups):
# d2Thetas_dxixjs_ij is why this loop can't be moved out
totK = 0.0
for m in range(N_groups):
totK += psis[m][k]*d2Thetas_dxixjs_ij[m]
vec0[k] = totK #K(k, i, j)
# Krow = [K(k, i, j) for k in range(N_groups)]
for k in range(N_groups):
v = 0.0
for m in range(N_groups):
d = d2Thetas_dxixjs_ij[m]
# d += (2.0*Ws[m][i]*Ws[m][j]*Zs[m] - vec0[m])*Zs[m]*Thetas[m]
# d -= Zs[m]*(Ws[m][j]*dThetas_dxs[m][i] + Ws[m][i]*dThetas_dxs[m][j])
d += Zs[m]*((2.0*Ws[m][i]*Ws[m][j]*Zs[m] - vec0[m])*Thetas[m]
- (Ws[m][j]*dThetas_dxs[m][i] + Ws[m][i]*dThetas_dxs[m][j]))
v += d*psis[k][m]*Zs[m]
# psis[k][m] can be factored here
v += Zs[k]*(vec0[k] - Ws[k][i]*Ws[k][j]*Zs[k])
row[k] = (-v*Qs[k])
return d2lnGammas_subgroups_dxixjs
def unifac_dlnGammas_subgroups_dT(N_groups, Qs, psis, dpsis_dT, Thetas,
Theta_Psi_sum_invs, Theta_dPsidT_sum,
dlnGammas_subgroups_dT=None):
r'''
.. math::
\frac{\partial \ln \Gamma_i}{\partial T} = Q_i\left(
\sum_j^{gr} Z(j) \left[{\theta_j \frac{\partial \psi_{i,j}}{\partial T}}
+ {\theta_j \psi_{i,j} F(j)}Z(j) \right]- F(i) Z(i)
\right)
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
.. math::
Z(k) = \frac{1}{\sum_m \Theta_m \Psi_{m,k}}
'''
# Theta_Psi_sum_invs = Z
# Theta_dPsidT_sum = F
if dlnGammas_subgroups_dT is None:
dlnGammas_subgroups_dT = [0.0]*N_groups
for i in range(N_groups):
psisi, dpsis_dTi = psis[i], dpsis_dT[i]
tot = 0.0
for j in range(N_groups):
tot += (psisi[j]*Theta_dPsidT_sum[j]*Theta_Psi_sum_invs[j]
- dpsis_dTi[j])*Theta_Psi_sum_invs[j]*Thetas[j]
v = Qs[i]*(tot - Theta_dPsidT_sum[i]*Theta_Psi_sum_invs[i])
dlnGammas_subgroups_dT[i] = v
return dlnGammas_subgroups_dT
def unifac_d2lnGammas_subgroups_dT2(N_groups, Qs, psis, dpsis_dT, d2psis_dT2,
Thetas, Theta_Psi_sum_invs, Theta_dPsidT_sum,
Theta_d2PsidT2_sum, d2lnGammas_subgroups_dT2=None, vec0=None):
r'''
.. math::
\frac{\partial^2 \ln \Gamma_i}{\partial T^2} = -Q_i\left[
Z(i)G(i) - F(i)^2 Z(i)^2 + \sum_j\left(
\theta_j Z(j)\frac{\partial^2 \psi_{i,j}}{\partial T}
- Z(j)^2 \left(G(j)\theta_j \psi_{i,j} + 2 F_j \theta_j \frac{\partial \psi_{i,j}}{\partial T}\right)
+ 2Z(j)^3F(j)^2 \theta_j \psi_{i,j}
\right)\right]
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
.. math::
G(k) = \sum_m^{gr} \theta_m \frac{\partial^2 \psi_{m,k}}{\partial T^2}
.. math::
Z(k) = \frac{1}{\sum_m \Theta_m \Psi_{m,k}}
'''
if d2lnGammas_subgroups_dT2 is None:
d2lnGammas_subgroups_dT2 = [0.0]*N_groups
if vec0 is None:
vec0 = [0.0]*N_groups
Zs, Fs, Gs = Theta_Psi_sum_invs, Theta_dPsidT_sum, Theta_d2PsidT2_sum
for j in range(N_groups):
vec0[j] = 2.0*Fs[j]*Fs[j]*Thetas[j]*Zs[j]*Zs[j]*Zs[j]
for i in range(N_groups):
tot0 = 0.0
for j in range(N_groups):
tot0 += Zs[j]*Thetas[j]*(d2psis_dT2[i][j] - (Gs[j]*psis[i][j] + 2.0*Fs[j]*dpsis_dT[i][j])*Zs[j])
tot0 += vec0[j]*psis[i][j]
v = Qs[i]*(Zs[i]*(Fs[i]*Fs[i]*Zs[i] - Gs[i]) - tot0)
d2lnGammas_subgroups_dT2[i] = v
return d2lnGammas_subgroups_dT2
def unifac_d3lnGammas_subgroups_dT3(N_groups, Qs, psis, dpsis_dT, d2psis_dT2, d3psis_dT3,
Thetas, Theta_Psi_sum_invs, Theta_dPsidT_sum,
Theta_d2PsidT2_sum, Theta_d3PsidT3_sum,
d3lnGammas_subgroups_dT3=None):
r'''
.. math::
\frac{\partial^3 \ln \Gamma_i}{\partial T^3} =Q_i\left[-H(i) Z(i)
- 2F(i)^3 Z(i)^3 + 3F(i) G(i) Z(i)^2+ \left(
-\theta_j Z(j) \frac{\partial^3 \psi}{\partial T^3}
+ H(j) Z(j)^2 \theta(j)\psi_{i,j}
- 6F(j)^2 Z(j)^3 \theta_j \frac{\partial \psi_{i,j}}{\partial T}
+ 3 F(j) Z(j)^2 \theta(j) \frac{\partial^2 \psi_{i,j}}{\partial T^2}
++ 3G(j) \theta(j) Z(j)^2 \frac{\partial \psi_{i,j}}{\partial T}
+ 6F(j)^3 \theta(j) Z(j)^4 \psi_{i,j}
- 6F(j) G(j) \theta(j) Z(j)^3 \psi_{i,j}
\right)
\right]
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
.. math::
G(k) = \sum_m^{gr} \theta_m \frac{\partial^2 \psi_{m,k}}{\partial T^2}
.. math::
H(k) = \sum_m^{gr} \theta_m \frac{\partial^3 \psi_{m,k}}{\partial T^3}
.. math::
Z(k) = \frac{1}{\sum_m \Theta_m \Psi_{m,k}}
'''
if d3lnGammas_subgroups_dT3 is None:
d3lnGammas_subgroups_dT3 = [0.0]*N_groups
# TODO optimize
Us_inv, Fs, Gs, Hs = Theta_Psi_sum_invs, Theta_dPsidT_sum, Theta_d2PsidT2_sum, Theta_d3PsidT3_sum
for i in range(N_groups):
tot = 0.0
for j in range(N_groups):
# There is a bug in numba related to the three lines below.
# If Theta_U is not separated out, an error is raised
Theta_U = Thetas[j]*Us_inv[j]
tot -= Theta_U*d3psis_dT3[i][j]
tot += Hs[j]*Theta_U*psis[i][j]*Us_inv[j]
tot -= 6.0*Fs[j]*Fs[j]*Thetas[j]*dpsis_dT[i][j]*Us_inv[j]*Us_inv[j]*Us_inv[j]
tot += 3.0*Fs[j]*Thetas[j]*d2psis_dT2[i][j]*Us_inv[j]*Us_inv[j]
tot += 3.0*Gs[j]*Thetas[j]*dpsis_dT[i][j]*Us_inv[j]*Us_inv[j]
tot += 6.0*Fs[j]**3*Thetas[j]*psis[i][j]*Us_inv[j]**4
tot -= 6.0*Fs[j]*Gs[j]*Thetas[j]*psis[i][j]*Us_inv[j]**3
v = Qs[i]*(-Hs[i]*Us_inv[i] - 2.0*Fs[i]**3*Us_inv[i]**3 + 3.0*Fs[i]*Gs[i]*Us_inv[i]**2 + tot)
d3lnGammas_subgroups_dT3[i] = v
return d3lnGammas_subgroups_dT3
def unifac_Xs_pure(N, N_groups, vs, cmp_v_count_inv, Xs_pure=None):
if Xs_pure is None:
Xs_pure = [[0.0]*N for _ in range(N_groups)] # numba: delete
# Xs_pure = zeros((N_groups, N)) # numba: uncomment
for i in range(N_groups):
row = Xs_pure[i]
vsi = vs[i]
for j in range(N):
row[j] = vsi[j]*cmp_v_count_inv[j]
return Xs_pure
def unifac_Thetas_pure(N, N_groups, Xs_pure, Qs, Thetas_pure=None):
if Thetas_pure is None:
Thetas_pure = [[0.0]*N_groups for _ in range(N)] # numba: delete
# Thetas_pure = zeros((N, N_groups)) # numba: uncomment
for i in range(N):
# groups = self.cmp_group_idx[i]
tot = 0.0
row = Thetas_pure[i]
for j in range(N_groups):
tot += Qs[j]*Xs_pure[j][i]
tot_inv = 1.0/tot
for j in range(N_groups):
row[j] = Qs[j]*Xs_pure[j][i]*tot_inv
return Thetas_pure
def unifac_lnGammas_subgroups_pure(N, N_groups, Qs, Thetas_pure, cmp_group_idx, group_cmp_idx, psis, lnGammas_subgroups_pure=None):
if lnGammas_subgroups_pure is None:
lnGammas_subgroups_pure = [[0.0]*N for _ in range(N_groups)] # numba: delete
# lnGammas_subgroups_pure = zeros((N_groups, N)) # numba: uncomment
for k in range(N_groups):
row = lnGammas_subgroups_pure[k]
for i in group_cmp_idx[k]:
groups2 = cmp_group_idx[i]
Thetas_purei = Thetas_pure[i]
psisk = psis[k]
log_sum = 0.0
for m in groups2:
log_sum += Thetas_purei[m]*psis[m][k]
log_sum = log(log_sum)
last = 0.0
for m in groups2:
sub_subs = 0.0
for n in range(N_groups):
sub_subs += Thetas_purei[n]*psis[n][m]
last += Thetas_purei[m]*psisk[m]/sub_subs
v = Qs[k]*(1.0 - log_sum - last)
row[i] = v
return lnGammas_subgroups_pure
def unifac_dlnGammas_subgroups_pure_dT(N, N_groups, Qs, psis, dpsis_dT,
Thetas_pure, Theta_pure_Psi_sum_invs, Fs_pure, cmp_group_idx,
dlnGammas_subgroups_pure_dT=None, vec0=None):
if dlnGammas_subgroups_pure_dT is None:
dlnGammas_subgroups_pure_dT = [[0.0]*N for _ in range(N_groups)] # numba: delete
# dlnGammas_subgroups_pure_dT = zeros((N_groups, N)) # numba: uncomment
if vec0 is None:
vec0 = [0.0]*N_groups
for m in range(N):
groups2 = cmp_group_idx[m]
Thetas = Thetas_pure[m]
Theta_Psi_sum_invs = Theta_pure_Psi_sum_invs[m]
Theta_dPsidT_sum = Fs_pure[m]
vec0 = unifac_dlnGammas_subgroups_dT(N_groups, Qs, psis, dpsis_dT,
Thetas, Theta_Psi_sum_invs,
Theta_dPsidT_sum, vec0)
for k in range(N_groups):
if k in groups2:
dlnGammas_subgroups_pure_dT[k][m] = vec0[k]
return dlnGammas_subgroups_pure_dT
def unifac_d2lnGammas_subgroups_pure_dT2(N, N_groups, Qs, psis, dpsis_dT, d2psis_dT2, Thetas_pure, Theta_pure_Psi_sum_invs, Fs_pure, Gs_pure, cmp_group_idx, d2lnGammas_subgroups_pure_dT2=None, vec0=None):
if d2lnGammas_subgroups_pure_dT2 is None:
d2lnGammas_subgroups_pure_dT2 = [[0.0]*N for _ in range(N_groups)] # numba: delete
# d2lnGammas_subgroups_pure_dT2 = zeros((N_groups, N)) # numba: uncomment
if vec0 is None:
vec0 = [0.0]*N
for m in range(N):
groups2 = cmp_group_idx[m]
Thetas = Thetas_pure[m]
Theta_Psi_sum_invs = Theta_pure_Psi_sum_invs[m]
Theta_dPsidT_sum = Fs_pure[m]
Theta_d2PsidT2_sum = Gs_pure[m]
vec0 = unifac_d2lnGammas_subgroups_dT2(N_groups, Qs, psis, dpsis_dT, d2psis_dT2, Thetas, Theta_Psi_sum_invs, Theta_dPsidT_sum, Theta_d2PsidT2_sum)
for k in range(N_groups):
if k in groups2:
d2lnGammas_subgroups_pure_dT2[k][m] = vec0[k]
return d2lnGammas_subgroups_pure_dT2
def unifac_d3lnGammas_subgroups_pure_dT3(N, N_groups, Qs, psis, dpsis_dT, d2psis_dT2, d3psis_dT3, Thetas_pure, Theta_pure_Psi_sum_invs, Fs_pure, Gs_pure, Hs_pure, cmp_group_idx, d3lnGammas_subgroups_pure_dT3=None, vec0=None):
if d3lnGammas_subgroups_pure_dT3 is None:
d3lnGammas_subgroups_pure_dT3 = [[0.0]*N for _ in range(N_groups)] # numba: delete
# d3lnGammas_subgroups_pure_dT3 = zeros((N_groups, N)) # numba: uncomment
if vec0 is None:
vec0 = [0.0]*N
for m in range(N):
groups2 = cmp_group_idx[m]
Thetas = Thetas_pure[m]
Theta_Psi_sum_invs = Theta_pure_Psi_sum_invs[m]
Theta_dPsidT_sum = Fs_pure[m]
Theta_d2PsidT2_sum = Gs_pure[m]
Theta_d3PsidT3_sum = Hs_pure[m]
row = unifac_d3lnGammas_subgroups_dT3(N_groups, Qs, psis, dpsis_dT, d2psis_dT2, d3psis_dT3, Thetas, Theta_Psi_sum_invs, Theta_dPsidT_sum, Theta_d2PsidT2_sum, Theta_d3PsidT3_sum)
for k in range(N_groups):
if k in groups2:
d3lnGammas_subgroups_pure_dT3[k][m] = row[k]
return d3lnGammas_subgroups_pure_dT3
def unifac_lngammas_r(N, N_groups, lnGammas_subgroups_pure, lnGammas_subgroups, vs, lngammas_r=None):
if lngammas_r is None:
lngammas_r = [0.0]*N
for i in range(N):
tot = 0.0
for k in range(N_groups):
tot += vs[k][i]*(lnGammas_subgroups[k] - lnGammas_subgroups_pure[k][i])
lngammas_r[i] = tot
return lngammas_r
def unifac_dlngammas_r_dxs(N, N_groups, vs, dlnGammas_subgroups_dxs, dlngammas_r_dxs=None):
if dlngammas_r_dxs is None:
dlngammas_r_dxs = [[0.0]*N for _ in range(N)] # numba : delete
# dlngammas_r_dxs = zeros((N, N)) # numba : uncomment
for i in range(N):
row = dlngammas_r_dxs[i]
for j in range(N):
tot = 0.0
for m in range(N_groups):
tot += vs[m][i]*dlnGammas_subgroups_dxs[m][j]
row[j] = tot
return dlngammas_r_dxs
def unifac_d2lngammas_r_dxixjs(N, N_groups, vs, d2lnGammas_subgroups_dxixjs, d2lngammas_r_dxixjs=None):
if d2lngammas_r_dxixjs is None:
d2lngammas_r_dxixjs = [[[0.0]*N for _ in range(N)] for _ in range(N)] # numba : delete
# d2lngammas_r_dxixjs = zeros((N, N, N)) # numba : uncomment
for i in range(N):
matrix = d2lngammas_r_dxixjs[i]
for j in range(N):
row = matrix[j]
for k in range(N):
tot = 0.0
r = d2lnGammas_subgroups_dxixjs[j][k]
for m in range(N_groups):
tot += vs[m][i]*r[m]
row[k] = tot
return d2lngammas_r_dxixjs
def unifac_GE(T, xs, N, lngammas_r, lngammas_c):
GE = 0.0
for i in range(N):
GE += xs[i]*(lngammas_c[i] + lngammas_r[i])
GE *= R*T
return GE
def unifac_GE_skip_comb(T, xs, N, lngammas_r):
GE = 0.0
for i in range(N):
GE += xs[i]*lngammas_r[i]
GE *= R*T
return GE
def unifac_dGE_dxs(T, xs, N, lngammas_r, dlngammas_r_dxs, lngammas_c, dlngammas_c_dxs, dGE_dxs=None):
if dGE_dxs is None:
dGE_dxs = [0.0]*N
RT = R*T
for i in range(N):
dGE = lngammas_r[i] + lngammas_c[i]
for j in range(N):
dGE += xs[j]*(dlngammas_c_dxs[j][i] + dlngammas_r_dxs[j][i])
dGE_dxs[i] = dGE*RT
return dGE_dxs
def unifac_dGE_dxs_skip_comb(T, xs, N, lngammas_r, dlngammas_r_dxs, dGE_dxs=None):
if dGE_dxs is None:
dGE_dxs = [0.0]*N
RT = R*T
for i in range(N):
dGE = lngammas_r[i]
for j in range(N):
dGE += xs[j]*(dlngammas_r_dxs[j][i])
dGE_dxs[i] = dGE*RT
return dGE_dxs
def unifac_d2GE_dTdxs(T, xs, N, lngammas_r, dlngammas_r_dxs, dlngammas_r_dT, d2lngammas_r_dTdxs, lngammas_c, dlngammas_c_dxs, d2GE_dTdxs=None):
if d2GE_dTdxs is None:
d2GE_dTdxs = [0.0]*N
for i in range(N):
dGE = lngammas_r[i] + lngammas_c[i] + T*dlngammas_r_dT[i]
for j in range(N):
dGE += xs[j]*(dlngammas_c_dxs[j][i] + dlngammas_r_dxs[j][i])
dGE += T*xs[j]*d2lngammas_r_dTdxs[j][i] # ji should be consistent in all of them
d2GE_dTdxs[i] = dGE*R
return d2GE_dTdxs
def unifac_d2GE_dTdxs_skip_comb(T, xs, N, lngammas_r, dlngammas_r_dxs,dlngammas_r_dT, d2lngammas_r_dTdxs, d2GE_dTdxs=None):
if d2GE_dTdxs is None:
d2GE_dTdxs = [0.0]*N
for i in range(N):
dGE = lngammas_r[i] + T*dlngammas_r_dT[i]
for j in range(N):
dGE += xs[j]*(dlngammas_r_dxs[j][i] + T*d2lngammas_r_dTdxs[j][i])
d2GE_dTdxs[i] = dGE*R
return d2GE_dTdxs
def unifac_d2GE_dxixjs(T, xs, N, dlngammas_r_dxs, d2lngammas_r_dxixjs, dlngammas_c_dxs, d2lngammas_c_dxixjs, d2GE_dxixjs=None):
if d2GE_dxixjs is None:
d2GE_dxixjs = [[0.0]*N for _ in range(N)] # numba: delete
# d2GE_dxixjs = zeros((N, N)) # numba: uncomment
RT = R*T
for i in range(N):
row = d2GE_dxixjs[i]
for j in range(N):
dGE = dlngammas_c_dxs[i][j] + dlngammas_r_dxs[i][j]
dGE += dlngammas_c_dxs[j][i] + dlngammas_r_dxs[j][i]
for k in range(N):
dGE += xs[k]*(d2lngammas_c_dxixjs[k][i][j] + d2lngammas_r_dxixjs[k][i][j])
row[j] = dGE*RT
return d2GE_dxixjs
def unifac_d2GE_dxixjs_skip_comb(T, xs, N, dlngammas_r_dxs, d2lngammas_r_dxixjs, d2GE_dxixjs=None):
if d2GE_dxixjs is None:
d2GE_dxixjs = [[0.0]*N for _ in range(N)] # numba: delete
# d2GE_dxixjs = zeros((N, N)) # numba: uncomment
RT = R*T
for i in range(N):
row = d2GE_dxixjs[i]
for j in range(N):
dGE = dlngammas_r_dxs[i][j] + dlngammas_r_dxs[j][i]
for k in range(N):
dGE += xs[k]*d2lngammas_r_dxixjs[k][i][j]
row[j] = dGE*RT
return d2GE_dxixjs
def unifac_dGE_dT(N, T, xs, dlngammas_r_dT, GE):
tot = 0.0
for i in range(N):
tot += xs[i]*dlngammas_r_dT[i]
return R*T*tot + GE/T
def unifac_d2GE_dT2(N, T, xs, dlngammas_r_dT, d2lngammas_r_dT2):
tot0, tot1 = 0.0, 0.0
for i in range(N):
tot0 += xs[i]*d2lngammas_r_dT2[i]
tot1 += xs[i]*dlngammas_r_dT[i] # This line same as the dGE_dT
return R*(T*tot0 + (tot1 + tot1))
def unifac_d3GE_dT3(N, T, xs, d2lngammas_r_dT2, d3lngammas_r_dT3):
tot0, tot1 = 0.0, 0.0
for i in range(N):
tot0 += xs[i]*d3lngammas_r_dT3[i]
tot1 += xs[i]*d2lngammas_r_dT2[i] # This line same as the d2GE_dT2
return R*(T*tot0 + 3.0*tot1)
def unifac_gammas(N, xs, lngammas_r, lngammas_c, gammas=None):
if gammas is None:
gammas = [0.0]*N
for i in range(N):
gammas[i] = exp(lngammas_r[i] + lngammas_c[i])
return gammas
def unifac_gammas_from_args(xs, N, N_groups, vs, rs, qs, Qs,
psis, lnGammas_subgroups_pure,# Depends on T only
version, rs_34,
gammas=None):
skip_comb = version == 3
Xs, Xs_sum_inv = unifac_Xs(N=N, N_groups=N_groups, xs=xs, vs=vs)
Thetas, Thetas_sum_inv = unifac_Thetas(N_groups=N_groups, Xs=Xs, Qs=Qs)
Theta_Psi_sums = unifac_Theta_Psi_sums(N_groups=N_groups, Thetas=Thetas, psis=psis)
Theta_Psi_sum_invs = [0.0]*N_groups
for i in range(N_groups):
Theta_Psi_sum_invs[i] = 1.0/Theta_Psi_sums[i]
lnGammas_subgroups = unifac_lnGammas_subgroups(N_groups=N_groups, Qs=Qs, psis=psis, Thetas=Thetas,
Theta_Psi_sums=Theta_Psi_sums, Theta_Psi_sum_invs=Theta_Psi_sum_invs)
lngammas_r = unifac_lngammas_r(N=N, N_groups=N_groups, lnGammas_subgroups_pure=lnGammas_subgroups_pure,
lnGammas_subgroups=lnGammas_subgroups, vs=vs)
if gammas is None:
gammas = [0.0]*N
if skip_comb:
for i in range(N):
gammas[i] = exp(lngammas_r[i])
else:
Vis, rx_sum_inv = unifac_Vis(rs=rs, xs=xs, N=N)
Fis, qx_sum_inv = unifac_Vis(rs=qs, xs=xs, N=N)
if version == 1 or version == 3 or version == 4:
Vis_modified, r34x_sum_inv = unifac_Vis(rs=rs_34, xs=xs, N=N)
else:
Vis_modified = Vis
lngammas_c = unifac_lngammas_c(N=N, version=version, qs=qs, Fis=Fis, Vis=Vis, Vis_modified=Vis_modified)
for i in range(N):
gammas[i] = exp(lngammas_r[i] + lngammas_c[i])
return gammas
def unifac_dgammas_dxs(N, xs, gammas, dlngammas_r_dxs, dlngammas_c_dxs, dgammas_dxs=None):
if dgammas_dxs is None:
dgammas_dxs = [[0.0]*N for _ in range(N)] # numba: delete
# dgammas_dxs = zeros((N, N)) # numba: uncomment
for i in range(N):
dlngammas_r_dxsi = dlngammas_r_dxs[i]
dlngammas_c_dxsi = dlngammas_c_dxs[i]
dgammas_dxsi = dgammas_dxs[i]
for j in range(N):
dgammas_dxsi[j] = (dlngammas_r_dxsi[j] + dlngammas_c_dxsi[j])*gammas[i]
return dgammas_dxs
def unifac_dgammas_dxs_skip_comb(N, xs, gammas, dlngammas_r_dxs, dgammas_dxs=None):
if dgammas_dxs is None:
dgammas_dxs = [[0.0]*N for _ in range(N)] # numba: delete
# dgammas_dxs = zeros((N, N)) # numba: uncomment
for i in range(N):
dlngammas_r_dxsi = dlngammas_r_dxs[i]
dgammas_dxsi = dgammas_dxs[i]
for j in range(N):
dgammas_dxsi[j] = dlngammas_r_dxsi[j]*gammas[i]
return dgammas_dxs
def unifac_dgammas_dns(N, xs, dgammas_dxs, dgammas_dns=None):
if dgammas_dns is None:
dgammas_dns = [[0.0]*N for _ in range(N)] # numba: delete
# dgammas_dns = zeros((N, N)) # numba: uncomment
for i in range(N):
row = dgammas_dns[i]
dgammas_dxsi = dgammas_dxs[i]
xdx_tot = 0.0
for j in range(N):
xdx_tot += xs[j]*dgammas_dxsi[j]
for j in range(N):
row[j] = dgammas_dxsi[j] - xdx_tot
return dgammas_dns
def unifac_lngammas_c(N, version, qs, Fis, Vis, Vis_modified, lngammas_c=None):
if lngammas_c is None:
lngammas_c = [0.0]*N
if version == 4:
for i in range(N):
r = Vis_modified[i] # In the definition of V' used here, there is no mole fraction division needed
val = log(r) + 1.0 - r
lngammas_c[i] = val
else:
for i in range(N):
Vi_Fi = Vis[i]/Fis[i]
val = (1.0 - Vis_modified[i] + log(Vis_modified[i])
- 5.0*qs[i]*(1.0 - Vi_Fi + log(Vi_Fi)))
lngammas_c[i] = val
return lngammas_c
def unifac_dlngammas_c_dxs(N, version, qs, Fis, dFis_dxs, Vis, dVis_dxs, Vis_modified, dVis_modified_dxs, dlngammas_c_dxs=None):
if dlngammas_c_dxs is None:
dlngammas_c_dxs = [[0.0]*N for _ in range(N)] # numba: delete
# dlngammas_c_dxs = zeros((N, N)) # numba: uncomment
if version == 4:
for i in range(N):
row = dlngammas_c_dxs[i]
for j in range(N):
v = -dVis_modified_dxs[i][j] + dVis_modified_dxs[i][j]/Vis_modified[i]
row[j] = v
else:
for i in range(N):
row = dlngammas_c_dxs[i]
Fi_inv = 1.0/Fis[i]
for j in range(N):
val = -5.0*qs[i]*((dVis_dxs[i][j] - Vis[i]*dFis_dxs[i][j]*Fi_inv)/Vis[i]
- dVis_dxs[i][j]*Fi_inv + Vis[i]*dFis_dxs[i][j]*Fi_inv*Fi_inv
) - dVis_modified_dxs[i][j] + dVis_modified_dxs[i][j]/Vis_modified[i]
row[j] = val
return dlngammas_c_dxs
def unifac_d2lngammas_c_dxixjs(N, version, qs, Fis, dFis_dxs, d2Fis_dxixjs, Vis, dVis_dxs, d2Vis_dxixjs, Vis_modified, dVis_modified_dxs, d2Vis_modified_dxixjs, d2lngammas_c_dxixjs=None):
if d2lngammas_c_dxixjs is None:
d2lngammas_c_dxixjs = [[[0.0]*N for _ in range(N)] for _ in range(N)]# numba: delete
# d2lngammas_c_dxixjs = zeros((N, N, N)) # numba: uncomment
if version == 4:
for i in range(N):
Vi = Vis_modified[i]
matrix = d2lngammas_c_dxixjs[i]
for j in range(N):
row = matrix[j]
for k in range(N):
val = -d2Vis_modified_dxixjs[i][j][k] + 1.0/Vi*d2Vis_modified_dxixjs[i][j][k]
val -= 1.0/Vi**2*dVis_modified_dxs[i][j]*dVis_modified_dxs[i][k]
row[k] = val
else:
for i in range(N):
Vi = Vis[i]
qi = qs[i]
ViD = Vis_modified[i]
ViD_inv2 = 1.0/(ViD*ViD)
Fi = Fis[i]
x1 = 1.0/Fi
x4 = x1*x1
Fi_inv3 = x1*x1*x1
x5 = Vis[i]*x4
x15 = 1.0/Vi
Vi_inv2 = x15*x15
matrix = d2lngammas_c_dxixjs[i]
for j in range(N):
x6 = dFis_dxs[i][j]
x10 = dVis_dxs[i][j]
dViD_dxj = dVis_modified_dxs[i][j]
row = matrix[j]
for k in range(N):
x0 = d2Vis_modified_dxixjs[i][j][k]
x2 = d2Vis_dxixjs[i][j][k]
x3 = d2Fis_dxixjs[i][j][k]
x7 = dVis_dxs[i][k]
dViD_dxk = dVis_modified_dxs[i][k]
x8 = x6*x7
x9 = dFis_dxs[i][k]
x11 = x10*x9
x12 = 2.0*x6*x9
x13 = Vi*x1
x14 = x10 - x13*x6
val = (5.0*qi*(-x1*x14*x15*x9 + x1*x2 - x11*x4
+ x15*(x1*x11 + x1*x8 - x12*x5 + x13*x3 - x2)
- x3*x5 - x4*x8 + x14*x7*Vi_inv2 + Vi*x12*Fi_inv3)
- x0 + x0/ViD - dViD_dxj*dViD_dxk*ViD_inv2
)
row[k] = val
return d2lngammas_c_dxixjs
def unifac_d3lngammas_c_dxixjxks(N, version, qs, Fis, dFis_dxs, d2Fis_dxixjs, d3Fis_dxixjxks, Vis, dVis_dxs, d2Vis_dxixjs, d3Vis_dxixjxks, Vis_modified, dVis_modified_dxs, d2Vis_modified_dxixjs, d3Vis_modified_dxixjxks, d3lngammas_c_dxixjxks=None):
if d3lngammas_c_dxixjxks is None:
d3lngammas_c_dxixjxks = [[[[0.0]*N for _ in range(N)] for _ in range(N)] for _ in range(N)] # numba: delete
# d3lngammas_c_dxixjxks = zeros((N, N, N, N)) # numba: uncomment
if version == 4:
for i in range(N):
Vi = Vis_modified[i]
third = d3lngammas_c_dxixjxks[i]
for j in range(N):
hess = third[j]
for k in range(N):
row = hess[k]
for m in range(N):
val = d3Vis_modified_dxixjxks[i][j][k][m]*(1.0/Vi - 1.0)
val-= 1.0/Vi**2* (dVis_modified_dxs[i][j]*d2Vis_modified_dxixjs[i][k][m]
+ dVis_modified_dxs[i][k]*d2Vis_modified_dxixjs[i][j][m]
+ dVis_modified_dxs[i][m]*d2Vis_modified_dxixjs[i][j][k])
val += 2.0/Vi**3*dVis_modified_dxs[i][j]*dVis_modified_dxs[i][k]*dVis_modified_dxs[i][m]
row[m] = val
else:
for i in range(N):
Vi = Vis[i]
ViD = Vis_modified[i]
Fi = Fis[i]
qi = qs[i]
third = d3lngammas_c_dxixjxks[i]
for j in range(N):
hess = third[j]
for k in range(N):
row = hess[k]
for m in range(N):
x0 = d3Vis_modified_dxixjxks[i][j][k][m]#Derivative(ViD, xj, xk, xm)
x1 = 1/Fis[i]#1/Fi
x2 = 5.0*qs[i]
x3 = x2*d3Fis_dxixjxks[i][j][k][m]#Derivative(Fi, xj, xk, xm)
x4 = x2*d3Vis_dxixjxks[i][j][k][m]#Derivative(Vi, xj, xk, xm)
x5 = Vis_modified[i]**-2#ViD**(-2)
x6 = dVis_modified_dxs[i][j]#Derivative(ViD, xj)
x7 = dVis_modified_dxs[i][k]#Derivative(ViD, xk)
x8 = dVis_modified_dxs[i][m]#Derivative(ViD, xm)
x9 = Fis[i]**-2#Fi**(-2)
x10 = x2*x9
x11 = dFis_dxs[i][j]#Derivative(Fi, xj)
x12 = d2Fis_dxixjs[i][k][m]#Derivative(Fi, xk, xm)
x13 = x11*x12
x14 = d2Vis_dxixjs[i][k][m]#Derivative(Vi, xk, xm)
x15 = d2Fis_dxixjs[i][j][m]#Derivative(Fi, xj, xm)
x16 = dFis_dxs[i][k]#Derivative(Fi, xk)
x17 = x10*x16
x18 = d2Vis_dxixjs[i][j][m]#Derivative(Vi, xj, xm)
x19 = d2Fis_dxixjs[i][j][k]#Derivative(Fi, xj, xk)
x20 = dFis_dxs[i][m]#Derivative(Fi, xm)
x21 = x10*x20
x22 = d2Vis_dxixjs[i][j][k]#Derivative(Vi, xj, xk)
x23 = dVis_dxs[i][j]#Derivative(Vi, xj)
x24 = dVis_dxs[i][k]#Derivative(Vi, xk)
x25 = dVis_dxs[i][m]#Derivative(Vi, xm)
x26 = x2/Vis[i]**2
x27 = Fis[i]**(-3)
x28 = 10*qs[i]
x29 = x27*x28
x30 = Vi*x29
x31 = x11*x16
x32 = x20*x29
x33 = x25*x28
val = (-Vi*x3*x9 - x0 + x1*x3 + x1*x4 - x10*x11*x14 - x10*x12*x23
- x10*x13 - x10*x15*x24 - x10*x19*x25 + x11*x24*x32 + x13*x30
+ x14*x23*x26 + x15*x16*x30 - x15*x17 + x16*x23*x32 - x17*x18
+ x18*x24*x26 + x19*x20*x30 - x19*x21 - x21*x22 + x22*x25*x26
+ x27*x31*x33 + x31*x32 - x5*x6*d2Vis_modified_dxixjs[i][k][m]
- x5*x7*d2Vis_modified_dxixjs[i][j][m]
- x5*x8*d2Vis_modified_dxixjs[i][j][k]
+ x0/ViD + 2*x6*x7*x8/ViD**3 - x4/Vi - x23*x24*x33/Vi**3 - 30*Vi*qi*x20*x31/Fi**4)
row[m] = val
return d3lngammas_c_dxixjxks
[docs]class UNIFAC(GibbsExcess):
r'''Class for representing an a liquid with excess gibbs energy represented
by the UNIFAC equation. This model is capable of representing VL and LL
behavior, provided the correct interaction parameters are used. [1]_ and
[2]_ are good references on this model.
Parameters
----------
T : float
Temperature, [K]
xs : list[float]
Mole fractions, [-]
rs : list[float]
`r` parameters :math:`r_i = \sum_{k=1}^{n} \nu_k R_k`, [-]
qs : list[float]
`q` parameters :math:`q_i = \sum_{k=1}^{n}\nu_k Q_k`, [-]
Qs : list[float]
`Q` parameter for each subgroup; subgroups are not required to but are
suggested to be sorted from lowest number to highest number, [-]
vs : list[list[float]]
Indexed by [subgroup][count], this variable is the count of each
subgroups in each compound, [-]
psi_abc : tuple(list[list[float]], 3), optional
`psi` interaction parameters between each subgroup; indexed
[subgroup][subgroup], not symmetrical; first arg is the matrix for `a`,
then `b`, and then `c`. Only one of `psi_abc` or `psi_coeffs` is
required, [-]
psi_coeffs : list[list[tuple(float, 3)]], optional
`psi` interaction parameters between each subgroup; indexed
[subgroup][subgroup][letter], not symmetrical. Only one of `psi_abc`
or `psi_coeffs` is required, [-]
version : int, optional
Which version of the model to use [-]
* 0 - original UNIFAC, OR UNIFAC LLE
* 1 - Dortmund UNIFAC (adds T dept, 3/4 power)
* 2 - PSRK (original with T dept function)
* 3 - VTPR (drops combinatorial term, Dortmund UNIFAC otherwise)
* 4 - Lyngby/Larsen has different combinatorial, 2/3 power
* 5 - UNIFAC KT (2 params for psi, Lyngby/Larsen formulation;
otherwise same as original)
Attributes
----------
T : float
Temperature, [K]
xs : list[float]
Mole fractions, [-]
Notes
-----
In addition to the methods presented here, the methods of its base class
:obj:`thermo.activity.GibbsExcess` are available as well.
Examples
--------
The DDBST has published numerous sample problems using UNIFAC; a simple
binary system from example P05.22a in [2]_ with n-hexane and butanone-2
is shown below:
>>> from thermo.unifac import UFIP, UFSG
>>> GE = UNIFAC.from_subgroups(chemgroups=[{1:2, 2:4}, {1:1, 2:1, 18:1}], T=60+273.15, xs=[0.5, 0.5], version=0, interaction_data=UFIP, subgroups=UFSG)
>>> GE.gammas()
[1.4276025835, 1.3646545010]
>>> GE.GE(), GE.dGE_dT(), GE.d2GE_dT2()
(923.641197, 0.206721488, -0.00380070204)
>>> GE.HE(), GE.SE(), GE.dHE_dT(), GE.dSE_dT()
(854.77193363, -0.2067214889, 1.266203886, 0.0038007020460)
The solution given by the DDBST has the same values [1.428, 1.365],
and can be found here:
http://chemthermo.ddbst.com/Problems_Solutions/Mathcad_Files/05.22a%20VLE%20of%20Hexane-Butanone-2%20Via%20UNIFAC%20-%20Step%20by%20Step.xps
References
----------
.. [1] Poling, Bruce E., John M. Prausnitz, and John P. O`Connell. The
Properties of Gases and Liquids. 5th edition. New York: McGraw-Hill
Professional, 2000.
.. [2] Gmehling, Jürgen, Michael Kleiber, Bärbel Kolbe, and Jürgen Rarey.
Chemical Thermodynamics for Process Simulation. John Wiley & Sons, 2019.
'''
"""
List of functions not fully optimized (for Python anyway)
psis second derivative
lnGammas_subgroups_pure - "in" array check is approx. 2x as slow in numba
as coding the flor loop to check it
unifac_d3lnGammas_subgroups_dT3 has no optimization
d2lnGammas_subgroups_dT2 can have one more vec to save time
unifac_dlnGammas_subgroups_dT can have one more vec to save time
unifac_dlnGammas_subgroups_dxs can have one more vec to save time
"""
gammas_from_args = staticmethod(unifac_gammas_from_args)
__slots__ = GibbsExcess.__slots__ +('Thetas_sum_inv', 'Hs', '_Thetas_pure', 'Fs_pure', 'Theta_pure_Psi_sum_invs', '_dVis_dxs',
'_dVis_modified_dxs', 'rx_sum_inv', '_d2lnGammas_subgroups_dT2', 'VSXS', 'rs', '_d2lngammas_c_dxixjs', 'cmp_group_idx', '_Thetas', '_d3psis_dT3',
'N_groups', 'cmp_v_count_inv', 'Fs', 'Ws', '_d2lnGammas_subgroups_dTdxs', '_lngammas_c', 'qx_sum_inv', 'cmp_v_count', 'Gs',
'_dlnGammas_subgroups_dT', '_Vis_modified', 'r34x_sum_inv', '_dlngammas_r_dxs', '_dFis_dxs', '_Xs_pure', '_d2lngammas_r_dT2',
'skip_comb', '_d3lngammas_r_dT3', '_lnGammas_subgroups', 'qs', '_d2lngammas_r_dxixjs', '_dgammas_dxs', 'group_cmp_idx',
'_d3lnGammas_subgroups_pure_dT3', '_lnGammas_subgroups_pure', '_Fis', '_d2lngammas_r_dTdxs', '_d2Fis_dxixjs', 'Theta_Psi_sum_invs',
'_d3GE_dT3', '_d2Thetas_dxixjs', 'Qs', '_dpsis_dT', '_d2lnGammas_subgroups_dxixjs', 'rs_34', 'psi_b', '_d3lnGammas_subgroups_dT3',
'_Xs', 'Xs_sum_inv', '_dlnGammas_subgroups_dxs', '_dlngammas_c_dxs', 'Theta_pure_Psi_sums', '_psis', 'vs', 'Gs_pure', 'psi_a', '_dThetas_dxs',
'Theta_Psi_sums', '_d2Vis_dxixjs', '_dlnGammas_subgroups_pure_dT', '_d2Vis_modified_dxixjs', 'Hs_pure', '_lngammas_r', '_d2lnGammas_subgroups_pure_dT2',
'_d2psis_dT2', '_Vis', 'psi_c', 'version', '_dlngammas_r_dT', '_d3Vis_dxixjxks', '_d3Fis_dxixjxks', '_d3Vis_modified_dxixjxks', '_d3lngammas_c_dxixjxks')
@property
def model_id(self):
'''A unique numerical identifier refering to the thermodynamic model
being implemented. For internal use.
'''
return self.version + 500
[docs] def gammas_args(self, T=None):
r'''Return a tuple of arguments at the specified tempearture
that can be used to efficiently compute gammas at the
specified temperature but with varying compositions. This is
useful in the context of a TP flash.
'''
if T is not None:
obj = self.to_T_xs(T=T, xs=self.xs)
else:
obj = self
try:
rs_34 = obj.rs_34
except:
rs_34 = obj.rs
return (obj.N, obj.N_groups, obj.vs, obj.rs, obj.qs, obj.Qs,
obj.psis(), obj.lnGammas_subgroups_pure(),# Depends on T only
obj.version, rs_34)
[docs] @staticmethod
def from_subgroups(T, xs, chemgroups, subgroups=None,
interaction_data=None, version=0):
r'''Method to construct a UNIFAC object from a dictionary of
interaction parameters parameters and a list of dictionaries of UNIFAC keys.
As the actual implementation is matrix based not dictionary based, this method
can be quite convenient.
Parameters
----------
T : float
Temperature, [K]
xs : list[float]
Mole fractions, [-]
chemgroups : list[dict]
List of dictionaries of subgroup IDs and their counts for all species
in the mixture, [-]
subgroups : dict[int: UNIFAC_subgroup], optional
UNIFAC subgroup data; available dictionaries in this module include
UFSG (original), DOUFSG (Dortmund), or NISTUFSG. The default depends
on the given `version`, [-]
interaction_data : dict[int: dict[int: tuple(a_mn, b_mn, c_mn)]], optional
UNIFAC interaction parameter data; available dictionaries in this
module include UFIP (original), DOUFIP2006 (Dortmund parameters
published in 2006), DOUFIP2016 (Dortmund parameters published in
2016), and NISTUFIP. The default depends on the given `version`, [-]
version : int, optional
Which version of the model to use. Defaults to 0, [-]
* 0 - original UNIFAC, OR UNIFAC LLE
* 1 - Dortmund UNIFAC (adds T dept, 3/4 power)
* 2 - PSRK (original with T dept function)
* 3 - VTPR (drops combinatorial term, Dortmund UNIFAC otherwise)
* 4 - Lyngby/Larsen has different combinatorial, 2/3 power
* 5 - UNIFAC KT (2 params for psi, Lyngby/Larsen formulation;
otherwise same as original)
Returns
-------
UNIFAC : UNIFAC
Object for performing calculations with the UNIFAC activity
coefficient model, [-]
Notes
-----
.. warning::
For version 0, the interaction data and subgroups default to the
original UNIFAC model (not LLE).
For version 1, the interaction data defaults to the Dortmund parameters
publshed in 2016 (not 2006).
Examples
--------
Mixture of ['benzene', 'cyclohexane', 'acetone', 'ethanol']
according to the Dortmund UNIFAC model:
>>> from thermo.unifac import DOUFIP2006, DOUFSG
>>> T = 373.15
>>> xs = [0.2, 0.3, 0.1, 0.4]
>>> chemgroups = [{9: 6}, {78: 6}, {1: 1, 18: 1}, {1: 1, 2: 1, 14: 1}]
>>> GE = UNIFAC.from_subgroups(T=T, xs=xs, chemgroups=chemgroups, version=1, interaction_data=DOUFIP2006, subgroups=DOUFSG)
>>> GE
UNIFAC(T=373.15, xs=[0.2, 0.3, 0.1, 0.4], rs=[2.2578, 4.2816, 2.3373, 2.4951999999999996], qs=[2.5926, 5.181, 2.7308, 2.6616], Qs=[1.0608, 0.7081, 0.4321, 0.8927, 1.67, 0.8635], vs=[[0, 0, 1, 1], [0, 0, 0, 1], [6, 0, 0, 0], [0, 0, 0, 1], [0, 0, 1, 0], [0, 6, 0, 0]], psi_abc=([[0.0, 0.0, 114.2, 2777.0, 433.6, -117.1], [0.0, 0.0, 114.2, 2777.0, 433.6, -117.1], [16.07, 16.07, 0.0, 3972.0, 146.2, 134.6], [1606.0, 1606.0, 3049.0, 0.0, -250.0, 3121.0], [199.0, 199.0, -57.53, 653.3, 0.0, 168.2], [170.9, 170.9, -2.619, 2601.0, 464.5, 0.0]], [[0.0, 0.0, 0.0933, -4.674, 0.1473, 0.5481], [0.0, 0.0, 0.0933, -4.674, 0.1473, 0.5481], [-0.2998, -0.2998, 0.0, -13.16, -1.237, -1.231], [-4.746, -4.746, -12.77, 0.0, 2.857, -13.69], [-0.8709, -0.8709, 1.212, -1.412, 0.0, -0.8197], [-0.8062, -0.8062, 1.094, -1.25, 0.1542, 0.0]], [[0.0, 0.0, 0.0, 0.001551, 0.0, -0.00098], [0.0, 0.0, 0.0, 0.001551, 0.0, -0.00098], [0.0, 0.0, 0.0, 0.01208, 0.004237, 0.001488], [0.0009181, 0.0009181, 0.01435, 0.0, -0.006022, 0.01446], [0.0, 0.0, -0.003715, 0.000954, 0.0, 0.0], [0.001291, 0.001291, -0.001557, -0.006309, 0.0, 0.0]]), version=1)
'''
if subgroups is None:
if version == 0:
subgroups = UFSG
elif version == 1:
subgroups = DOUFSG
elif version == 2:
subgroups = PSRKSG
elif version == 3:
subgroups = VTPRSG
elif version == 4:
subgroups = LUFSG
elif version == 5:
subgroups = NISTKTUFSG
else:
raise ValueError("'version' must be a number from 0 to 5")
if interaction_data is None:
if not _unifac_ip_loaded: load_unifac_ip()
if version == 0:
interaction_data = UFIP
elif version == 1:
interaction_data = DOUFIP2016
elif version == 2:
interaction_data = PSRKIP
elif version == 3:
interaction_data = VTPRIP
elif version == 4:
interaction_data = LUFIP
elif version == 5:
interaction_data = NISTKTUFIP
else:
raise ValueError("'version' must be a number from 0 to 5")
scalar = type(xs) is list
rs = []
qs = []
for groups in chemgroups:
ri = 0.
qi = 0.
for subgroup_idx, count in groups.items():
if version != 3:
ri += subgroups[subgroup_idx].R*count
qi += subgroups[subgroup_idx].Q*count
rs.append(ri)
qs.append(qi)
# Make a dictionary containing the subgroups as keys and their count - the total number
# of them in ALL the compounds, regardless of mole fractions
group_counts = {}
for compound_subgroups in chemgroups:
for subgroup, count in compound_subgroups.items():
try:
group_counts[subgroup] += count
except KeyError:
group_counts[subgroup] = count
# Convert group counts into a list, sorted by index (lowest subgroup index is first element, highest subgroup index is the last)
subgroup_list = list(sorted(group_counts.keys()))
group_counts_list = [c for _, c in sorted(zip(group_counts.keys(), group_counts.values()))]
Qs = [subgroups[group].Q for group in subgroup_list]
vs = chemgroups_to_matrix(chemgroups)
psi_a, psi_b, psi_c = [], [], []
for sub1 in subgroup_list:
a_row, b_row, c_row = [], [], []
for sub2 in subgroup_list:
main1 = subgroups[sub1].main_group_id
main2 = subgroups[sub2].main_group_id
try:
v = interaction_data[main1][main2]
try:
a_row.append(v[0])
b_row.append(v[1])
c_row.append(v[2])
except:
a_row.append(v)
b_row.append(0.0)
c_row.append(0.0)
except KeyError:
a_row.append(0.0)
b_row.append(0.0)
c_row.append(0.0)
psi_a.append(a_row), psi_b.append(b_row), psi_c.append(c_row)
# debug = (rs, qs, Qs, vs, (psi_a, psi_b, psi_c))
if scalar:
return UNIFAC(T=T, xs=xs, rs=rs, qs=qs, Qs=Qs, vs=vs, psi_abc=(psi_a, psi_b, psi_c), version=version)
return UNIFAC(T=T, xs=xs, rs=array(rs), qs=array(qs), Qs=array(Qs), vs=array(vs, dtype=float), psi_abc=(array(psi_a), array(psi_b), array(psi_c)), version=version)
_model_attributes = ('rs', 'qs', 'psi_a', 'psi_b', 'psi_c', 'version')
def __repr__(self): # pragma: no cover
psi_abc = (self.psi_a, self.psi_b, self.psi_c)
s = 'UNIFAC('
s += f'T={self.T}, xs={self.xs}, rs={self.rs}, qs={self.qs}'
s += ', Qs={}, vs={}, psi_abc={}, version={}'.format(self.Qs, self.vs,
psi_abc, self.version)
s += ')'
return s
def __init__(self, T, xs, rs, qs, Qs, vs, psi_coeffs=None, psi_abc=None,
version=0):
self.T = T
self.xs = xs
self.scalar = scalar = type(xs) is list
# rs - 1d index by [component] parameter, calculated using the chemical's subgroups and their count
self.rs = rs
# qs - 1d index by [component] parameter, calculated using the chemical's subgroups and their count
self.qs = qs
self.Qs = Qs
# [subgroup][component] = number of subgroup in component where subgroup
# is an index, numbered sequentially by the number of subgroups in the mixture
self.vs = vs
# each psi_letter is a matrix of [subgroup_length][subgroups_length]
# the diagonal is zero
# Indexed by index of the subgroup in the mixture, again sorted lowest first
if psi_abc is not None:
self.psi_a, self.psi_b, self.psi_c = psi_abc
else:
if psi_coeffs is None:
raise ValueError("Missing psis")
self.psi_a = [[i[0] for i in l] for l in psi_coeffs]
self.psi_b = [[i[1] for i in l] for l in psi_coeffs]
self.psi_c = [[i[2] for i in l] for l in psi_coeffs]
self.N_groups = N_groups = len(self.psi_a)
self.N = N = len(rs)
self.version = version
self.skip_comb = version == 3
if self.version == 1:
power = 0.75
if scalar:
self.rs_34 = [ri**power for ri in rs]
else:
self.rs_34 = rs**0.75
elif self.version == 4:
power = 2.0/3.0 # Lyngby
# works in the various functions without change as never taking the der w.r.t. r
if scalar:
self.rs_34 = [ri**power for ri in rs]
else:
self.rs_34 = rs**power
self.cmp_v_count = cmp_v_count = []
for i in range(N):
tot = 0
for group in range(N_groups):
tot += vs[group][i]
cmp_v_count.append(tot)
if scalar:
cmp_v_count_inv = [1.0/ni for ni in cmp_v_count]
else:
self.cmp_v_count = cmp_v_count = array(cmp_v_count)
cmp_v_count_inv = 1.0/cmp_v_count
self.cmp_v_count_inv = cmp_v_count_inv
# Matrix of [component][list(indexes to groups in component)], list of list
cmp_group_idx = [[j for j in range(N_groups) if vs[j][i]] for i in range(N)]
# TODO figure out the best way to handle this with numba
# as each array was supposedly a different shape
if not scalar:
cmp_group_idx = tuple(array(v) for v in cmp_group_idx)
self.cmp_group_idx = cmp_group_idx
group_cmp_idx = []
for k in range(N_groups):
temp = []
for i in range(N):
groups2 = cmp_group_idx[i]
if k in groups2:
temp.append(i)
group_cmp_idx.append(temp)
if not scalar:
group_cmp_idx = tuple(array(v) for v in group_cmp_idx)
self.group_cmp_idx = group_cmp_idx
# Calculate the composition and temperature independent parameters on initialization
self.Thetas_pure()
self.Xs_pure()
[docs] def to_T_xs(self, T, xs):
r'''Method to construct a new :obj:`UNIFAC` instance at
temperature `T`, and mole fractions `xs`
with the same parameters as the existing object.
Parameters
----------
T : float
Temperature, [K]
xs : list[float]
Mole fractions of each component, [-]
Returns
-------
obj : UNIFAC
New :obj:`UNIFAC` object at the specified conditions [-]
Notes
-----
If the new temperature is the same temperature as the existing
temperature, if the `psi` terms or their derivatives have been
calculated, they will be set to the new object as well.
If the mole fractions are the same, various subgroup terms are also
kept.
'''
new = self.__class__.__new__(self.__class__)
new.T = T
new.xs = xs
new.N = self.N
new.scalar = self.scalar
new.N_groups = self.N_groups
new.rs = self.rs
new.qs = self.qs
new.Qs = self.Qs
new.vs = self.vs
new.cmp_v_count = self.cmp_v_count
new.cmp_v_count_inv = self.cmp_v_count_inv
new.cmp_group_idx = self.cmp_group_idx
new.group_cmp_idx = self.group_cmp_idx
new.version = self.version
new.skip_comb = self.skip_comb
new.psi_a, new.psi_b, new.psi_c = self.psi_a, self.psi_b, self.psi_c
try:
new.rs_34 = self.rs_34
except AttributeError:
pass
new._Thetas_pure = self._Thetas_pure
new._Xs_pure = self._Xs_pure
if T == self.T:
# interaction parameters that depend on T only
try:
new._psis = self._psis
except AttributeError:
pass
try:
new._dpsis_dT = self._dpsis_dT
except AttributeError:
pass
try:
new._d2psis_dT2 = self._d2psis_dT2
except AttributeError:
pass
try:
new._d3psis_dT3 = self._d3psis_dT3
except AttributeError:
pass
# pure parameters that depend on T only
try:
new._lnGammas_subgroups_pure = self._lnGammas_subgroups_pure
except AttributeError:
pass
try:
new._dlnGammas_subgroups_pure_dT = self._dlnGammas_subgroups_pure_dT
except AttributeError:
pass
try:
new._d2lnGammas_subgroups_pure_dT2 = self._d2lnGammas_subgroups_pure_dT2
except AttributeError:
pass
try:
new._d3lnGammas_subgroups_pure_dT3 = self._d3lnGammas_subgroups_pure_dT3
except AttributeError:
pass
if (self.scalar and xs == self.xs) or (not self.scalar and array_equal(xs, self.xs)):
try:
new._Fis = self._Fis
except AttributeError:
pass
try:
new.qx_sum_inv = self.qx_sum_inv
except AttributeError:
pass
try:
new._dFis_dxs = self._dFis_dxs
except AttributeError:
pass
try:
new._d2Fis_dxixjs = self._d2Fis_dxixjs
except AttributeError:
pass
try:
new._d3Fis_dxixjxks = self._d3Fis_dxixjxks
except AttributeError:
pass
try:
new._Vis_modified = self._Vis_modified
new.r34x_sum_inv = self.r34x_sum_inv
except AttributeError:
pass
try:
new._dVis_modified_dxs = self._dVis_modified_dxs
except AttributeError:
pass
try:
new._d2Vis_modified_dxixjs = self._d2Vis_modified_dxixjs
except AttributeError:
pass
try:
new._d3Vis_modified_dxixjxks = self._d3Vis_modified_dxixjxks
except AttributeError:
pass
# composition dependent - parameters not using psis
try:
new._Xs = self._Xs
except AttributeError:
pass
try:
new._Thetas = self._Thetas
new.Thetas_sum_inv = self.Thetas_sum_inv
except AttributeError:
pass
try:
new.Xs_sum_inv = self.Xs_sum_inv
except AttributeError:
pass
try:
new._dThetas_dxs = self._dThetas_dxs
except AttributeError:
pass
try:
new._d2Thetas_dxixjs = self._d2Thetas_dxixjs
except AttributeError:
pass
try:
new._lngammas_c = self._lngammas_c
except AttributeError:
pass
try:
new._dlngammas_c_dxs = self._dlngammas_c_dxs
except AttributeError:
pass
try:
new._d2lngammas_c_dxixjs = self._d2lngammas_c_dxixjs
except AttributeError:
pass
try:
new._d3lngammas_c_dxixjxks = self._d3lngammas_c_dxixjxks
except AttributeError:
pass
# gammas, theta_psi_sums, _theta_psi_sum_inv, lngammas_subgroups, lngammas_r
# SHOULD NOT be moved to a new class - use the same class if T and x is the same!
return new
[docs] def psis(self):
r'''Calculate the :math:`\Psi` term matrix for all groups interacting
with all other groups.
The main model calculates it as a function of three coefficients;
.. math::
\Psi_{mn} = \exp\left(\frac{-a_{mn} - b_{mn}T - c_{mn}T^2}{T}\right)
Only the first, `a` coefficient, is used in the original UNIFAC model
as well as the UNIFAC-LLE model, so the expression simplifies to:
.. math::
\Psi_{mn} = \exp\left(\frac{-a_{mn}}{T}\right)
For the Lyngby model, the temperature dependence is modified slightly,
as follows:
.. math::
\Psi_{mk} = e^{\frac{- a_{1} - a_{2} \left(T - T_{0}\right) - a_{3}
\left(T \ln{\left(\frac{T_{0}}{T} \right)} + T - T_{0}\right)}{T}}
with :math:`T_0 = 298.15` K and the `a` coefficients are specific to
each pair of main groups, and they are asymmetric, so
:math:`a_{0,mk} \ne a_{0,km}`.
Returns
-------
psis : list[list[float]]
`psi` terms, size subgroups x subgroups [-]
'''
try:
return self._psis
except AttributeError:
pass
T, N_groups = self.T, self.N_groups
# mT_inv = -1.0/T
psi_a, psi_b, psi_c = self.psi_a, self.psi_b, self.psi_c
if self.scalar:
psis = [[0.0]*N_groups for _ in range(N_groups)]
else:
psis = zeros((N_groups, N_groups))
self._psis = unifac_psis(T, N_groups, self.version, psi_a, psi_b, psi_c, psis)
return psis
[docs] def dpsis_dT(self):
r'''Calculate the :math:`\Psi` term first temperature derivative
matrix for all groups interacting with all other groups.
The main model calculates the derivative as a function of three
coefficients;
.. math::
\frac{\partial \Psi_{mn}}{\partial T} = \left(\frac{- 2 T c_{mn}
- b_{mn}}{T} - \frac{- T^{2} c_{mn} - T b_{mn} - a_{mn}}{T^{2}}
\right) e^{\frac{- T^{2} c_{mn} - T b_{mn} - a_{mn}}{T}}
Only the first, `a` coefficient, is used in the original UNIFAC model
as well as the UNIFAC-LLE model, so the expression simplifies to:
.. math::
\frac{\partial \Psi_{mn}}{\partial T} = \frac{a_{mn}
e^{- \frac{a_{mn}}{T}}}{T^{2}}
For the Lyngby model, the first temperature derivative is:
.. math::
\frac{\partial \Psi_{mk}}{\partial T} = \left(\frac{- a_{2} - a_{3}
\ln{\left(\frac{T_{0}}{T} \right)}}{T} - \frac{- a_{1} - a_{2}
\left(T - T_{0}\right) - a_{3} \left(T \ln{\left(\frac{T_{0}}{T}
\right)} + T - T_{0}\right)}{T^{2}}\right) e^{\frac{- a_{1} - a_{2}
\left(T - T_{0}\right) - a_{3} \left(T \ln{\left(\frac{T_{0}}{T}
\right)} + T - T_{0}\right)}{T}}
with :math:`T_0 = 298.15` K and the `a` coefficients are specific to
each pair of main groups, and they are asymmetric, so
:math:`a_{0,mk} \ne a_{0,km}`.
Returns
-------
dpsis_dT : list[list[float]]
First temperature derivative of`psi` terms, size subgroups x
subgroups [-]
'''
try:
return self._dpsis_dT
except AttributeError:
pass
try:
psis = self._psis
except AttributeError:
psis = self.psis()
T, N_groups = self.T, self.N_groups
psi_a, psi_b, psi_c = self.psi_a, self.psi_b, self.psi_c
if self.scalar:
dpsis_dT = [[0.0]*N_groups for _ in range(N_groups)]
else:
dpsis_dT = zeros((N_groups, N_groups))
self._dpsis_dT = unifac_dpsis_dT(T, N_groups, self.version, psi_a, psi_b, psi_c, psis, dpsis_dT)
return dpsis_dT
[docs] def d2psis_dT2(self):
r'''Calculate the :math:`\Psi` term second temperature derivative
matrix for all groups interacting with all other groups.
The main model calculates the derivative as a function of three
coefficients;
.. math::
\frac{\partial^2 \Psi_{mn}}{\partial T^2} = \frac{\left(- 2 c_{mn}
+ \frac{2 \left(2 T c_{mn} + b_{mn}\right)}{T} + \frac{\left(2 T
c_{mn} + b_{mn} - \frac{T^{2} c_{mn} + T b_{mn} + a_{mn}}{T}
\right)^{2}}{T} - \frac{2 \left(T^{2} c_{mn} + T b_{mn} + a_{mn}
\right)}{T^{2}}\right) e^{- \frac{T^{2} c_{mn} + T b_{mn} + a_{mn}}
{T}}}{T}
Only the first, `a` coefficient, is used in the original UNIFAC model
as well as the UNIFAC-LLE model, so the expression simplifies to:
.. math::
\frac{\partial^2 \Psi_{mn}}{\partial T^2} = \frac{a_{mn} \left(-2
+ \frac{a_{mn}}{T}\right) e^{- \frac{a_{mn}}{T}}}{T^{3}}
For the Lyngby model, the second temperature derivative is:
.. math::
\frac{\partial^2 \Psi_{mk}}{\partial T^2} = \frac{\left(2 a_{2}
+ 2 a_{3} \ln{\left(\frac{T_{0}}{T} \right)} + a_{3} + \left(a_{2}
+ a_{3} \ln{\left(\frac{T_{0}}{T} \right)} - \frac{a_{1} + a_{2}
\left(T - T_{0}\right) + a_{3} \left(T \ln{\left(\frac{T_{0}}{T}
\right)} + T - T_{0}\right)}{T}\right)^{2} - \frac{2 \left(a_{1}
+ a_{2} \left(T - T_{0}\right) + a_{3} \left(T \ln{\left(
\frac{T_{0}}{T} \right)} + T - T_{0}\right)\right)}{T}\right)
e^{- \frac{a_{1} + a_{2} \left(T - T_{0}\right) + a_{3} \left(
T \ln{\left(\frac{T_{0}}{T} \right)} + T - T_{0}\right)}{T}}}
{T^{2}}
with :math:`T_0 = 298.15` K and the `a` coefficients are specific to
each pair of main groups, and they are asymmetric, so
:math:`a_{0,mk} \ne a_{0,km}`.
Returns
-------
d2psis_dT2 : list[list[float]]
Second temperature derivative of`psi` terms, size subgroups x
subgroups [-]
'''
try:
return self._d2psis_dT2
except AttributeError:
pass
try:
psis = self._psis
except AttributeError:
psis = self.psis()
T, N_groups = self.T, self.N_groups
psi_a, psi_b, psi_c = self.psi_a, self.psi_b, self.psi_c
if self.scalar:
d2psis_dT2 = [[0.0]*N_groups for _ in range(N_groups)]
else:
d2psis_dT2 = zeros((N_groups, N_groups))
self._d2psis_dT2 = unifac_d2psis_dT2(T, N_groups, self.version, psi_a, psi_b, psi_c, psis, d2psis_dT2)
return d2psis_dT2
[docs] def d3psis_dT3(self):
r'''Calculate the :math:`\Psi` term third temperature derivative
matrix for all groups interacting with all other groups.
The main model calculates the derivative as a function of three
coefficients;
.. math::
\frac{\partial^3 \Psi_{mn}}{\partial T^3} = \frac{\left(6 c_{mn}
+ 6 \left(c_{mn} - \frac{2 T c_{mn} + b_{mn}}{T} + \frac{T^{2}
c_{mn} + T b_{mn} + a_{mn}}{T^{2}}\right) \left(2 T c_{mn} + b_{mn}
- \frac{T^{2} c_{mn} + T b_{mn} + a_{mn}}{T}\right) - \frac{6
\left(2 T c_{mn} + b_{mn}\right)}{T} - \frac{\left(2 T c_{mn}
+ b_{mn} - \frac{T^{2} c_{mn} + T b_{mn} + a_{mn}}{T}\right)^{3}}
{T} + \frac{6 \left(T^{2} c_{mn} + T b_{mn} + a_{mn}\right)}{T^{2}}
\right) e^{- \frac{T^{2} c_{mn} + T b_{mn} + a_{mn}}{T}}}{T^{2}}
Only the first, `a` coefficient, is used in the original UNIFAC model
as well as the UNIFAC-LLE model, so the expression simplifies to:
.. math::
\frac{\partial^3 \Psi_{mn}}{\partial T^3} = \frac{a_{mn} \left(6
- \frac{6 a_{mn}}{T} + \frac{a_{mn}^{2}}{T^{2}}\right) e^{-
\frac{a_{mn}}{T}}}{T^{4}}
For the Lyngby model, the third temperature derivative is:
.. math::
\frac{\partial^3 \Psi_{mk}}{\partial T^3} =
- \frac{\left(6 a_{2} + 6 a_{3} \ln{\left(\frac{T_{0}}{T} \right)}
+ 4 a_{3} + \left(a_{2} + a_{3} \ln{\left(\frac{T_{0}}{T} \right)}
- \frac{a_{1} + a_{2} \left(T - T_{0}\right) + a_{3} \left(T \ln{
\left(\frac{T_{0}}{T} \right)} + T - T_{0}\right)}{T}\right)^{3}
+ 3 \left(a_{2} + a_{3} \ln{\left(\frac{T_{0}}{T} \right)}
- \frac{a_{1} + a_{2} \left(T - T_{0}\right) + a_{3} \left(T \ln{
\left(\frac{T_{0}}{T} \right)} + T - T_{0}\right)}{T}\right) \left(
2 a_{2} + 2 a_{3} \ln{\left(\frac{T_{0}}{T} \right)} + a_{3}
- \frac{2 \left(a_{1} + a_{2} \left(T - T_{0}\right) + a_{3} \left(
T \ln{\left(\frac{T_{0}}{T} \right)} + T - T_{0}\right)\right)}{T}
\right) - \frac{6 \left(a_{1} + a_{2} \left(T - T_{0}\right)
+ a_{3} \left(T \ln{\left(\frac{T_{0}}{T} \right)} + T - T_{0}
\right)\right)}{T}\right) e^{- \frac{a_{1} + a_{2} \left(T - T_{0}
\right) + a_{3} \left(T \ln{\left(\frac{T_{0}}{T} \right)}
+ T - T_{0}\right)}{T}}}{T^{3}}
with :math:`T_0 = 298.15` K and the `a` coefficients are specific to
each pair of main groups, and they are asymmetric, so
:math:`a_{0,mk} \ne a_{0,km}`.
Returns
-------
d3psis_dT3 : list[list[float]]
Third temperature derivative of`psi` terms, size subgroups x
subgroups [-]
'''
try:
return self._d3psis_dT3
except AttributeError:
pass
try:
psis = self._psis
except AttributeError:
psis = self.psis()
T, N_groups = self.T, self.N_groups
psi_a, psi_b, psi_c = self.psi_a, self.psi_b, self.psi_c
if self.scalar:
d3psis_dT3 = [[0.0]*N_groups for _ in range(N_groups)]
else:
d3psis_dT3 = zeros((N_groups, N_groups))
self._d3psis_dT3 = unifac_d3psis_dT3(T, N_groups, self.version, psi_a, psi_b, psi_c, psis, d3psis_dT3)
return d3psis_dT3
[docs] def Vis(self):
r'''Calculate the :math:`V_i` terms used in calculating the
combinatorial part. A function of mole fractions and the parameters
`r` only.
.. math::
V_i = \frac{r_i}{\sum_j r_j x_j}
This is used in the UNIFAC, UNIFAC-LLE, UNIFAC Dortmund, UNIFAC-NIST,
and PSRK models.
Returns
-------
Vis : list[float]
`V` terms size number of components, [-]
'''
try:
return self._Vis
except:
pass
rs, xs, N = self.rs, self.xs, self.N
if self.scalar:
Vis = [0.0]*N
else:
Vis = zeros(N)
self._Vis, self.rx_sum_inv = unifac_Vis(rs, xs, N, Vis)
return Vis
[docs] def dVis_dxs(self):
r'''Calculate the mole fraction derivative of the :math:`V_i` terms
used in calculating the combinatorial part. A function of mole
fractions and the parameters `r` only.
.. math::
\frac{\partial V_i}{\partial x_j} = -r_i r_j V_{sum}^2
.. math::
V_{sum} = \frac{1}{\sum_j r_j x_j}
This is used in the UNIFAC, UNIFAC-LLE, UNIFAC Dortmund, UNIFAC-NIST,
and PSRK models.
Returns
-------
dVis_dxs : list[list[float]]
`V` terms size number of components by number of components, [-]
'''
try:
return self._dVis_dxs
except AttributeError:
pass
try:
rx_sum_inv = self.rx_sum_inv
except AttributeError:
self.Vis()
rx_sum_inv = self.rx_sum_inv
rs, N = self.rs, self.N
if self.scalar:
dVis_dxs = [[0.0]*N for _ in range(N)]
else:
dVis_dxs = zeros((N, N))
self._dVis_dxs = unifac_dVis_dxs(rs, rx_sum_inv, N, dVis_dxs)
return dVis_dxs
[docs] def d2Vis_dxixjs(self):
r'''Calculate the second mole fraction derivative of the :math:`V_i`
terms used in calculating the combinatorial part. A function of mole
fractions and the parameters `r` only.
.. math::
\frac{\partial V_i}{\partial x_j \partial x_k} =
2 r_i r_j r_k V_{sum}^3
.. math::
V_{sum} = \frac{1}{\sum_j r_j x_j}
This is used in the UNIFAC, UNIFAC-LLE, UNIFAC Dortmund, UNIFAC-NIST,
and PSRK models.
Returns
-------
d2Vis_dxixjs : list[list[list[float]]]
`V` terms size number of components by number of components by
number of components, [-]
'''
try:
return self._d2Vis_dxixjs
except AttributeError:
pass
try:
rx_sum_inv = self.rx_sum_inv
except AttributeError:
self.Vis()
rx_sum_inv = self.rx_sum_inv
rs, N = self.rs, self.N
if self.scalar:
d2Vis_dxixjs = [[[0.0]*N for _ in range(N)] for _ in range(N)]
else:
d2Vis_dxixjs = zeros((N, N, N))
self._d2Vis_dxixjs = unifac_d2Vis_dxixjs(rs, rx_sum_inv, N, d2Vis_dxixjs)
return d2Vis_dxixjs
[docs] def d3Vis_dxixjxks(self):
r'''Calculate the third mole fraction derivative of the :math:`V_i`
terms used in calculating the combinatorial part. A function of mole
fractions and the parameters `r` only.
.. math::
\frac{\partial V_i}{\partial x_j \partial x_k \partial x_m} =
-6 r_i r_j r_k r_m V_{sum}^4
.. math::
V_{sum} = \frac{1}{\sum_j r_j x_j}
This is used in the UNIFAC, UNIFAC-LLE, UNIFAC Dortmund, UNIFAC-NIST,
and PSRK models.
Returns
-------
d3Vis_dxixjxks : list[list[list[list[float]]]]
`V` terms size number of components by number of components by
number of components by number of components, [-]
'''
try:
return self._d3Vis_dxixjxks
except AttributeError:
pass
try:
rx_sum_inv = self.rx_sum_inv
except AttributeError:
self.Vis()
rx_sum_inv = self.rx_sum_inv
rs, N = self.rs, self.N
if self.scalar:
d3Vis_dxixjxks = [[[[0.0]*N for _ in range(N)] for _ in range(N)] for _ in range(N)]
else:
d3Vis_dxixjxks = zeros((N, N, N, N))
self._d3Vis_dxixjxks = unifac_d3Vis_dxixjxks(rs, rx_sum_inv, N, d3Vis_dxixjxks)
return d3Vis_dxixjxks
[docs] def Fis(self):
r'''Calculate the :math:`F_i` terms used in calculating the
combinatorial part. A function of mole fractions and the parameters
`q` only.
.. math::
F_i = \frac{q_i}{\sum_j q_j x_j}
This is used in the UNIFAC, UNIFAC-LLE, UNIFAC Dortmund, UNIFAC-NIST,
and PSRK models.
Returns
-------
Fis : list[float]
`F` terms size number of components, [-]
'''
try:
return self._Fis
except AttributeError:
pass
qs, xs, N = self.qs, self.xs, self.N
if self.scalar:
Fis = [0.0]*N
else:
Fis = zeros(N)
self._Fis, self.qx_sum_inv = unifac_Vis(qs, xs, N, Fis)
return Fis
[docs] def dFis_dxs(self):
r'''Calculate the mole fraction derivative of the :math:`F_i` terms
used in calculating the combinatorial part. A function of mole
fractions and the parameters `q` only.
.. math::
\frac{\partial F_i}{\partial x_j} = -q_i q_j G_{sum}^2
.. math::
G_{sum} = \frac{1}{\sum_j q_j x_j}
This is used in the UNIFAC, UNIFAC-LLE, UNIFAC Dortmund, UNIFAC-NIST,
and PSRK models.
Returns
-------
dFis_dxs : list[list[float]]
`F` terms size number of components by number of components, [-]
'''
try:
return self._dFis_dxs
except AttributeError:
pass
try:
qx_sum_inv = self.qx_sum_inv
except AttributeError:
self.Fis()
qx_sum_inv = self.qx_sum_inv
qs, N = self.qs, self.N
if self.scalar:
dFis_dxs = [[0.0]*N for _ in range(N)]
else:
dFis_dxs = zeros((N, N))
self._dFis_dxs = unifac_dVis_dxs(qs, qx_sum_inv, N, dFis_dxs)
return dFis_dxs
[docs] def d2Fis_dxixjs(self):
r'''Calculate the second mole fraction derivative of the :math:`F_i`
terms used in calculating the combinatorial part. A function of mole
fractions and the parameters `q` only.
.. math::
\frac{\partial F_i}{\partial x_j \partial x_k} =
2 q_i q_j q_k G_{sum}^3
.. math::
G_{sum} = \frac{1}{\sum_j q_j x_j}
This is used in the UNIFAC, UNIFAC-LLE, UNIFAC Dortmund, UNIFAC-NIST,
and PSRK models.
Returns
-------
d2Fis_dxixjs : list[list[list[float]]]
`F` terms size number of components by number of components by
number of components, [-]
'''
try:
return self._d2Fis_dxixjs
except AttributeError:
pass
try:
qx_sum_inv = self.qx_sum_inv
except AttributeError:
self.Fis()
qx_sum_inv = self.qx_sum_inv
qs, N = self.qs, self.N
if self.scalar:
d2Fis_dxixjs = [[[0.0]*N for _ in range(N)] for _ in range(N)]
else:
d2Fis_dxixjs = zeros((N, N, N))
self._d2Fis_dxixjs = unifac_d2Vis_dxixjs(qs, qx_sum_inv, N, d2Fis_dxixjs )
return d2Fis_dxixjs
[docs] def d3Fis_dxixjxks(self):
r'''Calculate the third mole fraction derivative of the :math:`F_i`
terms used in calculating the combinatorial part. A function of mole
fractions and the parameters `q` only.
.. math::
\frac{\partial F_i}{\partial x_j \partial x_k \partial x_m} =
-6 q_i q_j q_k q_m G_{sum}^4
.. math::
G_{sum} = \frac{1}{\sum_j q_j x_j}
This is used in the UNIFAC, UNIFAC-LLE, UNIFAC Dortmund, UNIFAC-NIST,
and PSRK models.
Returns
-------
d3Fis_dxixjxks : list[list[list[list[float]]]]
`F` terms size number of components by number of components by
number of components by number of components, [-]
'''
try:
return self._d3Fis_dxixjxks
except AttributeError:
pass
try:
qx_sum_inv = self.qx_sum_inv
except AttributeError:
self.Fis()
qx_sum_inv = self.qx_sum_inv
qs, N = self.qs, self.N
if self.scalar:
d3Fis_dxixjxks = [[[[0.0]*N for _ in range(N)] for _ in range(N)] for _ in range(N)]
else:
d3Fis_dxixjxks = zeros((N, N, N, N))
self._d3Fis_dxixjxks = unifac_d3Vis_dxixjxks(qs, qx_sum_inv, N, d3Fis_dxixjxks)
return d3Fis_dxixjxks
[docs] def Vis_modified(self):
r'''Calculate the :math:`V_i'` terms used in calculating the
combinatorial part. A function of mole fractions and the parameters
`r` only.
.. math::
V_i' = \frac{r_i^n}{\sum_j r_j^n x_j}
This is used in the UNIFAC Dortmund and UNIFAC-NIST model with
n=0.75, and the Lyngby model with n=2/3.
Returns
-------
Vis_modified : list[float]
Modified `V` terms size number of components, [-]
'''
try:
return self._Vis_modified
except:
pass
rs_34, xs, N = self.rs_34, self.xs, self.N
if self.scalar:
Vis_modified = [0.0]*N
else:
Vis_modified = zeros(N)
self._Vis_modified, self.r34x_sum_inv = unifac_Vis(rs_34, xs, N, Vis_modified)
return Vis_modified
[docs] def dVis_modified_dxs(self):
r'''Calculate the mole fraction derivative of the :math:`V_i'` terms
used in calculating the combinatorial part. A function of mole
fractions and the parameters `r` only.
.. math::
\frac{\partial V_i'}{\partial x_j} = -r_i^n r_j^n V_{sum}^2
.. math::
V_{sum} = \frac{1}{\sum_j r_j^n x_j}
This is used in the UNIFAC Dortmund and UNIFAC-NIST model with
n=0.75, and the Lyngby model with n=2/3.
Returns
-------
dVis_modified_dxs : list[list[float]]
`V'` terms size number of components by number of components, [-]
'''
try:
return self._dVis_modified_dxs
except AttributeError:
pass
try:
r34x_sum_inv = self.r34x_sum_inv
except AttributeError:
self.Vis_modified()
r34x_sum_inv = self.r34x_sum_inv
rs_34, N = self.rs_34, self.N
if self.scalar:
dVis_modified = [[0.0]*N for _ in range(N)]
else:
dVis_modified = zeros((N, N))
self._dVis_modified_dxs = unifac_dVis_dxs(rs_34, r34x_sum_inv, N, dVis_modified)
return dVis_modified
[docs] def d2Vis_modified_dxixjs(self):
r'''Calculate the second mole fraction derivative of the :math:`V_i'`
terms used in calculating the combinatorial part. A function of mole
fractions and the parameters `r` only.
.. math::
\frac{\partial V_i'}{\partial x_j \partial x_k} =
2 r_i^n r_j^n r_k^n V_{sum}^3
.. math::
V_{sum} = \frac{1}{\sum_j r_j^n x_j}
This is used in the UNIFAC Dortmund and UNIFAC-NIST model with
n=0.75, and the Lyngby model with n=2/3.
Returns
-------
d2Vis_modified_dxixjs : list[list[list[float]]]
`V'` terms size number of components by number of components by
number of components, [-]
'''
try:
return self._d2Vis_modified_dxixjs
except AttributeError:
pass
try:
r34x_sum_inv = self.r34x_sum_inv
except AttributeError:
self.Vis_modified()
r34x_sum_inv = self.r34x_sum_inv
rs_34, N = self.rs_34, self.N
if self.scalar:
d2Vis_modified = [[[0.0]*N for _ in range(N)] for _ in range(N)]
else:
d2Vis_modified = zeros((N, N, N))
self._d2Vis_modified_dxixjs = unifac_d2Vis_dxixjs(rs_34, r34x_sum_inv, N, d2Vis_modified)
return d2Vis_modified
[docs] def d3Vis_modified_dxixjxks(self):
r'''Calculate the third mole fraction derivative of the :math:`V_i'`
terms used in calculating the combinatorial part. A function of mole
fractions and the parameters `r` only.
.. math::
\frac{\partial V_i'}{\partial x_j \partial x_k \partial x_m} =
-6 r_i^n r_j^n r_k^n r_m^n V_{sum}^4
.. math::
V_{sum} = \frac{1}{\sum_j r_j x_j}
This is used in the UNIFAC Dortmund and UNIFAC-NIST model with
n=0.75, and the Lyngby model with n=2/3.
Returns
-------
d3Vis_modified_dxixjxks : list[list[list[list[float]]]]
`V'` terms size number of components by number of components by
number of components by number of components, [-]
'''
try:
return self._d3Vis_modified_dxixjxks
except AttributeError:
pass
try:
r34x_sum_inv = self.r34x_sum_inv
except AttributeError:
self.Vis_modified()
r34x_sum_inv = self.r34x_sum_inv
rs_34, N = self.rs_34, self.N
if self.scalar:
d3Vis_modified = [[[[0.0]*N for _ in range(N)] for _ in range(N)] for _ in range(N)]
else:
d3Vis_modified = zeros((N, N, N, N))
self._d3Vis_modified_dxixjxks = unifac_d3Vis_dxixjxks(rs_34, r34x_sum_inv, N, d3Vis_modified)
return d3Vis_modified
[docs] def Xs(self):
r'''Calculate the :math:`X_m` parameters
used in calculating the residual part. A function of mole
fractions and group counts only.
.. math::
X_m = \frac{ \sum_j \nu^j_m x_j}{\sum_j \sum_n \nu_n^j x_j}
Returns
-------
Xs : list[float]
:math:`X_m` terms, size number of subgroups, [-]
'''
try:
return self._Xs
except AttributeError:
pass
# [subgroup][component] = number of subgroup in component where subgroup
# is an index, numbered sequentially by the number of subgroups in the mixture
vs, xs = self.vs, self.xs
N, N_groups = self.N, self.N_groups
if self.scalar:
Xs = [0.0]*N_groups
else:
Xs = zeros(N_groups)
self._Xs, self.Xs_sum_inv = unifac_Xs(N, N_groups, xs, vs, Xs)
return Xs
def _Xs_sum_inv(self):
try:
return self.Xs_sum_inv
except AttributeError:
self.Xs()
return self.Xs_sum_inv
[docs] def Thetas(self):
r'''Calculate the :math:`\Theta_m` parameters
used in calculating the residual part. A function of mole
fractions and group counts only.
.. math::
\Theta_m = \frac{Q_m X_m}{\sum_{n} Q_n X_n}
Returns
-------
Thetas : list[float]
:math:`\Theta_m` terms, size number of subgroups, [-]
'''
try:
return self._Thetas
except AttributeError:
pass
Qs, N_groups = self.Qs, self.N_groups
try:
Xs = self._Xs
except AttributeError:
Xs = self.Xs()
if self.scalar:
Thetas = [0.0]*N_groups
else:
Thetas = zeros(N_groups)
self._Thetas, self.Thetas_sum_inv = unifac_Thetas(N_groups, Xs, Qs, Thetas)
return Thetas
def _Thetas_sum_inv(self):
try:
return self.Thetas_sum_inv
except AttributeError:
self.Thetas()
return self.Thetas_sum_inv
[docs] def dThetas_dxs(self):
r'''Calculate the mole fraction derivatives of the :math:`\Theta_m`
parameters. A function of mole fractions and group counts only.
.. math::
\frac{\partial \Theta_i}{\partial x_j} =
FGQ_i\left[FG (\nu x)_{sum,i}
\left(\sum_k^{gr} FQ_k (\nu)_{sum,j} (\nu x)_{sum,k}
-\sum_k^{gr} Q_k \nu_{k,j}
\right)
- F (\nu)_{sum,j}(\nu x)_{sum,i} + \nu_{ij}
\right]
.. math::
G = \frac{1}{\sum_j Q_j X_j}
.. math::
F = \frac{1}{\sum_j \sum_n \nu_n^j x_j}
.. math::
(\nu)_{sum,i} = \sum_j \nu_{j,i}
.. math::
(\nu x)_{sum,i} = \sum_j \nu_{i,j}x_j
Returns
-------
dThetas_dxs : list[list[float]]
Mole fraction derivatives of :math:`\Theta_m` terms, size number of
subgroups by mole fractions and indexed in that order, [-]
'''
try:
return self._dThetas_dxs
except AttributeError:
pass
try:
F = self.Xs_sum_inv
except AttributeError:
F = self._Xs_sum_inv()
try:
G = self.Thetas_sum_inv
except AttributeError:
G = self._Thetas_sum_inv()
Qs, N, N_groups = self.Qs, self.N, self.N_groups
# Xs_sum_inv and Thetas_sum_inv have already calculated _Xs, _Thetas
vs = self.vs
VS = self.cmp_v_count
if self.scalar:
dThetas_dxs = [[0.0]*N for _ in range(N_groups)]
else:
dThetas_dxs = zeros((N_groups, N))
try:
VSXS = self.VSXS
except AttributeError:
VSXS = self._VSXS()
# # Index [subgroup][component]
self._dThetas_dxs = unifac_dThetas_dxs(N_groups, N, Qs, vs, VS, VSXS, F, G, dThetas_dxs)
return dThetas_dxs
[docs] def d2Thetas_dxixjs(self):
r'''Calculate the mole fraction derivatives of the :math:`\Theta_m`
parameters. A function of mole fractions and group counts only.
.. math::
\frac{\partial^2 \Theta_i}{\partial x_j \partial x_k} =
\frac{Q_i}{\sum_n Q_n (\nu x)_{sum,n}}\left[
-F(\nu)_{sum,j} \nu_{i,k} - F (\nu)_{sum,k}\nu_{i,j}
+ 2F^2(\nu)_{sum,j} (\nu)_{sum,k} (\nu x)_{sum,i}
+ \frac{F (\nu x)_{sum,i}\left[
\sum_n(-2 F Q_n (\nu)_{sum,j} (\nu)_{sum,k}
(\nu x)_{sum,n} + Q_n (\nu)_{sum,j} \nu_{n,k} + Q_n (\nu)_{sum,k}\nu_{n,j}
)\right] }
{\sum_n^{gr} Q_n (\nu x)_{sum,n} }
+ \frac{2(\nu x)_{sum,i}(\sum_n^{gr}[-FQ_n (\nu)_{sum,j} (\nu x)_{sum,n} + Q_n \nu_{n,j}])
(\sum_n^{gr}[-FQ_n (\nu)_{sum,k} (\nu x)_{sum,n} + Q_n \nu_{n,k}]) }
{\left( \sum_n^{gr} Q_n (\nu x)_{sum,n} \right)^2}
- \frac{\nu_{i,j}(\sum_n^{gr} -FQ_n (\nu)_{sum,k} (\nu x)_{sum,n} + Q_n \nu_{n,k} )}
{\left( \sum_n^{gr} Q_n (\nu x)_{sum,n} \right)}
- \frac{\nu_{i,k}(\sum_n^{gr} -FQ_n (\nu)_{sum,j} (\nu x)_{sum,n} + Q_n \nu_{n,j} )}
{\left( \sum_n^{gr} Q_n (\nu x)_{sum,n} \right)}
+ \frac{F(\nu)_{sum,j} (\nu x)_{sum,i} (\sum_n^{gr} -FQ_n (\nu)_{sum,k}
(\nu x)_{sum,n} + Q_n \nu_{n,k})}
{\left(\sum_n^{gr} Q_n (\nu x)_{sum,n} \right)}
+ \frac{F(\nu)_{sum,k} (\nu x)_{sum,i} (\sum_n^{gr} -FQ_n (\nu)_{sum,j}
(\nu x)_{sum,n} + Q_n \nu_{n,j})}
{\left(\sum_n^{gr} Q_n (\nu x)_{sum,n} \right)}
\right]
.. math::
G = \frac{1}{\sum_j Q_j X_j}
.. math::
F = \frac{1}{\sum_j \sum_n \nu_n^j x_j}
.. math::
(\nu)_{sum,i} = \sum_j \nu_{j,i}
.. math::
(\nu x)_{sum,i} = \sum_j \nu_{i,j}x_j
Returns
-------
d2Thetas_dxixjs : list[list[list[float]]]
:math:`\Theta_m` terms, size number of subgroups by mole fractions
and indexed in that order, [-]
'''
try:
return self._d2Thetas_dxixjs
except AttributeError:
pass
try:
F = self.Xs_sum_inv
except AttributeError:
F = self._Xs_sum_inv()
try:
G = self.Thetas_sum_inv
except AttributeError:
G = self._Thetas_sum_inv()
Qs, N, N_groups = self.Qs, self.N, self.N_groups
vs = self.vs
VS = self.cmp_v_count
try:
VSXS = self.VSXS
except AttributeError:
VSXS = self._VSXS()
if self.scalar:
d2Thetas_dxixjs = [[[0.0]*N_groups for _ in range(N)] for _ in range(N)]
else:
d2Thetas_dxixjs = zeros((N, N, N_groups))
self._d2Thetas_dxixjs = unifac_d2Thetas_dxixjs(N_groups, N, Qs, vs, VS, VSXS, F, G, d2Thetas_dxixjs)
return d2Thetas_dxixjs
def _VSXS(self):
try:
return self.VSXS
except AttributeError:
pass
N_groups = self.N_groups
if self.scalar:
VSXS = [0.0]*N_groups
else:
VSXS = zeros(N_groups)
self.VSXS = unifac_VSXS(self.N, N_groups, self.vs, self.xs, VSXS)
return VSXS
def _Theta_Psi_sums(self):
r'''
Computes the following term for each group `k`, size number of groups.
.. math::
\sum_m \Theta_m \Psi_{mk}
'''
try:
return self.Theta_Psi_sums
except AttributeError:
pass
try:
Thetas = self._Thetas
except AttributeError:
Thetas = self.Thetas()
try:
psis = self._psis
except AttributeError:
psis = self.psis()
N_groups = self.N_groups
if self.scalar:
Theta_Psi_sums = [0.0]*N_groups
else:
Theta_Psi_sums = zeros(N_groups)
self.Theta_Psi_sums = unifac_Theta_Psi_sums(N_groups, Thetas, psis, Theta_Psi_sums)
return Theta_Psi_sums
def _Theta_Psi_sum_invs(self):
r'''
Computes the following term for each group `k`, size number of groups.
.. math::
U(k) = \frac{1}{\sum_m \Theta_m \Psi_{m,k}}
'''
try:
return self.Theta_Psi_sum_invs
except AttributeError:
try:
Theta_Psi_sums = self.Theta_Psi_sums
except AttributeError:
Theta_Psi_sums = self._Theta_Psi_sums()
if self.scalar:
self.Theta_Psi_sum_invs = [1.0/v for v in Theta_Psi_sums]
else:
self.Theta_Psi_sum_invs = 1.0/Theta_Psi_sums
return self.Theta_Psi_sum_invs
def _Ws(self):
r'''
Computes the following for each `k` and each `i`, indexed by [k][i]
`k` is in groups, and `i` is in components.
.. math::
W(k,i) = \sum_m^{gr} \psi_{m,k} \frac{\partial \theta_m}{\partial x_i}
'''
try:
return self.Ws
except AttributeError:
pass
try:
psis = self._psis
except AttributeError:
psis = self.psis()
try:
dThetas_dxs = self._dThetas_dxs
except AttributeError:
dThetas_dxs = self.dThetas_dxs()
N, N_groups = self.N, self.N_groups
if self.scalar:
Ws = [[0.0]*N for _ in range(N_groups)]
else:
Ws = zeros((N_groups, N))
self.Ws = unifac_ws(N, N_groups, psis, dThetas_dxs, Ws)
return Ws
def _Fs(self):
r'''Computes the following:
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
'''
try:
return self.Fs
except AttributeError:
pass
try:
Thetas = self._Thetas
except AttributeError:
Thetas = self.Thetas()
try:
dpsis_dT = self._dpsis_dT
except AttributeError:
dpsis_dT = self.dpsis_dT()
N_groups = self.N_groups
if self.scalar:
Fs = [0.0]*N_groups
else:
Fs = zeros(N_groups)
self.Fs = unifac_Theta_Psi_sums(N_groups, Thetas, dpsis_dT, Fs)
return Fs
def _Gs(self):
r'''Computes the following:
.. math::
G(k) = \sum_m^{gr} \theta_m \frac{\partial^2 \psi_{m,k}}{\partial T^2}
'''
try:
return self.Gs
except AttributeError:
pass
try:
Thetas = self._Thetas
except AttributeError:
Thetas = self.Thetas()
try:
d2psis_dT2 = self._d2psis_dT2
except AttributeError:
d2psis_dT2 = self.d2psis_dT2()
N_groups = self.N_groups
if self.scalar:
Gs = [0.0]*N_groups
else:
Gs = zeros(N_groups)
self.Gs = unifac_Theta_Psi_sums(N_groups, Thetas, d2psis_dT2, Gs)
# self.Gs = Gs = []
# for k in range(N_groups):
# tot = 0.0
# for m in range(N_groups):
# tot += Thetas[m]*d2psis_dT2[m][k]
# Gs.append(tot)
return Gs
def _Hs(self):
r'''Computes the following:
.. math::
H(k) = \sum_m^{gr} \theta_m \frac{\partial^3 \psi_{m,k}}{\partial T^3}
'''
try:
return self.Hs
except AttributeError:
pass
try:
Thetas = self._Thetas
except AttributeError:
Thetas = self.Thetas()
try:
d3psis_dT3 = self._d3psis_dT3
except AttributeError:
d3psis_dT3 = self.d3psis_dT3()
N_groups = self.N_groups
if self.scalar:
Hs = [0.0]*N_groups
else:
Hs = zeros(N_groups)
self.Hs = unifac_Theta_Psi_sums(N_groups, Thetas, d3psis_dT3, Hs)
return Hs
def _Theta_pure_Psi_sums(self):
try:
return self.Theta_pure_Psi_sums
except AttributeError:
pass
Thetas_pure = self._Thetas_pure
try:
psis = self._psis
except AttributeError:
psis = self.psis()
N_groups, N = self.N_groups, self.N
if self.scalar:
Theta_pure_Psi_sums = [[0.0]*N_groups for _ in range(N)]
else:
Theta_pure_Psi_sums = zeros((N, N_groups))
self.Theta_pure_Psi_sums = unifac_Theta_pure_Psi_sums(N, N_groups, psis, Thetas_pure, Theta_pure_Psi_sums)
return Theta_pure_Psi_sums
def _Theta_pure_Psi_sum_invs(self):
r'''
Computes the following term for each group `k`, size number of groups.
.. math::
U(k) = \frac{1}{\sum_m \Theta_m \Psi_{m,k}}
'''
try:
return self.Theta_pure_Psi_sum_invs
except AttributeError:
try:
Theta_pure_Psi_sums = self.Theta_pure_Psi_sums
except AttributeError:
Theta_pure_Psi_sums = self._Theta_pure_Psi_sums()
if self.scalar:
self.Theta_pure_Psi_sum_invs = [[1.0/v for v in row] for row in Theta_pure_Psi_sums]
else:
self.Theta_pure_Psi_sum_invs = 1.0/Theta_pure_Psi_sums
return self.Theta_pure_Psi_sum_invs
def _Fs_pure(self):
r'''Computes the following:
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
'''
try:
return self.Fs_pure
except AttributeError:
pass
Thetas_pure = self._Thetas_pure
try:
dpsis_dT = self._dpsis_dT
except AttributeError:
dpsis_dT = self.dpsis_dT()
N_groups, N = self.N_groups, self.N
if self.scalar:
Fs_pure = [[0.0]*N_groups for _ in range(N)]
else:
Fs_pure = zeros((N, N_groups))
self.Fs_pure = unifac_Theta_pure_Psi_sums(N, N_groups, dpsis_dT, Thetas_pure, Fs_pure)
return Fs_pure
def _Gs_pure(self):
r'''Computes the following:
.. math::
G(k) = \sum_m^{gr} \theta_m \frac{\partial^2 \psi_{m,k}}{\partial T^2}
'''
try:
return self.Gs_pure
except AttributeError:
pass
Thetas_pure = self._Thetas_pure
try:
d2psis_dT2 = self._d2psis_dT2
except AttributeError:
d2psis_dT2 = self.d2psis_dT2()
N_groups, N = self.N_groups, self.N
if self.scalar:
Gs_pure = [[0.0]*N_groups for _ in range(N)]
else:
Gs_pure = zeros((N, N_groups))
self.Gs_pure = unifac_Theta_pure_Psi_sums(N, N_groups, d2psis_dT2, Thetas_pure, Gs_pure)
return Gs_pure
def _Hs_pure(self):
r'''Computes the following:
.. math::
H(k) = \sum_m^{gr} \theta_m \frac{\partial^3 \psi_{m,k}}{\partial T^3}
'''
try:
return self.Hs_pure
except AttributeError:
pass
Thetas_pure = self._Thetas_pure
try:
d3psis_dT3 = self._d3psis_dT3
except AttributeError:
d3psis_dT3 = self.d3psis_dT3()
N_groups, N = self.N_groups, self.N
if self.scalar:
Hs_pure = [[0.0]*N_groups for _ in range(N)]
else:
Hs_pure = zeros((N, N_groups))
self.Hs_pure = unifac_Theta_pure_Psi_sums(N, N_groups, d3psis_dT3, Thetas_pure, Hs_pure)
return Hs_pure
[docs] def lnGammas_subgroups(self):
r'''Calculate the :math:`\ln \Gamma_k` parameters for the phase;
depends on the phases's composition and temperature.
.. math::
\ln \Gamma_k = Q_k \left[1 - \ln \sum_m \Theta_m \Psi_{mk} - \sum_m
\frac{\Theta_m \Psi_{km}}{\sum_n \Theta_n \Psi_{nm}}\right]
Returns
-------
lnGammas_subgroups : list[float]
Gamma parameters for each subgroup, size number of subgroups, [-]
'''
try:
return self._lnGammas_subgroups
except AttributeError:
pass
try:
Thetas = self._Thetas
except AttributeError:
Thetas = self.Thetas()
try:
psis = self._psis
except AttributeError:
psis = self.psis()
try:
Theta_Psi_sums = self.Theta_Psi_sums
except AttributeError:
Theta_Psi_sums = self._Theta_Psi_sums()
try:
Theta_Psi_sum_invs = self.Theta_Psi_sum_invs
except AttributeError:
Theta_Psi_sum_invs = self._Theta_Psi_sum_invs()
N, N_groups, Qs = self.N, self.N_groups, self.Qs
if self.scalar:
lnGammas_subgroups = [0.0]*N_groups
else:
lnGammas_subgroups = zeros(N_groups)
self._lnGammas_subgroups = unifac_lnGammas_subgroups(N_groups, Qs, psis, Thetas, Theta_Psi_sums, Theta_Psi_sum_invs, lnGammas_subgroups)
return lnGammas_subgroups
[docs] def dlnGammas_subgroups_dxs(self):
r'''Calculate the mole fraction derivatives of the :math:`\ln \Gamma_k`
parameters for the phase; depends on the phases's composition and
temperature.
.. math::
\frac{\partial \ln \Gamma_k}{\partial x_i} = Q_k\left(
-\frac{\sum_m^{gr} \psi_{m,k} \frac{\partial \theta_m}{\partial x_i}}{\sum_m^{gr} \theta_m \psi_{m,k}}
- \sum_m^{gr} \frac{\psi_{k,m} \frac{\partial \theta_m}{\partial x_i}}{\sum_n^{gr} \theta_n \psi_{n,m}}
+ \sum_m^{gr} \frac{(\sum_n^{gr} \psi_{n,m}\frac{\partial \theta_n}{\partial x_i})\theta_m \psi_{k,m}}{(\sum_n^{gr} \theta_n \psi_{n,m})^2}
\right)
The group W is used internally as follows to simplfy the number of
evaluations.
.. math::
W(k,i) = \sum_m^{gr} \psi_{m,k} \frac{\partial \theta_m}{\partial x_i}
Returns
-------
dlnGammas_subgroups_dxs : list[list[float]]
Mole fraction derivatives of Gamma parameters for each subgroup,
size number of subgroups by number of components and indexed in
that order, [-]
'''
try:
return self._dlnGammas_subgroups_dxs
except AttributeError:
pass
try:
Thetas = self._Thetas
except AttributeError:
Thetas = self.Thetas()
try:
psis = self._psis
except AttributeError:
psis = self.psis()
try:
Theta_Psi_sum_invs = self.Theta_Psi_sum_invs
except AttributeError:
Theta_Psi_sum_invs = self._Theta_Psi_sum_invs()
try:
dThetas_dxs = self._dThetas_dxs
except AttributeError:
dThetas_dxs = self.dThetas_dxs()
try:
Ws = self.Ws
except AttributeError:
Ws = self._Ws()
N, N_groups, Qs = self.N, self.N_groups, self.Qs
if self.scalar:
dlnGammas_subgroups_dxs = [[0.0]*N for _ in range(N_groups)]
else:
dlnGammas_subgroups_dxs = zeros((N_groups, N))
self._dlnGammas_subgroups_dxs = unifac_dlnGammas_subgroups_dxs(N, N_groups, Qs, Ws, psis, Thetas, Theta_Psi_sum_invs,
dThetas_dxs, dlnGammas_subgroups_dxs)
return dlnGammas_subgroups_dxs
[docs] def d2lnGammas_subgroups_dTdxs(self):
r'''Calculate the temperature and mole fraction derivatives of the
:math:`\ln \Gamma_k` parameters for the phase; depends on the phases's
composition and temperature.
.. math::
\frac{\partial^2 \ln \Gamma_k}{\partial x_i \partial T} = -Q_k\left(
D(k,i) Z(k) - B(k)W(k,i) Z(k)^2
+ \sum_m^{gr} (Z(m) \frac{\partial \theta_m}{\partial x_i}\frac{\partial \psi_{k,m}}{\partial T})
-\sum_m^{gr} (B(m) Z(m)^2 \psi_{k,m} \frac{\partial \theta_m}{\partial x_i})
-\sum_m^{gr}(D(m,i) Z(m)^2 \theta_m \psi_{k,m})
- \sum_m^{gr} (W(m,i) Z(m)^2 \theta_m \frac{\partial \psi_{k,m}}{\partial T})
+ \sum_m^{gr} 2 B(m) W(m,i) Z(m)^3 \theta_m \psi_{k,m}
\right)
The following groups are used as follows to simplfy the number of
evaluations:
.. math::
W(k,i) = \sum_m^{gr} \psi_{m,k} \frac{\partial \theta_m}{\partial x_i}
.. math::
Z(k) = \frac{1}{\sum_m \Theta_m \Psi_{mk}}
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
In the below expression, k` refers to a group, and `i` refers to a
component.
.. math::
D(k,i) = \sum_m^{gr} \frac{\partial \theta_m}{\partial x_i}
\frac{\partial \psi_{m,k}}{\partial T}
Returns
-------
d2lnGammas_subgroups_dTdxs : list[list[float]]
Temperature and mole fraction derivatives of Gamma parameters for
each subgroup, size number of subgroups by number of components and
indexed in that order, [1/K]
'''
try:
return self._d2lnGammas_subgroups_dTdxs
except:
pass
try:
Thetas = self._Thetas
except AttributeError:
Thetas = self.Thetas()
try:
psis = self._psis
except AttributeError:
psis = self.psis()
try:
dpsis_dT = self._dpsis_dT
except AttributeError:
dpsis_dT = self.dpsis_dT()
try:
dThetas_dxs = self._dThetas_dxs
except AttributeError:
dThetas_dxs = self.dThetas_dxs()
try:
Zs = self.Theta_Psi_sum_invs
except AttributeError:
Zs = self._Theta_Psi_sum_invs()
try:
Ws = self.Ws
except AttributeError:
Ws = self._Ws()
N, N_groups, Qs = self.N, self.N_groups, self.Qs
try:
Fs = self.Fs
except AttributeError:
Fs = self._Fs()
if self.scalar:
d2lnGammas_subgroups_dTdxs = [[0.0]*N for _ in range(N_groups)]
else:
d2lnGammas_subgroups_dTdxs = zeros((N_groups, N))
self._d2lnGammas_subgroups_dTdxs = unifac_d2lnGammas_subgroups_dTdxs(N, N_groups, Qs, Fs, Zs,
Ws, psis, dpsis_dT, Thetas, dThetas_dxs,
d2lnGammas_subgroups_dTdxs=d2lnGammas_subgroups_dTdxs)
return d2lnGammas_subgroups_dTdxs
[docs] def d2lnGammas_subgroups_dxixjs(self):
r'''Calculate the second mole fraction derivatives of the
:math:`\ln \Gamma_k` parameters for the phase; depends on the phases's
composition and temperature.
.. math::
\frac{\partial^2 \ln \Gamma_k}{\partial x_i \partial x_j} = -Q_k\left(
-Z(k) K(k,i,j) - \sum_m^{gr} Z(m)^2 K(m,i,j)\theta_m \psi_{k,m}
-W(k,i) W(k,j) Z(k)^2
+ \sum_m^{gr} Z_m \psi_{k,m} \frac{\partial^2 \theta_m}{\partial x_i \partial x_j}
- \sum_m \left(W(m,j) Z(m)^2 \psi_{k,m} \frac{\partial \theta_m}{\partial x_i}
+ W(m,i) Z(m)^2 \psi(k,m) \frac{\partial \theta_m}{\partial x_j}\right)
+ \sum_m^{gr} 2 W(m,i) W(m,j) Z(m)^3 \theta_m \psi_{k,m}\right)
The following groups are used as follows to simplfy the number of
evaluations:
.. math::
W(k,i) = \sum_m^{gr} \psi_{m,k} \frac{\partial \theta_m}{\partial x_i}
.. math::
Z(k) = \frac{1}{\sum_m \Theta_m \Psi_{mk}}
.. math::
K(k, i, j) = \sum_m^{gr} \psi_{m,k} \frac{\partial^2 \theta_m}{\partial x_i \partial x_j}
Returns
-------
d2lnGammas_subgroups_dxixjs : list[list[list[float]]]
Second mole fraction derivatives of Gamma parameters for each
subgroup, size number of components by number of components by
number of subgroups and indexed in that order, [-]
'''
try:
return self._d2lnGammas_subgroups_dxixjs
except:
pass
try:
Thetas = self._Thetas
except AttributeError:
Thetas = self.Thetas()
try:
psis = self._psis
except AttributeError:
psis = self.psis()
try:
dThetas_dxs = self._dThetas_dxs
except AttributeError:
dThetas_dxs = self.dThetas_dxs()
try:
d2Thetas_dxixjs = self._d2Thetas_dxixjs
except AttributeError:
d2Thetas_dxixjs = self.d2Thetas_dxixjs()
try:
Zs = self.Theta_Psi_sum_invs
except AttributeError:
Zs = self._Theta_Psi_sum_invs()
try:
Ws = self.Ws
except AttributeError:
Ws = self._Ws()
N, N_groups, Qs = self.N, self.N_groups, self.Qs
if self.scalar:
d2lnGammas_subgroups_dxixjs = [[[0.0]*N_groups for _ in range(N)] for _ in range(N)]
else:
d2lnGammas_subgroups_dxixjs = zeros((N, N, N_groups))
self._d2lnGammas_subgroups_dxixjs = unifac_d2lnGammas_subgroups_dxixjs(N, N_groups, Qs, Zs, Ws, psis, Thetas, dThetas_dxs, d2Thetas_dxixjs, d2lnGammas_subgroups_dxixjs)
return d2lnGammas_subgroups_dxixjs
[docs] def dlnGammas_subgroups_dT(self):
r'''Calculate the first temperature derivative of the
:math:`\ln \Gamma_k` parameters for the phase; depends on the phases's
composition and temperature.
.. math::
\frac{\partial \ln \Gamma_i}{\partial T} = Q_i\left(
\sum_j^{gr} Z(j) \left[{\theta_j \frac{\partial \psi_{i,j}}{\partial T}}
+ {\theta_j \psi_{i,j} F(j)}Z(j) \right]- F(i) Z(i)
\right)
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
.. math::
Z(k) = \frac{1}{\sum_m \Theta_m \Psi_{m,k}}
Returns
-------
dlnGammas_subgroups_dT : list[float]
First temperature derivative of ln Gamma parameters for each
subgroup, size number of subgroups, [1/K]
'''
try:
return self._dlnGammas_subgroups_dT
except:
pass
try:
Thetas = self._Thetas
except AttributeError:
Thetas = self.Thetas()
try:
psis = self._psis
except AttributeError:
psis = self.psis()
try:
dpsis_dT = self._dpsis_dT
except AttributeError:
dpsis_dT = self.dpsis_dT()
try:
Zs = self.Theta_Psi_sum_invs
except AttributeError:
Zs = self._Theta_Psi_sum_invs()
try:
Fs = self.Fs
except AttributeError:
Fs = self._Fs()
N, N_groups, Qs = self.N, self.N_groups, self.Qs
if self.scalar:
dlnGammas_subgroups_dT = [0.0]*N_groups
else:
dlnGammas_subgroups_dT = zeros(N_groups)
self._dlnGammas_subgroups_dT = unifac_dlnGammas_subgroups_dT(N_groups, Qs, psis, dpsis_dT, Thetas, Zs, Fs, dlnGammas_subgroups_dT)
return dlnGammas_subgroups_dT
[docs] def d2lnGammas_subgroups_dT2(self):
r'''Calculate the second temperature derivative of the
:math:`\ln \Gamma_k` parameters for the phase; depends on the phases's
composition and temperature.
.. math::
\frac{\partial^2 \ln \Gamma_i}{\partial T^2} = -Q_i\left[
Z(i)G(i) - F(i)^2 Z(i)^2 + \sum_j\left(
\theta_j Z(j)\frac{\partial^2 \psi_{i,j}}{\partial T}
- Z(j)^2 \left(G(j)\theta_j \psi_{i,j} + 2 F_j \theta_j \frac{\partial \psi_{i,j}}{\partial T}\right)
+ 2Z(j)^3F(j)^2 \theta_j \psi_{i,j}
\right)\right]
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
.. math::
G(k) = \sum_m^{gr} \theta_m \frac{\partial^2 \psi_{m,k}}{\partial T^2}
.. math::
Z(k) = \frac{1}{\sum_m \Theta_m \Psi_{m,k}}
Returns
-------
d2lnGammas_subgroups_dT2 : list[float]
Second temperature derivative of ln Gamma parameters for each
subgroup, size number of subgroups, [1/K^2]
'''
try:
return self._d2lnGammas_subgroups_dT2
except:
pass
try:
Thetas = self._Thetas
except AttributeError:
Thetas = self.Thetas()
try:
psis = self._psis
except AttributeError:
psis = self.psis()
try:
dpsis_dT = self._dpsis_dT
except AttributeError:
dpsis_dT = self.dpsis_dT()
try:
d2psis_dT2 = self._d2psis_dT2
except AttributeError:
d2psis_dT2 = self.d2psis_dT2()
try:
Zs = self.Theta_Psi_sum_invs
except AttributeError:
Zs = self._Theta_Psi_sum_invs()
try:
Fs = self.Fs
except AttributeError:
Fs = self._Fs()
try:
Gs = self.Gs
except AttributeError:
Gs = self._Gs()
N, N_groups, Qs = self.N, self.N_groups, self.Qs
if self.scalar:
d2lnGammas_subgroups_dT2 = [0.0]*N_groups
else:
d2lnGammas_subgroups_dT2 = zeros(N_groups)
self._d2lnGammas_subgroups_dT2 = row = unifac_d2lnGammas_subgroups_dT2(
N_groups, Qs, psis, dpsis_dT, d2psis_dT2, Thetas, Zs, Fs, Gs, d2lnGammas_subgroups_dT2)
return row
[docs] def d3lnGammas_subgroups_dT3(self):
r'''Calculate the third temperature derivative of the
:math:`\ln \Gamma_k` parameters for the phase; depends on the phases's
composition and temperature.
.. math::
\frac{\partial^3 \ln \Gamma_i}{\partial T^3} =Q_i\left[-H(i) Z(i)
- 2F(i)^3 Z(i)^3 + 3F(i) G(i) Z(i)^2+ \left(
-\theta_j Z(j) \frac{\partial^3 \psi}{\partial T^3}
+ H(j) Z(j)^2 \theta(j)\psi_{i,j}
- 6F(j)^2 Z(j)^3 \theta_j \frac{\partial \psi_{i,j}}{\partial T}
+ 3 F(j) Z(j)^2 \theta(j) \frac{\partial^2 \psi_{i,j}}{\partial T^2}
++ 3G(j) \theta(j) Z(j)^2 \frac{\partial \psi_{i,j}}{\partial T}
+ 6F(j)^3 \theta(j) Z(j)^4 \psi_{i,j}
- 6F(j) G(j) \theta(j) Z(j)^3 \psi_{i,j}
\right)
\right]
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
.. math::
G(k) = \sum_m^{gr} \theta_m \frac{\partial^2 \psi_{m,k}}{\partial T^2}
.. math::
H(k) = \sum_m^{gr} \theta_m \frac{\partial^3 \psi_{m,k}}{\partial T^3}
.. math::
Z(k) = \frac{1}{\sum_m \Theta_m \Psi_{m,k}}
Returns
-------
d3lnGammas_subgroups_dT3 : list[float]
Third temperature derivative of ln Gamma parameters for each
subgroup, size number of subgroups, [1/K^3]
'''
try:
return self._d3lnGammas_subgroups_dT3
except:
pass
try:
Thetas = self._Thetas
except AttributeError:
Thetas = self.Thetas()
try:
psis = self._psis
except AttributeError:
psis = self.psis()
try:
dpsis_dT = self._dpsis_dT
except AttributeError:
dpsis_dT = self.dpsis_dT()
try:
d2psis_dT2 = self._d2psis_dT2
except AttributeError:
d2psis_dT2 = self.d2psis_dT2()
try:
d3psis_dT3 = self._d3psis_dT3
except AttributeError:
d3psis_dT3 = self.d3psis_dT3()
try:
Zs = self.Theta_Psi_sum_invs
except AttributeError:
Zs = self._Theta_Psi_sum_invs()
try:
Fs = self.Fs
except AttributeError:
Fs = self._Fs()
try:
Gs = self.Gs
except AttributeError:
Gs = self._Gs()
try:
Hs = self.Hs
except AttributeError:
Hs = self._Hs()
N, N_groups, Qs = self.N, self.N_groups, self.Qs
if self.scalar:
d3lnGammas_subgroups_dT3 = [0.0]*N_groups
else:
d3lnGammas_subgroups_dT3 = zeros(N_groups)
self._d3lnGammas_subgroups_dT3 = unifac_d3lnGammas_subgroups_dT3(N_groups, Qs, psis, dpsis_dT, d2psis_dT2, d3psis_dT3,
Thetas, Zs, Fs, Gs, Hs, d3lnGammas_subgroups_dT3)
return d3lnGammas_subgroups_dT3
[docs] def Xs_pure(self):
r'''Calculate the :math:`X_m` parameters for each chemical in the
mixture as a pure species, used in calculating the residual part. A
function of group counts only, not even mole fractions or temperature.
.. math::
X_m = \frac{\nu_m}{\sum^{gr}_n \nu_n}
Returns
-------
Xs_pure : list[list[float]]
:math:`X_m` terms, size number of subgroups by number of components
and indexed in that order, [-]
'''
try:
return self._Xs_pure
except AttributeError:
pass
# Independent of mole fractions and temperature
vs, cmp_v_count_inv = self.vs, self.cmp_v_count_inv
N, N_groups = self.N, self.N_groups
if self.scalar:
Xs_pure = [[0.0]*N for _ in range(N_groups)]
else:
Xs_pure = zeros((N_groups, N))
self._Xs_pure = unifac_Xs_pure(N, N_groups, vs, cmp_v_count_inv, Xs_pure)
return Xs_pure
[docs] def Thetas_pure(self):
r'''Calculate the :math:`\Theta_m` parameters for each chemical in the
mixture as a pure species, used in calculating the residual part.
A function of group counts only.
.. math::
\Theta_m = \frac{Q_m X_m}{\sum_{n} Q_n X_n}
Returns
-------
Thetas_pure : list[list[float]]
:math:`\Theta_m` terms, size number of components by number of
subgroups and indexed in that order, [-]
'''
# Composition and temperature independent
try:
return self._Thetas_pure
except AttributeError:
pass
Xs_pure, Qs = self.Xs_pure(), self.Qs
N, N_groups = self.N, self.N_groups
if self.scalar:
Thetas_pure = [[0.0]*N_groups for _ in range(N)]
else:
Thetas_pure = zeros((N, N_groups))
# Revised! Keep in order [component][subgroup]
self._Thetas_pure = unifac_Thetas_pure(N, N_groups, Xs_pure, Qs, Thetas_pure)
return Thetas_pure
[docs] def lnGammas_subgroups_pure(self):
r'''Calculate the :math:`\ln \Gamma_k` pure component parameters for
the phase; depends on the phases's temperature only.
.. math::
\ln \Gamma_k = Q_k \left[1 - \ln \sum_m \Theta_m \Psi_{mk} - \sum_m
\frac{\Theta_m \Psi_{km}}{\sum_n \Theta_n \Psi_{nm}}\right]
In this model, the :math:`\Theta` values come from the
:obj:`UNIFAC.Thetas_pure` method, where each compound is assumed to be
pure.
Returns
-------
lnGammas_subgroups_pure : list[list[float]]
Gamma parameters for each subgroup, size number of subgroups by
number of components and indexed in that order, [-]
'''
try:
return self._lnGammas_subgroups_pure
except AttributeError:
pass
try:
psis = self._psis
except AttributeError:
psis = self.psis()
N, N_groups, Qs = self.N, self.N_groups, self.Qs
Thetas_pure, cmp_group_idx = self._Thetas_pure, self.cmp_group_idx
if self.scalar:
lnGammas_subgroups_pure = [[0.0]*N for _ in range(N_groups)]
else:
lnGammas_subgroups_pure = zeros((N_groups, N))
# Future note: lnGammas_subgroups_pure will not zero all arrays
self._lnGammas_subgroups_pure = unifac_lnGammas_subgroups_pure(N, N_groups, Qs, Thetas_pure, cmp_group_idx, self.group_cmp_idx, psis, lnGammas_subgroups_pure)
return lnGammas_subgroups_pure
[docs] def dlnGammas_subgroups_pure_dT(self):
r'''Calculate the first temperature derivative of :math:`\ln \Gamma_k`
pure component parameters for the phase; depends on the phases's
temperature only.
.. math::
\frac{\partial \ln \Gamma_i}{\partial T} = Q_i\left(
\sum_j^{gr} Z(j) \left[{\theta_j \frac{\partial \psi_{i,j}}{\partial T}}
+ {\theta_j \psi_{i,j} F(j)}Z(j) \right]- F(i) Z(i)
\right)
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
.. math::
Z(k) = \frac{1}{\sum_m \Theta_m \Psi_{m,k}}
In this model, the :math:`\Theta` values come from the
:obj:`UNIFAC.Thetas_pure` method, where each compound is assumed to be
pure.
Returns
-------
dlnGammas_subgroups_pure_dT : list[list[float]]
First temperature derivative of ln Gamma parameters for each
subgroup, size number of subgroups by number of components and
indexed in that order, [1/K]
'''
# Temperature dependent only!
try:
return self._dlnGammas_subgroups_pure_dT
except:
pass
# The followign are calculated on initialization - no caching needed
Xs_pure = self._Xs_pure
Thetas_pure = self._Thetas_pure
try:
psis = self._psis
except AttributeError:
psis = self.psis()
try:
dpsis_dT = self._dpsis_dT
except AttributeError:
dpsis_dT = self.dpsis_dT()
N, N_groups, Qs = self.N, self.N_groups, self.Qs
cmp_group_idx = self.cmp_group_idx
try:
Theta_pure_Psi_sum_invs = self.Theta_pure_Psi_sum_invs
except AttributeError:
Theta_pure_Psi_sum_invs = self._Theta_pure_Psi_sum_invs()
try:
Fs_pure = self.Fs_pure
except AttributeError:
Fs_pure = self._Fs_pure()
if self.scalar:
dlnGammas_subgroups_pure_dT = [[0.0]*N for _ in range(N_groups)]
else:
dlnGammas_subgroups_pure_dT = zeros((N_groups, N))
self._dlnGammas_subgroups_pure_dT = unifac_dlnGammas_subgroups_pure_dT(N, N_groups, Qs, psis, dpsis_dT,
Thetas_pure, Theta_pure_Psi_sum_invs,
Fs_pure, cmp_group_idx,
dlnGammas_subgroups_pure_dT)
return dlnGammas_subgroups_pure_dT
[docs] def d2lnGammas_subgroups_pure_dT2(self):
r'''Calculate the second temperature derivative of :math:`\ln \Gamma_k`
pure component parameters for the phase; depends on the phases's
temperature only.
.. math::
\frac{\partial^2 \ln \Gamma_i}{\partial T^2} = -Q_i\left[
Z(i)G(i) - F(i)^2 Z(i)^2 + \sum_j\left(
\theta_j Z(j)\frac{\partial^2 \psi_{i,j}}{\partial T}
- Z(j)^2 \left(G(j)\theta_j \psi_{i,j} + 2 F_j \theta_j \frac{\partial \psi_{i,j}}{\partial T}\right)
+ 2Z(j)^3F(j)^2 \theta_j \psi_{i,j}
\right)\right]
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
.. math::
G(k) = \sum_m^{gr} \theta_m \frac{\partial^2 \psi_{m,k}}{\partial T^2}
.. math::
Z(k) = \frac{1}{\sum_m \Theta_m \Psi_{m,k}}
In this model, the :math:`\Theta` values come from the
:obj:`UNIFAC.Thetas_pure` method, where each compound is assumed to be
pure.
Returns
-------
d2lnGammas_subgroups_pure_dT2 : list[list[float]]
Second temperature derivative of ln Gamma parameters for each
subgroup, size number of subgroups by number of components and
indexed in that order, [1/K^2]
'''
try:
return self._d2lnGammas_subgroups_pure_dT2
except:
pass
Thetas_pure, Qs = self.Thetas_pure(), self.Qs
psis, dpsis_dT, d2psis_dT2 = self.psis(), self.dpsis_dT(), self.d2psis_dT2()
N, N_groups = self.N, self.N_groups
cmp_group_idx = self.cmp_group_idx
# Index by [component][subgroup]
try:
Theta_pure_Psi_sum_invs = self.Theta_pure_Psi_sum_invs
except AttributeError:
Theta_pure_Psi_sum_invs = self._Theta_pure_Psi_sum_invs()
try:
Fs_pure = self.Fs_pure
except AttributeError:
Fs_pure = self._Fs_pure()
try:
Gs_pure = self.Gs_pure
except AttributeError:
Gs_pure = self._Gs_pure()
if self.scalar:
d2lnGammas_subgroups_pure_dT2 = [[0.0]*N for _ in range(N_groups)]
else:
d2lnGammas_subgroups_pure_dT2 = zeros((N_groups, N))
# Index by [subgroup][component]
self._d2lnGammas_subgroups_pure_dT2 = unifac_d2lnGammas_subgroups_pure_dT2(N, N_groups, Qs, psis, dpsis_dT, d2psis_dT2, Thetas_pure, Theta_pure_Psi_sum_invs, Fs_pure, Gs_pure, cmp_group_idx, d2lnGammas_subgroups_pure_dT2)
return d2lnGammas_subgroups_pure_dT2
[docs] def d3lnGammas_subgroups_pure_dT3(self):
r'''Calculate the third temperature derivative of :math:`\ln \Gamma_k`
pure component parameters for the phase; depends on the phases's
temperature only.
.. math::
\frac{\partial^3 \ln \Gamma_i}{\partial T^3} =Q_i\left[-H(i) Z(i)
- 2F(i)^3 Z(i)^3 + 3F(i) G(i) Z(i)^2+ \left(
-\theta_j Z(j) \frac{\partial^3 \psi}{\partial T^3}
+ H(j) Z(j)^2 \theta(j)\psi_{i,j}
- 6F(j)^2 Z(j)^3 \theta_j \frac{\partial \psi_{i,j}}{\partial T}
+ 3 F(j) Z(j)^2 \theta(j) \frac{\partial^2 \psi_{i,j}}{\partial T^2}
++ 3G(j) \theta(j) Z(j)^2 \frac{\partial \psi_{i,j}}{\partial T}
+ 6F(j)^3 \theta(j) Z(j)^4 \psi_{i,j}
- 6F(j) G(j) \theta(j) Z(j)^3 \psi_{i,j}
\right)
\right]
.. math::
F(k) = \sum_m^{gr} \theta_m \frac{\partial \psi_{m,k}}{\partial T}
.. math::
G(k) = \sum_m^{gr} \theta_m \frac{\partial^2 \psi_{m,k}}{\partial T^2}
.. math::
H(k) = \sum_m^{gr} \theta_m \frac{\partial^3 \psi_{m,k}}{\partial T^3}
.. math::
Z(k) = \frac{1}{\sum_m \Theta_m \Psi_{m,k}}
In this model, the :math:`\Theta` values come from the
:obj:`UNIFAC.Thetas_pure` method, where each compound is assumed to be
pure.
Returns
-------
d3lnGammas_subgroups_pure_dT3 : list[list[float]]
Third temperature derivative of ln Gamma parameters for each
subgroup, size number of subgroups by number of components and
indexed in that order, [1/K^3]
'''
try:
return self._d3lnGammas_subgroups_pure_dT3
except:
pass
Thetas_pure, Qs = self.Thetas_pure(), self.Qs
psis, dpsis_dT, d2psis_dT2, d3psis_dT3 = self.psis(), self.dpsis_dT(), self.d2psis_dT2(), self.d3psis_dT3()
N, N_groups = self.N, self.N_groups
cmp_group_idx = self.cmp_group_idx
try:
Theta_pure_Psi_sum_invs = self.Theta_pure_Psi_sum_invs
except AttributeError:
Theta_pure_Psi_sum_invs = self._Theta_pure_Psi_sum_invs()
try:
Fs_pure = self.Fs_pure
except AttributeError:
Fs_pure = self._Fs_pure()
try:
Gs_pure = self.Gs_pure
except AttributeError:
Gs_pure = self._Gs_pure()
try:
Hs_pure = self.Hs_pure
except AttributeError:
Hs_pure = self._Hs_pure()
if self.scalar:
d3lnGammas_subgroups_pure_dT3 = [[0.0]*N for _ in range(N_groups)]
else:
d3lnGammas_subgroups_pure_dT3 = zeros((N_groups, N))
# Index by [subgroup][component]
self._d3lnGammas_subgroups_pure_dT3 = unifac_d3lnGammas_subgroups_pure_dT3(N, N_groups, Qs, psis, dpsis_dT, d2psis_dT2, d3psis_dT3, Thetas_pure, Theta_pure_Psi_sum_invs, Fs_pure, Gs_pure, Hs_pure, cmp_group_idx, d3lnGammas_subgroups_pure_dT3)
return d3lnGammas_subgroups_pure_dT3
[docs] def lngammas_r(self):
r'''Calculates the residual part of the UNIFAC model.
.. math::
\ln \gamma_i^r = \sum_{k}^{gr} \nu_k^{(i)} \left[ \ln \Gamma_k
- \ln \Gamma_k^{(i)} \right]
where the second Gamma is the pure-component Gamma of group `k` in
component `i`.
Returns
-------
lngammas_r : list[float]
Residual lngammas terms, size number of components [-]
'''
try:
return self._lngammas_r
except AttributeError:
pass
lnGammas_subgroups_pure = self.lnGammas_subgroups_pure()
lnGammas_subgroups = self.lnGammas_subgroups()
vs = self.vs
N, N_groups = self.N, self.N_groups
if self.scalar:
lngammas_r = [0.0]*N
else:
lngammas_r = zeros(N)
if N != 1:
unifac_lngammas_r(N, N_groups, lnGammas_subgroups_pure, lnGammas_subgroups, vs, lngammas_r)
self._lngammas_r = lngammas_r
return lngammas_r
[docs] def dlngammas_r_dT(self):
r'''Calculates the first temperature derivative of the residual part of
the UNIFAC model.
.. math::
\frac{\partial \ln \gamma_i^r}{\partial T} = \sum_{k}^{gr}
\nu_k^{(i)} \left[ \frac{\partial \ln \Gamma_k}{\partial T}
- \frac{\partial \ln \Gamma_k^{(i)}}{\partial T} \right]
where the second Gamma is the pure-component Gamma of group `k` in
component `i`.
Returns
-------
dlngammas_r_dT : list[float]
Residual lngammas terms first temperature derivative, size number
of components [1/K]
'''
try:
return self._dlngammas_r_dT
except AttributeError:
pass
dlnGammas_subgroups_pure_dT = self.dlnGammas_subgroups_pure_dT()
dlnGammas_subgroups_dT = self.dlnGammas_subgroups_dT()
vs = self.vs
N, N_groups = self.N, self.N_groups
if self.scalar:
dlngammas_r_dT = [0.0]*N
else:
dlngammas_r_dT = zeros(N)
self._dlngammas_r_dT = unifac_lngammas_r(N, N_groups, dlnGammas_subgroups_pure_dT, dlnGammas_subgroups_dT, vs, dlngammas_r_dT)
return dlngammas_r_dT
dlngammas_dT = dlngammas_r_dT
[docs] def d2lngammas_r_dT2(self):
r'''Calculates the second temperature derivative of the residual part of
the UNIFAC model.
.. math::
\frac{\partial^2 \ln \gamma_i^r}{\partial T^2} = \sum_{k}^{gr}
\nu_k^{(i)} \left[ \frac{\partial^2 \ln \Gamma_k}{\partial T^2}
- \frac{\partial^2 \ln \Gamma_k^{(i)}}{\partial T^2} \right]
where the second Gamma is the pure-component Gamma of group `k` in
component `i`.
Returns
-------
d2lngammas_r_dT2 : list[float]
Residual lngammas terms second temperature derivative, size number
of components [1/K^2]
'''
try:
return self._d2lngammas_r_dT2
except AttributeError:
pass
d2lnGammas_subgroups_pure_dT2 = self.d2lnGammas_subgroups_pure_dT2()
d2lnGammas_subgroups_dT2 = self.d2lnGammas_subgroups_dT2()
vs = self.vs
N, N_groups = self.N, self.N_groups
if self.scalar:
d2lngammas_r_dT2 = [0.0]*N
else:
d2lngammas_r_dT2 = zeros(N)
self._d2lngammas_r_dT2 = unifac_lngammas_r(N, N_groups, d2lnGammas_subgroups_pure_dT2, d2lnGammas_subgroups_dT2, vs, d2lngammas_r_dT2)
return d2lngammas_r_dT2
d2lngammas_dT2 = d2lngammas_r_dT2
[docs] def d3lngammas_r_dT3(self):
r'''Calculates the third temperature derivative of the residual part of
the UNIFAC model.
.. math::
\frac{\partial^3 \ln \gamma_i^r}{\partial T^3} = \sum_{k}^{gr}
\nu_k^{(i)} \left[ \frac{\partial^23\ln \Gamma_k}{\partial T^3}
- \frac{\partial^3 \ln \Gamma_k^{(i)}}{\partial T^3} \right]
where the second Gamma is the pure-component Gamma of group `k` in
component `i`.
Returns
-------
d3lngammas_r_dT3 : list[float]
Residual lngammas terms third temperature derivative, size number
of components [1/K^3]
'''
try:
return self._d3lngammas_r_dT3
except AttributeError:
pass
d3lnGammas_subgroups_pure_dT3 = self.d3lnGammas_subgroups_pure_dT3()
d3lnGammas_subgroups_dT3 = self.d3lnGammas_subgroups_dT3()
vs = self.vs
N, N_groups = self.N, self.N_groups
if self.scalar:
d3lngammas_r_dT3 = [0.0]*N
else:
d3lngammas_r_dT3 = zeros(N)
self._d3lngammas_r_dT3 = unifac_lngammas_r(N, N_groups, d3lnGammas_subgroups_pure_dT3, d3lnGammas_subgroups_dT3, vs, d3lngammas_r_dT3)
return d3lngammas_r_dT3
d3lngammas_dT3 = d3lngammas_r_dT3
[docs] def dlngammas_r_dxs(self):
r'''Calculates the first mole fraction derivative of the residual part
of the UNIFAC model.
.. math::
\frac{\partial \ln \gamma_i^r}{\partial x_j} = \sum_{m}^{gr} \nu_m^{(i)}
\frac{\partial \ln \Gamma_m}{\partial x_j}
Returns
-------
dlngammas_r_dxs : list[list[float]]
First mole fraction derivative of residual lngammas terms, size
number of components by number of components [-]
'''
try:
return self._dlngammas_r_dxs
except AttributeError:
pass
vs, N, N_groups = self.vs, self.N, self.N_groups
dlnGammas_subgroups_dxs = self.dlnGammas_subgroups_dxs()
if self.scalar:
dlngammas_r_dxs = [[0.0]*N for _ in range(N)]
else:
dlngammas_r_dxs = zeros((N, N))
self._dlngammas_r_dxs = unifac_dlngammas_r_dxs(N, N_groups, vs, dlnGammas_subgroups_dxs, dlngammas_r_dxs)
for i in range(N):
row = dlngammas_r_dxs[i]
for j in range(N):
tot = 0.0
for m in range(N_groups):
tot += vs[m][i]*dlnGammas_subgroups_dxs[m][j]
row[j] = tot
return dlngammas_r_dxs
[docs] def d2lngammas_r_dTdxs(self):
r'''Calculates the first mole fraction derivative of the temperature
derivative of the residual part of the UNIFAC model.
.. math::
\frac{\partial^2 \ln \gamma_i^r}{\partial x_j \partial T} =
\sum_{m}^{gr} \nu_m^{(i)} \frac{\partial^2 \ln \Gamma_m}
{\partial x_j \partial T}
Returns
-------
d2lngammas_r_dTdxs : list[list[float]]
First mole fraction derivative and temperature derivative of
residual lngammas terms, size number of components by number of
components [-]
'''
try:
return self._d2lngammas_r_dTdxs
except AttributeError:
pass
vs = self.vs
N, N_groups = self.N, self.N_groups
d2lnGammas_subgroups_dTdxs = self.d2lnGammas_subgroups_dTdxs()
if self.scalar:
d2lngammas_r_dTdxs = [[0.0]*N for _ in range(N)]
else:
d2lngammas_r_dTdxs = zeros((N, N))
self._d2lngammas_r_dTdxs = unifac_dlngammas_r_dxs(N, N_groups, vs, d2lnGammas_subgroups_dTdxs, d2lngammas_r_dTdxs)
return d2lngammas_r_dTdxs
[docs] def d2lngammas_r_dxixjs(self):
r'''Calculates the second mole fraction derivative of the residual part
of the UNIFAC model.
.. math::
\frac{\partial^2 \ln \gamma_i^r}{\partial x_j^2} = \sum_{m}^{gr}
\nu_m^{(i)} \frac{\partial^2 \ln \Gamma_m}{\partial x_j^2}
Returns
-------
d2lngammas_r_dxixjs : list[list[list[float]]]
Second mole fraction derivative of the residual lngammas terms,
size number of components by number of components by number of
components [-]
'''
try:
return self._d2lngammas_r_dxixjs
except AttributeError:
pass
vs = self.vs
N, N_groups = self.N, self.N_groups
d2lnGammas_subgroups_dxixjs = self.d2lnGammas_subgroups_dxixjs()
if self.scalar:
d2lngammas_r_dxixjs = [[[0.0]*N for _ in range(N)] for _ in range(N)]
else:
d2lngammas_r_dxixjs = zeros((N, N, N))
self._d2lngammas_r_dxixjs = unifac_d2lngammas_r_dxixjs(N, N_groups, vs, d2lnGammas_subgroups_dxixjs, d2lngammas_r_dxixjs)
return d2lngammas_r_dxixjs
[docs] def GE(self):
r'''Calculate the excess Gibbs energy with the UNIFAC model.
.. math::
G^E = RT\sum_i x_i \left(\ln \gamma_i^c + \ln \gamma_i^r \right)
For the VTPR model, the combinatorial component is set to zero.
Returns
-------
GE : float
Excess Gibbs energy, [J/mol]
'''
try:
return self._GE
except AttributeError:
pass
T, xs, N = self.T, self.xs, self.N
if N == 1:
GE = 0.0
else:
lngammas_r = self.lngammas_r()
if self.skip_comb:
GE = unifac_GE_skip_comb(T, xs, N, lngammas_r)
else:
lngammas_c = self.lngammas_c()
GE = unifac_GE(T, xs, N, lngammas_r, lngammas_c)
self._GE = GE
return GE
[docs] def dGE_dxs(self):
r'''Calculate the first composition derivative of excess Gibbs energy
with the UNIFAC model.
.. math::
\frac{\partial G^E}{\partial x_i} = RT\left(\ln \gamma_i^c
+ \ln \gamma_i^r \right)
+ RT\sum_j x_j \left(\frac{\partial \ln \gamma_j^c}{\partial x_i}
+ \frac{\partial \ln \gamma_j^r}{\partial x_i} \right)
Returns
-------
dGE_dxs : list[float]
First composition derivative of excess Gibbs energy, [J/mol]
'''
try:
return self._dGE_dxs
except AttributeError:
pass
T, xs, N, skip_comb = self.T, self.xs, self.N, self.skip_comb
lngammas_r = self.lngammas_r()
dlngammas_r_dxs = self.dlngammas_r_dxs()
if self.scalar:
dGE_dxs = [0.0]*N
else:
dGE_dxs = zeros(N)
if skip_comb:
self._dGE_dxs = unifac_dGE_dxs_skip_comb(T, xs, N, lngammas_r, dlngammas_r_dxs, dGE_dxs)
else:
lngammas_c = self.lngammas_c()
dlngammas_c_dxs = self.dlngammas_c_dxs()
self._dGE_dxs = unifac_dGE_dxs(T, xs, N, lngammas_r, dlngammas_r_dxs, lngammas_c, dlngammas_c_dxs, dGE_dxs)
return dGE_dxs
[docs] def d2GE_dTdxs(self):
r'''Calculate the first composition derivative and temperature
derivative of excess Gibbs energy with the UNIFAC model.
.. math::
\frac{\partial^2 G^E}{\partial T\partial x_i} =
RT\left(\frac{\partial \ln \gamma_i^r}{\partial T}
+ \sum_j x_j \frac{\partial \ln \gamma_j^r}{\partial x_i} \right)
+ R\left[ \frac{\partial \ln \gamma_i^c}{\partial x_i}
+ \frac{\partial \ln \gamma_i^r}{\partial x_i}
+ \sum_j x_j \left( \frac{\partial \ln \gamma_j^c}{\partial x_i}
+ \frac{\partial \ln \gamma_j^r}{\partial x_i}\right)\right]
Returns
-------
dGE_dxs : list[float]
First composition derivative and first temperature derivative of
excess Gibbs energy, [J/mol/K]
'''
try:
return self._d2GE_dTdxs
except AttributeError:
pass
T, xs, N, skip_comb = self.T, self.xs, self.N, self.skip_comb
lngammas_r = self.lngammas_r()
dlngammas_r_dxs = self.dlngammas_r_dxs()
dlngammas_r_dT = self.dlngammas_r_dT()
d2lngammas_r_dTdxs = self.d2lngammas_r_dTdxs()
if self.scalar:
d2GE_dTdxs = [0.0]*N
else:
d2GE_dTdxs = zeros(N)
if skip_comb:
self._d2GE_dTdxs = unifac_d2GE_dTdxs_skip_comb(T, xs, N, lngammas_r, dlngammas_r_dxs,dlngammas_r_dT, d2lngammas_r_dTdxs, d2GE_dTdxs)
else:
lngammas_c = self.lngammas_c()
dlngammas_c_dxs = self.dlngammas_c_dxs()
self._d2GE_dTdxs = unifac_d2GE_dTdxs(T, xs, N, lngammas_r, dlngammas_r_dxs, dlngammas_r_dT, d2lngammas_r_dTdxs, lngammas_c, dlngammas_c_dxs, d2GE_dTdxs)
return d2GE_dTdxs
[docs] def d2GE_dxixjs(self):
r'''Calculate the second composition derivative of excess Gibbs energy
with the UNIFAC model.
.. math::
\frac{\partial^2 G^E}{\partial x_j \partial x_k} = RT
\left[\sum_i \left(
\frac{\partial \ln \gamma_i^c}{\partial x_j \partial x_k}
+ \frac{\partial \ln \gamma_i^r}{\partial x_j \partial x_k}
\right)
+ \frac{\partial \ln \gamma_j^c}{\partial x_k}
+ \frac{\partial \ln \gamma_j^r}{\partial x_k}
+ \frac{\partial \ln \gamma_k^c}{\partial x_j}
+ \frac{\partial \ln \gamma_k^r}{\partial x_j}\right]
Returns
-------
d2GE_dxixjs : list[list[float]]
Second composition derivative of excess Gibbs energy, [J/mol]
'''
try:
return self._d2GE_dxixjs
except AttributeError:
pass
T, xs, N, skip_comb = self.T, self.xs, self.N, self.skip_comb
dlngammas_r_dxs = self.dlngammas_r_dxs()
d2lngammas_r_dxixjs = self.d2lngammas_r_dxixjs()
if self.scalar:
d2GE_dxixjs = [[0.0]*N for _ in range(N)]
else:
d2GE_dxixjs = zeros((N, N))
if N != 1:
if skip_comb:
unifac_d2GE_dxixjs_skip_comb(T, xs, N, dlngammas_r_dxs, d2lngammas_r_dxixjs, d2GE_dxixjs)
else:
dlngammas_c_dxs = self.dlngammas_c_dxs()
d2lngammas_c_dxixjs = self.d2lngammas_c_dxixjs()
unifac_d2GE_dxixjs(T, xs, N, dlngammas_r_dxs, d2lngammas_r_dxixjs, dlngammas_c_dxs, d2lngammas_c_dxixjs, d2GE_dxixjs)
self._d2GE_dxixjs = d2GE_dxixjs
return d2GE_dxixjs
[docs] def dGE_dT(self):
r'''Calculate the first temperature derivative of excess Gibbs energy
with the UNIFAC model.
.. math::
\frac{\partial G^E}{\partial T} =
RT\sum_i x_i \frac{\partial \ln \gamma_i^r}{\partial T}
+ \frac{G^E}{T}
Returns
-------
dGE_dT : float
First temperature derivative of excess Gibbs energy, [J/mol/K]
'''
try:
return self._dGE_dT
except AttributeError:
pass
self._dGE_dT = dGE_dT = unifac_dGE_dT(self.N, self.T, self.xs, self.dlngammas_r_dT(), self.GE())
return dGE_dT
[docs] def d2GE_dT2(self):
r'''Calculate the second temperature derivative of excess Gibbs energy
with the UNIFAC model.
.. math::
\frac{\partial^2 G^E}{\partial T^2} =
RT\sum_i x_i \frac{\partial^2 \ln \gamma_i^r}{\partial T^2}
+ 2R\sum_i x_i \frac{\partial \ln \gamma_i^r}{\partial T}
Returns
-------
d2GE_dT2 : float
Second temperature derivative of excess Gibbs energy, [J/mol/K^2]
'''
try:
return self._d2GE_dT2
except AttributeError:
pass
T, xs, N = self.T, self.xs, self.N
dlngammas_r_dT = self.dlngammas_r_dT()
d2lngammas_r_dT2 = self.d2lngammas_r_dT2()
self._d2GE_dT2 = d2GE_dT2 = unifac_d2GE_dT2(N, T, xs, dlngammas_r_dT, d2lngammas_r_dT2)
return d2GE_dT2
[docs] def d3GE_dT3(self):
r'''Calculate the third temperature derivative of excess Gibbs energy
with the UNIFAC model.
.. math::
\frac{\partial^3 G^E}{\partial T^3} =
RT\sum_i x_i \frac{\partial^3 \ln \gamma_i^r}{\partial T^3}
+ 3R\sum_i x_i \frac{\partial^2 \ln \gamma_i^r}{\partial T^2}
Returns
-------
d3GE_dT3 : float
Third temperature derivative of excess Gibbs energy, [J/mol/K^3]
'''
try:
return self._d3GE_dT3
except AttributeError:
pass
T, xs, N = self.T, self.xs, self.N
d2lngammas_r_dT2 = self.d2lngammas_r_dT2()
d3lngammas_r_dT3 = self.d3lngammas_r_dT3()
self._d3GE_dT3 = d3GE_dT3 = unifac_d3GE_dT3(N, T, xs, d2lngammas_r_dT2, d3lngammas_r_dT3)
return d3GE_dT3
[docs] def gammas(self):
r'''Calculates the activity coefficients with the UNIFAC model.
.. math::
\gamma_i = \exp\left(\ln \gamma_i^c + \ln \gamma_i^r \right)
For the VTPR variant, the combinatorial part is skipped:
.. math::
\gamma_i = \exp(\ln \gamma_i^r)
Returns
-------
gammas : list[float]
Activity coefficients, size number of components [-]
'''
try:
return self._gammas
except:
pass
xs, N = self.xs, self.N
try:
lngammas_r = self._lngammas_r
except AttributeError:
lngammas_r = self.lngammas_r()
if self.skip_comb:
if self.scalar:
self._gammas = gammas = [exp(ri) for ri in lngammas_r]
else:
self._gammas = gammas = npexp(lngammas_r)
else:
try:
lngammas_c = self._lngammas_c
except AttributeError:
lngammas_c = self.lngammas_c()
if self.scalar:
gammas = [0.0]*N
else:
gammas = zeros(N)
self._gammas = unifac_gammas(N, xs, lngammas_r, lngammas_c, gammas)
self._gammas = gammas
return gammas
[docs] def dgammas_dT(self):
r'''Calculates the first temperature derivative of activity
coefficients with the UNIFAC model.
.. math::
\frac{\partial \gamma_i}{\partial T} = \gamma_i\frac{\partial \ln
\gamma_i^r}{\partial T}
Returns
-------
dgammas_dT : list[float]
First temperature derivative of activity coefficients, size number
of components [1/K]
'''
try:
return self._dgammas_dT
except:
pass
try:
gammas = self._gammas
except AttributeError:
gammas = self.gammas()
try:
dlngammas_r_dT = self._dlngammas_r_dT
except AttributeError:
dlngammas_r_dT = self.dlngammas_r_dT()
if self.scalar:
self._dgammas_dT = dgammas_dT = [dlngammas_r_dT[i]*gammas[i] for i in range(self.N)]
else:
self._dgammas_dT = dgammas_dT = dlngammas_r_dT*gammas
return dgammas_dT
[docs] def dgammas_dns(self):
try:
return self._dgammas_dns
except AttributeError:
pass
dgammas_dxs = self.dgammas_dxs()
N = self.N
if self.scalar:
dgammas_dns = [[0.0]*N for _ in range(N)]
else:
dgammas_dns = zeros((N, N))
self._dgammas_dns = unifac_dgammas_dns(N, self.xs, dgammas_dxs, dgammas_dns)
return dgammas_dns
[docs] def dgammas_dxs(self):
r'''Calculates the first mole fraction derivative of activity
coefficients with the UNIFAC model.
.. math::
\frac{\partial \gamma_i}{\partial x_j} = \gamma_i
\left(\frac{\partial \ln \gamma_i^r}{\partial x_j}
+ \frac{\partial \ln \gamma_i^c}{\partial x_j}
\right)
For the VTPR variant, the combinatorial part is skipped:
.. math::
\frac{\partial \gamma_i}{\partial x_j} = \gamma_i
\left(\frac{\partial \ln \gamma_i^r}{\partial x_j}
\right)
Returns
-------
dgammas_dxs : list[list[float]]
First mole fraction derivative of activity coefficients, size
number of components by number of components [-]
'''
try:
return self._dgammas_dxs
except:
pass
try:
gammas = self._gammas
except AttributeError:
gammas = self.gammas()
xs, N = self.xs, self.N
try:
dlngammas_r_dxs = self._dlngammas_r_dxs
except AttributeError:
dlngammas_r_dxs = self.dlngammas_r_dxs()
if self.scalar:
dgammas_dxs = [[0.0]*N for _ in range(N)]
else:
dgammas_dxs = zeros((N, N))
if self.skip_comb:
self._dgammas_dxs = unifac_dgammas_dxs_skip_comb(N, xs, gammas, dlngammas_r_dxs, dgammas_dxs)
else:
try:
dlngammas_c_dxs = self._dlngammas_c_dxs
except AttributeError:
dlngammas_c_dxs = self.dlngammas_c_dxs()
self._dgammas_dxs = unifac_dgammas_dxs(N, xs, gammas, dlngammas_r_dxs, dlngammas_c_dxs, dgammas_dxs)
return dgammas_dxs
[docs] def lngammas_c(self):
r'''Calculates the combinatorial part of the UNIFAC model. For the
modified UNIFAC model, the equation is as follows; for the original
UNIFAC and UNIFAC LLE, replace :math:`V_i'` with :math:`V_i`.
.. math::
\ln \gamma_i^c = 1 - {V'}_i + \ln({V'}_i) - 5q_i \left(1
- \frac{V_i}{F_i}+ \ln\left(\frac{V_i}{F_i}\right)\right)
For the Lyngby model:
.. math::
\ln \gamma_i^c = \ln \left(V_i'\right) + 1
- V_i'
Returns
-------
lngammas_c : list[float]
Combinatorial lngammas terms, size number of components [-]
'''
try:
return self._lngammas_c
except AttributeError:
pass
try:
Vis = self._Vis
except AttributeError:
Vis = self.Vis()
try:
Fis = self._Fis
except AttributeError:
Fis = self.Fis()
N, version, qs = self.N, self.version, self.qs
if self.version in (1, 4):
try:
Vis_modified = self._Vis_modified
except AttributeError:
Vis_modified = self.Vis_modified()
else:
Vis_modified = Vis
if self.scalar:
lngammas_c = [0.0]*N
else:
lngammas_c = zeros(N)
if N != 1:
unifac_lngammas_c(N, version, qs, Fis, Vis, Vis_modified, lngammas_c)
self._lngammas_c = lngammas_c
return lngammas_c
[docs] def dlngammas_c_dT(self):
r'''Temperature derivatives of the combinatorial part of the UNIFAC
model. Zero in all variations.
.. math::
\frac{\partial \ln \gamma_i^c}{\partial T} = 0
Returns
-------
dlngammas_c_dT : list[float]
Combinatorial lngammas term temperature derivatives, size number of
components, [-]
'''
if self.scalar:
return [0.0]*self.N
return zeros(self.N)
[docs] def d2lngammas_c_dT2(self):
r'''Second temperature derivatives of the combinatorial part of the
UNIFAC model. Zero in all variations.
.. math::
\frac{\partial^2 \ln \gamma_i^c}{\partial T^2} = 0
Returns
-------
d2lngammas_c_dT2 : list[float]
Combinatorial lngammas term second temperature derivatives, size
number of components, [-]
'''
if self.scalar:
return [0.0]*self.N
return zeros(self.N)
[docs] def d3lngammas_c_dT3(self):
r'''Third temperature derivatives of the combinatorial part of the
UNIFAC model. Zero in all variations.
.. math::
\frac{\partial^3 \ln \gamma_i^c}{\partial T^3} = 0
Returns
-------
d3lngammas_c_dT3 : list[float]
Combinatorial lngammas term second temperature derivatives, size
number of components, [-]
'''
if self.scalar:
return [0.0]*self.N
return zeros(self.N)
[docs] def d2lngammas_c_dTdx(self):
r'''Second temperature derivative and first mole fraction derivative of
the combinatorial part of the UNIFAC model. Zero in all variations.
.. math::
\frac{\partial^3 \ln \gamma_i^c}{\partial T^2 \partial x_j} = 0
Returns
-------
d2lngammas_c_dTdx : list[list[float]]
Combinatorial lngammas term second temperature derivatives, size
number of components by number of components, [-]
'''
if self.scalar:
return [0.0]*self.N
return zeros(self.N)
[docs] def dlngammas_c_dxs(self):
r'''First composition derivative of
the combinatorial part of the UNIFAC model. For the modified UNIFAC
model, the equation is as follows; for the original UNIFAC and UNIFAC
LLE, replace :math:`V_i'` with :math:`V_i`.
.. math::
\frac{\partial \ln \gamma^c_i}{\partial x_j} =
-5q_i\left[ \left( \frac{\frac{\partial V_i}{\partial x_j}}{F_i}
- \frac{V_i \frac{\partial F_i}{\partial x_j}}{F_i^2}
\right)\frac{F_i}{V_i} - \frac{\frac{\partial V_i}{\partial x_j}}{F_i}
+ \frac{V_i\frac{\partial F_i}{\partial x_j}}{F_i^2}
\right]
- \frac{\partial V_i'}{\partial x_j}
+ \frac{\frac{\partial V_i'}{\partial x_j}}{V_i'}
For the Lyngby model, the following equations are used:
.. math::
\frac{\partial \ln \gamma^c_i}{\partial x_j} =
\frac{-\partial V_i'}{\partial x_j} + \frac{1}{V_i'}
\frac{\partial V_i'}{\partial x_j}
Returns
-------
dlngammas_c_dxs : list[list[float]]
Combinatorial lngammas term first composition derivative, size
number of components by number of components, [-]
'''
try:
return self._dlngammas_c_dxs
except AttributeError:
pass
N, version, qs = self.N, self.version, self.qs
try:
Vis = self._Vis
except AttributeError:
Vis = self.Vis()
try:
dVis_dxs = self._dVis_dxs
except AttributeError:
dVis_dxs = self.dVis_dxs()
try:
Fis = self._Fis
except AttributeError:
Fis = self.Fis()
try:
dFis_dxs = self._dFis_dxs
except AttributeError:
dFis_dxs = self.dFis_dxs()
if version in (1, 4):
try:
Vis_modified = self._Vis_modified
except AttributeError:
Vis_modified = self.Vis_modified()
try:
dVis_modified_dxs = self._dVis_modified_dxs
except AttributeError:
dVis_modified_dxs = self.dVis_modified_dxs()
else:
Vis_modified = Vis
dVis_modified_dxs = dVis_dxs
if self.scalar:
dlngammas_c_dxs = [[0.0]*N for _ in range(N)]
else:
dlngammas_c_dxs = zeros((N, N))
# index style - [THE GAMMA FOR WHICH THE DERIVATIVE IS BEING CALCULATED][THE VARIABLE BEING CHANGED CAUsING THE DIFFERENCE]
self._dlngammas_c_dxs = unifac_dlngammas_c_dxs(N, version, qs, Fis, dFis_dxs, Vis, dVis_dxs, Vis_modified, dVis_modified_dxs, dlngammas_c_dxs)
return dlngammas_c_dxs
""" Sympy code used to get these derivatives - not yet validated with numerical values from SymPy!
Second and third derivative formulas generated with SymPy.
from sympy import *
N = 3
N = range(N)
xs = x0, x1, x2 = symbols('x0, x1, x2')
rs = r0, r1, r2 = symbols('r0, r1, r2')
qs = q0, q1, q2 = symbols('q0, q1, q2') # Pure component property (made from subgroups, but known)
rsxs = sum([rs[i]*xs[i] for i in range(N)])
Vis = [rs[i]/rsxs for i in range(N)]
qsxs = sum([qs[i]*xs[i] for i in range(N)])
Fis = [qs[i]/qsxs for i in range(N)]
Vis = V0, V1, V2 = symbols('V0, V1, V2', cls=Function)
VisD = V0D, V1D, V2D = symbols('V0D, V1D, V2D', cls=Function)
Fis = F0, F1, F2 = symbols('F0, F1, F2', cls=Function)
Vis = [Vis[i](x0, x1, x2) for i in range(N)]
VisD = [VisD[i](x0, x1, x2) for i in range(N)]
Fis = [Fis[i](x0, x1, x2) for i in range(N)]
loggammacs = [1 - VisD[i] + log(VisD[i]) - 5*qs[i]*(1 - Vis[i]/Fis[i]
+ log(Vis[i]/Fis[i])) for i in range(N)]
# Variable to use for substitutions
Vi, ViD, Fi, xj, xk, xm, qi = symbols('V_i, Vi\', F_i, x_j, x_k, x_m, q_i')
# First derivative
good_first = diff(loggammacs[0], x1).subs(V0(x0, x1, x2), Vi).subs(F0(x0, x1, x2), Fi).subs(V0D(x0, x1, x2), ViD).subs(x1, xj).subs(q0, qi)
good_first = simplify(expand(simplify(good_first)))
# Second derivative
good_second = diff(loggammacs[0], x1, x2).subs(V0(x0, x1, x2), Vi).subs(F0(x0, x1, x2), Fi).subs(V0D(x0, x1, x2), ViD).subs(x1, xj).subs(x2, xk).subs(q0, qi)
# Third derivative
good_third = diff(loggammacs[0], x0, x1, x2).subs(V0(x0, x1, x2), Vi).subs(F0(x0, x1, x2), Fi).subs(V0D(x0, x1, x2), ViD).subs(x0, xj).subs(x1, xk).subs(x2, xm).subs(q0, qi)
good_third = simplify(good_third)
"""
"""For the Lyngby model composition derivatives remaining:
from sympy import *
N = 4
N = range(N)
xs = x0, x1, x2, x3 = symbols('x0, x1, x2, x3')
Vis = V0, V1, V2, V3 = symbols('V0, V1, V2, V3', cls=Function)
Vis = [Vis[i](x0, x1, x2, x3) for i in range(N)]
loggammacs = [1 + log(Vis[i]/xs[i]) - Vis[i]/xs[i] for i in range(N)]
diff(loggammacs[0], xs[1], xs[2])
"""
[docs] def d2lngammas_c_dxixjs(self):
r'''Second composition derivative of
the combinatorial part of the UNIFAC model. For the modified UNIFAC
model, the equation is as follows; for the original UNIFAC and UNIFAC
LLE, replace :math:`V_i'` with :math:`V_i`.
.. math::
\frac{\partial \ln \gamma^c_i}{\partial x_j \partial x_k} =
5 q_{i} \left(\frac{- \frac{d^{2}}{d x_{k}d x_{j}} V_{i} + \frac{V_{i}
\frac{d^{2}}{d x_{k}d x_{j}} F_{i}}{F_{i}} + \frac{\frac{d}{d x_{j}} F_{i}
\frac{d}{d x_{k}} V_{i}}{F_{i}} + \frac{\frac{d}{d x_{k}} F_{i}
\frac{d}{d x_{j}} V_{i}}{F_{i}} - \frac{2 V_{i} \frac{d}{d x_{j}}
F_{i} \frac{d}{d x_{k}} F_{i}}{F_{i}^{2}}}{V_{i}} + \frac{\left(
\frac{d}{d x_{j}} V_{i} - \frac{V_{i} \frac{d}{d x_{j}} F_{i}}
{F_{i}}\right) \frac{d}{d x_{k}} V_{i}}{V_{i}^{2}}
+ \frac{\frac{d^{2}}{d x_{k}d x_{j}} V_{i}}{F_{i}} - \frac{\left(
\frac{d}{d x_{j}} V_{i} - \frac{V_{i} \frac{d}{d x_{j}} F_{i}}{
F_{i}}\right) \frac{d}{d x_{k}} F_{i}}{F_{i} V_{i}} - \frac{V_{i}
\frac{d^{2}}{d x_{k}d x_{j}} F_{i}}{F_{i}^{2}} - \frac{\frac{d}
{d x_{j}} F_{i} \frac{d}{d x_{k}} V_{i}}{F_{i}^{2}}
- \frac{\frac{d}{d x_{k}} F_{i} \frac{d}{d x_{j}} V_{i}}{F_{i}^{2}}
+ \frac{2 V_{i} \frac{d}{d x_{j}} F_{i} \frac{d}{d x_{k}} F_{i}}
{F_{i}^{3}}\right) - \frac{d^{2}}{d x_{k}d x_{j}} Vi'
+ \frac{\frac{d^{2}}{d x_{k}d x_{j}} Vi'}{Vi'} - \frac{\frac{d}
{d x_{j}} Vi' \frac{d}{d x_{k}} Vi'}{Vi'^{2}}
For the Lyngby model, the following equations are used:
.. math::
\frac{\partial^2 \ln \gamma^c_i}{\partial x_j \partial x_k} =
-\frac{\partial^2 V_i'}{\partial x_j \partial x_k}
+ \frac{1}{V_i'} \frac{\partial^2 V_i'}{\partial x_j \partial x_k}
- \frac{1}{\left(V_i'\right)^2} \frac{\partial V_i'}{\partial x_j}
\frac{\partial V_i'}{\partial x_k}
Returns
-------
d2lngammas_c_dxixjs : list[list[list[float]]]
Combinatorial lngammas term second composition derivative, size
number of components by number of components by number of
components, [-]
'''
try:
return self._d2lngammas_c_dxixjs
except AttributeError:
pass
N, version, qs = self.N, self.version, self.qs
try:
Vis = self._Vis
except AttributeError:
Vis = self.Vis()
try:
dVis_dxs = self._dVis_dxs
except AttributeError:
dVis_dxs = self.dVis_dxs()
try:
d2Vis_dxixjs = self._d2Vis_dxixjs
except AttributeError:
d2Vis_dxixjs = self.d2Vis_dxixjs()
try:
Fis = self._Fis
except AttributeError:
Fis = self.Fis()
try:
dFis_dxs = self._dFis_dxs
except AttributeError:
dFis_dxs = self.dFis_dxs()
try:
d2Fis_dxixjs = self._d2Fis_dxixjs
except AttributeError:
d2Fis_dxixjs = self.d2Fis_dxixjs()
if self.version in (1, 4):
try:
Vis_modified = self._Vis_modified
except AttributeError:
Vis_modified = self.Vis_modified()
try:
dVis_modified_dxs = self._dVis_modified_dxs
except AttributeError:
dVis_modified_dxs = self.dVis_modified_dxs()
try:
d2Vis_modified_dxixjs = self._d2Vis_modified_dxixjs
except AttributeError:
d2Vis_modified_dxixjs = self.d2Vis_modified_dxixjs()
else:
Vis_modified = Vis
dVis_modified_dxs = dVis_dxs
d2Vis_modified_dxixjs = d2Vis_dxixjs
if self.scalar:
d2lngammas_c_dxixjs = [[[0.0]*N for _ in range(N)] for _ in range(N)]
else:
d2lngammas_c_dxixjs = zeros((N, N, N))
self._d2lngammas_c_dxixjs = unifac_d2lngammas_c_dxixjs(N, version, qs, Fis, dFis_dxs, d2Fis_dxixjs, Vis, dVis_dxs, d2Vis_dxixjs, Vis_modified, dVis_modified_dxs, d2Vis_modified_dxixjs, d2lngammas_c_dxixjs)
return d2lngammas_c_dxixjs
[docs] def d3lngammas_c_dxixjxks(self):
r'''Third composition derivative of
the combinatorial part of the UNIFAC model. For the modified UNIFAC
model, the equation is as follows; for the original UNIFAC and UNIFAC
LLE, replace :math:`V_i'` with :math:`V_i`.
.. math::
\frac{\partial \ln \gamma^c_i}{\partial x_j \partial x_k
\partial x_m} = - \frac{d^{3}}{d x_{m}d x_{k}d x_{j}} Vi'
+ \frac{\frac{d^{3}}{d x_{m}d x_{k}d x_{j}} Vi'}{Vi'}
- \frac{\frac{d}{d x_{j}} Vi' \frac{d^{2}}{d x_{m}d x_{k}} Vi'}
{Vi'^{2}} - \frac{\frac{d}{d x_{k}} Vi' \frac{d^{2}}{d x_{m}d
x_{j}} Vi'}{Vi'^{2}} - \frac{\frac{d}{d x_{m}} Vi' \frac{d^{2}}
{d x_{k}d x_{j}} Vi'}{Vi'^{2}} + \frac{2 \frac{d}{d x_{j}} Vi'
\frac{d}{d x_{k}} Vi' \frac{d}{d x_{m}} Vi'}{Vi'^{3}} - \frac{5
q_{i} \frac{d^{3}}{d x_{m}d x_{k}d x_{j}} V_{i}}{V_{i}}
+ \frac{5 q_{i} \frac{d}{d x_{j}} V_{i} \frac{d^{2}}{d x_{m}d x_{k}} V_{i}}{V_{i}^{2}}
+ \frac{5 q_{i} \frac{d}{d x_{k}} V_{i} \frac{d^{2}}{d x_{m}d x_{j}} V_{i}}{V_{i}^{2}}
+ \frac{5 q_{i} \frac{d}{d x_{m}} V_{i} \frac{d^{2}}{d x_{k}d x_{j}} V_{i}}{V_{i}^{2}}
- \frac{10 q_{i} \frac{d}{d x_{j}} V_{i} \frac{d}{d x_{k}} V_{i} \frac{d}{d x_{m}} V_{i}}{V_{i}^{3}}
+ \frac{5 q_{i} \frac{d^{3}}{d x_{m}d x_{k}d x_{j}} F_{i}}{F_{i}}
+ \frac{5 q_{i} \frac{d^{3}}{d x_{m}d x_{k}d x_{j}} V_{i}}{F_{i}}
- \frac{5 V_{i} q_{i} \frac{d^{3}}{d x_{m}d x_{k}d x_{j}} F_{i}}{F_{i}^{2}}
- \frac{5 q_{i} \frac{d}{d x_{j}} F_{i} \frac{d^{2}}{d x_{m}d x_{k}} F_{i}}{F_{i}^{2}}
- \frac{5 q_{i} \frac{d}{d x_{j}} F_{i} \frac{d^{2}}{d x_{m}d x_{k}} V_{i}}{F_{i}^{2}}
- \frac{5 q_{i} \frac{d}{d x_{k}} F_{i} \frac{d^{2}}{d x_{m}d x_{j}} F_{i}}{F_{i}^{2}}
- \frac{5 q_{i} \frac{d}{d x_{k}} F_{i} \frac{d^{2}}{d x_{m}d x_{j}} V_{i}}{F_{i}^{2}}
- \frac{5 q_{i} \frac{d}{d x_{m}} F_{i} \frac{d^{2}}{d x_{k}d x_{j}} F_{i}}{F_{i}^{2}}
- \frac{5 q_{i} \frac{d}{d x_{m}} F_{i} \frac{d^{2}}{d x_{k}d x_{j}} V_{i}}{F_{i}^{2}}
- \frac{5 q_{i} \frac{d}{d x_{j}} V_{i} \frac{d^{2}}{d x_{m}d x_{k}} F_{i}}{F_{i}^{2}}
- \frac{5 q_{i} \frac{d}{d x_{k}} V_{i} \frac{d^{2}}{d x_{m}d x_{j}} F_{i}}{F_{i}^{2}}
- \frac{5 q_{i} \frac{d}{d x_{m}} V_{i} \frac{d^{2}}{d x_{k}d x_{j}} F_{i}}{F_{i}^{2}}
+ \frac{10 V_{i} q_{i} \frac{d}{d x_{j}} F_{i} \frac{d^{2}}{d x_{m}d x_{k}} F_{i}}{F_{i}^{3}}
+ \frac{10 V_{i} q_{i} \frac{d}{d x_{k}} F_{i} \frac{d^{2}}{d x_{m}d x_{j}} F_{i}}{F_{i}^{3}}
+ \frac{10 V_{i} q_{i} \frac{d}{d x_{m}} F_{i} \frac{d^{2}}{d x_{k}d x_{j}} F_{i}}{F_{i}^{3}}
+ \frac{10 q_{i} \frac{d}{d x_{j}} F_{i} \frac{d}{d x_{k}} F_{i} \frac{d}{d x_{m}} F_{i}}{F_{i}^{3}}
+ \frac{10 q_{i} \frac{d}{d x_{j}} F_{i} \frac{d}{d x_{k}} F_{i} \frac{d}{d x_{m}} V_{i}}{F_{i}^{3}}
+ \frac{10 q_{i} \frac{d}{d x_{j}} F_{i} \frac{d}{d x_{m}} F_{i} \frac{d}{d x_{k}} V_{i}}{F_{i}^{3}}
+ \frac{10 q_{i} \frac{d}{d x_{k}} F_{i} \frac{d}{d x_{m}} F_{i} \frac{d}{d x_{j}} V_{i}}{F_{i}^{3}}
- \frac{30 V_{i} q_{i} \frac{d}{d x_{j}} F_{i} \frac{d}{d x_{k}} F_{i} \frac{d}{d x_{m}} F_{i}}{F_{i}^{4}}
For the Lyngby model, the following equations are used:
.. math::
\frac{\partial^3 \ln \gamma^c_i}{\partial x_j \partial x_k \partial
x_m} = \frac{\partial^3 V_i'}{\partial x_j \partial x_k \partial
x_m}\left(\frac{1}{V_i'} - 1\right)
- \frac{1}{(V_i')^2}\left(
\frac{\partial V_i'}{\partial x_j}\frac{\partial V_i'}{\partial x_k \partial x_m}
+ \frac{\partial V_i'}{\partial x_k}\frac{\partial V_i'}{\partial x_j \partial x_m}
+ \frac{\partial V_i'}{\partial x_m}\frac{\partial V_i'}{\partial x_j \partial x_k}
\right)
+ \frac{2}{(V_i')^3}\frac{\partial V_i'}{\partial x_j}
\frac{\partial V_i'}{\partial x_k}\frac{\partial V_i'}{\partial x_m}
Returns
-------
d3lngammas_c_dxixjxks : list[list[list[list[float]]]]
Combinatorial lngammas term third composition derivative, size
number of components by number of components by number of
components by number of components, [-]
'''
try:
return self._d3lngammas_c_dxixjxks
except AttributeError:
pass
N, version, qs = self.N, self.version, self.qs
Vis = self.Vis()
dVis_dxs = self.dVis_dxs()
d2Vis_dxixjs = self.d2Vis_dxixjs()
d3Vis_dxixjxks = self.d3Vis_dxixjxks()
Fis = self.Fis()
dFis_dxs = self.dFis_dxs()
d2Fis_dxixjs = self.d2Fis_dxixjs()
d3Fis_dxixjxks = self.d3Fis_dxixjxks()
if version in (1, 4):
Vis_modified = self.Vis_modified()
dVis_modified_dxs = self.dVis_modified_dxs()
d2Vis_modified_dxixjs = self.d2Vis_modified_dxixjs()
d3Vis_modified_dxixjxks = self.d3Vis_modified_dxixjxks()
else:
Vis_modified = Vis
dVis_modified_dxs = dVis_dxs
d2Vis_modified_dxixjs = d2Vis_dxixjs
d3Vis_modified_dxixjxks = d3Vis_dxixjxks
if self.scalar:
d3lngammas_c_dxixjxks = [[[[0.0]*N for _ in range(N)] for _ in range(N)] for _ in range(N)]
else:
d3lngammas_c_dxixjxks = zeros((N, N, N, N))
self._d3lngammas_c_dxixjxks = unifac_d3lngammas_c_dxixjxks(N, version, qs, Fis, dFis_dxs, d2Fis_dxixjs, d3Fis_dxixjxks, Vis, dVis_dxs, d2Vis_dxixjs, d3Vis_dxixjxks, Vis_modified, dVis_modified_dxs, d2Vis_modified_dxixjs, d3Vis_modified_dxixjxks, d3lngammas_c_dxixjxks)
return d3lngammas_c_dxixjxks