Beispiel #1
0
 def _shift_resample(self, resolution, box, threshold=1e-5, max_padding=20):
     lower = math.to_int(
         math.ceil(
             math.maximum(0, self.box.lower - box.lower) / self.dx -
             threshold))
     upper = math.to_int(
         math.ceil(
             math.maximum(0, box.upper - self.box.upper) / self.dx -
             threshold))
     total_padding = math.sum(lower) + math.sum(upper)
     if total_padding > max_padding:
         return NotImplemented
     elif total_padding > 0:
         from phi.field import pad
         padded = pad(
             self, {
                 dim: (int(lower[i]), int(upper[i]))
                 for i, dim in enumerate(self.shape.spatial.names)
             })
         grid_box, grid_resolution, grid_values = padded.box, padded.resolution, padded.values
     else:
         grid_box, grid_resolution, grid_values = self.box, self.resolution, self.values
     origin_in_local = grid_box.global_to_local(box.lower) * grid_resolution
     data = math.sample_subgrid(grid_values, origin_in_local, resolution)
     return data
Beispiel #2
0
    def _stagger_sample(self, box, resolution):
        """
    Samples this field on a staggered grid.
    In addition to sampling, extrapolates the field using an occupancy mask generated from the points.
        :param box: physical dimensions of the grid
        :param resolution: grid resolution
        :return: StaggeredGrid
        """
        resolution = np.array(resolution)
        valid_indices = math.to_int(math.floor(self.sample_points))
        valid_indices = math.minimum(math.maximum(0, valid_indices), resolution - 1)
        # Correct format for math.scatter
        valid_indices = batch_indices(valid_indices)

        active_mask = math.scatter(self.sample_points, valid_indices, 1, math.concat([[valid_indices.shape[0]], resolution, [1]], axis=-1), duplicates_handling='any')

        mask = math.pad(active_mask, [[0, 0]] + [[1, 1]] * self.rank + [[0, 0]], "constant")

        if isinstance(self.data, (int, float, np.ndarray)):
            values = math.zeros_like(self.sample_points) + self.data
        else:
            values = self.data
        
        result = []
        ones_1d = math.unstack(math.ones_like(values), axis=-1)[0]
        staggered_shape = [i + 1 for i in resolution]
        dx = box.size / resolution

        dims = range(len(resolution))
        for d in dims: 
            staggered_offset = math.stack([(0.5 * dx[i] * ones_1d if i == d else 0.0 * ones_1d) for i in dims], axis=-1)

            indices = math.to_int(math.floor(self.sample_points + staggered_offset))
            
            valid_indices = math.maximum(0, math.minimum(indices, resolution))
            valid_indices = batch_indices(valid_indices)

            values_d = math.expand_dims(math.unstack(values, axis=-1)[d], axis=-1)
            result.append(math.scatter(self.sample_points, valid_indices, values_d, [indices.shape[0]] + staggered_shape + [1], duplicates_handling=self.mode))

            d_slice = tuple([(slice(0, -2) if i == d else slice(1,-1)) for i in dims])
            u_slice = tuple([(slice(2, None) if i == d else slice(1,-1)) for i in dims])
            active_mask = math.minimum(mask[(slice(None),) + d_slice + (slice(None),)], active_mask)
            active_mask = math.minimum(mask[(slice(None),) + u_slice + (slice(None),)], active_mask)
        
        staggered_tensor_prep = unstack_staggered_tensor(math.concat(result, axis=-1))
        grid_values = StaggeredGrid(staggered_tensor_prep)
        # Fix values at boundary of liquids (using StaggeredGrid these might not receive a value, so we replace it with a value inside the liquid)
        grid_values, _ = extrapolate(grid_values, active_mask, voxel_distance=2)
        return grid_values
Beispiel #3
0
def _crop_for_interpolation(data, offset_float, window_resolution):
    offset = math.to_int(offset_float)
    slices = [
        slice(o, o + res + 1) for o, res in zip(offset, window_resolution)
    ]
    data = data[tuple([slice(None)] + slices + [slice(None)])]
    return data
Beispiel #4
0
 def cell_index(self, global_position):
     local_position = self.box.global_to_local(
         global_position) * self.resolution
     position = math.to_int(local_position - 0.5)
     position = math.maximum(0, position)
     position = math.minimum(position, self.resolution - 1)
     return position
Beispiel #5
0
 def _grid_sample(self, box, resolution):
     """
 Samples this field on a regular grid.
     :param box: physical dimensions of the grid
     :param resolution: grid resolution
     :return: CenteredGrid
     """
     sample_indices_nd = math.to_int(
         math.round(box.global_to_local(self.sample_points) * resolution))
     sample_indices_nd = math.minimum(
         math.maximum(0, sample_indices_nd), resolution - 1
     )  # Snap outside points to edges, otherwise scatter raises an error
     # Correct format for math.scatter
     valid_indices = _batch_indices(sample_indices_nd)
     shape = (math.shape(
         self.data)[0], ) + tuple(resolution) + (self.data.shape[-1], )
     scattered = math.scatter(self.sample_points,
                              valid_indices,
                              self.data,
                              shape,
                              duplicates_handling=self.mode)
     return CenteredGrid(data=scattered,
                         box=box,
                         extrapolation='constant',
                         name=self.name + '_centered')
Beispiel #6
0
 def _grid_sample(self, box, resolution):
     """
 Samples this field on a regular grid.
     :param box: physical dimensions of the grid
     :param resolution: grid resolution
     :return: CenteredGrid
     """
     valid_indices = math.to_int(math.floor(self.sample_points))
     valid_indices = math.minimum(math.maximum(0, valid_indices), resolution - 1)
     # Correct format for math.scatter
     valid_indices = batch_indices(valid_indices)
     scattered = math.scatter(self.sample_points, valid_indices, self.data, math.concat([[valid_indices.shape[0]], resolution, [1]], axis=-1), duplicates_handling=self.mode)
     return CenteredGrid(data=scattered, box=box, extrapolation='constant', name=self.name+'_centered')
Beispiel #7
0
 def after_gather(self, selection: dict):
     result = self
     for name, selection in selection.items():
         if isinstance(selection, int):
             result = result.without(name)
         elif isinstance(selection, slice):
             start = selection.start or 0
             stop = selection.stop or self.get_size(name)
             step = selection.step or 1
             if stop < 0:
                 stop += self.get_size(name)
                 assert stop >= 0
             new_size = math.to_int(math.ceil(math.wrap((stop - start) / step)))
             if new_size.rank == 0:
                 new_size = int(new_size)  # NumPy array not allowed because not hashable
             result = result.with_size(name, new_size)
         else:
             raise NotImplementedError(f"{type(selection)} not supported. Only (int, slice) allowed.")
     return result
Beispiel #8
0
    def _grid_scatter(self, box: Box, resolution: math.Shape):
        """
        Approximately samples this field on a regular grid using math.scatter().

        Args:
          box: physical dimensions of the grid
          resolution: grid resolution
          box: Box: 
          resolution: math.Shape: 

        Returns:
          CenteredGrid

        """
        closest_index = math.to_int(math.round(box.global_to_local(self.points) * resolution - 0.5))
        if self._add_overlapping:
            duplicates_handling = 'add'
        else:
            duplicates_handling = 'mean'
        scattered = math.scatter(closest_index, self.values, resolution, duplicates_handling=duplicates_handling, outside_handling='discard', scatter_dims=('points',))
        return scattered
Beispiel #9
0
def _required_paddings_transposed(box, dx, target):
    lower = math.to_int(
        math.ceil(math.maximum(0, box.lower - target.lower) / dx))
    upper = math.to_int(
        math.ceil(math.maximum(0, target.upper - box.upper) / dx))
    return [lower, upper]