def encode(self): assert self._type_map is not None orientation = np.zeros_like(self._type_map) cnt = np.zeros_like(self._type_map) # Limit dry and wet types to these that are actually used in the simulation. uniq_types = set(np.unique(self._type_map.base)) dry_types = list(set(nt.get_dry_node_type_ids()) & uniq_types) wet_types = list(set(nt.get_wet_node_type_ids()) & uniq_types) orient_types = list(set(nt.get_orientation_node_type_ids()) & uniq_types) # Convert to a numpy array. dry_types = self._type_map.dtype.type(dry_types) wet_types = self._type_map.dtype.type(wet_types) orient_types = self._type_map.dtype.type(orient_types) # Check if there are any node types that need the orientation vector. needs_orientation = False for nt_code in uniq_types: if nt._NODE_TYPES[nt_code].needs_orientation: needs_orientation = True break if needs_orientation: for i, vec in enumerate(self.subdomain.grid.basis): l = len(list(vec)) - 1 shifted_map = self._type_map for j, shift in enumerate(vec): shifted_map = np.roll(shifted_map, int(-shift), axis=l-j) cnt[util.in_anyd_fast(shifted_map, dry_types)] += 1 # FIXME: we're currently only processing the primary directions # here if vec.dot(vec) == 1: idx = np.logical_and( util.in_anyd_fast(self._type_map, orient_types), shifted_map == 0) orientation[idx] = self.subdomain.grid.vec_to_dir(list(vec)) # Remap type IDs. max_type_code = max(self._type_id_remap.keys()) type_choice_map = np.zeros(max_type_code + 1, dtype=np.uint32) for orig_code, new_code in self._type_id_remap.iteritems(): type_choice_map[orig_code] = new_code self._type_map[:] = self._encode_node(orientation, self._encoded_param_map, np.choose(np.int32(self._type_map), type_choice_map), self._scratch_map) # Drop the reference to the map array. self._type_map = None
def tag_directions(self): """Creates direction tags for nodes that support it. Direction tags are a way of summarizing which distributions at a node will be undefined after streaming. :rvalue: True if there are any nodes supporting tagging, False otherwise """ # For directions which are not periodic, keep the ghost nodes to avoid # detecting some missing directions. ngs = list(self.spec._nonghost_slice) for i, periodic in enumerate(reversed(self.spec._periodicity)): if not periodic: ngs[i] = slice(None) ngs = tuple(ngs) # Limit dry and wet types to these that are actually used in the simulation. uniq_types = set(np.unique(self._type_map.base)) dry_types = list(set(nt.get_dry_node_type_ids()) & uniq_types) wet_types = list(set(nt.get_wet_node_type_ids()) & uniq_types) orient_types = list(set(nt.get_link_tag_node_type_ids()) & uniq_types) if not orient_types: return False # Convert to a numpy array. dry_types = self._type_map.dtype.type(dry_types) wet_types = self._type_map.dtype.type(wet_types) orient_types = self._type_map.dtype.type(orient_types) # Only do direction tagging for nodes that do not have # orientation/direction already. orient_map = ( util.in_anyd_fast(self._type_map_base[ngs], orient_types) & (self._orientation_base[ngs] == 0)) l = self.grid.dim - 1 # Skip the stationary vector. for i, vec in enumerate(self.grid.basis[1:]): shifted_map = self._type_map_base[ngs] for j, shift in enumerate(vec): if shift == 0: continue shifted_map = np.roll(shifted_map, int(-shift), axis=l-j) # If the given distribution points to a fluid node, tag it as # active. idx = orient_map & util.in_anyd_fast(shifted_map, wet_types) self._orientation_base[ngs][idx] |= (1 << i) self.config.logger.debug('... link tagging done.') return True
def tag_directions(self): """Creates direction tags for nodes that support it. Direction tags are a way of summarizing which distributions at a node will be undefined after streaming. :rvalue: True if there are any nodes supporting tagging, False otherwise """ # For directions which are not periodic, keep the ghost nodes to avoid # detecting some missing directions. ngs = list(self.spec._nonghost_slice) for i, periodic in enumerate(reversed(self.spec._periodicity)): if not periodic: ngs[i] = slice(None) # Limit dry and wet types to these that are actually used in the simulation. uniq_types = set(np.unique(self._type_map.base)) dry_types = list(set(nt.get_dry_node_type_ids()) & uniq_types) wet_types = list(set(nt.get_wet_node_type_ids()) & uniq_types) orient_types = list(set(nt.get_link_tag_node_type_ids()) & uniq_types) if not orient_types: return False # Convert to a numpy array. dry_types = self._type_map.dtype.type(dry_types) wet_types = self._type_map.dtype.type(wet_types) orient_types = self._type_map.dtype.type(orient_types) # Only do direction tagging for nodes that do not have # orientation/direction already. orient_map = ( util.in_anyd_fast(self._type_map_base[ngs], orient_types) & (self._orientation_base[ngs] == 0)) l = self.grid.dim - 1 # Skip the stationary vector. for i, vec in enumerate(self.grid.basis[1:]): shifted_map = self._type_map_base[ngs] for j, shift in enumerate(vec): if shift == 0: continue shifted_map = np.roll(shifted_map, int(-shift), axis=l-j) # If the given distribution points to a fluid node, tag it as # active. idx = orient_map & util.in_anyd_fast(shifted_map, wet_types) self._orientation_base[ngs][idx] |= (1 << i) self.config.logger.debug('... link tagging done.') return True
def _fluid_map_base(self): assert not self._type_map_encoded uniq_types = set(np.unique(self._type_map_base)) wet_types = list(set(nt.get_wet_node_type_ids()) & uniq_types) wet_types = self._type_map.dtype.type(wet_types) return util.in_anyd_fast(self._type_map_base, wet_types)
def detect_orientation(self, orientation): # Limit dry and wet types to these that are actually used in the simulation. uniq_types = set(np.unique(self._type_map.base)) dry_types = list(set(nt.get_dry_node_type_ids()) & uniq_types) orient_types = list( set(nt.get_orientation_node_type_ids()) & uniq_types) # Convert to a numpy array. dry_types = self._type_map.dtype.type(dry_types) orient_types = self._type_map.dtype.type(orient_types) orient_map = util.in_anyd_fast(self._type_map, orient_types) l = len(list(self.subdomain.grid.basis[0])) - 1 for vec in self.subdomain.grid.basis: # FIXME: we currently only process the primary directions if vec.dot(vec) != 1: continue shifted_map = self._type_map for j, shift in enumerate(vec): if shift == 0: continue shifted_map = np.roll(shifted_map, int(-shift), axis=l - j) # Only set orientation where it's not already defined (=0). idx = orient_map & (shifted_map == 0) & (orientation == 0) orientation[idx] = self.subdomain.grid.vec_to_dir(list(vec))
def _draw_geometry(self, tg_buffer, width, height, block): geo_map = np.zeros((height, width), dtype=np.uint8) geo_map.reshape(width * height)[:] = block.vis_geo_buffer[:] geo_map = np.rot90(geo_map, 3) dry_types = geo_map.dtype.type(node_type.get_dry_node_type_ids()) tg_buffer[util.in_anyd_fast(geo_map, dry_types)] = self._color_wall
def detect_orientation(self, use_tags): # Limit dry and wet types to these that are actually used in the simulation. uniq_types = set(np.unique(self._type_map.base)) dry_types = list(set(nt.get_dry_node_type_ids()) & uniq_types) orient_types = list((set(nt.get_orientation_node_type_ids()) - set(nt.get_link_tag_node_type_ids() if use_tags else [])) & uniq_types) if not orient_types: return # Convert to a numpy array. dry_types = self._type_map.dtype.type(dry_types) orient_types = self._type_map.dtype.type(orient_types) orient_map = util.in_anyd_fast(self._type_map_base, orient_types) l = self.grid.dim - 1 for vec in self.grid.basis: # Orientaion only handles the primary directions. More complex # setups need link tagging. if vec.dot(vec) != 1: continue shifted_map = self._type_map_base for j, shift in enumerate(vec): if shift == 0: continue shifted_map = np.roll(shifted_map, int(-shift), axis=l-j) # Only set orientation where it's not already defined (=0). idx = orient_map & (shifted_map == 0) & (self._orientation_base == 0) self._orientation_base[idx] = self.grid.vec_to_dir(list(vec))
def detect_orientation(self, use_tags): # Limit dry and wet types to these that are actually used in the simulation. uniq_types = set(np.unique(self._type_map.base)) dry_types = list(set(nt.get_dry_node_type_ids()) & uniq_types) orient_types = list( (set(nt.get_orientation_node_type_ids()) - set(nt.get_link_tag_node_type_ids() if use_tags else [])) & uniq_types) if not orient_types: return # Convert to a numpy array. dry_types = self._type_map.dtype.type(dry_types) orient_types = self._type_map.dtype.type(orient_types) orient_map = util.in_anyd_fast(self._type_map_base, orient_types) l = self.grid.dim - 1 for vec in self.grid.basis: # Orientaion only handles the primary directions. More complex # setups need link tagging. if vec.dot(vec) != 1: continue shifted_map = self._type_map_base for j, shift in enumerate(vec): if shift == 0: continue shifted_map = np.roll(shifted_map, int(-shift), axis=l - j) # Only set orientation where it's not already defined (=0). idx = orient_map & (shifted_map == 0) & (self._orientation_base == 0) self._orientation_base[idx] = self.grid.vec_to_dir(list(vec))
def fluid_map(self): """Returns a boolean array indicating which nodes are "wet" ( represent fluid and have valid macroscopic fields).""" fm = self.visualization_map() uniq_types = set(np.unique(fm)) wet_types = list(set(nt.get_wet_node_type_ids()) & uniq_types) wet_types = self._type_map.dtype.type(wet_types) return util.in_anyd_fast(fm, wet_types)
def _fluid_map_base(self, wet=True): assert not self._type_map_encoded if wet: uniq_types = set(np.unique(self._type_map_base)) wet_types = list(set(nt.get_wet_node_type_ids()) & uniq_types) wet_types = self._type_map.dtype.type(wet_types) return util.in_anyd_fast(self._type_map_base, wet_types) else: return self._type_map_base == 0
def fluid_map(self, wet=True): """Returns a boolean array indicating which nodes are "wet" ( represent fluid and have valid macroscopic fields).""" fm = self.visualization_map() if wet: uniq_types = set(np.unique(fm)) wet_types = list(set(nt.get_wet_node_type_ids()) & uniq_types) wet_types = self._type_map.dtype.type(wet_types) return util.in_anyd_fast(fm, wet_types) else: return fm == 0
def _postprocess_nodes(self): uniq_types = set(np.unique(self._type_map_base)) dry_types = list(set(nt.get_dry_node_type_ids()) & uniq_types) dry_types = self._type_map.dtype.type(dry_types) # Find nodes which are walls themselves and are completely surrounded by # walls. These nodes are marked as unused, as they do not contribute to # the dynamics of the fluid in any way. cnt = np.zeros_like(self._type_map_base).astype(np.uint32) for i, vec in enumerate(self.grid.basis): a = np.roll(self._type_map_base, int(-vec[0]), axis=1) a = np.roll(a, int(-vec[1]), axis=0) cnt[util.in_anyd_fast(a, dry_types)] += 1 self._type_map_base[(cnt == self.grid.Q)] = nt._NTUnused.id
def _postprocess_nodes(self): uniq_types = set(np.unique(self._type_map.base)) dry_types = list(set(nt.get_dry_node_type_ids()) & uniq_types) dry_types = self._type_map.dtype.type(dry_types) # Find nodes which are walls themselves and are completely surrounded by # walls. These nodes are marked as unused, as they do not contribute to # the dynamics of the fluid in any way. cnt = np.zeros_like(self._type_map.base).astype(np.uint32) for i, vec in enumerate(self.grid.basis): a = np.roll(self._type_map.base, int(-vec[0]), axis=1) a = np.roll(a, int(-vec[1]), axis=0) cnt[util.in_anyd_fast(a, dry_types)] += 1 self._type_map.base[(cnt == self.grid.Q)] = nt._NTUnused.id
def _fluid_map(self, wet=True, base=True, allow_unused=None): assert not self._type_map_encoded if base: src = self._type_map_base else: src = self._type_map if wet: uniq_types = set(np.unique(src)) wet_types = list(set(nt.get_wet_node_type_ids(allow_unused=allow_unused)) & uniq_types) wet_types = self._type_map.dtype.type(wet_types) return util.in_anyd_fast(src, wet_types) else: return src == 0
def _postprocess_nodes(self): uniq_types = set(np.unique(self._type_map.base)) dry_types = list(set(nt.get_dry_node_type_ids()) & uniq_types) dry_types = self._type_map.dtype.type(dry_types) # Find nodes which are walls themselves and are completely surrounded by # walls. These nodes are marked as unused, as they do not contribute to # the dynamics of the fluid in any way. dry_map = util.in_anyd_fast(self._type_map.base, dry_types).astype(np.uint8) neighbors = np.zeros((3, 3, 3), dtype=np.uint8) neighbors[1,1,1] = 1 for ei in self.grid.basis: neighbors[1 + ei[2], 1 + ei[1], 1 + ei[0]] = 1 where = (filters.convolve(dry_map, neighbors, mode='wrap') == self.grid.Q) self._type_map.base[where] = nt._NTUnused.id
def _postprocess_nodes(self): uniq_types = set(np.unique(self._type_map_base)) dry_types = list(set(nt.get_dry_node_type_ids()) & uniq_types) dry_types = self._type_map.dtype.type(dry_types) # Find nodes which are walls themselves and are completely surrounded by # walls. These nodes are marked as unused, as they do not contribute to # the dynamics of the fluid in any way. dry_map = util.in_anyd_fast(self._type_map_base, dry_types).astype(np.uint8) neighbors = np.zeros((3, 3, 3), dtype=np.uint8) neighbors[1, 1, 1] = 1 for ei in self.grid.basis: neighbors[1 + ei[2], 1 + ei[1], 1 + ei[0]] = 1 where = (filters.convolve(dry_map, neighbors, mode='wrap') == self.grid.Q) self._type_map_base[where] = nt._NTUnused.id
def detect_orientation(self, orientation): # Limit dry and wet types to these that are actually used in the simulation. uniq_types = set(np.unique(self._type_map.base)) dry_types = list(set(nt.get_dry_node_type_ids()) & uniq_types) orient_types = list(set(nt.get_orientation_node_type_ids()) & uniq_types) # Convert to a numpy array. dry_types = self._type_map.dtype.type(dry_types) orient_types = self._type_map.dtype.type(orient_types) orient_map = util.in_anyd_fast(self._type_map, orient_types) l = len(list(self.subdomain.grid.basis[0])) - 1 for vec in self.subdomain.grid.basis: # FIXME: we currently only process the primary directions if vec.dot(vec) != 1: continue shifted_map = self._type_map for j, shift in enumerate(vec): if shift == 0: continue shifted_map = np.roll(shifted_map, int(-shift), axis=l-j) # Only set orientation where it's not already defined (=0). idx = orient_map & (shifted_map == 0) & (orientation == 0) orientation[idx] = self.subdomain.grid.vec_to_dir(list(vec))
def test_inanyd_fast(self): a = np.random.random_integers(0, 20, (128, 128)) b = np.uint32([1, 4, 6, 10, 19]) np.testing.assert_array_equal( util.in_anyd(a, b), util.in_anyd_fast(a, b))
def fluid_map(self): fm = self.visualization_map() uniq_types = set(np.unique(fm)) wet_types = list(set(nt.get_wet_node_type_ids()) & uniq_types) wet_types = self._type_map.dtype.type(wet_types) return util.in_anyd_fast(fm, wet_types)
def test_inanyd_fast(self): a = np.random.random_integers(0, 20, (128, 128)) b = np.uint32([1, 4, 6, 10, 19]) np.testing.assert_array_equal(util.in_anyd(a, b), util.in_anyd_fast(a, b))
def _draw_geometry(self, tg_buffer, width, height, subdomain): geo_map = np.rot90(self._get_geo_map(width, height, subdomain), 3) dry_types = geo_map.dtype.type(node_type.get_dry_node_type_ids()) tg_buffer[util.in_anyd_fast(geo_map, dry_types)] = self._color_wall
def _draw_geometry(self, tg_buffer, width, height, block): geo_map = np.rot90(self._get_geo_map(width, height, block), 3) dry_types = geo_map.dtype.type(node_type.get_dry_node_type_ids()) tg_buffer[util.in_anyd_fast(geo_map, dry_types)] = self._color_wall