def slice_2d(field3d, settings): if isinstance(field3d, np.ndarray): field3d = CenteredGrid(field3d) if isinstance(field3d, StaggeredGrid): component = settings.get('component', 'length') if component in ('z', 'y', 'x'): field3d = field3d.unstack()[{ 'z': physics_config.z, 'y': physics_config.y, 'x': physics_config.x }[component] % 3] else: field3d = field3d.at_centers() assert isinstance(field3d, CenteredGrid) and field3d.rank == 3 depth = settings.get('depth', 0) projection = settings.get('projection', FRONT) removed_axis = { FRONT: physics_config.y, RIGHT: physics_config.x, TOP: physics_config.z }[projection] % 3 data = field3d.data[(slice(None), ) + tuple([ min(depth, field3d.resolution[i]) if i == removed_axis else slice(None) for i in range(3) ]) + (slice(None), )] if projection == RIGHT and not physics_config.is_x_first: data = np.transpose(data, axes=(0, 2, 1, 3)) return CenteredGrid(data, box=field3d.box.without_axis(removed_axis))
def test_bounds(self): tensor = math.zeros([1, 5, 5, 2]) f = StaggeredGrid(tensor) bounds = data_bounds(f) self.assertIsInstance(bounds, AABox) np.testing.assert_equal(bounds.lower, 0) np.testing.assert_equal(bounds.upper, [4, 4]) a = CenteredGrid(np.zeros([1, 4, 4, 1])) np.testing.assert_equal(a.box.size, [4, 4]) a = CenteredGrid(np.zeros([1, 4, 4, 1]), 1) np.testing.assert_equal(a.box.size, 1)
def test_inner_interpolation(self): data = math.zeros([1, 2, 3, 1]) data[0, :, :, 0] = [[1, 2, 3], [4, 5, 6]] f = CenteredGrid(data, box[0:2, 0:3]) g = CenteredGrid(math.zeros([1, 2, 2, 1]), box[0:2, 0.5:2.5]) # Resample optimized resampled = f.at(g) self.assertTrue(resampled.compatible(g)) np.testing.assert_equal(resampled.data[0, ..., 0], [[1.5, 2.5], [4.5, 5.5]]) # Resample unoptimized resampled2 = Field.at(f, g) self.assertTrue(resampled2.compatible(g)) np.testing.assert_equal(resampled2.data[0, ..., 0], [[1.5, 2.5], [4.5, 5.5]])
def test_struct_initializers(self): obj = ([4], CenteredGrid([1, 4, 1], box[0:1], content_type=struct.shape), ([9], [8, 2])) z = math.zeros(obj) self.assertIsInstance(z, tuple) np.testing.assert_equal(z[0], np.zeros([4])) z2 = math.zeros_like(z) np.testing.assert_equal(math.shape(z)[0], math.shape(z2)[0])
def poisson_solve(input_field, poisson_domain, solver=None): """ Solves the Poisson equation Δp = input_field for p. :param input_field: CenteredGrid :param poisson_domain: PoissonDomain instance :param solver: PoissonSolver to use, None for default :return: p as CenteredGrid, iteration count as int or None if not available :rtype: CenteredGrid, int """ from .sparse import SparseSciPy, SparseCG assert isinstance(input_field, CenteredGrid) if isinstance(poisson_domain, Domain): poisson_domain = PoissonDomain(poisson_domain) if solver is None: if math.choose_backend([ input_field.data, poisson_domain.active.data, poisson_domain.accessible.data ]).matches_name('SciPy'): solver = SparseSciPy() else: solver = SparseCG() pressure, iteration = solver.solve(input_field.data, poisson_domain, guess=None) pressure = CenteredGrid(pressure, input_field.box, name='pressure') return pressure, iteration
def poisson_solve(input_field, poisson_domain, solver=None, guess=None): """ Solves the Poisson equation Δp = input_field for p. :param input_field: CenteredGrid :param poisson_domain: PoissonDomain instance :param solver: PoissonSolver to use, None for default :param guess: CenteredGrid with same size and resolution as input_field :return: p as CenteredGrid, iteration count as int or None if not available :rtype: CenteredGrid, int """ assert isinstance(input_field, CenteredGrid) if guess is not None: assert isinstance(guess, CenteredGrid) assert guess.compatible(input_field) guess = guess.data if isinstance(poisson_domain, Domain): poisson_domain = PoissonDomain(poisson_domain) if solver is None: from .sparse import SparseSciPy, SparseCG if math.choose_backend([ input_field.data, poisson_domain.active.data, poisson_domain.accessible.data ]).matches_name('SciPy'): solver = SparseSciPy() else: from phi.physics.pressuresolver.fourier import FourierSolver solver = FourierSolver() & SparseCG() pressure, iteration = solver.solve(input_field.data, poisson_domain, guess=guess) pressure = CenteredGrid(pressure, input_field.box, extrapolation=input_field.extrapolation, name='pressure') return pressure, iteration
def centered_grid(self, data, components=1, dtype=None, name=None, batch_size=None, extrapolation=None): warnings.warn( "Domain.centered_shape and Domain.centered_grid are deprecated. Use CenteredGrid.sample() instead.", DeprecationWarning) from phi.physics.field import CenteredGrid if callable(data): # data is an initializer shape = self.centered_shape(components, batch_size=batch_size, name=name, extrapolation=extrapolation, age=()) try: grid = data(shape, dtype=dtype) except TypeError: grid = data(shape) if grid.age == (): grid._age = 0.0 else: grid = CenteredGrid.sample(data, self, batch_size=batch_size) assert grid.component_count == components, "Field has %d components but %d are required for '%s'" % ( grid.component_count, components, name) if dtype is not None and math.dtype(grid.data) != dtype: grid = grid.copied_with(data=math.cast(grid.data, dtype)) if name is not None: grid = grid.copied_with(name=name, tags=(name, ) + grid.tags) if extrapolation is not None: grid = grid.copied_with(extrapolation=extrapolation) return grid
def staggered_shape(self, batch_size=1, name=None, extrapolation=None, age=0.0): grids = [] for axis in range(self.rank): shape = _extend1(tensor_shape(batch_size, self.resolution, 1), axis) from phi.physics.field.staggered_grid import staggered_component_box box = staggered_component_box(self.resolution, axis, self.box) from phi.physics.field import CenteredGrid grid = CenteredGrid(shape, box, age=age, extrapolation=extrapolation, name=None, batch_size=batch_size, flags=(), content_type=struct.Struct.shape) grids.append(grid) from phi.physics.field import StaggeredGrid return StaggeredGrid(grids, age=age, box=self.box, name=name, batch_size=batch_size, extrapolation=extrapolation, flags=(), content_type=struct.Struct.shape)
def conv_layer(grid, filters, kernel_size, strides=1, padding='valid', activation=None, use_bias=True, name=None, trainable=True, reuse=None): assert isinstance(grid, CenteredGrid) if grid.rank == 2: result = tf.layers.conv2d(grid.data, filters, kernel_size, strides=strides, activation=activation, padding=padding, name=name, use_bias=use_bias, trainable=trainable, reuse=reuse) if padding != 'valid': box = grid.box else: w_upper = kernel_size // 2 w_lower = (kernel_size - 1) // 2 box = AABox(grid.box.lower + w_lower * grid.dx, grid.box.upper - w_upper * grid.dx) return CenteredGrid(result, box=box, extrapolation=grid.extrapolation) else: raise NotImplementedError()
def test_struct_placeholders(self): obj = ([4], CenteredGrid([1, 4, 1], box[0:1], content_type=struct.shape), ([9], [8, 2])) tensorflow.reset_default_graph() p = placeholder(obj) self.assertEqual('Placeholder/0:0', p[0].name) self.assertEqual('Placeholder/1/data:0', p[1].data.name) self.assertIsInstance(p, tuple)
def dash_graph_plot(data, settings): # type: (object, dict) -> dict if data is None: return EMPTY_FIGURE if isinstance(data, np.ndarray): data = CenteredGrid(data) if isinstance(data, (CenteredGrid, StaggeredGrid)): component = settings.get('component', 'x') if data.rank == 1: return plot(data, settings) if data.rank == 2: if component == 'vec2' and data.component_count >= 2: return vector_field(data, settings) else: return heatmap(data, settings) if data.rank == 3: if component == 'vec2' and data.component_count >= 2: return vector_field(slice_2d(data, settings), settings) else: return heatmap(slice_2d(data, settings), settings) warnings.warn('No figure recipe for data %s' % data) return EMPTY_FIGURE
def poisson_gradient(_op, grad): return poisson_solve(CenteredGrid.sample( grad, poisson_domain.domain), poisson_domain, solver, None, gradient=gradient)[0].data
def _centered_grid(self, data, components=1, dtype=None, name=None, batch_size=None, extrapolation=None): warnings.warn( "Domain.centered_shape and Domain.centered_grid are deprecated. Use CenteredGrid.sample() instead.", DeprecationWarning) from phi.physics.field import CenteredGrid if extrapolation is None: extrapolation = Material.extrapolation_mode(self.boundaries) if callable(data): # data is an initializer shape = self.centered_shape(components, batch_size=batch_size, name=name, extrapolation=extrapolation, age=()) try: data = data(shape, dtype=dtype) except TypeError: data = data(shape) if data.age == (): data._age = 0.0 from phi.physics.field import Field if isinstance(data, Field): assert_same_rank(data.rank, self.rank, 'data does not match Domain') data = data.at(CenteredGrid.getpoints(self.box, self.resolution)) if name is not None: data = data.copied_with(name=name, extrapolation=extrapolation) data._batch_size = batch_size grid = data elif isinstance(data, (int, float)): shape = self.centered_shape(components, batch_size=batch_size, name=name, extrapolation=extrapolation, age=0.0) grid = math.zeros(shape, dtype=dtype) + data else: grid = CenteredGrid(data, box=self.box, extrapolation=extrapolation, name=name) return grid
def _residual_block_1d(grid, nb_channels, kernel_size=3, stride=1, activation=tf.nn.leaky_relu, _project_shortcut=False, padding="SYMMETRIC", name=None, training=False, trainable=True, reuse=tf.AUTO_REUSE): y = grid.data shortcut = y pad1 = [(kernel_size - 1) // 2, kernel_size // 2] # down-sampling is performed with a stride of 2 y = tf.pad(y, [[0, 0], pad1, [0, 0]], mode=padding) y = tf.layers.conv1d(y, nb_channels, kernel_size=kernel_size, strides=stride, padding='valid', name=None if name is None else name + "/conv1", trainable=trainable, reuse=reuse) # y = tf.layers.batch_normalization(y, name=None if name is None else name+"/norm1", training=training, trainable=trainable, reuse=reuse) y = activation(y) y = tf.pad(y, [[0, 0], pad1, [0, 0]], mode=padding) y = tf.layers.conv1d(y, nb_channels, kernel_size=kernel_size, strides=1, padding='valid', name=None if name is None else name + "/conv2", trainable=trainable, reuse=reuse) # y = tf.layers.batch_normalization(y, name=None if name is None else name+"/norm2", training=training, trainable=trainable, reuse=reuse) # identity shortcuts used directly when the input and output are of the same dimensions if _project_shortcut or stride != 1: # when the dimensions increase projection shortcut is used to match dimensions (done by 1×1 convolutions) # when the shortcuts go across feature maps of two sizes, they are performed with a stride of 2 shortcut = tf.pad(shortcut, [[0, 0], pad1, [0, 0]], mode=padding) shortcut = tf.layers.conv1d(shortcut, nb_channels, kernel_size=(1, 1), strides=stride, padding='valid', name=None if name is None else name + "/convid", trainable=trainable, reuse=reuse) # shortcut = tf.layers.batch_normalization(shortcut, name=None if name is None else name+"/normid", training=training, trainable=trainable, reuse=reuse) y += shortcut y = activation(y) return CenteredGrid(y, box=grid.box, extrapolation=grid.extrapolation)
def test_paths(self): obj = { 'Vels': [CenteredGrid(numpy.zeros([1, 4, 1]), box[0:1], name='v')] } with struct.unsafe(): names = struct.flatten( struct.map(lambda attr: attr.path(), obj, trace=True)) self.assertEqual(names[0], 'Vels.0.data')
def test_subtraction_centered_grid(self): """subtract one field from another""" shape = [32, 27] for boundary in [CLOSED, PERIODIC, OPEN]: domain = Domain(shape, boundaries=(boundary, boundary)) centered_grid = CenteredGrid.sample(Noise(), domain) result_array = (centered_grid - centered_grid).data np.testing.assert_array_equal(result_array, 0)
def test_addition_centered_grid(self): """add one field to another""" shape = [32, 27] for boundary in [CLOSED, PERIODIC, OPEN]: domain = Domain(shape, boundaries=(boundary, boundary)) centered_grid = CenteredGrid.sample(1, domain) result_array = (centered_grid + centered_grid).data np.testing.assert_array_equal(result_array, 2)
def slice_2d(field3d, settings): if isinstance(field3d, np.ndarray): field3d = CenteredGrid(field3d) if isinstance(field3d, StaggeredGrid): component = settings.get('component', 'length') if component in ('z', 'y', 'x'): field3d = field3d.unstack()[('z', 'y', 'x').index(component)] else: field3d = field3d.at_centers() assert isinstance(field3d, CenteredGrid) and field3d.rank == 3 depth = settings.get('depth', 0) projection = settings.get('projection', FRONT) if projection == FRONT: # Remove Y axis data = field3d.data[:, :, min(depth, field3d.resolution[1]), :, :] field2d = CenteredGrid(data, box=field3d.box.without_axis(1)) elif projection == RIGHT: # Remove X axis data = field3d.data[:, :, min(depth, field3d.resolution[2]), :, :] data = np.transpose(data, axes=(0, 2, 1, 3)) field2d = CenteredGrid(data, box=field3d.box.without_axis(2)) elif projection == TOP: # Remove Z axis data = field3d.data[:, min(depth, field3d.resolution[0]), :, :, :] field2d = CenteredGrid(data, box=field3d.box.without_axis(0)) else: raise ValueError('Unknown projection: %s' % projection) return field2d
def test_struct_placeholders(self): bounds = box[0:1] # outside unsafe with struct.unsafe(): obj = ([4], CenteredGrid([1, 4, 1], bounds), ([9], [8, 2])) tensorflow.reset_default_graph() p = placeholder(obj) self.assertEqual(p[0].name, '0:0') self.assertEqual(p[1].data.name, '1/data:0') self.assertIsInstance(p, tuple)
def test_division_centered_grid(self): """divide one field by another""" shape = [32, 27] for boundary in [CLOSED, PERIODIC, OPEN]: domain = Domain(shape, boundaries=(boundary, boundary)) centered_grid = CenteredGrid.sample(2, domain) result_array = (centered_grid / centered_grid.copied_with( data=4 * np.ones([1] + shape + [1]))).data np.testing.assert_array_equal(result_array, 1. / 2)
def test_multiplication_centered_grid(self): """multiply one field with another""" shape = [32, 27] for boundary in [CLOSED, PERIODIC, OPEN]: domain = Domain(shape, boundaries=(boundary, boundary)) centered_grid = CenteredGrid.sample(1, domain) result_array = (centered_grid * centered_grid.copied_with( data=2 * np.ones([1] + shape + [1]))).data np.testing.assert_array_equal(result_array, 2)
def test_struct_initializers(self): bounds = box[0:1] # outside unsafe with struct.unsafe(): obj = ([4], CenteredGrid([1, 4, 1], bounds), ([9], [8, 2])) z = math.zeros(obj) self.assertIsInstance(z, tuple) np.testing.assert_equal(z[0], np.zeros([4])) z2 = math.zeros_like(z) np.testing.assert_equal(math.shape(z)[0], math.shape(z2)[0])
def test_constant_resample(self): field = ConstantField([0, 1]) self.assertEqual(field.component_count, 2) # --- Resample to CenteredGrid --- at_cgrid = field.at(CenteredGrid(np.zeros([1, 4, 4, 1]))) np.testing.assert_equal(at_cgrid.data.shape, [1, 4, 4, 2]) # --- Resample to StaggeredGrid --- at_sgrid = field.at(Fluid([4, 4]).velocity) np.testing.assert_equal(at_sgrid.unstack()[0].data.shape, [1, 5, 4, 1]) np.testing.assert_equal(at_sgrid.unstack()[1].data.shape, [1, 4, 5, 1])
def test_mixed_boundaries_resample(self): data = np.reshape([[1,2], [3,4]], (1,2,2,1)) field = CenteredGrid(data, extrapolation=[('boundary', 'constant'), 'periodic']) print(data[0,...,0]) np.testing.assert_equal(field.sample_at([(0.5,0.5)]), [[1]]) np.testing.assert_equal(field.sample_at([[10,0.5]]), [[0]]) np.testing.assert_equal(field.sample_at([[0.5,2.5]]), [[1]]) np.testing.assert_equal(field.sample_at([[0.5,1.5]]), [[2]]) np.testing.assert_equal(field.sample_at([[-10,0.5]]), [[1]]) np.testing.assert_equal(field.sample_at([[-10,1.5]]), [[2]])
def test_reconst(self, set_accuracy=1e-5, shape=[40, 40], first_order_tolerance=3, second_order_tolerance=40, boundary_list=[PERIODIC, OPEN, CLOSED]): for boundary in boundary_list: domain = Domain(shape, boundaries=(boundary, boundary)) solver_list = [ ('SparseCG', lambda field: poisson_solve(field, domain, SparseCG(accuracy=set_accuracy)), lambda field: field.laplace()), ('GeometricCG', lambda field: poisson_solve(field, domain, GeometricCG(accuracy=set_accuracy)), lambda field: field.laplace()), #('SparseSciPy', lambda field: poisson_solve(field, domain, SparseSciPy()), lambda field: field.laplace()), # ('Fourier', lambda field: poisson_solve(field, domain, Fourier()))] # TODO: poisson_solve() causes resolution to be empty ('FFT', math.fourier_poisson, math.fourier_laplace)] in_data = CenteredGrid.sample(Noise(), domain) sloped_data = (np.array([np.arange(shape[1]) for _ in range(shape[0])]).reshape([1] + shape + [1]) / 10 + 1) in_data = in_data.copied_with(data=sloped_data) for name, solver, laplace in solver_list: print('Testing {} boundary with {} solver... '.format(boundary, name)), _test_reconstruction_first_order(in_data, solver, laplace, set_accuracy, name, first_order_tolerance=first_order_tolerance) _test_reconstruction_second_order(in_data, solver, laplace, set_accuracy, name, second_order_tolerance=second_order_tolerance) print('Testing {} boundary with {} solver... '.format(boundary, 'higher order FFT')), _run_higher_order_fft_reconstruction(in_data, set_accuracy, order=2, tolerance=second_order_tolerance)
def centered_shape(self, components=1, batch_size=1, name=None, extrapolation=None, age=0.0): warnings.warn( "Domain.centered_shape and Domain.centered_grid are deprecated. Use CenteredGrid.sample() instead.", DeprecationWarning) from phi.physics.field import CenteredGrid return CenteredGrid(tensor_shape(batch_size, self.resolution, components), age=age, box=self.box, extrapolation=extrapolation, name=name, batch_size=batch_size, flags=(), content_type=struct.Struct.shape)
def poisson_solve(input_field, poisson_domain, solver=None, guess=None, gradient='implicit'): """ Solves the Poisson equation Δp = input_field for p. :param gradient: one of ('implicit', 'autodiff', 'inverse') If 'autodiff', use the built-in autodiff for backpropagation. The intermediate results of each loop iteration will be permanently stored if backpropagation is used. If 'implicit', computes a forward pressure solve in reverse accumulation backpropagation. This requires less memory but is only accurate if the solution is fully converged. :param input_field: CenteredGrid :param poisson_domain: PoissonDomain instance :param solver: PoissonSolver to use, None for default :param guess: CenteredGrid with same size and resolution as input_field :return: p as CenteredGrid, iteration count as int or None if not available :rtype: CenteredGrid, int """ assert isinstance(input_field, CenteredGrid) if guess is not None: assert isinstance(guess, CenteredGrid) assert guess.compatible(input_field) guess = guess.data if isinstance(poisson_domain, Domain): poisson_domain = PoissonDomain(poisson_domain) if solver is None: solver = _choose_solver(input_field.resolution, math.choose_backend([input_field.data, poisson_domain.active.data, poisson_domain.accessible.data])) if not struct.any(Material.open(poisson_domain.domain.boundaries)): # has no open boundary input_field = input_field - math.mean(input_field.data, axis=tuple(range(1, 1 + input_field.rank)), keepdims=True) # Subtract mean divergence assert gradient in ('autodiff', 'implicit', 'inverse') if gradient == 'autodiff': pressure, iteration = solver.solve(input_field.data, poisson_domain, guess, enable_backprop=True) else: if gradient == 'implicit': def poisson_gradient(_op, grad): return poisson_solve(CenteredGrid.sample(grad, poisson_domain.domain), poisson_domain, solver, None, gradient=gradient)[0].data else: # gradient = 'inverse' def poisson_gradient(_op, grad): return CenteredGrid.sample(grad, poisson_domain.domain).laplace(physical_units=False).data pressure, iteration = math.with_custom_gradient(solver.solve, [input_field.data, poisson_domain, guess, False], poisson_gradient, input_index=0, output_index=0, name_base='poisson_solve') pressure = CenteredGrid(pressure, input_field.box, extrapolation=input_field.extrapolation, name='pressure') return pressure, iteration
def apply_A(pressure): pressure = CenteredGrid(pressure, extrapolation=extrapolation) pressure_padded = pressure.padded([[1, 1]] * pressure.rank) return _weighted_sliced_laplace_nd(pressure_padded.data, weights=fluid_mask)
def test_points_flag(self): data = math.zeros([1, 2, 3, 1]) f = CenteredGrid(data, box[0:2, 0:3]) p = f.points assert SAMPLE_POINTS in p.flags assert p.points is p
def test_compatibility(self): f = CenteredGrid(math.zeros([1, 3, 4, 1]), box[0:3, 0:4]) g = CenteredGrid(math.zeros([1, 3, 3, 1]), box[0:3, 0:4]) np.testing.assert_equal(f.dx, [1, 1]) self.assertTrue(f.points.compatible(f)) self.assertFalse(f.compatible(g))