示例#1
0
 def test_domain_grid_from_constant(self):
     domain = Domain(x=4, y=3)
     # int / float
     grid = domain.scalar_grid(1)
     math.assert_close(grid.values, 1)
     # complex
     grid = domain.grid(1 + 1j)
     math.assert_close(grid.values, 1 + 1j)
     # NumPy
     grid = domain.grid(numpy.array(1))
     math.assert_close(grid.values, 1)
     # PyTorch
     grid = domain.grid(torch.tensor(1, dtype=torch.float32))
     math.assert_close(grid.values, 1)
     # TensorFlow
     grid = domain.grid(tf.constant(1, tf.float32))
     math.assert_close(grid.values, 1)
示例#2
0
        def test_demo_vs_numpy(self):
            dt = 0.1
            # Physical parameters
            L = 4 * 2 * np.pi  # 2 * np.pi / 0.15  # 4*2*np.pi#/0.15
            c1 = 5  # 0.01
            # Numerical Parameters
            grid_pts = 64
            nu = 0  # 1e-8
            N = 0  # 3
            arakawa_coeff = 0
            kappa_coeff = 0
            # Derived Parameters
            dx = L / grid_pts
            k0 = 2 * np.pi / L
            # Get input data
            rnd_noise = np.random.rand(grid_pts * grid_pts).reshape(
                grid_pts, grid_pts)
            sine = get_2d_sine((grid_pts, grid_pts), L)
            init_values = sine / 1000
            density_coeff = 1
            omega_coeff = -1 / 2
            phi_coeff = -1 / 2
            x = grid_pts
            y = grid_pts
            params = dict(c1=c1,
                          nu=nu,
                          N=N,
                          arakawa_coeff=arakawa_coeff,
                          kappa_coeff=kappa_coeff)
            # NumPy reference
            hw = HW(
                c1=c1,
                nu=nu,
                N=N,
                arakawa_coeff=arakawa_coeff,
                kappa_coeff=kappa_coeff,
                debug=False,
            )
            hw_state_numpy = Namespace(
                density=init_values * density_coeff,
                omega=init_values * omega_coeff,
                phi=init_values * phi_coeff,
                age=0,
                dx=dx,
            )
            # Phi version
            domain = Domain(x=x,
                            y=y,
                            boundaries=PERIODIC,
                            bounds=Box[0:L, 0:L])
            hw_state_phi = Namespace(
                density=domain.grid(
                    math.tensor(init_values * density_coeff, names=["x",
                                                                    "y"])),
                omega=domain.grid(
                    math.tensor(init_values * omega_coeff, names=["x", "y"])),
                phi=domain.grid(
                    math.tensor(init_values * phi_coeff, names=["x", "y"])),
                # domain=domain,
                age=0,
                dx=dx,
            )
            from functools import partial

            get_phi = partial(get_domain_phi, domain=domain)
            rk4_step2 = partial(rk4_step, params=params, get_phi=get_phi)
            app = App("Hasegawa-Wakatani", dt=dt)
            app.set_state(hw_state_phi,
                          step_function=rk4_step2,
                          show=["density", "omega", "phi"])
            app.prepare()

            # Run
            def compare(iterable):
                for k in iterable[0].keys():
                    compare = []
                    for state in iterable:
                        if isinstance(state[k], field._grid.Grid):
                            val = state[k].values.numpy(order="x,y,z")[0]
                        else:
                            val = state[k]
                        compare.append(val)
                    assert len(compare) == 2
                    print(f"  {k:<7}:" +
                          f"  {np.max(np.abs(compare[0]-compare[1])):.7f}" +
                          f"  {np.array_equal(*compare)}" +
                          f"  {np.max(np.abs(compare[0]-compare[1])):.2g}")
                return True

            np_times = []
            phi_times = []
            for i in range(0, STEPS + 1):
                print(f"step {i:>3} {i*dt:>12.7f}")
                # Numpy
                t0 = time.time()
                hw_state_numpy = hw.rk4_step(hw_state_numpy, dt=dt)
                np_time = time.time() - t0
                np_times.append(np_time)
                # Phi
                t0 = time.time()
                app.step()
                phi_time = time.time() - t0
                phi_times.append(phi_time)
                hw_state_phi = app.state
                compare([hw_state_numpy, hw_state_phi])
                # if i % 100 == 0:
                #    plot({'numpy': hw_state_numpy.density,
                #          'phi': hw_state_phi.density.values.numpy(order='zyx')[0],
                #          'diff': hw_state_numpy.density - hw_state_phi.density.values.numpy(order='zyx')[0]},
                #         title=f"step: {i}")
                # assert np.allclose(hw_state_numpy.density, hw_state_phi.density.values.numpy(order='zyx')[0])
            print(f"Comparison | NumPy      | PhiFlow")

            def get_str(name, func, vals):
                return " | ".join([
                    f"{name:<10}",
                    f"{func(vals[0]):<10.4f}",
                    f"{func(vals[1]):<10.4f}",
                ])

            print(get_str("Mean (s)", np.mean, (np_times, phi_times)))
            print(get_str("Median (s)", np.median, (np_times, phi_times)))
            print(get_str("Min (s)", np.min, (np_times, phi_times)))
            print(get_str("Max (s)", np.max, (np_times, phi_times)))
示例#3
0
 def test_gradient(self):
     domain = Domain(x=4, y=3)
     phi = domain.grid() * (1, 2)
     grad = field.gradient(phi, stack_dim='gradient')
     self.assertEqual(('spatial', 'spatial', 'channel', 'channel'),
                      grad.shape.types)
示例#4
0
 def test_domain_grid_memory_allocation(self):
     domain = Domain(x=10000, y=10000, z=10000, w=10000)
     grid = domain.grid()
     self.assertEqual((10000, ) * 4, grid.shape.sizes)
     sgrid = domain.staggered_grid()
     self.assertEqual((10000, 10000, 10000, 10000, 4), sgrid.shape.sizes)
示例#5
0
 def test_domain_grid_from_tensor(self):
     domain = Domain(x=4, y=3)
     grid = domain.grid(Noise(vector=2))
     grid2 = domain.grid(grid.values)
     math.assert_close(grid.values, grid2.values)
示例#6
0
文件: flip.py 项目: salbali/PhiFlow
def make_incompressible(
    velocity: StaggeredGrid,
    domain: Domain,
    obstacles: tuple or list or StaggeredGrid = (),
    particles: PointCloud or None = None,
    solve_params: math.LinearSolve = math.LinearSolve(),
    pressure_guess: CenteredGrid = None
) -> Tuple[StaggeredGrid, CenteredGrid, math.Tensor, CenteredGrid,
           StaggeredGrid]:
    """
    Projects the given velocity field by solving for the pressure and subtracting its spatial_gradient.

    Args:
        velocity: Current velocity field as StaggeredGrid
        obstacles: Sequence of `phi.physics.Obstacle` objects or binary StaggeredGrid marking through-flow cell faces
        particles (Optional if occupation masks are provided): Pointcloud holding the current positions of the particles
        domain (Optional if occupation masks are provided): Domain object
        pressure_guess (Optional): Initial pressure guess as CenteredGrid
        solve_params: Parameters for the pressure solve

    Returns:
      velocity: divergence-free velocity of type `type(velocity)`
      pressure: solved pressure field, `CenteredGrid`
      iterations: Number of iterations required to solve for the pressure
      divergence: divergence field of input velocity, `CenteredGrid`
      occupation_mask: StaggeredGrid
    """
    points = particles.with_(values=math.wrap(1))
    occupied_centered = points >> domain.grid()
    occupied_staggered = points >> domain.staggered_grid()

    if isinstance(obstacles, StaggeredGrid):
        accessible = obstacles
    else:
        accessible = domain.accessible_mask(
            union(*[obstacle.geometry for obstacle in obstacles]),
            type=StaggeredGrid)

    # --- Extrapolation is needed to exclude border divergence from the `occupied_centered` mask and thus
    # from the pressure solve. If particles are randomly distributed, the `occupied_centered` mask
    # could sometimes include the divergence at the borders (due to single particles right at the edge
    # which temporarily deform the `occupied_centered` mask when moving into a new cell) which would then
    # get compensated by the pressure. This is unwanted for falling liquids and therefore prevented by this
    # extrapolation. ---
    velocity_field, _ = extrapolate_valid(velocity * occupied_staggered,
                                          occupied_staggered, 1)
    velocity_field *= accessible  # Enforces boundary conditions after extrapolation
    div = field.divergence(
        velocity_field
    ) * occupied_centered  # Multiplication with `occupied_centered` excludes border divergence from pressure solve

    def matrix_eq(p):
        return field.where(
            occupied_centered,
            field.divergence(
                field.spatial_gradient(p, type=StaggeredGrid) * accessible), p)

    converged, pressure, iterations = field.solve(matrix_eq,
                                                  div,
                                                  pressure_guess
                                                  or domain.grid(),
                                                  solve_params=solve_params)
    gradp = field.spatial_gradient(pressure,
                                   type=type(velocity_field)) * accessible
    return velocity_field - gradp, pressure, iterations, div, occupied_staggered