예제 #1
0
def test_solve_spherical():
    pde = laplacian_spherical
    generator = ExampleGeneratorSpherical(512)

    # 0-boundary condition; solution should be u(r, theta, phi) = 0 identically
    f = lambda th, ph: 0.
    g = lambda th, ph: 0.
    condition = DirichletBVPSpherical(r_0=0., f=f, r_1=1., g=g)
    solution, loss_history = solve_spherical(pde,
                                             condition,
                                             0.0,
                                             1.0,
                                             max_epochs=500,
                                             return_best=True)
    rs, thetas, phis = generator.get_examples()
    us = solution(rs, thetas, phis, as_type='np')
    assert np.isclose(us, np.zeros_like(us),
                      atol=0.005).all(), f"Solution is not straight 0s: {us}"

    # 1-boundary condition; solution should be u(r, theta, phi) = 1 identically
    f = lambda th, ph: 1.
    g = lambda th, ph: 1.
    condition = DirichletBVPSpherical(r_0=0., f=f, r_1=1., g=g)
    solution, loss_history = solve_spherical(pde,
                                             condition,
                                             0.0,
                                             1.0,
                                             max_epochs=500,
                                             return_best=True)
    rs, thetas, phis = generator.get_examples()
    us = solution(rs, thetas, phis, as_type='np')
    assert np.isclose(us, np.ones_like(us),
                      atol=0.005).all(), f"Solution is not straight 1s: {us}"

    print("solve_spherical tests passed")
예제 #2
0
def test_monitor_spherical():
    pde = laplacian_spherical

    f = lambda th, ph: 0.
    g = lambda th, ph: 0.
    condition = DirichletBVPSpherical(r_0=0., f=f, r_1=1., g=g)
    monitor = MonitorSpherical(0.0, 1.0, check_every=1)
    solve_spherical(pde, condition, 0.0, 1.0, max_epochs=50, monitor=monitor)

    print("MonitorSpherical test passed")
예제 #3
0
def test_train_generator_spherical():
    pde = laplacian_spherical
    condition = NoConditionSpherical()
    train_generator = ExampleGeneratorSpherical(size=64,
                                                r_min=0.,
                                                r_max=1.,
                                                method='equally-spaced-noisy')
    r, th, ph = train_generator.get_examples()
    assert (0. < r.min()) and (r.max() < 1.)
    assert (0. <= th.min()) and (th.max() <= np.pi)
    assert (0. <= ph.min()) and (ph.max() <= 2 * np.pi)

    valid_generator = ExampleGeneratorSpherical(size=64,
                                                r_min=1.,
                                                r_max=1.,
                                                method='equally-radius-noisy')
    r, th, ph = valid_generator.get_examples()
    assert (r == 1).all()
    assert (0. <= th.min()) and (th.max() <= np.pi)
    assert (0. <= ph.min()) and (ph.max() <= 2 * np.pi)

    solve_spherical(pde,
                    condition,
                    0.0,
                    1.0,
                    train_generator=train_generator,
                    valid_generator=valid_generator,
                    max_epochs=5)
    with raises(ValueError):
        _ = ExampleGeneratorSpherical(64, method='bad_generator')

    with raises(ValueError):
        _ = ExampleGeneratorSpherical(64, r_min=-1.0)

    with raises(ValueError):
        _ = ExampleGeneratorSpherical(64, r_min=1.0, r_max=0.0)

    print("GeneratorSpherical tests passed")
예제 #4
0
def test_electric_potential_uniformly_charged_ball():
    """
    electric potential on uniformly charged solid sphere
    refer to http://www.phys.uri.edu/~gerhard/PHY204/tsl94.pdf
    """
    # free charge volume density
    rho = 1.
    # medium permittivity
    epsilon = 1.
    # Coulomb constant
    k = 1. / (4 * np.pi * epsilon)
    # radius of the ball
    R = 1.
    # total electric charge on solid sphere
    Q = (4 / 3) * np.pi * (R**3) * rho
    # electric potential at sphere center
    v_0 = 1.5 * k * Q / R
    # electric potential on sphere boundary
    v_R = k * Q / R
    # analytic solution of electric potential
    analytic_solution = lambda r, th, ph: k * Q / (2 * R) * (3 - (r / R)**2)

    pde = lambda u, r, theta, phi: laplacian_spherical(u, r, theta, phi
                                                       ) + rho / epsilon
    condition = DirichletBVPSpherical(r_0=0.,
                                      f=lambda th, ph: v_0,
                                      r_1=R,
                                      g=lambda th, ph: v_R)
    monitor = MonitorSpherical(0.0, R, check_every=50)

    solution, loss_history, analytic_mse = solve_spherical(
        pde,
        condition,
        0.,
        R,
        max_epochs=500,
        return_best=True,
        analytic_solution=analytic_solution,
        monitor=monitor)
    generator = ExampleGeneratorSpherical(512)
    rs, thetas, phis = generator.get_examples()
    us = solution(rs, thetas, phis, as_type="np")
    vs = analytic_solution(rs, thetas, phis).detach().cpu().numpy()
    abs_diff = abs(us - vs)

    assert np.isclose(us, vs, atol=0.008).all(), \
        f"Solution doesn't match analytic expectation {us} != {vs}, abs_diff={abs_diff}"

    print("electric-potential-on-uniformly-charged-solid-sphere passed")
예제 #5
0
def test_solve_spherical():
    pde = laplacian_spherical
    generator = GeneratorSpherical(512)

    # 0-boundary condition; solution should be u(r, theta, phi) = 0 identically
    f = lambda th, ph: 0.
    g = lambda th, ph: 0.
    condition = DirichletBVPSpherical(r_0=0., f=f, r_1=1., g=g)
    with pytest.warns(FutureWarning):
        solution, loss_history = solve_spherical(pde,
                                                 condition,
                                                 0.0,
                                                 1.0,
                                                 max_epochs=2,
                                                 return_best=True)
    assert isinstance(solution, SolutionSpherical)
예제 #6
0
def test_solve_spherical():
    pde = laplacian_spherical
    generator = GeneratorSpherical(512)

    # 0-boundary condition; solution should be u(r, theta, phi) = 0 identically
    f = lambda th, ph: 0.
    g = lambda th, ph: 0.
    condition = DirichletBVPSpherical(r_0=0., f=f, r_1=1., g=g)
    solution, loss_history = solve_spherical(pde,
                                             condition,
                                             0.0,
                                             1.0,
                                             max_epochs=2,
                                             return_best=True)
    rs, thetas, phis = generator.get_examples()
    us = solution(rs, thetas, phis, as_type='np')
예제 #7
0
def test_electric_potential_gaussian_charged_density():
    # total charge
    Q = 1.
    # standard deviation of gaussian
    sigma = 1.
    # medium permittivity
    epsilon = 1.
    # Coulomb constant
    k = 1 / (4 * np.pi * epsilon)
    # coefficient of gaussian term
    gaussian_coeff = Q / (sigma**3) / np.power(2 * np.pi, 1.5)
    # distribution of charge
    rho_f = lambda r: gaussian_coeff * torch.exp(-r.pow(2) / (2 * sigma**2))
    # analytic solution, refer to https://en.wikipedia.org/wiki/Poisson%27s_equation
    analytic_solution = lambda r, th, ph: (k * Q / r) * torch.erf(r / (np.sqrt(
        2) * sigma))

    pde = lambda u, r, th, ph: laplacian_spherical(u, r, th, ph) + rho_f(
        r) / epsilon
    r_0, r_1 = 0.1, 3.
    v_0 = (k * Q / r_0) * erf(r_0 / (np.sqrt(2) * sigma))
    v_1 = (k * Q / r_1) * erf(r_1 / (np.sqrt(2) * sigma))
    condition = DirichletBVPSpherical(r_0, lambda th, ph: v_0, r_1,
                                      lambda th, ph: v_1)
    monitor = MonitorSpherical(r_0, r_1, check_every=50)

    solution, loss_history, analytic_mse = solve_spherical(
        pde,
        condition,
        r_0,
        r_1,
        max_epochs=500,
        return_best=True,
        analytic_solution=analytic_solution,
        monitor=monitor)

    generator = ExampleGeneratorSpherical(512, r_min=r_0, r_max=r_1)
    rs, thetas, phis = generator.get_examples()
    us = solution(rs, thetas, phis, as_type="np")
    vs = analytic_solution(rs, thetas, phis).detach().cpu().numpy()
    rdiff = abs(us - vs) / vs
    assert np.isclose(us, vs, rtol=0.05).all(), \
        f"Solution doesn't match analytic expectattion {us} != {vs}, relative-diff={rdiff}"

    print("electric-potential-on-gaussian-charged-density passed")
예제 #8
0
def test_electric_potential_gaussian_charged_density():
    # total charge
    Q = 1.
    # standard deviation of gaussian
    sigma = 1.
    # medium permittivity
    epsilon = 1.
    # Coulomb constant
    k = 1 / (4 * np.pi * epsilon)
    # coefficient of gaussian term
    gaussian_coeff = Q / (sigma**3) / np.power(2 * np.pi, 1.5)
    # distribution of charge
    rho_f = lambda r: gaussian_coeff * torch.exp(-r.pow(2) / (2 * sigma**2))
    # analytic solution, refer to https://en.wikipedia.org/wiki/Poisson%27s_equation
    analytic_solution = lambda r, th, ph: (k * Q / r) * torch.erf(r / (np.sqrt(
        2) * sigma))

    # interior and exterior radius
    r_0, r_1 = 0.1, 3.
    # values at interior and exterior boundary
    v_0 = (k * Q / r_0) * erf(r_0 / (np.sqrt(2) * sigma))
    v_1 = (k * Q / r_1) * erf(r_1 / (np.sqrt(2) * sigma))

    def validate(solution):
        generator = GeneratorSpherical(512, r_min=r_0, r_max=r_1)
        rs, thetas, phis = generator.get_examples()
        us = solution(rs, thetas, phis, to_numpy=True)
        vs = analytic_solution(rs, thetas, phis).detach().cpu().numpy()
        assert us.shape == vs.shape

    # solving the problem using normal network (subject to the influence of polar singularity of laplacian operator)

    pde1 = lambda u, r, th, ph: laplacian_spherical(u, r, th, ph) + rho_f(
        r) / epsilon
    condition1 = DirichletBVPSpherical(r_0, lambda th, ph: v_0, r_1,
                                       lambda th, ph: v_1)
    monitor1 = MonitorSpherical(r_0, r_1, check_every=50)
    with pytest.warns(FutureWarning):
        solution1, metrics_history = solve_spherical(
            pde1,
            condition1,
            r_0,
            r_1,
            max_epochs=2,
            return_best=True,
            analytic_solution=analytic_solution,
            monitor=monitor1,
        )
    validate(solution1)

    # solving the problem using spherical harmonics (laplcian computation is optimized)
    max_degree = 2
    harmonics_fn = RealSphericalHarmonics(max_degree=max_degree)
    harmonic_laplacian = HarmonicsLaplacian(max_degree=max_degree)
    pde2 = lambda R, r, th, ph: harmonic_laplacian(R, r, th, ph) + rho_f(
        r) / epsilon
    R_0 = torch.tensor([v_0 * 2] + [0 for _ in range((max_degree + 1)**2 - 1)])
    R_1 = torch.tensor([v_1 * 2] + [0 for _ in range((max_degree + 1)**2 - 1)])

    def analytic_solution2(r, th, ph):
        sol = torch.zeros(r.shape[0], (max_degree + 1)**2)
        sol[:, 0:1] = 2 * analytic_solution(r, th, ph)
        return sol

    condition2 = DirichletBVPSphericalBasis(r_0=r_0,
                                            R_0=R_0,
                                            r_1=r_1,
                                            R_1=R_1,
                                            max_degree=max_degree)
    monitor2 = MonitorSphericalHarmonics(r_0,
                                         r_1,
                                         check_every=50,
                                         harmonics_fn=harmonics_fn)
    net2 = FCNN(n_input_units=1, n_output_units=(max_degree + 1)**2)
    with pytest.warns(FutureWarning):
        solution2, metrics_history = solve_spherical(
            pde2,
            condition2,
            r_0,
            r_1,
            net=net2,
            max_epochs=2,
            return_best=True,
            analytic_solution=analytic_solution2,
            monitor=monitor2,
            harmonics_fn=harmonics_fn,
        )
    validate(solution2)