Ejemplo n.º 1
0
def test_laplace():

    laplace = lambda u, x, y: diff(u, x, order=2) + diff(u, y, order=2)
    bc = DirichletBVP2D(x_min=0,
                        x_min_val=lambda y: torch.sin(np.pi * y),
                        x_max=1,
                        x_max_val=lambda y: 0,
                        y_min=0,
                        y_min_val=lambda x: 0,
                        y_max=1,
                        y_max_val=lambda x: 0)

    net = FCNN(n_input_units=2, hidden_units=(32, 32))
    solution_neural_net_laplace, _ = solve2D(pde=laplace,
                                             condition=bc,
                                             xy_min=(0, 0),
                                             xy_max=(1, 1),
                                             net=net,
                                             max_epochs=300,
                                             train_generator=Generator2D(
                                                 (32, 32), (0, 0), (1, 1),
                                                 method='equally-spaced-noisy',
                                                 xy_noise_std=(0.01, 0.01)),
                                             batch_size=64)
    solution_analytical_laplace = lambda x, y: np.sin(np.pi * y) * np.sinh(
        np.pi * (1 - x)) / np.sinh(np.pi)

    xs, ys = np.linspace(0, 1, 101), np.linspace(0, 1, 101)
    xx, yy = np.meshgrid(xs, ys)
    sol_net = solution_neural_net_laplace(xx, yy, as_type='np')
    sol_ana = solution_analytical_laplace(xx, yy)
    assert isclose(sol_net, sol_ana, atol=0.01).all()
    print('Laplace test passed.')
Ejemplo n.º 2
0
def test_monitor():

    laplace = lambda u, x, y: diff(u, x, order=2) + diff(u, y, order=2)
    bc = DirichletBVP2D(x_min=0,
                        x_min_val=lambda y: torch.sin(np.pi * y),
                        x_max=1,
                        x_max_val=lambda y: 0,
                        y_min=0,
                        y_min_val=lambda x: 0,
                        y_max=1,
                        y_max_val=lambda x: 0)

    net = FCNN(n_input_units=2, hidden_units=(32, 32))
    solution_neural_net_laplace, _ = solve2D(
        pde=laplace,
        condition=bc,
        xy_min=(0, 0),
        xy_max=(1, 1),
        net=net,
        max_epochs=3,
        train_generator=Generator2D((32, 32), (0, 0), (1, 1),
                                    method='equally-spaced-noisy'),
        batch_size=64,
        monitor=Monitor2D(check_every=1, xy_min=(0, 0), xy_max=(1, 1)))
    print('Monitor test passed.')
Ejemplo n.º 3
0
def test_laplace():
    laplace = lambda u, x, y: diff(u, x, order=2) + diff(u, y, order=2)
    bc = DirichletBVP2D(x_min=0,
                        x_min_val=lambda y: torch.sin(np.pi * y),
                        x_max=1,
                        x_max_val=lambda y: 0,
                        y_min=0,
                        y_min_val=lambda x: 0,
                        y_max=1,
                        y_max_val=lambda x: 0)

    net = FCNN(n_input_units=2, hidden_units=(32, 32))
    solution_neural_net_laplace, loss_history = solve2D(
        pde=laplace,
        condition=bc,
        xy_min=(0, 0),
        xy_max=(1, 1),
        net=net,
        max_epochs=3,
        train_generator=Generator2D((32, 32), (0, 0), (1, 1),
                                    method='equally-spaced-noisy',
                                    xy_noise_std=(0.01, 0.01)),
        batch_size=64)
    assert isinstance(solution_neural_net_laplace, Solution2D)
    assert isinstance(loss_history, dict)
    keys = ['train_loss', 'valid_loss']
    for key in keys:
        assert key in loss_history
        assert isinstance(loss_history[key], list)
    assert len(loss_history[keys[0]]) == len(loss_history[keys[1]])
Ejemplo n.º 4
0
def test_train_generator():
    laplace = lambda u, x, y: diff(u, x, order=2) + diff(u, y, order=2)
    bc = DirichletBVP2D(
        x_min=0, x_min_val=lambda y: torch.sin(np.pi * y),
        x_max=1, x_max_val=lambda y: 0,
        y_min=0, y_min_val=lambda x: 0,
        y_max=1, y_max_val=lambda x: 0
    )

    net = FCNN(n_input_units=2, hidden_units=(32, 32))
    solution_neural_net_laplace, _ = solve2D(
        pde=laplace, condition=bc, xy_min=(0, 0), xy_max=(1, 1),
        net=net, max_epochs=3,
        train_generator=Generator2D((32, 32), (0, 0), (1, 1), method='equally-spaced-noisy'),
        batch_size=64,
        monitor=Monitor2D(check_every=1, xy_min=(0, 0), xy_max=(1, 1))
    )

    train_gen = Generator2D((32, 32), (0, 0), (1, 1), method='equally-spaced')
    solution_neural_net_laplace, _ = solve2D(
        pde=laplace, condition=bc, xy_min=(0, 0), xy_max=(1, 1),
        net=net, max_epochs=3, train_generator=train_gen, batch_size=64
    )
    train_gen = Generator2D((32, 32), (0, 0), (1, 1), method='equally-spaced-noisy')
    solution_neural_net_laplace, _ = solve2D(
        pde=laplace, condition=bc, xy_min=(0, 0), xy_max=(1, 1),
        net=net, max_epochs=3, train_generator=train_gen, batch_size=64
    )

    with raises(ValueError):
        train_gen = Generator2D((32, 32), (0, 0), (1, 1), method='magic')

    valid_gen = Generator2D((32, 32), (0, 0), (1, 1), method='equally-spaced-noisy')
    train_gen = Generator2D((32, 32), (0, 0), (1, 1), method='equally-spaced')
    solution_neural_net_laplace, _ = solve2D(
        pde=laplace, condition=bc,
        net=net, max_epochs=3, train_generator=train_gen, valid_generator=valid_gen, batch_size=64
    )

    with raises(RuntimeError):
        solution_neural_net_laplace, _ = solve2D(
            pde=laplace, condition=bc,
            net=net, max_epochs=3, batch_size=64
        )
Ejemplo n.º 5
0
def test_train_generator():
    laplace = lambda u, x, y: diff(u, x, order=2) + diff(u, y, order=2)
    bc = DirichletBVP2D(x_min=0,
                        x_min_val=lambda y: torch.sin(np.pi * y),
                        x_max=1,
                        x_max_val=lambda y: 0,
                        y_min=0,
                        y_min_val=lambda x: 0,
                        y_max=1,
                        y_max_val=lambda x: 0)

    net = FCNN(n_input_units=2, hidden_units=(32, 32))

    with pytest.raises(ValueError), pytest.warns(FutureWarning):
        solution_neural_net_laplace, _ = solve2D(pde=laplace,
                                                 condition=bc,
                                                 net=net,
                                                 max_epochs=3,
                                                 batch_size=64)
Ejemplo n.º 6
0
def test_heat():

    k, L, T = 0.3, 2, 3
    heat = lambda u, x, t: diff(u, t) - k * diff(u, x, order=2)

    ibvp = IBVP1D(x_min=0,
                  x_min_val=lambda t: 0,
                  x_max=L,
                  x_max_val=lambda t: 0,
                  t_min=0,
                  t_min_val=lambda x: torch.sin(np.pi * x / L))
    net = FCNN(n_input_units=2, hidden_units=(32, 32))

    def mse(u, x, y):
        true_u = torch.sin(np.pi * y) * torch.sinh(np.pi *
                                                   (1 - x)) / np.sinh(np.pi)
        return torch.mean((u - true_u)**2)

    solution_neural_net_heat, _ = solve2D(pde=heat,
                                          condition=ibvp,
                                          xy_min=(0, 0),
                                          xy_max=(L, T),
                                          net=net,
                                          max_epochs=300,
                                          train_generator=Generator2D(
                                              (32, 32), (0, 0), (L, T),
                                              method='equally-spaced-noisy'),
                                          batch_size=64,
                                          metrics={'mse': mse})
    solution_analytical_heat = lambda x, t: np.sin(np.pi * x / L) * np.exp(
        -k * np.pi**2 * t / L**2)

    xs = np.linspace(0, L, 101)
    ts = np.linspace(0, T, 101)
    xx, tt = np.meshgrid(xs, ts)
    make_animation(solution_neural_net_heat, xs, ts)  # test animation
    sol_ana = solution_analytical_heat(xx, tt)
    sol_net = solution_neural_net_heat(xx, tt, as_type='np')
    assert isclose(sol_net, sol_ana, atol=0.01).all()
    print('Heat test passed.')
Ejemplo n.º 7
0
def test_neumann_boundaries_2():

    k, L, T = 0.3, 2, 3
    heat = lambda u, x, t: diff(u, t) - k * diff(u, x, order=2)
    solution_analytical_heat = lambda x, t: np.sin(np.pi * x / L) * np.exp(
        -k * np.pi**2 * t / L**2)

    # Neumann on the left Dirichlet on the right
    ibvp = IBVP1D(
        x_min=0,
        x_min_prime=lambda t: np.pi / L * torch.exp(-k * np.pi**2 * t / L**2),
        x_max=L,
        x_max_val=lambda t: 0,
        t_min=0,
        t_min_val=lambda x: torch.sin(np.pi * x / L))

    net = FCNN(n_input_units=2, hidden_units=(32, 32))

    solution_neural_net_heat, _ = solve2D(pde=heat,
                                          condition=ibvp,
                                          xy_min=(0, 0),
                                          xy_max=(L, T),
                                          net=net,
                                          max_epochs=300,
                                          train_generator=Generator2D(
                                              (32, 32), (0, 0), (L, T),
                                              method='equally-spaced-noisy'),
                                          batch_size=64)

    xs = np.linspace(0, L, 101)
    ts = np.linspace(0, T, 101)
    xx, tt = np.meshgrid(xs, ts)
    make_animation(solution_neural_net_heat, xs, ts)  # test animation
    sol_ana = solution_analytical_heat(xx, tt)
    sol_net = solution_neural_net_heat(xx, tt, as_type='np')
    assert isclose(sol_net, sol_ana, atol=0.1).all()
    print('Neumann on the left Dirichlet on the right test passed.')
Ejemplo n.º 8
0
def test_arbitrary_boundary():
    def solution_analytical_problem_c(x, y):
        return np.log(1 + x**2 + y**2)

    def gradient_solution_analytical_problem_c(x, y):
        return 2 * x / (1 + x**2 + y**2), 2 * y / (1 + x**2 + y**2),

    # creating control points for Dirichlet boundary conditions

    edge_length = 2.0 / np.sin(np.pi / 3) / 4
    points_on_each_edge = 11
    step_size = edge_length / (points_on_each_edge - 1)

    direction_theta = np.pi * 2 / 3
    left_turn_theta = np.pi * 1 / 3
    right_turn_theta = -np.pi * 2 / 3

    dirichlet_control_points_problem_c = []
    point_x, point_y = 0.0, -1.0
    for i_edge in range(6):
        for i_step in range(points_on_each_edge - 1):
            dirichlet_control_points_problem_c.append(
                DirichletControlPoint(loc=(point_x, point_y),
                                      val=solution_analytical_problem_c(
                                          point_x, point_y)))
            point_x += step_size * np.cos(direction_theta)
            point_y += step_size * np.sin(direction_theta)
        direction_theta += left_turn_theta if (i_edge %
                                               2 == 0) else right_turn_theta

    # dummy control points to form closed domain

    radius_circle = 1.0 / np.sin(np.pi / 6)
    center_circle_x = radius_circle * np.cos(np.pi / 6)
    center_circle_y = 0.0

    dirichlet_control_points_problem_c_dummy = []
    for theta in np.linspace(-np.pi * 5 / 6, np.pi * 5 / 6, 60):
        point_x = center_circle_x + radius_circle * np.cos(theta)
        point_y = center_circle_y + radius_circle * np.sin(theta)
        dirichlet_control_points_problem_c_dummy.append(
            DirichletControlPoint(loc=(point_x, point_y),
                                  val=solution_analytical_problem_c(
                                      point_x, point_y)))

    # all Dirichlet control points

    dirichlet_control_points_problem_c_all = \
        dirichlet_control_points_problem_c + dirichlet_control_points_problem_c_dummy

    # creating control points for Neumann boundary condition

    edge_length = 2.0 / np.sin(np.pi / 3) / 4
    points_on_each_edge = 11
    step_size = edge_length / (points_on_each_edge - 1)

    normal_theta = np.pi / 6

    direction_theta = -np.pi * 1 / 3
    left_turn_theta = np.pi * 1 / 3
    right_turn_theta = -np.pi * 2 / 3

    neumann_control_points_problem_c = []
    point_x, point_y = 0.0, 1.0
    for i_edge in range(6):
        normal_x = np.cos(normal_theta)
        normal_y = np.sin(normal_theta)

        # skip the points on the "tip", their normal vector is undefined?
        point_x += step_size * np.cos(direction_theta)
        point_y += step_size * np.sin(direction_theta)

        for i_step in range(points_on_each_edge - 2):
            grad_x, grad_y = gradient_solution_analytical_problem_c(
                point_x, point_y)
            neumann_val = grad_x * normal_x + grad_y * normal_y
            neumann_control_points_problem_c.append(
                NeumannControlPoint(loc=(point_x, point_y),
                                    val=neumann_val,
                                    normal_vector=(normal_x, normal_y)))
            point_x += step_size * np.cos(direction_theta)
            point_y += step_size * np.sin(direction_theta)
        direction_theta += left_turn_theta if (i_edge %
                                               2 == 0) else right_turn_theta
        normal_theta += left_turn_theta if (i_edge %
                                            2 == 0) else right_turn_theta

    # dummy control points to form closed domain

    radius_circle = 1.0 / np.sin(np.pi / 6)
    center_circle_x = -radius_circle * np.cos(np.pi / 6)
    center_circle_y = 0.0

    neumann_control_points_problem_c_dummy = []
    for theta in np.linspace(np.pi * 1 / 6, np.pi * 11 / 6, 60):
        point_x = center_circle_x + radius_circle * np.cos(theta)
        point_y = center_circle_y + radius_circle * np.sin(theta)
        normal_x = np.cos(theta)
        normal_y = np.sin(theta)
        grad_x, grad_y = gradient_solution_analytical_problem_c(
            point_x, point_y)
        neumann_val = grad_x * normal_x + grad_y * normal_y
        neumann_control_points_problem_c_dummy.append(
            NeumannControlPoint(loc=(point_x, point_y),
                                val=neumann_val,
                                normal_vector=(normal_x, normal_y)))

    # all Neumann control points

    neumann_control_points_problem_c_all = \
        neumann_control_points_problem_c + neumann_control_points_problem_c_dummy

    cbc_problem_c = CustomBoundaryCondition(
        center_point=Point(loc=(0.0, 0.0)),
        dirichlet_control_points=dirichlet_control_points_problem_c_all,
        neumann_control_points=neumann_control_points_problem_c_all)

    def get_grid(x_from_to,
                 y_from_to,
                 x_n_points=100,
                 y_n_points=100,
                 as_tensor=False):
        x_from, x_to = x_from_to
        y_from, y_to = y_from_to
        if as_tensor:
            x = torch.linspace(x_from, x_to, x_n_points)
            y = torch.linspace(y_from, y_to, y_n_points)
            return torch.meshgrid(x, y)
        else:
            x = np.linspace(x_from, x_to, x_n_points)
            y = np.linspace(y_from, y_to, y_n_points)
            return np.meshgrid(x, y)

    def to_np(tensor):
        return tensor.detach().numpy()

    xx_train, yy_train = get_grid(x_from_to=(-1, 1),
                                  y_from_to=(-1, 1),
                                  x_n_points=28,
                                  y_n_points=28,
                                  as_tensor=True)
    is_in_domain_train = cbc_problem_c.in_domain(xx_train, yy_train)
    xx_train, yy_train = to_np(xx_train), to_np(yy_train)
    xx_train, yy_train = xx_train[is_in_domain_train], yy_train[
        is_in_domain_train]
    train_gen = PredefinedGenerator(xx_train, yy_train)

    xx_valid, yy_valid = get_grid(x_from_to=(-1, 1),
                                  y_from_to=(-1, 1),
                                  x_n_points=10,
                                  y_n_points=10,
                                  as_tensor=True)
    is_in_domain_valid = cbc_problem_c.in_domain(xx_valid, yy_valid)
    xx_valid, yy_valid = to_np(xx_valid), to_np(yy_valid)
    xx_valid, yy_valid = xx_valid[is_in_domain_valid], yy_valid[
        is_in_domain_valid]
    valid_gen = PredefinedGenerator(xx_valid, yy_valid)

    def rmse(u, x, y):
        true_u = torch.log(1 + x**2 + y**2)
        return torch.mean((u - true_u)**2)**0.5

    # nabla^2 psi(x, y) = (e^(-x))(x-2+y^3+6y)
    def de_problem_c(u, x, y):
        return diff(u, x, order=2) + diff(u, y, order=2) + torch.exp(
            u) - 1.0 - x**2 - y**2 - 4.0 / (1.0 + x**2 + y**2)**2

    # fully connected network with one hidden layer (100 hidden units with ELU activation)
    net = FCNN(n_input_units=2, hidden_units=(100, 100), actv=nn.ELU)
    adam = optim.Adam(params=net.parameters(), lr=0.001)

    # train on 28 X 28 grid
    solution_neural_net_problem_c, history_problem_c = solve2D(
        pde=de_problem_c,
        condition=cbc_problem_c,
        xy_min=(-1, -1),
        xy_max=(1, 1),
        train_generator=train_gen,
        valid_generator=valid_gen,
        net=net,
        max_epochs=1,
        batch_size=128,
        optimizer=adam,
        monitor=Monitor2D(check_every=1,
                          xy_min=(-1, -1),
                          xy_max=(1, 1),
                          valid_generator=valid_gen),
        metrics={'rmse': rmse})

    xs = torch.tensor([p.loc[0] for p in dirichlet_control_points_problem_c],
                      requires_grad=True).reshape(-1, 1)
    ys = torch.tensor([p.loc[1] for p in dirichlet_control_points_problem_c],
                      requires_grad=True).reshape(-1, 1)
    us = solution_neural_net_problem_c(xs, ys, as_type='np')
    true_us = solution_analytical_problem_c(to_np(xs), to_np(ys))
    assert isclose(us, true_us, atol=1e-4).all()

    xs = torch.tensor([p.loc[0] for p in neumann_control_points_problem_c],
                      requires_grad=True).reshape(-1, 1)
    ys = torch.tensor([p.loc[1] for p in neumann_control_points_problem_c],
                      requires_grad=True).reshape(-1, 1)
    us = solution_neural_net_problem_c(xs, ys)
    nxs = torch.tensor([
        p.normal_vector[0] for p in neumann_control_points_problem_c
    ]).reshape(-1, 1)
    nys = torch.tensor([
        p.normal_vector[1] for p in neumann_control_points_problem_c
    ]).reshape(-1, 1)
    normal_derivative = to_np(nxs * diff(us, xs) +
                              nys * diff(us, ys)).flatten()
    true_normal_derivative = np.array(
        [p.val for p in neumann_control_points_problem_c])
    assert isclose(normal_derivative, true_normal_derivative, atol=1e-2).all()