| """Sampling utilities for generating training and evaluation points.""" |
| import torch |
|
|
|
|
| def sample_coordinate(config, resample=False, num_samp=-1, time=False): |
| """Sample 1D coordinates with optional jittering. |
| |
| Args: |
| config: Configuration with domain parameters (T, L) |
| resample: If True, add random jitter to points |
| num_samp: Number of samples (default: config.num_samp_bulk) |
| time: If True, sample time domain [0, T], else space domain [-L, L] |
| |
| Returns: |
| 1D tensor of coordinates |
| """ |
| if num_samp < 0: |
| num_samp = config.num_samp_bulk |
|
|
| if time: |
| T = config.T |
| coord = torch.linspace(0, T, num_samp) |
| if resample: |
| jitter = (torch.rand(num_samp) * 2 - 1) * T / num_samp |
| coord = torch.clamp(coord + jitter, 0, T) |
| else: |
| L = config.L |
| coord = torch.linspace(-L, L, num_samp) |
| if resample: |
| jitter = (torch.rand(num_samp) * 2 - 1) * L / num_samp |
| coord = coord + jitter |
|
|
| return coord |
|
|
|
|
| def sample_bulk(config, resample=False, num_samp=-1): |
| """Sample spacetime bulk domain as (t, x) meshgrid. |
| |
| Args: |
| config: Configuration with domain parameters |
| resample: If True, add random jitter to grid points |
| num_samp: Number of samples per dimension |
| |
| Returns: |
| Tensor of shape (num_samp², 2) with columns [t, x] |
| """ |
| t = sample_coordinate(config, resample, num_samp, time=True) |
| x = sample_coordinate(config, resample, num_samp, time=False) |
|
|
| tt, xx = torch.meshgrid(t, x, indexing='ij') |
| return torch.stack([tt.flatten(), xx.flatten()], dim=1) |
|
|
|
|
| def sample_slice(zval, config, resample=False, num_samp=-1, time=True): |
| """Sample a time or space slice. |
| |
| Args: |
| zval: Constant value for the sliced dimension |
| config: Configuration with domain parameters |
| resample: If True, add random jitter to points |
| num_samp: Number of samples |
| time: If True, slice at constant time t=zval, else constant space x=zval |
| |
| Returns: |
| Tensor of shape (num_samp, 2) with columns [t, x] |
| """ |
| if num_samp < 0: |
| num_samp = config.num_samp_bulk |
|
|
| if time: |
| x = sample_coordinate(config, resample, num_samp, time=False) |
| t = zval * torch.ones_like(x) |
| else: |
| t = sample_coordinate(config, resample, num_samp, time=True) |
| x = zval * torch.ones_like(t) |
|
|
| return torch.stack([t, x], dim=1) |
|
|
|
|
| def sample_boundary(config, resample=False, num_samp=-1, ic_only=False, bc_only=False): |
| """Sample initial and boundary conditions. |
| |
| Args: |
| config: Configuration with domain parameters |
| resample: If True, add random jitter to points |
| num_samp: Number of samples per boundary |
| ic_only: If True, return only initial condition (t=0) |
| bc_only: If True, return only spatial boundaries (x=±L) |
| |
| Returns: |
| Tensor of boundary points with shape (N, 2) |
| """ |
| L = config.L |
| input_0 = sample_slice(0, config, resample, num_samp, time=True) |
| input_left = sample_slice(-L, config, resample, num_samp, time=False) |
| input_right = sample_slice(L, config, resample, num_samp, time=False) |
|
|
| if ic_only: |
| return input_0 |
| elif bc_only: |
| return torch.cat([input_left, input_right], dim=0) |
| else: |
| return torch.cat([input_0, input_left, input_right], dim=0) |