def test_get_internals(): parametric_circle = lambda x1, x2, t: [diff(x1, t) - x2, diff(x2, t) + x1] init_vals_pc = [ IVP(t_0=0.0, u_0=0.0), IVP(t_0=0.0, u_0=1.0), ] solver = Solver1D( ode_system=parametric_circle, conditions=init_vals_pc, t_min=0.0, t_max=2 * np.pi, ) solver.fit(max_epochs=1) internals = solver.get_internals() assert isinstance(internals, dict) internals = solver.get_internals(return_type='list') assert isinstance(internals, dict) internals = solver.get_internals(return_type='dict') assert isinstance(internals, dict) internals = solver.get_internals(['generator', 'n_batches'], return_type='dict') assert isinstance(internals, dict) internals = solver.get_internals(['generator', 'n_batches'], return_type='list') assert isinstance(internals, list) internals = solver.get_internals('train_generator') assert isinstance(internals, BaseGenerator)
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.')
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.')
def test_lotka_volterra(): alpha, beta, delta, gamma = 1, 1, 1, 1 lotka_volterra = lambda x, y, t : [diff(x, t) - (alpha*x - beta*x*y), diff(y, t) - (delta*x*y - gamma*y)] init_vals_lv = [ IVP(t_0=0.0, x_0=1.5), IVP(t_0=0.0, x_0=1.0) ] nets_lv = [ FCNN(hidden_units=(32, 32), actv=SinActv), FCNN(hidden_units=(32, 32), actv=SinActv), ] solution_lv, _ = solve_system(ode_system=lotka_volterra, conditions=init_vals_lv, t_min=0.0, t_max=12, nets=nets_lv, max_epochs=12000, monitor=Monitor(t_min=0.0, t_max=12, check_every=100)) ts = np.linspace(0, 12, 100) prey_net, pred_net = solution_lv(ts, as_type='np') def dPdt(P, t): return [P[0]*alpha - beta*P[0]*P[1], delta*P[0]*P[1] - gamma*P[1]] P0 = [1.5, 1.0] Ps = odeint(dPdt, P0, ts) prey_num = Ps[:,0] pred_num = Ps[:,1] assert isclose(prey_net, prey_num, atol=0.1).all() assert isclose(pred_net, pred_num, atol=0.1).all() print('Lotka Volterra test passed.')
def spherical_curl(u_r, u_theta, u_phi, r, theta, phi): r"""Derives and evaluates the spherical curl of a spherical vector field :math:`u` :param u_r: :math:`r`-component of the vector field :math:`u`, must have shape (n_samples, 1) :type u_r: `torch.Tensor` :param u_theta: :math:`\theta`-component of the vector field :math:`u`, must have shape (n_samples, 1) :type u_theta: `torch.Tensor` :param u_phi: :math:`\phi`-component of the vector field :math:`u`, must have shape (n_samples, 1) :type u_phi: `torch.Tensor` :param r: a vector of :math:`r`-coordinate values, must have shape (n_samples, 1) :type r: `torch.Tensor` :param theta: a vector of :math:`\theta`-coordinate values, must have shape (n_samples, 1) :type theta: `torch.Tensor` :param phi: a vector of :math:`\phi`-coordinate values, must have shape (n_samples, 1) :type phi: `torch.Tensor` :return: :math:`r`, :math:`\theta`, and :math:`\phi` components of the curl, each with shape (n_samples, 1) :rtype: tuple[`torch.Tensor`] """ d_r = lambda u: diff(u, r) d_theta = lambda u: diff(u, theta) d_phi = lambda u: diff(u, phi) curl_r = (d_theta(u_phi * sin(theta)) - d_phi(u_theta)) / (r * sin(theta)) curl_theta = (d_phi(u_r) / sin(theta) - d_r(u_phi * r)) / r curl_phi = (d_r(u_theta * r) - d_theta(u_r)) / r return curl_r, curl_theta, curl_phi
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]])
def laplacian_spherical(u, r, theta, phi): """a helper function that computes the Laplacian in spherical coordinates """ r_component = diff(u * r, r, order=2) / r theta_component = diff(torch.sin(theta) * diff(u, theta), theta) / (r**2 * torch.sin(theta)) phi_component = diff(u, phi, order=2) / (r**2 * torch.sin(theta)**2) return r_component + theta_component + phi_component
def test_legacy_signature(): u, t = get_data(flatten_u=False, flatten_t=False) with pytest.warns(FutureWarning): diff(x=u, t=t) with pytest.warns(FutureWarning): safe_diff(x=u, t=t) with pytest.warns(FutureWarning): unsafe_diff(x=u, t=t)
def test_higher_order_derivatives(): u, t = get_data(flatten_u=False, flatten_t=False, f=lambda x: x**2) assert torch.isclose(diff(u, t), t * 2).all() assert torch.isclose(diff(u, t, order=2), 2 * torch.ones_like(t)).all() for order in range(3, 10): assert torch.isclose(diff(u, t, order=order), torch.zeros_like(t)).all() u, t = get_data(flatten_u=False, flatten_t=False, f=torch.exp) for order in range(1, 10): assert torch.isclose(diff(u, t, order=order), u).all()
def test_ibvp_ode(): x0, x1 = random.random(), random.random() + 1 u0, u0_prime = random.random(), random.random() u1, u1_prime = random.random(), random.random() net = FCNN(1, 1) # test Dirichlet-Dirichlet condition = DoubleEndedBVP1D(x_min=x0, x_max=x1, x_min_val=u0, x_max_val=u1) x = x0 * ones assert all_close(condition.enforce(net, x), u0), 'left Dirichlet BC not satisfied' x = x1 * ones assert all_close(condition.enforce(net, x), u1), 'right Dirichlet BC not satisfied' # test Dirichlet-Neumann condition = DoubleEndedBVP1D(x_min=x0, x_max=x1, x_min_val=u0, x_max_prime=u1_prime) x = x0 * ones assert all_close(condition.enforce(net, x), u0), 'left Dirichlet BC not satisfied' x = x1 * ones assert all_close(diff(condition.enforce(net, x), x), u1_prime), 'right Neumann BC not satisfied' # test Neumann-Dirichlet condition = DoubleEndedBVP1D(x_min=x0, x_max=x1, x_min_prime=u0_prime, x_max_val=u1) x = x0 * ones assert all_close(diff(condition.enforce(net, x), x), u0_prime), 'left Neumann BC not satisfied' x = x1 * ones assert all_close(condition.enforce(net, x), u1), 'right Dirichlet BC not satisfied' # test Neumann-Neumann condition = DoubleEndedBVP1D(x_min=x0, x_max=x1, x_min_prime=u0_prime, x_max_prime=u1_prime) x = x0 * ones assert all_close(diff(condition.enforce(net, x), x), u0_prime), 'left Neumann BC not satisfied' x = x1 * ones assert all_close(diff(condition.enforce(net, x), x), u1_prime), 'right Neumann BC not satisfied'
def test_double_ended_bvp_1d(x0, x1, u00, u01, u10, u11, ones, net11): u0, u0_prime = u00, u01 u1, u1_prime = u10, u11 # test Dirichlet-Dirichlet condition = DoubleEndedBVP1D(x_min=x0, x_max=x1, x_min_val=u0, x_max_val=u1) x = x0 * ones assert all_close(condition.enforce(net11, x), u0), 'left Dirichlet BC not satisfied' x = x1 * ones assert all_close(condition.enforce(net11, x), u1), 'right Dirichlet BC not satisfied' # test Dirichlet-Neumann condition = DoubleEndedBVP1D(x_min=x0, x_max=x1, x_min_val=u0, x_max_prime=u1_prime) x = x0 * ones assert all_close(condition.enforce(net11, x), u0), 'left Dirichlet BC not satisfied' x = x1 * ones assert all_close(diff(condition.enforce(net11, x), x), u1_prime), 'right Neumann BC not satisfied' # test Neumann-Dirichlet condition = DoubleEndedBVP1D(x_min=x0, x_max=x1, x_min_prime=u0_prime, x_max_val=u1) x = x0 * ones assert all_close(diff(condition.enforce(net11, x), x), u0_prime), 'left Neumann BC not satisfied' x = x1 * ones assert all_close(condition.enforce(net11, x), u1), 'right Dirichlet BC not satisfied' # test Neumann-Neumann condition = DoubleEndedBVP1D(x_min=x0, x_max=x1, x_min_prime=u0_prime, x_max_prime=u1_prime) x = x0 * ones assert all_close(diff(condition.enforce(net11, x), x), u0_prime), 'left Neumann BC not satisfied' x = x1 * ones assert all_close(diff(condition.enforce(net11, x), x), u1_prime), 'right Neumann BC not satisfied'
def test_monitor(): exponential = lambda x, t: diff(x, t) - x init_val_ex = IVP(t_0=0.0, x_0=1.0) solution_ex, _ = solve(ode=exponential, condition=init_val_ex, t_min=0.0, t_max=2.0, max_epochs=3, monitor=Monitor(t_min=0.0, t_max=2.0, check_every=1)) print('Monitor test passed.')
def spherical_grad(u, r, theta, phi): r"""Derives and evaluates the spherical gradient of a spherical scalar field :math:`u` :param u: a scalar field :math:`u`, must have shape (n_samples, 1) :type u: `torch.Tensor` :param r: a vector of :math:`r`-coordinate values, must have shape (n_samples, 1) :type r: `torch.Tensor` :param theta: a vector of :math:`\theta`-coordinate values, must have shape (n_samples, 1) :type theta: `torch.Tensor` :param phi: a vector of :math:`\phi`-coordinate values, must have shape (n_samples, 1) :type phi: `torch.Tensor` :return: :math:`r`, :math:`\theta`, and :math:`\phi` components of the gradient, each with shape (n_samples, 1) :rtype: tuple[`torch.Tensor`] """ grad_r = diff(u, r) grad_theta = diff(u, theta) / r grad_phi = diff(u, phi) / (r * sin(theta)) return grad_r, grad_theta, grad_phi
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 )
def test_ivp(x0, y0, y1, ones, net11): x = x0 * ones cond = IVP(x0, y0) y = cond.enforce(net11, x) assert torch.isclose(y, y0 * ones).all(), "y(x_0) != y_0" cond = IVP(x0, y0, y1) y = cond.enforce(net11, x) assert all_close(y, y0), "y(x_0) != y_0" assert all_close(diff(y, x), y1), "y'(x_0) != y'_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)
def test_ode_system(): parametric_circle = lambda u1, u2, t: [diff(u1, t) - u2, diff(u2, t) + u1] init_vals_pc = [IVP(t_0=0.0, u_0=0.0), IVP(t_0=0.0, u_0=1.0)] solution_pc, loss_history = solve_system( ode_system=parametric_circle, conditions=init_vals_pc, t_min=0.0, t_max=2 * np.pi, max_epochs=10, ) assert isinstance(solution_pc, Solution) 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]])
def test_monitor(): exponential = lambda u, t: diff(u, t) - u init_val_ex = IVP(t_0=0.0, u_0=1.0) solution_ex, _ = solve(ode=exponential, condition=init_val_ex, t_min=0.0, t_max=2.0, max_epochs=3, monitor=Monitor(t_min=0.0, t_max=2.0, check_every=1))
def test_ode_ivp(): oscillator = lambda x, t: diff(x, t, order=2) + x init_val_ho = IVP(t_0=0.0, x_0=0.0, x_0_prime=1.0) solution_ho, _ = solve(ode=oscillator, condition=init_val_ho, max_epochs=3000, t_min=0.0, t_max=2*np.pi) ts = np.linspace(0, 2*np.pi, 100) x_net = solution_ho(ts, as_type='np') x_ana = np.sin(ts) assert isclose(x_net, x_ana, atol=0.1).all() print('IVP basic test passed.')
def test_ode_bvp(): oscillator = lambda x, t: diff(x, t, order=2) + x bound_val_ho = DirichletBVP(t_0=0.0, x_0=0.0, t_1=1.5*np.pi, x_1=-1.0) solution_ho, _ = solve(ode=oscillator, condition=bound_val_ho, max_epochs=3000, t_min=0.0, t_max=1.5*np.pi) ts = np.linspace(0, 1.5*np.pi, 100) x_net = solution_ho(ts, as_type='np') x_ana = np.sin(ts) assert isclose(x_net, x_ana, atol=0.1).all() print('BVP basic test passed.')
def test_ode_system(): parametric_circle = lambda x1, x2, t : [diff(x1, t) - x2, diff(x2, t) + x1] init_vals_pc = [ IVP(t_0=0.0, x_0=0.0), IVP(t_0=0.0, x_0=1.0) ] solution_pc, _ = solve_system(ode_system=parametric_circle, conditions=init_vals_pc, t_min=0.0, t_max=2*np.pi, max_epochs=5000,) ts = np.linspace(0, 2*np.pi, 100) x1_net, x2_net = solution_pc(ts, as_type='np') x1_ana, x2_ana = np.sin(ts), np.cos(ts) assert isclose(x1_net, x1_ana, atol=0.1).all() assert isclose(x2_net, x2_ana, atol=0.1).all() print('solve_system basic test passed.')
def spherical_vector_laplacian(u_r, u_theta, u_phi, r, theta, phi): r"""Derives and evaluates the spherical laplacian of a spherical vector field :math:`u` :param u_r: :math:`r`-component of the vector field :math:`u`, must have shape (n_samples, 1) :type u_r: `torch.Tensor` :param u_theta: :math:`\theta`-component of the vector field :math:`u`, must have shape (n_samples, 1) :type u_theta: `torch.Tensor` :param u_phi: :math:`\phi`-component of the vector field :math:`u`, must have shape (n_samples, 1) :type u_phi: `torch.Tensor` :param r: a vector of :math:`r`-coordinate values, must have shape (n_samples, 1) :type r: `torch.Tensor` :param theta: a vector of :math:`\theta`-coordinate values, must have shape (n_samples, 1) :type theta: `torch.Tensor` :param phi: a vector of :math:`\phi`-coordinate values, must have shape (n_samples, 1) :type phi: `torch.Tensor` :return: the laplacian evaluated at :math:`(r, \theta, \phi)`, with shape (n_samples, 1) :rtype: `torch.Tensor` """ d_theta = lambda u: diff(u, theta) d_phi = lambda u: diff(u, phi) scalar_lap = lambda u: spherical_laplacian(u, r, theta, phi) lap_r = \ scalar_lap(u_r) \ - 2 * u_r / r ** 2 \ - 2 * d_theta(u_theta * sin(theta)) / (r ** 2 * sin(theta)) \ - 2 * d_phi(u_phi) / (r ** 2 * sin(theta)) lap_theta = \ scalar_lap(u_theta) \ - u_theta / (r ** 2 * sin(theta) ** 2) \ + 2 * d_theta(u_r) / r ** 2 \ - 2 * cos(theta) * d_phi(u_phi) / (r ** 2 * sin(theta) ** 2) lap_phi = \ scalar_lap(u_phi) \ - u_phi / (r ** 2 * sin(theta) ** 2) \ + 2 * d_phi(u_r) / (r ** 2 * sin(theta)) \ + 2 * cos(theta) * d_phi(u_theta) / (r ** 2 * sin(theta) ** 2) return lap_r, lap_theta, lap_phi
def test_ivp(): x = x0 * ones net = FCNN(1, 1) cond = IVP(x0, y0) y = cond.enforce(net, x) assert torch.isclose(y, y0 * ones).all(), "y(x_0) != y_0" cond = IVP(x0, y0, y1) y = cond.enforce(net, x) assert all_close(y, y0), "y(x_0) != y_0" assert all_close(diff(y, x), y1), "y'(x_0) != y'_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.')
def spherical_div(u_r, u_theta, u_phi, r, theta, phi): r"""Derives and evaluates the spherical divergence of a spherical vector field :math:`u` :param u_r: :math:`r`-component of the vector field :math:`u`, must have shape (n_samples, 1) :type u_r: `torch.Tensor` :param u_theta: :math:`\theta`-component of the vector field :math:`u`, must have shape (n_samples, 1) :type u_theta: `torch.Tensor` :param u_phi: :math:`\phi`-component of the vector field :math:`u`, must have shape (n_samples, 1) :type u_phi: `torch.Tensor` :param r: a vector of :math:`r`-coordinate values, must have shape (n_samples, 1) :type r: `torch.Tensor` :param theta: a vector of :math:`\theta`-coordinate values, must have shape (n_samples, 1) :type theta: `torch.Tensor` :param phi: a vector of :math:`\phi`-coordinate values, must have shape (n_samples, 1) :type phi: `torch.Tensor` :return: the divergence evaluated at :math:`(r, \theta, \phi)`, with shape (n_samples, 1) :rtype: `torch.Tensor` """ div_r = diff(u_r * r**2, r) / r**2 div_theta = diff(u_theta * sin(theta), theta) / (r * sin(theta)) div_phi = diff(u_phi, phi) / (r * sin(theta)) return div_r + div_theta + div_phi
def spherical_laplacian(u, r, theta, phi): r"""Derives and evaluates the spherical laplacian of a spherical scalar field :math:`u` :param u: a scalar field :math:`u`, must have shape (n_samples, 1) :type u: `torch.Tensor` :param r: a vector of :math:`r`-coordinate values, must have shape (n_samples, 1) :type r: `torch.Tensor` :param theta: a vector of :math:`\theta`-coordinate values, must have shape (n_samples, 1) :type theta: `torch.Tensor` :param phi: a vector of :math:`\phi`-coordinate values, must have shape (n_samples, 1) :type phi: `torch.Tensor` :return: the laplacian evaluated at :math:`(r, \theta, \phi)`, with shape (n_samples, 1) :rtype: `torch.Tensor` """ d_r = lambda u: diff(u, r) d_theta = lambda u: diff(u, theta) d_phi = lambda u: diff(u, phi) lap_r = d_r(d_r(u) * r**2) / r**2 lap_theta = d_theta(d_theta(u) * sin(theta)) / (r**2 * sin(theta)) lap_phi = d_phi(d_phi(u)) / (r**2 * sin(theta)**2) return lap_r + lap_theta + lap_phi
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.')
def test_ode(): def mse(x, t): true_x = torch.sin(t) return torch.mean((x - true_x) ** 2) exponential = lambda x, t: diff(x, t) - x init_val_ex = IVP(t_0=0.0, x_0=1.0) solution_ex, _ = solve(ode=exponential, condition=init_val_ex, t_min=0.0, t_max=2.0, shuffle=False, max_epochs=2000, return_best=True, metrics={'mse': mse}) ts = np.linspace(0, 2.0, 100) x_net = solution_ex(ts, as_type='np') x_ana = np.exp(ts) assert isclose(x_net, x_ana, atol=0.1).all() print('solve basic test passed.')
def test_ode(): def mse(u, t): true_u = torch.sin(t) return torch.mean((u - true_u) ** 2) exponential = lambda u, t: diff(u, t) - u init_val_ex = IVP(t_0=0.0, u_0=1.0) solution_ex, loss_history = solve(ode=exponential, condition=init_val_ex, t_min=0.0, t_max=2.0, shuffle=False, max_epochs=10, return_best=True, metrics={'mse': mse}) assert isinstance(solution_ex, Solution1D) 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]])
def test_train_generator(): exponential = lambda x, t: diff(x, t) - x init_val_ex = IVP(t_0=0.0, x_0=1.0) train_gen = Generator1D(size=32, t_min=0.0, t_max=2.0, method='uniform') solution_ex, _ = solve(ode=exponential, condition=init_val_ex, t_min=0.0, t_max=2.0, train_generator=train_gen, max_epochs=3) train_gen = Generator1D(size=32, t_min=0.0, t_max=2.0, method='equally-spaced') solution_ex, _ = solve(ode=exponential, condition=init_val_ex, t_min=0.0, t_max=2.0, train_generator=train_gen, max_epochs=3) train_gen = Generator1D(size=32, t_min=0.0, t_max=2.0, method='equally-spaced-noisy') solution_ex, _ = solve(ode=exponential, condition=init_val_ex, t_min=0.0, t_max=2.0, train_generator=train_gen, max_epochs=3) train_gen = Generator1D(size=32, t_min=0.0, t_max=2.0, method='equally-spaced-noisy', noise_std=0.01) solution_ex, _ = solve(ode=exponential, condition=init_val_ex, t_min=0.0, t_max=2.0, train_generator=train_gen, max_epochs=3) train_gen = Generator1D(size=32, t_min=np.log10(0.1), t_max=np.log10(2.0), method='log-spaced') solution_ex, _ = solve(ode=exponential, condition=init_val_ex, t_min=0.1, t_max=2.0, train_generator=train_gen, max_epochs=3) train_gen = Generator1D(size=32, t_min=np.log10(0.1), t_max=np.log10(2.0), method='log-spaced-noisy') solution_ex, _ = solve(ode=exponential, condition=init_val_ex, t_min=0.1, t_max=2.0, train_generator=train_gen, max_epochs=3) train_gen = Generator1D(size=32, t_min=np.log10(0.1), t_max=np.log10(2.0), method='log-spaced-noisy', noise_std=0.01) solution_ex, _ = solve(ode=exponential, condition=init_val_ex, t_min=0.1, t_max=2.0, train_generator=train_gen, max_epochs=3) with raises(ValueError): train_gen = Generator1D(size=32, t_min=0.0, t_max=2.0, method='magic') print('ExampleGenerator test passed.')