flow
Kokkos cut-cell IBM incompressible Navier-Stokes solver + pnm pore extraction
Loading...
Searching...
No Matches
state_initialization.py
Go to the documentation of this file.
1"""Helpers for continuation sweeps and cross-resolution solver initialization."""
2
3import numpy as np
4
5
6def fit_force_law(u_mean_samples, force_samples):
7 """Fit ``force ~= a*u_mean + b*u_mean**2`` in a least-squares sense."""
8 u_mean_samples = np.asarray(u_mean_samples, dtype=np.float64)
9 force_samples = np.asarray(force_samples, dtype=np.float64)
10 design = np.column_stack([u_mean_samples, u_mean_samples ** 2])
11 coeffs, *_ = np.linalg.lstsq(design, force_samples, rcond=None)
12 return float(coeffs[0]), float(coeffs[1])
13
14
15def predict_u_mean(force, linear_coeff, quadratic_coeff):
16 """Invert ``force = a*u_mean + b*u_mean**2`` for the positive root."""
17 force = float(force)
18 linear_coeff = float(linear_coeff)
19 quadratic_coeff = float(quadratic_coeff)
20 if abs(quadratic_coeff) < 1e-14:
21 if abs(linear_coeff) < 1e-14:
22 raise ValueError("force law is degenerate")
23 return force / linear_coeff
24 disc = linear_coeff ** 2 + 4.0 * quadratic_coeff * force
25 if disc < 0.0:
26 raise ValueError("force law has no real solution for the requested force")
27 return (-linear_coeff + np.sqrt(disc)) / (2.0 * quadratic_coeff)
28
29
30def scale_solver_state(solver, previous_u_mean, target_u_mean, previous_force, target_force):
31 """Scale an already converged solver state in place for continuation."""
32 if abs(previous_u_mean) < 1e-14:
33 raise ValueError("previous_u_mean must be non-zero")
34 if abs(previous_force) < 1e-14:
35 raise ValueError("previous_force must be non-zero")
36 solver.scale_state(
37 float(target_u_mean) / float(previous_u_mean),
38 float(target_force) / float(previous_force),
39 )
40
41
43 """Copy ``u``, ``v``, ``w`` and ``p`` from a solver into NumPy arrays."""
44 return {
45 "u": np.asarray(solver.get_u(), dtype=np.float64),
46 "v": np.asarray(solver.get_v(), dtype=np.float64),
47 "w": np.asarray(solver.get_w(), dtype=np.float64),
48 "p": np.asarray(solver.get_p(), dtype=np.float64),
49 }
50
51
52def load_solver_state(solver, state):
53 """Load a previously extracted state into a solver."""
54 solver.set_state(
55 np.asarray(state["u"], dtype=np.float64),
56 np.asarray(state["v"], dtype=np.float64),
57 np.asarray(state["w"], dtype=np.float64),
58 np.asarray(state["p"], dtype=np.float64),
59 )
60
61
62def _resample_axis(field, target_coords, axis):
63 """Periodically resample one axis of a structured field."""
64 source_coords = np.linspace(0.0, 1.0, field.shape[axis], endpoint=False)
65 field = np.moveaxis(field, axis, 0)
66 resampled = np.empty((target_coords.size,) + field.shape[1:], dtype=np.float64)
67 for index in np.ndindex(field.shape[1:]):
68 resampled[(slice(None),) + index] = np.interp(
69 target_coords,
70 source_coords,
71 field[(slice(None),) + index],
72 period=1.0,
73 )
74 return np.moveaxis(resampled, 0, axis)
75
76
77def resample_field_linear(field, target_shape):
78 """Periodically resample a scalar field to a new ``(nz, ny, nx)`` shape."""
79 field = np.asarray(field, dtype=np.float64)
80 if field.ndim != 3:
81 raise ValueError("field must have shape (nz, ny, nx)")
82 target_shape = tuple(int(v) for v in target_shape)
83 if len(target_shape) != 3:
84 raise ValueError("target_shape must have length 3")
85
86 target_z = np.linspace(0.0, 1.0, target_shape[0], endpoint=False)
87 target_y = np.linspace(0.0, 1.0, target_shape[1], endpoint=False)
88 target_x = np.linspace(0.0, 1.0, target_shape[2], endpoint=False)
89
90 resampled = _resample_axis(field, target_x, axis=2)
91 resampled = _resample_axis(resampled, target_y, axis=1)
92 resampled = _resample_axis(resampled, target_z, axis=0)
93 return resampled
94
95
96def resample_state_linear(state, target_shape):
97 """Resample all entries of a state dictionary with linear interpolation."""
98 return {
99 name: resample_field_linear(field, target_shape)
100 for name, field in state.items()
101 }
fit_force_law(u_mean_samples, force_samples)
resample_state_linear(state, target_shape)
scale_solver_state(solver, previous_u_mean, target_u_mean, previous_force, target_force)
predict_u_mean(force, linear_coeff, quadratic_coeff)
_resample_axis(field, target_coords, axis)
load_solver_state(solver, state)
resample_field_linear(field, target_shape)