def test_properties_dict(self): world = World() world.add(Fluid(Domain([16, 16])), physics=IncompressibleFlow()) world.add(Inflow(Sphere((8, 8), radius=4))) # world.add(ConstantDensity(box[0:2, 6:10], 1.0)) world.add(Fan(Sphere((10, 8), 5), [-1, 0])) struct.properties_dict(world.state)
def simulate(centers): world = World() fluid = world.add(Fluid(Domain([5, 4], boundaries=CLOSED, box=AABox(0, [40, 32])), buoyancy_factor=0.1, batch_size=centers.shape[0]), physics=IncompressibleFlow(pressure_solver=SparseCG(max_iterations=3))) world.add(Inflow(Sphere(center=centers, radius=3), rate=0.2)) world.add(Fan(Sphere(center=centers, radius=5), acceleration=[1.0, 0])) world.step(dt=1.5) world.step(dt=1.5) world.step(dt=1.5) print() return fluid.density.data[0, ...], fluid.velocity.unstack()[0].data[0, ...], fluid.velocity.unstack()[1].data[0, ...]
def simulate(centers): world = World() fluid = world.add(Fluid(Domain(x=5, y=4, bounds=Box(0, [40, 32])), buoyancy_factor=0.1, batch_size=centers.shape[0]), physics=IncompressibleFlow()) world.add(Inflow(Sphere(center=centers, radius=3), rate=0.2)) world.add(Fan(Sphere(center=centers, radius=5), acceleration=[1.0, 0])) world.step(dt=1.5) world.step(dt=1.5) world.step(dt=1.5) assert not math.close(fluid.density.values, 0) print() return fluid.density.values.batch[0], fluid.velocity.values.batch[0]
def points(self, points: Tensor or Number or tuple or list, values: Tensor or Number = None, radius: Tensor or float or int or None = None, extrapolation: math.Extrapolation = math.extrapolation.ZERO, color: str or Tensor or tuple or list or None = None) -> PointCloud: """ Create a `phi.field.PointCloud` from the given `points`. The created field has no channel dimensions and all points carry the value `1`. Args: points: point locations in physical units values: (optional) values of the particles, defaults to 1. radius: (optional) size of the particles extrapolation: (optional) extrapolation to use, defaults to extrapolation.ZERO color: (optional) color used when plotting the points Returns: `phi.field.PointCloud` object """ extrapolation = extrapolation if isinstance(extrapolation, math.Extrapolation) else self.boundaries[extrapolation] if radius is None: radius = math.mean(self.bounds.size) * 0.005 # --- Parse points: tuple / list --- if isinstance(points, (tuple, list)): if len(points) == 0: # no points points = math.zeros(instance(points=0), channel(vector=1)) elif isinstance(points[0], Number): # single point points = math.tensor([points], instance('points'), channel('vector')) else: points = math.tensor(points, instance('points'), channel('vector')) elements = Sphere(points, radius) if values is None: values = math.tensor(1.) return PointCloud(elements, values, extrapolation, add_overlapping=False, bounds=self.bounds, color=color)
def tensor_as_field(t: Tensor): """ Interpret a `Tensor` as a `CenteredGrid` or `PointCloud` depending on its dimensions. Unlike the `CenteredGrid` constructor, this function will have the values sampled at integer points for each spatial dimension. Args: t: `Tensor` with either `spatial` or `instance` dimensions. Returns: `CenteredGrid` or `PointCloud` """ if spatial(t): assert not instance( t ), f"Cannot interpret tensor as Field because it has both spatial and instance dimensions: {t.shape}" bounds = Box(-0.5, math.wrap(spatial(t), channel('vector')) - 0.5) return CenteredGrid(t, 0, bounds=bounds) if instance(t): assert not spatial( t ), f"Cannot interpret tensor as Field because it has both spatial and instance dimensions: {t.shape}" assert 'vector' in t.shape, f"Cannot interpret tensor as PointCloud because it has not vector dimension." point_count = instance(t).volume bounds = data_bounds(t) radius = math.vec_length( bounds.size) / (1 + point_count**(1 / t.vector.size)) return PointCloud(Sphere(t, radius=radius))
def respect_boundaries(particles: PointCloud, domain: Domain, not_accessible: list, offset: float = 0.5) -> PointCloud: """ Enforces boundary conditions by correcting possible errors of the advection step and shifting particles out of obstacles or back into the domain. Args: particles: PointCloud holding particle positions as elements domain: Domain for which any particles outside should get shifted inwards not_accessible: List of Obstacle or Geometry objects where any particles inside should get shifted outwards offset: Minimum distance between particles and domain boundary / obstacle surface after particles have been shifted. Returns: PointCloud where all particles are inside the domain / outside of obstacles. """ new_positions = particles.elements.center for obj in not_accessible: if isinstance(obj, Obstacle): obj = obj.geometry new_positions = obj.push(new_positions, shift_amount=offset) new_positions = (~domain.bounds).push(new_positions, shift_amount=offset) return particles.with_( elements=Sphere(new_positions, math.mean(particles.bounds.size) * 0.005))
def _test_make_incompressible(self, grid_type: type, extrapolation: math.Extrapolation, **batch_dims): result = None for i, backend in enumerate(BACKENDS): with backend: smoke = CenteredGrid(Sphere( center=(math.random_uniform(batch(**batch_dims)) * 100, 10), radius=5), extrapolation, x=16, y=20, bounds=Box[0:100, 0:100]) velocity = grid_type(0, extrapolation, x=16, y=20, bounds=Box[0:100, 0:100]) for _ in range(2): velocity += smoke * (0, 0.1) @ velocity velocity, _ = fluid.make_incompressible(velocity) math.assert_close(divergence(velocity).values, 0, abs_tolerance=2e-5) if result is None: result = velocity else: field.assert_close( result, abs_tolerance=1e-5, msg= f"Simulation with {backend} does not match {BACKENDS[:i]}" )
def test_gradient_batch_independence(self): session = Session(None) # Used to run the TensorFlow graph world = World() fluid = world.add(Fluid(Domain([40, 32], boundaries=CLOSED), buoyancy_factor=0.1, batch_size=2), physics=IncompressibleFlow()) world.add(Inflow(Sphere(center=numpy.array([[5, 4], [5, 8]]), radius=3), rate=0.2)) fluid.velocity = variable(fluid.velocity) # create TensorFlow variable # fluid.velocity *= 0 initial_state = fluid.state # Remember the state at t=0 for later visualization session.initialize_variables() for frame in range(3): world.step(dt=1.5) target = session.run(fluid.density).data[0, ...] loss = tf.nn.l2_loss(fluid.density.data[1, ...] - target) self_loss = tf.nn.l2_loss(fluid.density.data[0, ...] - target) # loss = self_loss optim = tf.train.GradientDescentOptimizer(learning_rate=0.2).minimize(loss) session.initialize_variables() for optim_step in range(3): _, loss_value, sl_value = session.run([optim, loss, self_loss]) staggered_velocity = session.run(initial_state.velocity).staggered_tensor() numpy.testing.assert_equal(staggered_velocity[0, ...], 0) assert numpy.all(~numpy.isnan(staggered_velocity))
def test_effects(self): world = World() fluid = world.add(Fluid(Domain([16, 16]))) fan = world.add(Fan(Sphere((10, 8), 5), [-1, 0])) obstacle = world.add(Obstacle(box[0:1, 0:1])) world.step(dt=1) world.step(dt=0.5) assert fluid.age == fan.age == obstacle.age == 1.5
def test_effects(self): world = World() fluid = world.add(Fluid(Domain(x=16, y=16)), physics=IncompressibleFlow()) fan = world.add(Fan(Sphere((10, 8), 5), [-1, 0])) obstacle = world.add(Obstacle(Box[0:1, 0:1])) world.step(dt=1) world.step(dt=0.5) assert fluid.age == fan.age == obstacle.age == 1.5
def test_plot_multiple(self): grid = CenteredGrid(Noise(batch(b=2)), 0, Box[0:1, 0:1], x=50, y=10) grid2 = CenteredGrid(grid, 0, Box[0:2, 0:1], x=20, y=50) points = wrap([(.2, .4), (.9, .8)], instance('points'), channel('vector')) cloud = PointCloud(Sphere(points, radius=0.1), bounds=Box(0, [1, 1])) titles = math.wrap([['b=0', 'b=0', 'points'], ['b=1', 'b=1', '']], spatial('rows,cols')) self._test_plot(grid, grid2, cloud, row_dims='b', title=titles)
def _test_make_incompressible_batched(self, grid_type): DOMAIN = Domain(x=16, y=16, boundaries=CLOSED, bounds=Box[0:100, 0:100]) smoke = DOMAIN.scalar_grid(Sphere(center=(math.random_uniform(batch=2) * 100, 10), radius=5)) velocity = DOMAIN.vector_grid(0, grid_type) for _ in range(2): velocity += smoke * (0, 0.1) >> velocity velocity, pressure, _, _ = fluid.make_incompressible(velocity, DOMAIN) math.assert_close(divergence(velocity).values, 0, abs_tolerance=2e-5) return velocity.values
def test_smoke_plume(self): world = World() world.batch_size = 3 fluid = world.add(Fluid(Domain(x=16, y=16)), physics=IncompressibleFlow()) inflow = world.add(Inflow(Sphere((8, 8), radius=4))) world.step() world.step(fluid) self.assertAlmostEqual(fluid.age, 2.0) self.assertAlmostEqual(inflow.age, 1.0)
def test_simpleplume(self): world = World() world.batch_size = 3 fluid = world.add(Fluid(Domain([16, 16]))) inflow = world.add(Inflow(Sphere((8, 8), radius=4))) world.step() world.step(fluid) self.assertAlmostEqual(fluid.age, 2.0) self.assertAlmostEqual(inflow.age, 1.0)
def test_convert_point_cloud(self): loc = math.random_uniform(instance(points=4), channel(vector=2)) val = math.random_normal(instance(points=4), channel(vector=2)) points = PointCloud(Sphere(loc, radius=1), val) for backend in BACKENDS: converted = field.convert(points, backend) self.assertEqual(converted.values.default_backend, backend) self.assertEqual(converted.elements.center.default_backend, backend) self.assertEqual(converted.elements.radius.default_backend, backend)
def test_overlay(self): grid = CenteredGrid(Noise(), extrapolation.ZERO, x=64, y=8, bounds=Box(0, [1, 1])) points = wrap([(.2, .4), (.9, .8)], instance('points'), channel('vector')) cloud = PointCloud(Sphere(points, radius=.1)) self._test_plot(overlay(grid, grid * (0.1, 0.02), cloud), title='Overlay')
def test_plot_point_cloud_2d_large(self): spheres = PointCloud( Sphere(wrap([(2, 4), (9, 8), (7, 8)], instance('points'), channel('vector')), radius=1)) cells = PointCloud( geom.pack_dims( CenteredGrid(0, 0, x=3, y=3, bounds=Box[4:6, 2:4]).elements, 'x,y', instance('points'))) cloud = field.stack([spheres, cells], instance('stack')) self._test_plot(cloud)
def test_plot_point_cloud_2d(self): spheres = PointCloud( Sphere(wrap([(.2, .4), (.9, .8), (.7, .8)], instance('points'), channel('vector')), radius=.1)) cells = PointCloud( geom.pack_dims( CenteredGrid(0, 0, x=3, y=3, bounds=Box[.4:.6, .2:.4]).elements, 'x,y', instance('points'))) cloud = field.stack([spheres, cells], instance('stack')) self._test_plot(cloud)
def test_fluid_tf(self): world = World() fluid = Fluid(Domain([16, 16])) world.add(fluid) world.add(Inflow(Sphere((8, 8), radius=4))) world.add(Obstacle(box[4:16, 0:8])) fluid_in = fluid.copied_with(density=placeholder, velocity=placeholder) fluid_out = world.step(fluid_in) self.assertIsInstance(fluid_out, Fluid) session = Session(Scene.create('data', copy_calling_script=False)) fluid = session.run(fluid_out, {fluid_in: fluid}) fluid = session.run(fluid_out, {fluid_in: fluid}) self.assertIsInstance(fluid, Fluid)
def test_plot_vector_3d_batched(self): sphere = CenteredGrid(SoftGeometryMask( Sphere(x=.5, y=.5, z=.5, radius=.4)), x=10, y=10, z=10, bounds=Box(x=1, y=1, z=1)) * (.1, 0, 0) cylinder = CenteredGrid(geom.infinite_cylinder( x=16, y=16, inf_dim='z', radius=10), x=32, y=32, z=32) * (0, 0, .1) self._test_plot(sphere, cylinder)
def test_batched_sphere(self): moving_sphere = Sphere(center=np.stack( [np.ones(10), np.linspace(0, 10, 10)], axis=-1), radius=1) growing_sphere = Sphere(center=0, radius=np.linspace(0, 10, 10)) # 0D indexing values = moving_sphere.value_at(np.zeros([10, 2]) + [1, 4]) np.testing.assert_equal(values[:, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0]) values = growing_sphere.value_at(np.zeros([10, 2]) + [0, 4]) np.testing.assert_equal(values[:, 0], [0, 0, 0, 0, 1, 1, 1, 1, 1, 1]) # 1D indexing values = moving_sphere.value_at(np.zeros([10, 3, 2]) + [1, 4]) np.testing.assert_equal(values.shape, [10, 3, 1]) np.testing.assert_equal(values[:, 0, 0], [0, 0, 0, 1, 1, 0, 0, 0, 0, 0]) values = growing_sphere.value_at(np.zeros([10, 3, 2]) + [0, 4]) np.testing.assert_equal(values.shape, [10, 3, 1]) np.testing.assert_equal(values[:, 0, 0], [0, 0, 0, 0, 1, 1, 1, 1, 1, 1])
def test_staggered_grid_sizes_by_extrapolation(self): s = spatial(x=20, y=10) for initializer in [0, Noise(vector=2), (0, 1), Sphere((0, 0), 1)]: g_const = StaggeredGrid(initializer, extrapolation.ZERO, resolution=s) self.assertEqual(g_const.shape, spatial(x=20, y=10) & channel(vector=2)) self.assertEqual(g_const.values.vector[0].shape, spatial(x=19, y=10)) g_periodic = StaggeredGrid(initializer, extrapolation.PERIODIC, resolution=s) self.assertEqual(g_periodic.shape, spatial(x=20, y=10) & channel(vector=2)) self.assertEqual(g_periodic.values.vector[0].shape, spatial(x=20, y=10)) g_boundary = StaggeredGrid(initializer, extrapolation.BOUNDARY, resolution=s) self.assertEqual(g_boundary.shape, spatial(x=20, y=10) & channel(vector=2)) self.assertEqual(g_boundary.values.vector[0].shape, spatial(x=21, y=10))
def test_union_varying(self): box = Box[0:1, 0:1] sphere = Sphere((0, 0), radius=1) union = geom.union(box, sphere) math.assert_close(union.approximate_signed_distance((1, 1)), union.approximate_signed_distance((0, -1)), 0)
def test_sphere_constructor_kwargs(self): s = Sphere(x=0.5, y=2, radius=1.) self.assertEqual(s.center.shape.get_item_names('vector'), ('x', 'y'))
def test_sphere_volume(self): sphere = Sphere(math.tensor([(0, 0, 0), (1, 1, 1)], batch('batch'), channel('vector')), radius=math.tensor([1, 2], batch('batch'))) math.assert_close(sphere.volume, [4 / 3 * math.PI, 4 / 3 * 8 * math.PI])
def test_circle_area(self): sphere = Sphere(math.tensor([(0, 0), (1, 1)], batch('batch'), channel('vector')), radius=math.tensor([1, 2], batch('batch'))) math.assert_close(sphere.volume, [math.PI, 4 * math.PI])
def geometry_at(time): return Sphere([time], radius=5)
def test_properties_dict(self): world = World() world.add(Fluid(Domain(x=16, y=16)), physics=IncompressibleFlow()) world.add(Inflow(Sphere((8, 8), radius=4))) world.add(Fan(Sphere((10, 8), 5), [-1, 0])) struct.properties_dict(world.state)
def test_effects(self): world = World() world.add(Fluid(Domain([16, 16]))) world.add(Fan(Sphere((10, 8), 5), [-1, 0])) world.step() world.step()
def elements(self): return Sphere(self.sample_points, radius=0.0)