fixed false usage of _dim -> dim() method should be called. UNTESTED
This commit is contained in:
parent
8a50af80b9
commit
ec23f3acd4
74
field.py
74
field.py
|
|
@ -128,7 +128,7 @@ class Field3d:
|
||||||
return cls(data,origin,spacing)
|
return cls(data,origin,spacing)
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def allocate(cls,dim,origin,spacing,fill=None,dtype=np.float64,pseudo=False):
|
def allocate(cls,dim,origin,spacing,fill=None,dtype=np.float64):
|
||||||
'''Allocates an empty field, or a field filled with 'fill'.'''
|
'''Allocates an empty field, or a field filled with 'fill'.'''
|
||||||
assert isinstance(dim,(tuple,list,np.ndarray)) and len(dim)==3,\
|
assert isinstance(dim,(tuple,list,np.ndarray)) and len(dim)==3,\
|
||||||
"'dim' must be a tuple/list of length 3."
|
"'dim' must be a tuple/list of length 3."
|
||||||
|
|
@ -136,18 +136,26 @@ class Field3d:
|
||||||
"'origin' must be a tuple/list of length 3."
|
"'origin' must be a tuple/list of length 3."
|
||||||
assert isinstance(spacing,(tuple,list,np.ndarray)) and len(spacing)==3,\
|
assert isinstance(spacing,(tuple,list,np.ndarray)) and len(spacing)==3,\
|
||||||
"'spacing' must be a tuple/list of length 3."
|
"'spacing' must be a tuple/list of length 3."
|
||||||
if pseudo:
|
|
||||||
data = np.empty((0,0,0))
|
|
||||||
r = cls(data,origin,spacing)
|
|
||||||
r._dim = dim
|
|
||||||
return r
|
|
||||||
else:
|
|
||||||
if fill is None:
|
if fill is None:
|
||||||
data = np.empty(dim,dtype=dtype)
|
data = np.empty(dim,dtype=dtype)
|
||||||
else:
|
else:
|
||||||
data = np.full(dim,fill,dtype=dtype)
|
data = np.full(dim,fill,dtype=dtype)
|
||||||
return cls(data,origin,spacing)
|
return cls(data,origin,spacing)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def pseudo_field(cls,dim,origin,spacing):
|
||||||
|
'''Creates a Field3d instance without allocating any memory.'''
|
||||||
|
assert isinstance(dim,(tuple,list,np.ndarray)) and len(dim)==3,\
|
||||||
|
"'dim' must be a tuple/list of length 3."
|
||||||
|
assert isinstance(origin,(tuple,list,np.ndarray)) and len(origin)==3,\
|
||||||
|
"'origin' must be a tuple/list of length 3."
|
||||||
|
assert isinstance(spacing,(tuple,list,np.ndarray)) and len(spacing)==3,\
|
||||||
|
"'spacing' must be a tuple/list of length 3."
|
||||||
|
data = np.empty((0,0,0))
|
||||||
|
r = cls(data,origin,spacing)
|
||||||
|
r._dim = dim
|
||||||
|
return r
|
||||||
|
|
||||||
def save(self,file,name='Field3d',truncate=False):
|
def save(self,file,name='Field3d',truncate=False):
|
||||||
import h5py
|
import h5py
|
||||||
is_open = isinstance(file,(h5py.File,h5py.Group))
|
is_open = isinstance(file,(h5py.File,h5py.Group))
|
||||||
|
|
@ -163,6 +171,9 @@ class Field3d:
|
||||||
def copy(self):
|
def copy(self):
|
||||||
return Field3d(self.data.copy(),self.origin,self.spacing)
|
return Field3d(self.data.copy(),self.origin,self.spacing)
|
||||||
|
|
||||||
|
def pseudo_copy(self):
|
||||||
|
return self.pseudo_field(self.dim(),self.origin,self.spacing)
|
||||||
|
|
||||||
def insert_subfield(self,subfield):
|
def insert_subfield(self,subfield):
|
||||||
assert all([abs(subfield.spacing[ii]-self.spacing[ii])<self.eps_collapse
|
assert all([abs(subfield.spacing[ii]-self.spacing[ii])<self.eps_collapse
|
||||||
for ii in range(3)]), "spacing differs. Got {}, have {}".format(subfield.spacing,self.spacing)
|
for ii in range(3)]), "spacing differs. Got {}, have {}".format(subfield.spacing,self.spacing)
|
||||||
|
|
@ -638,15 +649,39 @@ class ConnectedRegions:
|
||||||
self.label = map_tgt[self.label]
|
self.label = map_tgt[self.label]
|
||||||
self.count = np.max(map_tgt)
|
self.count = np.max(map_tgt)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_field(cls,fld3d,val,periodicity,connect_diagonals=False,bytes_label=32,invert_threshold=False):
|
||||||
|
if invert_threshold:
|
||||||
|
return cls(fld3d.data<val,periodicity,
|
||||||
|
connect_diagonals=connect_diagonals,bytes_label=bytes_label)
|
||||||
|
else:
|
||||||
|
return cls(fld3d.data>=val,periodicity,
|
||||||
|
connect_diagonals=connect_diagonals,bytes_label=bytes_label)
|
||||||
|
|
||||||
def volume(self,label=None):
|
def volume(self,label=None):
|
||||||
|
'''Returns volume of labeled regions. If 'label' is None all volumes
|
||||||
|
are returned including the volume of the background region. The array
|
||||||
|
is sorted by labels, i.e. vol[0] is the volume of the background region,
|
||||||
|
vol[1] the volume of label 1, etc. If 'label' is an integer value, only
|
||||||
|
the volume of the corresponding region is returned.
|
||||||
|
Note: it is more efficient to retrieve all volumes at once than querying
|
||||||
|
single labels.'''
|
||||||
if label is None:
|
if label is None:
|
||||||
return np.bincount(self.label.ravel())
|
return np.bincount(self.label.ravel())
|
||||||
else:
|
else:
|
||||||
return np.sum(self.label==label)
|
return np.sum(self.label==label)
|
||||||
|
|
||||||
def volume_domain(self):
|
def volume_domain(self):
|
||||||
|
'''Returns volume of entire domain. Should be equal to sum(volume()).'''
|
||||||
return np.prod(self._dim)
|
return np.prod(self._dim)
|
||||||
|
|
||||||
|
def labels_by_volume(self,descending=True):
|
||||||
|
'''Returns labels of connected regions sorted by volume.'''
|
||||||
|
labels = np.argsort(self.volume()[1:])+1
|
||||||
|
if descending:
|
||||||
|
labels = labels[::-1]
|
||||||
|
return labels
|
||||||
|
|
||||||
def discard_regions(self,selection):
|
def discard_regions(self,selection):
|
||||||
selection = self._parse_selection(selection)
|
selection = self._parse_selection(selection)
|
||||||
# Map tagged regions to zero in order to discard them
|
# Map tagged regions to zero in order to discard them
|
||||||
|
|
@ -658,9 +693,30 @@ class ConnectedRegions:
|
||||||
self.label = map_tgt[self.label]
|
self.label = map_tgt[self.label]
|
||||||
self.count = np.max(map_tgt)
|
self.count = np.max(map_tgt)
|
||||||
|
|
||||||
|
def vtk_contour(self,fld3,val,selection):
|
||||||
|
'''Computes contours of a Field3d only within selected structures.'''
|
||||||
|
assert isinstance(fld3,Field3d), "'fld3' must be a Field3d instance."
|
||||||
|
assert tuple(self._dim)==tuple(fld3.dim()), \
|
||||||
|
"'fld3' must be of dimension {}.".format(self._dim)
|
||||||
|
selection = self._parse_selection(selection)
|
||||||
|
from scipy import ndimage
|
||||||
|
# Create binary map of selection
|
||||||
|
map_tgt = np.zeros(self.count+1,dtype='bool')
|
||||||
|
map_tgt[selection] = True
|
||||||
|
binary_map = map_tgt[self.label]
|
||||||
|
# Add an extra cell to get the contour interpolation right
|
||||||
|
print(np.sum(binary_map))
|
||||||
|
binary_map = ndimage.binary_dilation(binary_map)
|
||||||
|
print(np.sum(binary_map))
|
||||||
|
# Extract the subfield
|
||||||
|
fld_con = fld3.copy()
|
||||||
|
fld_con.data[~binary_map] = np.nan
|
||||||
|
# Compute the contour
|
||||||
|
return fld_con.vtk_contour(val)
|
||||||
|
|
||||||
def _parse_selection(self,selection):
|
def _parse_selection(self,selection):
|
||||||
dtype = self.label.dtype
|
dtype = self.label.dtype
|
||||||
if isinstance(selection,int):
|
if np.issubdtype(type(selection),np.integer):
|
||||||
return np.array(selection,dtype=dtype)
|
return np.array(selection,dtype=dtype)
|
||||||
elif isinstance(selection,(list,tuple,np.ndarray)):
|
elif isinstance(selection,(list,tuple,np.ndarray)):
|
||||||
selection = np.array(selection)
|
selection = np.array(selection)
|
||||||
|
|
@ -673,7 +729,7 @@ class ConnectedRegions:
|
||||||
"Entry in selection is out-of-bounds."
|
"Entry in selection is out-of-bounds."
|
||||||
return selection
|
return selection
|
||||||
else:
|
else:
|
||||||
raise ValueError('Invalid input.')
|
raise ValueError('Invalid input. Accepting int,list,tuple,ndarray.')
|
||||||
|
|
||||||
|
|
||||||
class ChunkIterator:
|
class ChunkIterator:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue