Skip to content

Commit f98d8ac

Browse files
committed
getting tighter now
1 parent e86b437 commit f98d8ac

File tree

8 files changed

+152
-51
lines changed

8 files changed

+152
-51
lines changed

.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -159,3 +159,4 @@ openpnm/core/.DS_Store
159159
*/.DS_Store
160160
*.DS_Store
161161
*.nblink
162+
.idea

openpnm/core/_base2.py

+4-2
Original file line numberDiff line numberDiff line change
@@ -188,9 +188,11 @@ def __getitem__(self, key):
188188
# meant for exploring the idea of putting phase values in the
189189
# network dict, like pn['pore.temperature.air'], but we're not doing
190190
# that now.
191-
if '*' in key:
191+
if key.startswith('*'):
192192
d = {}
193-
key = key[1:]
193+
key = key[1:] # Remove astrisk
194+
if key.startswith('.'): # Remove leading dot if *. was given
195+
key = key[1:]
194196
for k, v in self.items():
195197
if k.endswith(key):
196198
d[k[:-len(key)-1]] = super().__getitem__(k)

openpnm/models/collections/phase/__init__.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,4 @@
22
from .water import water
33
from .mercury import mercury
44
from .liquid_mixture import liquid_mixture
5-
from .gas_mixture import gas_mixture
5+
from .gas_mixture import binary_gas_mixture, gas_mixture

openpnm/models/collections/phase/gas_mixture.py

+25-3
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,13 @@
22
from openpnm.utils import get_model_collection
33

44

5-
def gas_mixture(regen_mode=None, domain=None):
6-
return get_model_collection(collection=_gas_mixture,
5+
def binary_gas_mixture(regen_mode=None, domain=None):
6+
return get_model_collection(collection=_binary_gas_mixture,
77
regen_mode=regen_mode,
88
domain=domain)
99

1010

11-
_gas_mixture = {
11+
_binary_gas_mixture = {
1212
'pore.molecular_weight': {
1313
'model': mods.mixtures.mixture_molecular_weight,
1414
},
@@ -34,3 +34,25 @@ def gas_mixture(regen_mode=None, domain=None):
3434
'model': mods.diffusivity.gas_mixture_diffusivity,
3535
},
3636
}
37+
38+
39+
def gas_mixture(regen_mode=None, domain=None):
40+
return get_model_collection(collection=_gas_mixture,
41+
regen_mode=regen_mode,
42+
domain=domain)
43+
44+
45+
_gas_mixture = {
46+
'pore.molecular_weight': {
47+
'model': mods.mixtures.mixture_molecular_weight,
48+
},
49+
'pore.viscosity': {
50+
'model': mods.viscosity.gas_mixture_viscosity,
51+
},
52+
'pore.thermal_conductivity': {
53+
'model': mods.thermal_conductivity.gas_mixture_thermal_conductivity,
54+
},
55+
'pore.heat_capacity': {
56+
'model': mods.heat_capacity.mixture_heat_capacity,
57+
},
58+
}

openpnm/models/phase/diffusivity/_funcs.py

+6-5
Original file line numberDiff line numberDiff line change
@@ -212,6 +212,7 @@ def gas_mixture_LJ_epsilon(target):
212212
Calculates the effective molecular diameter for a binary mixture
213213
"""
214214
es = [c['param.lennard_jones_epsilon'] for c in target.components.values()]
215+
assert len(es) == 2
215216
eAB = np.sqrt(np.prod(es))
216217
return eAB
217218

@@ -344,13 +345,13 @@ class MixDict(dict):
344345
only two components of a mixture that has several. This is necessary for
345346
use of the fuller model for calculating binary diffusivities.
346347
"""
348+
347349
def __init__(self, target, components):
348350
super().__init__(target)
349351
self.components = {}
350352
for item in components:
351353
self.components.update({item.name: item})
352354

353-
354355
comps = list(target.components.values())
355356
values = {}
356357
for i in range(len(comps)):
@@ -361,10 +362,10 @@ def __init__(self, target, components):
361362
B = comps[j]
362363
temp = MixDict(target=target, components=(A, B))
363364
D = fuller_mixture(target=temp,
364-
molecular_weight=molecular_weight,
365-
molar_diffusion_volume=molar_diffusion_volume,
366-
temperature=temperature,
367-
pressure=pressure)
365+
molecular_weight=molecular_weight,
366+
molar_diffusion_volume=molar_diffusion_volume,
367+
temperature=temperature,
368+
pressure=pressure)
368369
yB = target['pore.mole_fraction.' + B.name]
369370
denom += yB/D
370371
yA = target['pore.mole_fraction.' + A.name]

openpnm/phase/_mixture.py

+93-21
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
import numpy as np
22
import logging
3-
from copy import deepcopy
43
from openpnm.phase import Phase
5-
from openpnm.models.collections.phase import liquid_mixture, gas_mixture
4+
from openpnm.models.collections.phase import liquid_mixture
5+
from openpnm.models.collections.phase import gas_mixture, binary_gas_mixture
66
from openpnm.models.phase.mixtures import mole_summation
7-
from openpnm.utils import HealthDict, PrintableList, SubDict
7+
from openpnm.utils import HealthDict
88
from openpnm.utils import Docorator, Workspace
99

1010

@@ -15,22 +15,14 @@
1515

1616
__all__ = [
1717
'Mixture',
18-
'GasMixture',
18+
'BinaryGasMixture',
19+
'MultiGasMixture',
1920
'LiquidMixture',
2021
]
2122

2223

2324
class MixtureSettings:
24-
r"""
25-
The following settings are specific to Mixture objects
26-
27-
Parameters
28-
----------
29-
components : list of strings
30-
The names of each pure component object that constitute the mixture
31-
32-
"""
33-
components = []
25+
...
3426

3527

3628
@docstr.get_sections(base='Mixture', sections=['Parameters'])
@@ -64,10 +56,21 @@ def __getitem__(self, key):
6456
if key.split('.')[-1] in self.components.keys():
6557
comp = self.project[key.split('.')[-1]]
6658
vals = comp[key.rsplit('.', maxsplit=1)[0]]
59+
elif key.endswith('*'):
60+
key = key[:-1]
61+
if key.endswith('.'):
62+
key = key[:-1]
63+
vals = self._get_comp_vals(key)
6764
else:
6865
raise KeyError(key)
6966
return vals
7067

68+
def _get_comp_vals(self, propname):
69+
vals = {}
70+
for comp in self.components.keys():
71+
vals[comp] = self[propname + '.' + comp]
72+
return vals
73+
7174
def __str__(self):
7275
horizontal_rule = '―' * 78
7376
temp = super().__str__().split(horizontal_rule)
@@ -101,8 +104,13 @@ def _set_comps(self, components):
101104
def add_comp(self, component, mole_fraction=0.0):
102105
self['pore.mole_fraction.' + component.name] = mole_fraction
103106

104-
def remove_comp(self, compname):
105-
del self['pore.mole_fraction.' + compname]
107+
def remove_comp(self, component):
108+
if hasattr(component, 'name'):
109+
component = component.name
110+
try:
111+
del self['pore.mole_fraction.' + component]
112+
except KeyError:
113+
pass
106114

107115
def check_mixture_health(self):
108116
r"""
@@ -133,6 +141,7 @@ def check_mixture_health(self):
133141

134142

135143
class LiquidMixture(Mixture):
144+
136145
def __init__(self, **kwargs):
137146
super().__init__(**kwargs)
138147
self.models.update(liquid_mixture())
@@ -171,10 +180,6 @@ def x(self, compname=None, x=None):
171180

172181

173182
class GasMixture(Mixture):
174-
def __init__(self, **kwargs):
175-
super().__init__(**kwargs)
176-
self.models.update(gas_mixture())
177-
self.regenerate_models()
178183

179184
def y(self, compname=None, y=None):
180185
r"""
@@ -208,13 +213,80 @@ def y(self, compname=None, y=None):
208213
self['pore.mole_fraction.' + compname] = y
209214

210215

216+
class MultiGasMixture(GasMixture):
217+
218+
def __init__(self, **kwargs):
219+
super().__init__(**kwargs)
220+
self.models.clear()
221+
self.models.update(gas_mixture())
222+
self.regenerate_models()
223+
224+
class BinaryGasMixture(GasMixture):
225+
226+
def __init__(self, **kwargs):
227+
super().__init__(**kwargs)
228+
self.models.clear()
229+
self.models.update(binary_gas_mixture())
230+
self.regenerate_models()
231+
232+
def add_comp(self, component, mole_fraction=0.0):
233+
if len(self['pore.mole_fraction'].keys()) >= 2:
234+
raise Exception("Binary mixtures cannot have more than 2 components"
235+
+ ", remove one first")
236+
super().add_component(component=component, mole_fraction=mole_fraction)
237+
238+
211239
if __name__ == '__main__':
212240
import openpnm as op
213241
pn = op.network.Demo()
214242
o2 = op.phase.GasByName(network=pn, species='o2', name='pure_O2')
215243
n2 = op.phase.GasByName(network=pn, species='n2', name='pure_N2')
216-
air = op.phase.GasMixture(network=pn, components=[o2, n2])
244+
air = op.phase.BinaryGasMixture(network=pn, components=[o2, n2], name='air')
217245
air.y(o2.name, 0.21)
218246
air['pore.mole_fraction.pure_N2'] = 0.79
219247
air.regenerate_models()
220248
print(air)
249+
250+
ch4 = op.phase.GasByName(network=pn, species='ch4', name='methane')
251+
h2 = op.phase.GasByName(network=pn, species='h2', name='hydrogen')
252+
h2o = op.phase.GasByName(network=pn, species='h2o', name='water')
253+
co2 = op.phase.GasByName(network=pn, species='co2', name='co2')
254+
syngas = op.phase.MultiGasMixture(network=pn, components=[ch4, h2, h2o, co2],
255+
name='syngas')
256+
syngas.y(h2.name, 0.25)
257+
syngas.y(ch4.name, 0.25)
258+
syngas.y(h2o.name, 0.25)
259+
syngas.y(co2.name, 0.25)
260+
syngas.regenerate_models()
261+
print(syngas)
262+
263+
264+
265+
266+
267+
268+
269+
270+
271+
272+
273+
274+
275+
276+
277+
278+
279+
280+
281+
282+
283+
284+
285+
286+
287+
288+
289+
290+
291+
292+

openpnm/phase/_species.py

+18-14
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def mixture(self):
3838
for comp in item.components.values():
3939
if self is comp:
4040
return item
41+
logger.warn("No mixture phase found for this species")
4142

4243

4344
class SpeciesByName(Species):
@@ -61,22 +62,25 @@ class SpeciesByName(Species):
6162
"""
6263

6364
def __init__(self, species, **kwargs):
64-
super().__init__(**kwargs)
65+
# Create temp first to ensure all look-ups pass before initializing obj
66+
temp = {}
6567
CAS = chem.CAS_from_any(species)
66-
self['param.CAS'] = CAS
68+
temp['param.CAS'] = CAS
6769
a = chem.identifiers.search_chemical(CAS)
68-
self['param.common_name'] = a.common_name
69-
self['param.molecular_weight'] = a.MW/1000 # Convert to kg/mol
70-
self['param.critical_temperature'] = chem.critical.Tc(CAS)
71-
self['param.critical_pressure'] = chem.critical.Pc(CAS)
72-
self['param.critical_volume'] = chem.critical.Vc(CAS)
73-
self['param.critical_compressibilty_factor'] = chem.critical.Zc(CAS)
74-
self['param.boiling_temperature'] = chem.Tb(CAS)
75-
self['param.melting_temperature'] = chem.Tm(CAS)
76-
self['param.acentric_factor'] = chem.acentric.omega(CAS)
77-
self['param.dipole_moment'] = chem.dipole.dipole_moment(CAS)
78-
self['param.lennard_jones_epsilon'] = k*chem.lennard_jones.Stockmayer(CAS)
79-
self['param.lennard_jones_sigma'] = chem.lennard_jones.molecular_diameter(CAS)
70+
temp['param.common_name'] = a.common_name
71+
temp['param.molecular_weight'] = a.MW/1000 # Convert to kg/mol
72+
temp['param.critical_temperature'] = chem.critical.Tc(CAS)
73+
temp['param.critical_pressure'] = chem.critical.Pc(CAS)
74+
temp['param.critical_volume'] = chem.critical.Vc(CAS)
75+
temp['param.critical_compressibilty_factor'] = chem.critical.Zc(CAS)
76+
temp['param.boiling_temperature'] = chem.Tb(CAS)
77+
temp['param.melting_temperature'] = chem.Tm(CAS)
78+
temp['param.acentric_factor'] = chem.acentric.omega(CAS)
79+
temp['param.dipole_moment'] = chem.dipole.dipole_moment(CAS)
80+
temp['param.lennard_jones_epsilon'] = k*chem.lennard_jones.Stockmayer(CAS)
81+
temp['param.lennard_jones_sigma'] = chem.lennard_jones.molecular_diameter(CAS)
82+
super().__init__(**kwargs)
83+
self._params.update(temp)
8084

8185

8286
class GasByName(SpeciesByName):

tests/unit/phase/MixtureTest.py

+4-5
Original file line numberDiff line numberDiff line change
@@ -31,14 +31,13 @@ def test_set_component_by_property(self):
3131
del self.air['pore.mole_fraction.pure_CO2']
3232
assert len(self.air.components) == 2
3333

34-
def test_set_component_method(self):
34+
def test_add_and_remove_component_method(self):
3535
net = op.network.Demo()
3636
o2 = op.phase.GasByName(network=net, species='o2', name='pure_O2')
3737
n2 = op.phase.GasByName(network=net, species='n2', name='pure_N2')
38-
air = op.phase.GasMixture(network=net)
39-
air.y(o2.name, 0.21)
40-
air['pore.mole_fraction.pure_N2'] = 0.79
41-
air.regenerate_models()
38+
air = op.phase.GasMixture(network=net, components=[n2, o2])
39+
air.remove_comp(n2)
40+
air.remove_component(o2)
4241

4342
def test_check_health(self):
4443
self.air['pore.mole_fraction.pure_N2'] = 0.79

0 commit comments

Comments
 (0)