Download scripts/hll_reference.py from OneScience-Group/PINN-SWE-CircularDamBreak: direct link, hf CLI and curl.
- Browser
- Download file 4.14 kB
-
https://huggingface.co/OneScience-Group/PINN-SWE-CircularDamBreak/resolve/main/scripts/hll_reference.py
- Command line
-
hf download hf://OneScience-Group/PINN-SWE-CircularDamBreak/scripts/hll_reference.py
-
curl -L -o hll_reference.py https://huggingface.co/OneScience-Group/PINN-SWE-CircularDamBreak/resolve/main/scripts/hll_reference.py
4.14 kB
| """Independent first-order HLL evaluation solver for the SAME dCDB9 case. | |
| This module is imported only by result.py after PINN training and inference. | |
| It cannot supply labels to train.py. Cell-centered 0.04 m mesh, CFL=0.25, | |
| periodic boundary conditions; explicit unsplit forward Euler time stepping. | |
| """ | |
| import time | |
| import numpy as np | |
| import torch | |
| def solve(config, x, y, times, path, device): | |
| started = time.monotonic() | |
| ny, nx = len(y), len(x) | |
| xy = torch.stack(torch.meshgrid(torch.as_tensor(y, dtype=torch.float32, device=device), | |
| torch.as_tensor(x, dtype=torch.float32, device=device), indexing='ij')) | |
| physics = config['physics'] | |
| inside = xy.square().sum(dim=0) <= physics['dam_radius'] ** 2 | |
| conserved = torch.zeros((3, ny, nx), dtype=torch.float32, device=device) | |
| conserved[0] = torch.where(inside, float(physics['depth_inside']), float(physics['depth_outside'])) | |
| dx, dy = float(x[1] - x[0]), float(y[1] - y[0]) | |
| gravity, cfl = physics['gravity'], config['evaluation']['hll_cfl'] | |
| snapshots, diagnostics = [], [] | |
| t, step = 0.0, 0 | |
| initial_mass = conserved[0].double().sum().item() * dx * dy | |
| # Array axes [component,y,x]: x-momentum is component 1 / spatial dim 2; | |
| # y-momentum is component 2 / spatial dim 1. | |
| for target in times: | |
| while t < float(target) - 1e-12: | |
| h = conserved[0] | |
| sound = torch.sqrt(gravity * h) | |
| max_x = (conserved[1].abs() / h + sound).max().item() | |
| max_y = (conserved[2].abs() / h + sound).max().item() | |
| dt = min(cfl / (max_x / dx + max_y / dy), float(target) - t) | |
| fx = interface_flux(conserved, gravity, momentum=1, dim=2) | |
| fy = interface_flux(conserved, gravity, momentum=2, dim=1) | |
| conserved = conserved - (dt / dx) * (fx - torch.roll(fx, 1, 2)) - (dt / dy) * (fy - torch.roll(fy, 1, 1)) | |
| t += dt | |
| step += 1 | |
| if step % 100 == 0: | |
| print('HLL_PROGRESS', {'step': step, 't': t, 'dt': dt, | |
| 'min_depth': conserved[0].min().item()}, flush=True) | |
| if not torch.isfinite(conserved).all() or conserved[0].min() <= 0: | |
| raise FloatingPointError('HLL reference is nonfinite or violates wet-cell positivity.') | |
| primitive = torch.stack((conserved[0], conserved[1] / conserved[0], conserved[2] / conserved[0]), dim=-1) | |
| snapshots.append(primitive.cpu().numpy()) | |
| mass = conserved[0].double().sum().item() * dx * dy | |
| diagnostics.append({'time': float(target), 'mass': mass, | |
| 'relative_mass_drift': (mass - initial_mass) / initial_mass, | |
| 'min_depth': conserved[0].min().item(), 'steps': step}) | |
| print('HLL_SNAPSHOT', diagnostics[-1], flush=True) | |
| fields = np.stack(snapshots) | |
| np.savez_compressed(path, x=x, y=y, times=times, fields=fields, | |
| variables=np.array(['h', 'u', 'v']), dx=dx, dy=dy, cfl=cfl) | |
| return fields, {'scheme': 'independent first-order unsplit HLL with Davis wave speeds', | |
| 'initial_condition': 'paper Eq.55', 'training_use': False, | |
| 'dx': dx, 'dy': dy, 'cfl': cfl, 'boundary': 'periodic', | |
| 'dtype': 'float32', 'steps': step, 'diagnostics': diagnostics, | |
| 'elapsed_seconds': time.monotonic() - started} | |
| def interface_flux(state, gravity, momentum, dim): | |
| """HLL numerical flux on forward cell interfaces, with periodic wrap.""" | |
| neighbor = torch.roll(state, -1, dim) | |
| hl, hr = state[0], neighbor[0] | |
| vl, vr = state[momentum] / hl, neighbor[momentum] / hr | |
| sl = torch.minimum(vl - (gravity * hl).sqrt(), vr - (gravity * hr).sqrt()) | |
| sr = torch.maximum(vl + (gravity * hl).sqrt(), vr + (gravity * hr).sqrt()) | |
| fl, fr = state * vl, neighbor * vr | |
| fl[momentum] += 0.5 * gravity * hl.square() | |
| fr[momentum] += 0.5 * gravity * hr.square() | |
| hll = (sr * fl - sl * fr + sl * sr * (neighbor - state)) / (sr - sl) | |
| return torch.where((sl >= 0)[None], fl, torch.where((sr <= 0)[None], fr, hll)) | |