Example #1
0
 def grid_sample(self, resolution, size, batch_size=1, channels=None):
     channels = channels or self.channels or len(size)
     shape = (batch_size, ) + tuple(resolution) + (channels, )
     rndj = math.to_complex(
         self.math.random_normal(shape)) + 1j * math.to_complex(
             self.math.random_normal(shape))  # Note: there is no complex32
     k = math.fftfreq(
         resolution) * resolution / size * self.scale  # in physical units
     k = math.sum(k**2, axis=-1, keepdims=True)
     lowest_frequency = 0.1
     weight_mask = 1 / (1 + math.exp(
         (lowest_frequency - k) * 1e3))  # High pass filter
     # --- Compute 1/k ---
     k[(0, ) * len(k.shape)] = np.inf
     inv_k = 1 / k
     inv_k[(0, ) * len(k.shape)] = 0
     # --- Compute result ---
     fft = rndj * inv_k**self.smoothness * weight_mask
     array = math.real(math.ifft(fft))
     array /= math.std(array,
                       axis=tuple(range(1, math.ndims(array))),
                       keepdims=True)
     array -= math.mean(array,
                        axis=tuple(range(1, math.ndims(array))),
                        keepdims=True)
     array = math.to_float(array)
     return array
Example #2
0
 def data(self, data):
     if data is None:
         return None
     if isinstance(data, (tuple, list)):
         data = np.array(data)  # numbers or objects
     if self.content_type in (struct.shape, struct.staticshape):
         assert math.ndims(data) == 1
     else:
         if math.ndims(data) < 2:
             data = math.expand_dims(data, 0, number=2 - math.ndims(data))
     return data
Example #3
0
 def __dataop__(self, other, linear_if_scalar, data_operator):
     if isinstance(other, StaggeredGrid):
         assert self.compatible(
             other), 'Fields are not compatible: %s and %s' % (self, other)
         data = [
             data_operator(c1, c2) for c1, c2 in zip(self.data, other.data)
         ]
         flags = propagate_flags_operation(self.flags + other.flags, False,
                                           self.rank, self.component_count)
     elif math.ndims(other) > 0 and math.staticshape(other)[-1] > 1:
         other_components = math.unstack(math.as_tensor(other),
                                         axis=-1,
                                         keepdims=True)
         data = [
             data_operator(c1, c2)
             for c1, c2 in zip(self.data, other_components)
         ]
         flags = propagate_flags_operation(self.flags, False, self.rank,
                                           self.component_count)
     else:
         data = [data_operator(c1, other) for c1 in self.data]
         flags = propagate_flags_operation(self.flags, linear_if_scalar,
                                           self.rank, self.component_count)
     return self.copied_with(data=np.array(data, dtype=np.object),
                             flags=flags)
Example #4
0
 def sample(value, domain, batch_size=None, name=None):
     assert isinstance(domain, Domain)
     if isinstance(value, Field):
         assert_same_rank(
             value.rank, domain.rank,
             'rank of value (%s) does not match domain (%s)' %
             (value.rank, domain.rank))
         if isinstance(value,
                       CenteredGrid) and value.box == domain.box and np.all(
                           value.resolution == domain.resolution):
             data = value.data
         else:
             point_field = CenteredGrid.getpoints(domain.box,
                                                  domain.resolution)
             point_field._batch_size = batch_size
             data = value.at(point_field).data
     else:  # value is constant
         if callable(value):
             x = CenteredGrid.getpoints(
                 domain.box, domain.resolution).copied_with(
                     extrapolation=Material.extrapolation_mode(
                         domain.boundaries),
                     name=name)
             value = value(x)
             return value
         components = math.staticshape(
             value)[-1] if math.ndims(value) > 0 else 1
         data = math.add(
             math.zeros((batch_size, ) + tuple(domain.resolution) +
                        (components, )), value)
     return CenteredGrid(data,
                         box=domain.box,
                         extrapolation=Material.extrapolation_mode(
                             domain.boundaries),
                         name=name)
Example #5
0
 def data(self, data):
     if data is None:
         return None
     if isinstance(data, (tuple, list)):
         data = np.array(data)  # numbers or objects
     while math.ndims(data) < 2:
         data = math.expand_dims(data)
     return data
Example #6
0
 def grid_sample(self, resolution, size, batch_size=1, dtype=np.float32):
     shape = (batch_size,) + tuple(resolution) + (self.channels,)
     rndj = math.randn(shape, dtype) + 1j * math.randn(shape, dtype)
     k = math.fftfreq(resolution) * resolution / size * self.scale  # in physical units
     k = math.sum(k ** 2, axis=-1, keepdims=True)
     lowest_frequency = 0.1
     weight_mask = 1 / (1 + math.exp((lowest_frequency - k) * 1e3))  # High pass filter
     # --- Compute 1/k ---
     k[(0,) * len(k.shape)] = np.inf
     inv_k = 1 / k
     inv_k[(0,) * len(k.shape)] = 0
     # --- Compute result ---
     fft = rndj * inv_k ** self.smoothness * weight_mask
     array = math.real(math.ifft(fft)).astype(dtype)
     array /= math.std(array, axis=tuple(range(1, math.ndims(array))), keepdims=True)
     array -= math.mean(array, axis=tuple(range(1, math.ndims(array))), keepdims=True)
     return array
Example #7
0
 def data(self, data):
     assert math.is_tensor(data), data
     rank = math.ndims(data)
     assert rank <= 3
     if rank < 3:
         assert rank in (0, 1)  # Scalar field / vector field
         data = math.expand_dims(data, 0, 3 - rank)
     return math.to_float(data)
Example #8
0
 def shape(self):
     with struct.unsafe():
         if math.ndims(self.data) > 0:
             data_shape = (self._batch_size, self._point_count,
                           self.component_count)
         else:
             data_shape = ()
         return self.copied_with(data=data_shape,
                                 sample_points=(self._batch_size,
                                                self._point_count,
                                                self.rank))
Example #9
0
 def unstack(self):
     unstacked = {}
     for arg in self.function_args:
         if isinstance(arg, Field):
             unstacked[arg] = arg.unstack()
         elif math.is_tensor(arg) and math.ndims(arg) > 0:
             unstacked[arg] = math.unstack(arg, axis=-1, keepdims=True)
         else:
             unstacked[arg] = [arg] * self.component_count
         assert len(unstacked[arg]) == self.component_count
     result = [_SymbolicOpField(self.function, [unstacked[arg][i] for arg in self.function_args]) for i in range(self.component_count)]
     return result
Example #10
0
def _determine_component_count(args):
    result = None
    for arg in args:
        arg_channels = None
        if isinstance(arg, Field):
            arg_channels = arg.component_count
        elif math.is_tensor(arg) and math.ndims(arg) > 0:
            arg_channels = arg.shape[-1]
        if result is None:
            result = arg_channels
        else:
            assert result == arg_channels or arg_channels is None
    return result
Example #11
0
 def to_box(value, resolution_hint=None):
     if value is None:
         result = AABox(0, resolution_hint)
     elif isinstance(value, AABox):
         result = value
     elif isinstance(value, int):
         if resolution_hint is None:
             result = AABox(0, value)
         else:
             size = [value] * (1 if math.ndims(resolution_hint) == 0 else
                               len(resolution_hint))
             result = AABox(0, size)
     else:
         result = AABox(box)
     if resolution_hint is not None:
         assert_same_rank(len(resolution_hint), result,
                          'AABox rank does not match resolution.')
     return result
Example #12
0
 def to_box(value, resolution_hint=None):
     if value is None:
         assert resolution_hint is not None
         result = AABox(0, resolution_hint)
     elif isinstance(value, AABox):
         result = value
     elif isinstance(value, int):
         if resolution_hint is None:
             result = AABox(0, value)
         else:
             size = [value] * (1 if math.ndims(resolution_hint) == 0 else
                               len(resolution_hint))
             result = AABox(0, size)
     elif isinstance(value, (tuple, list)):
         result = AABox(0, box)
     else:
         raise ValueError("Box extent not understood: '%s'" % value)
     if resolution_hint is not None:
         assert_same_rank(len(resolution_hint), result,
                          'AABox rank does not match resolution.')
     return result
Example #13
0
 def sample(value, domain, batch_size=None):
     assert isinstance(domain, Domain)
     if isinstance(value, Field):
         assert_same_rank(
             value.rank, domain.rank,
             'rank of value (%s) does not match domain (%s)' %
             (value.rank, domain.rank))
         if isinstance(value,
                       CenteredGrid) and value.box == domain.box and np.all(
                           value.resolution == domain.resolution):
             data = value.data
         else:
             data = value.sample_at(
                 CenteredGrid.getpoints(domain.box, domain.resolution).data)
     else:  # value is constant
         components = math.staticshape(
             value)[-1] if math.ndims(value) > 0 else 1
         data = math.zeros((batch_size, ) + tuple(domain.resolution) +
                           (components, )) + value
     return CenteredGrid(data,
                         box=domain.box,
                         extrapolation=Material.extrapolation_mode(
                             domain.boundaries))
Example #14
0
 def sample_at(self, points):
     points_rank = math.spatial_rank(points)
     src_rank = math.spatial_rank(self.location)
     # --- Expand shapes to format (batch_size, points_dims..., src_dims..., channels) ---
     points = math.expand_dims(points, axis=-2, number=src_rank)
     src_location = math.expand_dims(self.location,
                                     axis=-3,
                                     number=points_rank)
     src_strength = math.expand_dims(self.strength, axis=-1)
     if math.ndims(src_strength) == 1:
         src_strength = math.expand_dims(src_strength, axis=-2)
     src_strength = math.expand_dims(src_strength,
                                     axis=-3,
                                     number=points_rank)
     src_axes = tuple(range(-2, -2 - src_rank, -1))
     # --- Compute distances and falloff ---
     distances = points - src_location
     if self.falloff is not None:
         falloff_value = self.falloff(distances)
         strength = src_strength * falloff_value
     else:
         strength = src_strength
     # --- Compute velocities ---
     if math.staticshape(points)[-1] == 2:  # Curl in 2D
         dist_1, dist_2 = math.unstack(distances, axis=-1)
         if GLOBAL_AXIS_ORDER.is_x_first:
             velocity = strength * math.stack([-dist_2, dist_1], axis=-1)
         else:
             velocity = strength * math.stack([dist_2, -dist_1], axis=-1)
     elif math.staticshape(points)[-1] == 3:  # Curl in 3D
         raise NotImplementedError('not yet implemented')
     else:
         raise AssertionError(
             'Vector product not available in > 3 dimensions')
     velocity = math.sum(velocity, axis=src_axes)
     return velocity
Example #15
0
 def rank(self):
     if math.ndims(self.size) > 0:
         return self.size.shape[-1]
     else:
         return None
Example #16
0
 def rank(self):
     if math.ndims(self.upper) > 0:
         return math.staticshape(self.upper)[-1]
     else:
         return None
Example #17
0
 def _get(vector, axis):
     if math.ndims(vector) == 0:
         return vector
     else:
         return vector[..., axis]
Example #18
0
 def sample_points(self, sample_points):
     assert math.ndims(sample_points) == 3, sample_points.shape
     return sample_points
Example #19
0
 def location(self, loc):
     loc = math.to_float(loc)
     assert math.staticshape(loc)[-1] in (2, 3)
     if math.ndims(loc) < 2:
         loc = math.expand_dims(loc, axis=0, number=2 - math.ndims(loc))
     return loc
Example #20
0
 def apply_A(pressure):
     from phi.physics.material import Material
     mode = 'replicate' if Material.solid(domain.domain.boundaries) else 'constant'
     padded = math.pad(pressure, [[0,0]] + [[1,1]]*(math.ndims(pressure)-2) + [[0,0]], mode=mode)
     return _weighted_sliced_laplace_nd(padded, weights=fluid_mask)
Example #21
0
class SampledField(Field):

    def __init__(self, name, sample_points, data=1, mode='add', point_count=None, **kwargs):
        Field.__init__(self, **struct.kwargs(locals(), ignore=['point_count']))
        self._point_count = point_count

    def sample_at(self, points, collapse_dimensions=True):
        raise NotImplementedError()

    def at(self, other_field, collapse_dimensions=True, force_optimization=False, return_self_if_compatible=False):
        if isinstance(other_field, SampledField) and other_field.sample_points is self.sample_points:
            return self
        elif isinstance(other_field, (CenteredGrid, Domain)):
            return self._grid_sample(other_field.box, other_field.resolution)
        elif isinstance(other_field, StaggeredGrid):
            return self._stagger_sample(other_field.box, other_field.resolution)

        else:
            return self

    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')

    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

    @struct.variable()
    def data(self, data):
        if isinstance(data, (tuple, list, np.ndarray)):
            data = math.zeros_like(self.sample_points) + data
        return data
    data.override(struct.staticshape, lambda self, data: (self._batch_size, self._point_count, self.component_count) if math.ndims(self.data) > 0 else ())

    @struct.constant(default='add')
    def mode(self, mode):
        assert mode in ('add', 'mean', 'any')
        return mode

    @struct.variable()
    def sample_points(self, sample_points):
        assert math.ndims(sample_points) == 3, sample_points.shape
        return sample_points
    sample_points.override(struct.staticshape, lambda self, data: (self._batch_size, self._point_count, self.rank))

    @property
    def rank(self):
        return math.staticshape(self.sample_points)[-1]

    @property
    def component_count(self):
        if math.ndims(self.data) == 0:
            return 1
        return math.shape(self.data)[-1]

    def unstack(self):
        raise NotImplementedError()

    @property
    def points(self):
        if SAMPLE_POINTS in self.flags or self.sample_points is self.data:
            return self
        return SampledField(self.name+'.points', self.sample_points, self.sample_points, flags=[SAMPLE_POINTS])

    def compatible(self, other_field):
        if not other_field.has_points:
            return True
        if isinstance(other_field, SampledField) and other_field.sample_points is self.sample_points:
            return True
        return False

    def __repr__(self):
        return '%s[%sx(%d), %dD]' % (self.__class__.__name__, self._point_count if self._point_count is not None else '?', self.component_count, self.rank)
Example #22
0
 def component_count(self):
     if math.ndims(self.data) == 0:
         return 1
     return math.shape(self.data)[-1]