| from __future__ import annotations |
|
|
| from collections.abc import Mapping |
| from pathlib import Path |
|
|
| import numpy as np |
| import scipy.io |
| import torch |
|
|
|
|
| def load_allen_cahn(path: Path) -> dict[str, np.ndarray | tuple[int, int]]: |
| if not path.is_file(): |
| raise FileNotFoundError(f"Allen-Cahn data not found: {path}") |
| data = scipy.io.loadmat(path) |
| missing = {"tt", "x", "uu"}.difference(data) |
| if missing: |
| raise ValueError(f"Allen-Cahn data is missing fields: {sorted(missing)}") |
| time_axis = np.asarray(data["tt"], dtype=np.float64).reshape(-1) |
| space_axis = np.asarray(data["x"], dtype=np.float64).reshape(-1) |
| raw_solution = np.real(np.asarray(data["uu"])) |
| expected_shape = (space_axis.size, time_axis.size) |
| if raw_solution.shape != expected_shape: |
| raise ValueError( |
| f"uu shape must be {expected_shape} in [x,t] order, got {raw_solution.shape}" |
| ) |
| exact_grid = raw_solution.T |
| mesh_x, mesh_t = np.meshgrid(space_axis, time_axis, indexing="xy") |
| coordinates = np.column_stack((mesh_x.ravel(), mesh_t.ravel())) |
| exact = exact_grid.reshape(-1, 1) |
| return { |
| "time": time_axis, |
| "space": space_axis, |
| "coordinates": coordinates, |
| "exact": exact, |
| "grid_shape": exact_grid.shape, |
| } |
|
|
|
|
| def sample_training_data( |
| dataset: Mapping, |
| n_train: int, |
| seed: int, |
| device: torch.device, |
| dtype: torch.dtype, |
| ) -> tuple[torch.Tensor, torch.Tensor]: |
| coordinates = np.asarray(dataset["coordinates"]) |
| exact = np.asarray(dataset["exact"]) |
| if n_train <= 0 or n_train > coordinates.shape[0]: |
| raise ValueError( |
| f"n_train must be between 1 and {coordinates.shape[0]}, got {n_train}" |
| ) |
| generator = np.random.default_rng(seed) |
| indices = generator.choice(coordinates.shape[0], n_train, replace=False) |
| return ( |
| torch.as_tensor(coordinates[indices], dtype=dtype, device=device), |
| torch.as_tensor(exact[indices], dtype=dtype, device=device), |
| ) |
|
|
|
|
| def batched_predict( |
| model: torch.nn.Module, |
| coordinates: np.ndarray, |
| batch_size: int, |
| device: torch.device, |
| dtype: torch.dtype, |
| ) -> np.ndarray: |
| if batch_size <= 0: |
| raise ValueError("evaluation batch size must be positive") |
| predictions = [] |
| model.eval() |
| with torch.no_grad(): |
| for start in range(0, coordinates.shape[0], batch_size): |
| batch = torch.as_tensor( |
| coordinates[start : start + batch_size], dtype=dtype, device=device |
| ) |
| predictions.append(model.predict_u(batch).cpu().numpy()) |
| return np.concatenate(predictions, axis=0) |
|
|