Skip to content

Commit

Permalink
Merge pull request #2810 from PMEAL/dev #patch
Browse files Browse the repository at this point in the history
Release v3.2.1
  • Loading branch information
ma-sadeghi committed Sep 1, 2023
2 parents 73bbc51 + ab6df00 commit 311f60d
Show file tree
Hide file tree
Showing 13 changed files with 118 additions and 73 deletions.
3 changes: 1 addition & 2 deletions .github/workflows/tests.yml
@@ -1,6 +1,6 @@
name: Tests

on: [push]
on: [pull_request]

jobs:
build:
Expand All @@ -15,7 +15,6 @@ jobs:
max-parallel: 9
matrix:
python-version: ['3.9', '3.10', '3.11']
# Add macos-latest to the next line once #2451 is fixed
os: [ubuntu-latest, windows-latest, macos-latest]
include:
- os: ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion openpnm/__version__.py
@@ -1 +1 @@
__version__ = '3.2.0.dev0'
__version__ = '3.2.0.dev4'
2 changes: 2 additions & 0 deletions openpnm/algorithms/__init__.py
Expand Up @@ -13,6 +13,8 @@
from ._transient_advection_diffusion import *

from ._fourier_conduction import *
from ._transient_fourier_conduction import *

from ._ohmic_conduction import *

from ._drainage import *
Expand Down
30 changes: 30 additions & 0 deletions openpnm/algorithms/_transient_fourier_conduction.py
@@ -0,0 +1,30 @@
import logging
from openpnm.algorithms import TransientReactiveTransport, FourierConduction


__all__ = ['TransientFourierConduction']


logger = logging.getLogger(__name__)


class TransientFourierConductionSettings():
r"""
Parameters
----------
%(TransientFourierConduction.parameters)s
"""
quantity = 'pore.temperature'
conductance = 'throat.thermal_conductance'
pore_volume = 'pore.volume'


class TransientFourierConduction(TransientReactiveTransport, FourierConduction):
r"""
A class to simulate transient thermal diffusion with heat source
"""

def __init__(self, name='trans_fourier_?', **kwargs):
super().__init__(name=name, **kwargs)
2 changes: 1 addition & 1 deletion openpnm/algorithms/_transport.py
Expand Up @@ -312,7 +312,7 @@ def rate(self, pores=[], throats=[], mode='group'):
g = np.tile(g, (2, 1)).T # Make conductance an Nt by 2 matrix
# The next line is critical for rates to be correct
g = np.flip(g, axis=1)
Qt = np.diff(g*X12, axis=1).squeeze()
Qt = np.diff(g*X12, axis=1).ravel()

if throats.size:
R = np.absolute(Qt[throats])
Expand Down
2 changes: 1 addition & 1 deletion openpnm/core/_base2.py
Expand Up @@ -315,7 +315,7 @@ def _get_name(self):
name = property(_get_name, _set_name)

def _get_project(self):
for proj in ws.values():
for proj in list(ws.values()):
if self in proj:
return proj

Expand Down
6 changes: 3 additions & 3 deletions openpnm/phase/_phase.py
Expand Up @@ -57,12 +57,12 @@ def __setitem__(self, key, value):
if '@' not in key:
super().__setitem__(key, value)
else:
# Deal with the fact that the label might only exist on the network
propname, domain = key.split('@')
element, prop = propname.split('.', 1)
# Fetch array from self
try:
try: # Fetch array from self if present
temp = self[element + '.' + prop]
except KeyError:
except KeyError: # Otherwise create it
temp = self._initialize_empty_array_like(value, element)
self[element + '.' + prop] = temp
# Insert values into masked locations
Expand Down
3 changes: 0 additions & 3 deletions openpnm/topotools/_topotools.py
Expand Up @@ -210,9 +210,6 @@ def trim(network, pores=[], throats=[]):
if (obj.Np == Np_old) and (obj.Nt == Nt_old):
Ps = Pkeep_inds
Ts = Tkeep_inds
else: # If subdomain object then Np/Nt < Np/Nt_old
Ps = obj.to_local(pores=Pkeep_inds, missing_vals=None)
Ts = obj.to_local(throats=Tkeep_inds, missing_vals=None)
for key in list(obj.keys()):
temp = obj.pop(key)
if key.split('.', 1)[0] == 'throat':
Expand Down
55 changes: 9 additions & 46 deletions openpnm/utils/_project.py
Expand Up @@ -15,44 +15,9 @@

__all__ = [
'Project',
'SimpleList',
]


class SimpleList:
"""A simple list class that prevents duplicates, and more!"""
def __init__(self, data=None):
if (data is not None):
self._list = list(data)
else:
self._list = list()

def __repr__(self): # pragma: no cover
return self._list.__repr__()

def __len__(self):
return len(self._list)

def __getitem__(self, ii):
if isinstance(ii, slice):
return self.__class__(self._list[ii])
else:
return self._list[ii]

def __delitem__(self, ii):
del self._list[ii]

def __str__(self): # pragma: no cover
return str(self._list)

def __iter__(self):
return self._list.__iter__()

def append(self, item):
if item not in self._list:
self._list.append(item)


class ProjectSettings(SettingsAttr):
r"""
uuid : str
Expand All @@ -74,7 +39,7 @@ def name(self, name):
self._name = name


class Project(SimpleList):
class Project(list):
r"""
This class provides a container for all OpenPNM objects in a given
simulation.
Expand Down Expand Up @@ -109,16 +74,14 @@ def __init__(self, *args, **kwargs):
ws[self.settings['name']] = self

def __getitem__(self, key):
if isinstance(key, str): # Enable dict-style retrieval if key is a string
obj = None
for item in self:
if item.name == key:
obj = item
if obj is None:
raise KeyError(key)
else:
obj = super().__getitem__(key)
return obj
try:
return super().__getitem__(key)
except TypeError:
if isinstance(key, str): # Enable dict-style lookup if key is a string
for item in self:
if item.name == key:
return item
raise KeyError(key)

def copy(self, name=None):
r"""
Expand Down
2 changes: 1 addition & 1 deletion openpnm/utils/_workspace.py
Expand Up @@ -123,7 +123,7 @@ def _validate_name(self, name=None):
name = name + '_01'
prefix, count = name.rsplit('_', 1)
n = [0]
for item in self.keys():
for item in list(self.keys()):
if item.startswith(prefix+'_'):
n.append(int(item.split(prefix+'_')[1]))
name = prefix+'_'+str(max(n)+1).zfill(2)
Expand Down
63 changes: 58 additions & 5 deletions openpnm/visualization/_plottools.py
Expand Up @@ -27,6 +27,7 @@ def plot_connections(network,
ax=None,
size_by=None,
color_by=None,
label_by=None,
cmap='jet',
color='b',
alpha=1.0,
Expand Down Expand Up @@ -55,8 +56,10 @@ def plot_connections(network,
An ndarray of throat values (e.g. alg['throat.rate']). These
values are used to scale the ``linewidth``, so if the lines are too
thin, then increase ``linewidth``.
color_by : str or array_like (optional)
color_by : array_like (optional)
An ndarray of throat values (e.g. alg['throat.rate']).
label_by : array_like (optional)
An array or list of values to use as labels
cmap : str or cmap object (optional)
The matplotlib colormap to use if specfying a throat property
for ``color_by``
Expand All @@ -71,6 +74,9 @@ def plot_connections(network,
Controls the thickness of drawn lines. Is used to scale the thickness
if ``size_by`` is given. Default is 1. If a value is provided for
``size_by`` then they are used to scale the ``linewidth``.
font : dict
A dictionary of key-value pairs that are used to control the font
appearance if `label_by` is provided.
**kwargs : dict
All other keyword arguments are passed on to the ``Line3DCollection``
class of matplotlib, so check their documentation for additional
Expand Down Expand Up @@ -149,20 +155,35 @@ class of matplotlib, so check their documentation for additional
if 'c' in kwargs.keys():
color = kwargs.pop('c')
color = mcolors.to_rgb(color) + tuple([alpha])
if isinstance(cmap, str):
try:
cmap = plt.colormaps.get_cmap(cmap)
except AttributeError:
cmap = plt.cm.get_cmap(cmap)
# Override colors with color_by if given
if color_by is not None:
color_by = np.array(color_by, dtype=np.float16)
if len(color_by) != len(Ts):
color_by = color_by[Ts]
if not np.all(np.isfinite(color_by)):
color_by[~np.isfinite(color_by)] = 0
logger.warning('nans or infs found in color_by array, setting to 0')
color = cm.get_cmap(name=cmap)(color_by / color_by.max())
vmin = kwargs.pop('vmin', color_by.min())
vmax = kwargs.pop('vmax', color_by.max())
cscale = (color_by - vmin) / (vmax - vmin)
color = cmap(cscale)
color[:, 3] = alpha
if size_by is not None:
if len(size_by) != len(Ts):
size_by = size_by[Ts]
if not np.all(np.isfinite(size_by)):
size_by[~np.isfinite(size_by)] = 0
logger.warning('nans or infs found in size_by array, setting to 0')
linewidth = size_by / size_by.max() * linewidth
if label_by is not None:
if len(label_by) != len(Ts):
label_by = label_by[Ts]
fontkws = kwargs.pop('font', {})

if ThreeD:
lc = Line3DCollection(throat_pos, colors=color, cmap=cmap,
Expand All @@ -172,6 +193,12 @@ class of matplotlib, so check their documentation for additional
lc = LineCollection(throat_pos, colors=color, cmap=cmap,
linestyles=linestyle, linewidths=linewidth,
antialiaseds=np.ones_like(network.Ts), **kwargs)
if label_by is not None:
for count, (P1, P2) in enumerate(network.conns[Ts, :]):
i, j, k = np.mean(network.coords[[P1, P2], :], axis=0)
ax.text(i, j, label_by[count],
ha='center', va='center',
**fontkws)
ax.add_collection(lc)

if np.size(Ts) > 0:
Expand All @@ -187,6 +214,7 @@ def plot_coordinates(network,
ax=None,
size_by=None,
color_by=None,
label_by=None,
cmap='jet',
color='r',
alpha=1.0,
Expand Down Expand Up @@ -215,6 +243,8 @@ def plot_coordinates(network,
you should do `size_by=net['pore.diameter']**2`.
color_by : str or array_like
An ndarray of pore values (e.g. alg['pore.concentration']).
label_by : array_like (optional)
An array or list of values to use as labels
cmap : str or cmap object
The matplotlib colormap to use if specfying a pore property
for ``color_by``
Expand All @@ -228,6 +258,9 @@ def plot_coordinates(network,
markersize : scalar
Controls size of marker, default is 1.0. This value is used to scale
the ``size_by`` argument if given.
font : dict
A dictionary of key-value pairs that are used to control the font
appearance if `label_by` is provided.
**kwargs
All other keyword arguments are passed on to the ``scatter``
function of matplotlib, so check their documentation for additional
Expand Down Expand Up @@ -310,18 +343,33 @@ def plot_coordinates(network,
color = kwargs.pop('c')
if 's' in kwargs.keys():
markersize = kwargs.pop('s')
if isinstance(cmap, str):
try:
cmap = plt.colormaps.get_cmap(cmap)
except AttributeError:
cmap = plt.cm.get_cmap(cmap)
if color_by is not None:
color_by = color_by[Ps]
color_by = np.array(color_by, dtype=np.float16)
if len(color_by) != len(Ps):
color_by = color_by[Ps]
if not np.all(np.isfinite(color_by)):
color_by[~np.isfinite(color_by)] = 0
logger.warning('nans or infs found in color_by array, setting to 0')
color = cm.get_cmap(name=cmap)(color_by / color_by.max())
vmin = kwargs.pop('vmin', color_by.min())
vmax = kwargs.pop('vmax', color_by.max())
cscale = (color_by - vmin) / (vmax - vmin)
color = cmap(cscale)
if size_by is not None:
if len(size_by) != len(Ps):
size_by = size_by[Ps]
if not np.all(np.isfinite(size_by)):
size_by[~np.isfinite(size_by)] = 0
logger.warning('nans or infs found in size_by array, setting to 0')
markersize = size_by / size_by.max() * markersize

if label_by is not None:
if len(label_by) != len(Ps):
label_by = label_by[Ps]
fontkws = kwargs.pop('font', {})
if ThreeD:
sc = ax.scatter(X, Y, Z,
c=color,
Expand All @@ -338,6 +386,11 @@ def plot_coordinates(network,
marker=marker,
alpha=alpha,
**kwargs)
if label_by is not None:
for count, (i, j, k) in enumerate(network.coords[Ps, :]):
ax.text(i, j, label_by[count],
ha='center', va='center',
**fontkws)
_scale_axes(ax=ax, X=Xl, Y=Yl, Z=np.zeros_like(Yl))

_label_axes(ax=ax, X=Xl, Y=Yl, Z=Zl)
Expand Down
2 changes: 1 addition & 1 deletion setup.cfg
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 3.2.0.dev0
current_version = 3.2.0.dev4
parse = (?P<major>\d+)\.(?P<minor>\d+)\.(?P<patch>\d+)\.(?P<release>\D+)(?P<build>\d+)?
serialize = {major}.{minor}.{patch}.{release}{build}

Expand Down

0 comments on commit 311f60d

Please sign in to comment.