Download scripts/problems.py from OneScience-Group/SA-PINNs: direct link, hf CLI and curl.
- Browser
- Download file 6.51 kB
-
https://huggingface.co/OneScience-Group/SA-PINNs/resolve/main/scripts/problems.py
- Command line
-
hf download hf://OneScience-Group/SA-PINNs/scripts/problems.py
-
curl -L -o problems.py https://huggingface.co/OneScience-Group/SA-PINNs/resolve/main/scripts/problems.py
6.51 kB
| from __future__ import annotations | |
| from collections.abc import Mapping | |
| import numpy as np | |
| import torch | |
| from model.sa_pinn import Burgers2D, Equation, Helmholtz2D, Laplace1D | |
| CASES = ("laplace", "helmholtz", "burgers") | |
| def exact_solution(case: str, coordinates: np.ndarray) -> np.ndarray | None: | |
| if case == "laplace": | |
| return np.sin(np.pi * coordinates[:, 0:1]) | |
| if case == "helmholtz": | |
| return np.sin(np.pi * coordinates[:, 0:1]) * np.sin( | |
| 4.0 * np.pi * coordinates[:, 1:2] | |
| ) | |
| if case == "burgers": | |
| return None | |
| raise ValueError(f"unsupported case: {case}") | |
| def build_equation(case: str, data_config: Mapping) -> Equation: | |
| if case == "laplace": | |
| return Laplace1D() | |
| if case == "helmholtz": | |
| return Helmholtz2D(float(data_config["wave_number"])) | |
| if case == "burgers": | |
| return Burgers2D(float(data_config["viscosity"])) | |
| raise ValueError(f"unsupported case: {case}") | |
| def generate_data(case: str, config: Mapping, seed: int) -> dict[str, np.ndarray | None]: | |
| generator = np.random.default_rng(seed) | |
| n_pde = int(config["n_pde"]) | |
| n_solution = int(config["n_sol"]) | |
| n_boundary = int(config["n_bnd"]) | |
| test_resolution = int(config["test_res"]) | |
| if min(n_pde, n_solution, n_boundary, test_resolution) <= 0: | |
| raise ValueError("all data counts must be positive") | |
| if case == "laplace": | |
| lower, upper = map(float, config["domain"]) | |
| x_pde = generator.uniform(lower, upper, (n_pde, 1)) | |
| x_boundary = np.array([[lower], [upper]], dtype=np.float64) | |
| u_boundary = exact_solution(case, x_boundary) | |
| x_data = np.linspace(lower, upper, n_solution)[:, None] | |
| u_data = exact_solution(case, x_data) | |
| noise_std = float(config.get("noise_std", 0.0)) | |
| if noise_std: | |
| u_data = u_data + noise_std * generator.standard_normal(u_data.shape) | |
| x_test = np.linspace(lower, upper, test_resolution)[:, None] | |
| test_shape = (test_resolution,) | |
| elif case == "helmholtz": | |
| x_lower, x_upper = map(float, config["domain_x"]) | |
| y_lower, y_upper = map(float, config["domain_y"]) | |
| x_pde = np.column_stack( | |
| ( | |
| generator.uniform(x_lower, x_upper, n_pde), | |
| generator.uniform(y_lower, y_upper, n_pde), | |
| ) | |
| ) | |
| if n_boundary < 4 or n_boundary % 4: | |
| raise ValueError("Helmholtz n_bnd must be divisible by 4 and at least 4") | |
| per_edge = n_boundary // 4 | |
| x_axis = np.linspace(x_lower, x_upper, per_edge) | |
| y_axis = np.linspace(y_lower, y_upper, per_edge) | |
| x_boundary = np.vstack( | |
| ( | |
| np.column_stack((x_axis, np.full(per_edge, y_lower))), | |
| np.column_stack((x_axis, np.full(per_edge, y_upper))), | |
| np.column_stack((np.full(per_edge, x_lower), y_axis)), | |
| np.column_stack((np.full(per_edge, x_upper), y_axis)), | |
| ) | |
| ) | |
| u_boundary = exact_solution(case, x_boundary) | |
| x_data = np.column_stack( | |
| ( | |
| generator.uniform(x_lower, x_upper, n_solution), | |
| generator.uniform(y_lower, y_upper, n_solution), | |
| ) | |
| ) | |
| u_data = exact_solution(case, x_data) | |
| grid_x = np.linspace(x_lower, x_upper, test_resolution) | |
| grid_y = np.linspace(y_lower, y_upper, test_resolution) | |
| mesh_x, mesh_y = np.meshgrid(grid_x, grid_y, indexing="xy") | |
| x_test = np.column_stack((mesh_x.ravel(), mesh_y.ravel())) | |
| test_shape = mesh_x.shape | |
| elif case == "burgers": | |
| x_lower, x_upper = map(float, config["domain_x"]) | |
| t_lower, t_upper = map(float, config["domain_t"]) | |
| x_pde = np.column_stack( | |
| ( | |
| generator.uniform(x_lower, x_upper, n_pde), | |
| generator.uniform(t_lower, t_upper, n_pde), | |
| ) | |
| ) | |
| if n_boundary < 2: | |
| raise ValueError("Burgers n_bnd must be at least 2") | |
| left_count = n_boundary // 2 | |
| right_count = n_boundary - left_count | |
| left_time = generator.uniform(t_lower, t_upper, left_count) | |
| right_time = generator.uniform(t_lower, t_upper, right_count) | |
| x_boundary = np.vstack( | |
| ( | |
| np.column_stack((np.full(left_count, x_lower), left_time)), | |
| np.column_stack((np.full(right_count, x_upper), right_time)), | |
| ) | |
| ) | |
| u_boundary = np.zeros((n_boundary, 1)) | |
| initial_x = generator.uniform(x_lower, x_upper, n_solution) | |
| x_data = np.column_stack((initial_x, np.full(n_solution, t_lower))) | |
| u_data = -np.sin(np.pi * initial_x)[:, None] | |
| grid_x = np.linspace(x_lower, x_upper, test_resolution) | |
| grid_t = np.linspace(t_lower, t_upper, test_resolution) | |
| mesh_x, mesh_t = np.meshgrid(grid_x, grid_t, indexing="xy") | |
| x_test = np.column_stack((mesh_x.ravel(), mesh_t.ravel())) | |
| test_shape = mesh_x.shape | |
| else: | |
| raise ValueError(f"unsupported case: {case}") | |
| return { | |
| "x_pde": np.asarray(x_pde, dtype=np.float64), | |
| "x_boundary": np.asarray(x_boundary, dtype=np.float64), | |
| "u_boundary": np.asarray(u_boundary, dtype=np.float64), | |
| "x_data": np.asarray(x_data, dtype=np.float64), | |
| "u_data": np.asarray(u_data, dtype=np.float64), | |
| "x_test": np.asarray(x_test, dtype=np.float64), | |
| "u_exact": exact_solution(case, np.asarray(x_test, dtype=np.float64)), | |
| "test_shape": test_shape, | |
| } | |
| def to_tensors( | |
| data: Mapping[str, np.ndarray | None], | |
| device: torch.device, | |
| dtype: torch.dtype, | |
| ) -> dict[str, torch.Tensor | None]: | |
| return { | |
| key: ( | |
| torch.as_tensor(value, dtype=dtype, device=device) | |
| if isinstance(value, np.ndarray) | |
| else None | |
| ) | |
| for key, value in data.items() | |
| if key != "test_shape" | |
| } | |
| def point_counts(data: Mapping[str, np.ndarray | None]) -> dict[str, int]: | |
| return { | |
| "pde": int(data["x_pde"].shape[0]), | |
| "boundary": int(data["x_boundary"].shape[0]), | |
| "data": int(data["x_data"].shape[0]) if data.get("x_data") is not None else 0, | |
| } | |
| def relative_l2(prediction: np.ndarray, reference: np.ndarray | None) -> float | None: | |
| if reference is None: | |
| return None | |
| return float( | |
| np.linalg.norm(prediction.reshape(-1) - reference.reshape(-1)) | |
| / (np.linalg.norm(reference.reshape(-1)) + 1.0e-12) | |
| ) | |