drbx 2.0.0.dev0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- drbx/__init__.py +20 -0
- drbx/__main__.py +5 -0
- drbx/cli.py +586 -0
- drbx/config/__init__.py +20 -0
- drbx/config/boutinp.py +556 -0
- drbx/config/model.py +34 -0
- drbx/config/normalization.py +66 -0
- drbx/data/atomic_rates/__init__.py +1 -0
- drbx/data/atomic_rates/iz_AMJUEL_H.x_2.1.5.json +213 -0
- drbx/data/atomic_rates/iz_AMJUEL_H.x_2.3.9a.json +213 -0
- drbx/data/atomic_rates/rec_AMJUEL_H.x_2.1.8.json +213 -0
- drbx/data/atomic_rates/rec_AMJUEL_H.x_2.3.13a.json +213 -0
- drbx/geometry/__init__.py +207 -0
- drbx/geometry/embedding.py +56 -0
- drbx/geometry/essos_import.py +1385 -0
- drbx/geometry/fci_geometry.py +4622 -0
- drbx/geometry/fci_maps.py +85 -0
- drbx/geometry/island_divertor.py +291 -0
- drbx/geometry/metric_tensor.py +99 -0
- drbx/geometry/open_slab.py +150 -0
- drbx/geometry/rotating_ellipse.py +253 -0
- drbx/geometry/shifted_torus.py +225 -0
- drbx/geometry/stellarator.py +287 -0
- drbx/geometry/vmec_extender_import.py +499 -0
- drbx/geometry/vmec_jax_import.py +306 -0
- drbx/linear/__init__.py +37 -0
- drbx/linear/dispersion.py +138 -0
- drbx/linear/eigen.py +91 -0
- drbx/native/__init__.py +224 -0
- drbx/native/array_backend.py +64 -0
- drbx/native/deck_runner.py +779 -0
- drbx/native/electromagnetic.py +250 -0
- drbx/native/expression.py +173 -0
- drbx/native/fci.py +295 -0
- drbx/native/fci_2_field_rhs.py +182 -0
- drbx/native/fci_4_field_rhs.py +1267 -0
- drbx/native/fci_boundaries.py +2494 -0
- drbx/native/fci_differentiable_case.py +304 -0
- drbx/native/fci_drb_EB_rhs.py +1243 -0
- drbx/native/fci_drb_rhs.py +190 -0
- drbx/native/fci_halo.py +1575 -0
- drbx/native/fci_helpers.py +350 -0
- drbx/native/fci_model.py +294 -0
- drbx/native/fci_neutral.py +139 -0
- drbx/native/fci_operators.py +4081 -0
- drbx/native/fci_sharding.py +597 -0
- drbx/native/fci_sheath_recycling.py +206 -0
- drbx/native/fci_time_integrator.py +96 -0
- drbx/native/fci_vorticity.py +198 -0
- drbx/native/fluid_1d.py +330 -0
- drbx/native/hasegawa_wakatani.py +196 -0
- drbx/native/limiters.py +57 -0
- drbx/native/mesh.py +238 -0
- drbx/native/metrics.py +234 -0
- drbx/native/neutrals/__init__.py +58 -0
- drbx/native/neutrals/atomic_rates.py +134 -0
- drbx/native/neutrals/detachment_sol_model.py +221 -0
- drbx/native/neutrals/reactions.py +164 -0
- drbx/native/neutrals/recycling_sol_model.py +197 -0
- drbx/native/sol_flux_tube.py +133 -0
- drbx/native/stellarator_turbulence.py +343 -0
- drbx/native/transport.py +134 -0
- drbx/native/units.py +32 -0
- drbx/native/vorticity.py +252 -0
- drbx/runtime/__init__.py +53 -0
- drbx/runtime/artifacts.py +161 -0
- drbx/runtime/memory.py +144 -0
- drbx/runtime/output.py +374 -0
- drbx/runtime/paths.py +9 -0
- drbx/runtime/performance.py +161 -0
- drbx/runtime/run_config.py +184 -0
- drbx/runtime/scheduler.py +99 -0
- drbx/runtime/state.py +40 -0
- drbx/validation/__init__.py +424 -0
- drbx/validation/autodiff_diffusion.py +329 -0
- drbx/validation/autodiff_diffusion_uncertainty.py +235 -0
- drbx/validation/diverted_tokamak_movie.py +558 -0
- drbx/validation/essos_fieldline_import_campaign.py +181 -0
- drbx/validation/essos_imported_artifact_audit.py +535 -0
- drbx/validation/essos_imported_drb_movie_campaign.py +2826 -0
- drbx/validation/essos_imported_fci_campaign.py +5241 -0
- drbx/validation/essos_imported_pytree_campaign.py +406 -0
- drbx/validation/essos_vmec_closed_field_campaign.py +314 -0
- drbx/validation/essos_vmec_closed_field_transient_campaign.py +629 -0
- drbx/validation/essos_vmec_fieldline_surface_campaign.py +620 -0
- drbx/validation/fluid_1d_mms_convergence.py +250 -0
- drbx/validation/geometry_lineouts.py +136 -0
- drbx/validation/geometry_slices.py +178 -0
- drbx/validation/publication_plotting.py +91 -0
- drbx/validation/stellarator_drb_pytree_campaign.py +621 -0
- drbx/validation/stellarator_fci_geometry_campaign.py +200 -0
- drbx/validation/stellarator_fci_operator_campaign.py +304 -0
- drbx/validation/stellarator_fci_suite_campaign.py +264 -0
- drbx/validation/stellarator_metric_mms_campaign.py +289 -0
- drbx/validation/stellarator_neutral_physics_campaign.py +255 -0
- drbx/validation/stellarator_sheath_recycling_campaign.py +331 -0
- drbx/validation/stellarator_sol_showcase.py +628 -0
- drbx/validation/stellarator_vorticity_campaign.py +304 -0
- drbx/validation/vmec_extender_edge_field_campaign.py +260 -0
- drbx/validation/vmec_extender_sol_smoke_campaign.py +365 -0
- drbx-2.0.0.dev0.dist-info/METADATA +380 -0
- drbx-2.0.0.dev0.dist-info/RECORD +106 -0
- drbx-2.0.0.dev0.dist-info/WHEEL +5 -0
- drbx-2.0.0.dev0.dist-info/entry_points.txt +2 -0
- drbx-2.0.0.dev0.dist-info/licenses/LICENSE +21 -0
- drbx-2.0.0.dev0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass
|
|
4
|
+
|
|
5
|
+
import jax.numpy as jnp
|
|
6
|
+
import numpy as np
|
|
7
|
+
|
|
8
|
+
from .fci_maps import FciMaps
|
|
9
|
+
from .metric_tensor import MetricTensor3D
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
@dataclass(frozen=True)
|
|
13
|
+
class SyntheticStellaratorGeometry:
|
|
14
|
+
"""Analytic non-axisymmetric stellarator-like geometry for validation."""
|
|
15
|
+
|
|
16
|
+
coordinates_x: jnp.ndarray
|
|
17
|
+
coordinates_y: jnp.ndarray
|
|
18
|
+
coordinates_z: jnp.ndarray
|
|
19
|
+
radial: jnp.ndarray
|
|
20
|
+
toroidal_angle: jnp.ndarray
|
|
21
|
+
poloidal_angle: jnp.ndarray
|
|
22
|
+
iota: jnp.ndarray
|
|
23
|
+
curvature: jnp.ndarray
|
|
24
|
+
connection_length: jnp.ndarray
|
|
25
|
+
metric: MetricTensor3D
|
|
26
|
+
maps: FciMaps
|
|
27
|
+
metadata: dict[str, float | int | str]
|
|
28
|
+
|
|
29
|
+
@property
|
|
30
|
+
def shape(self) -> tuple[int, int, int]:
|
|
31
|
+
return tuple(int(value) for value in self.radial.shape)
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def build_synthetic_stellarator_geometry(
|
|
35
|
+
*,
|
|
36
|
+
nx: int = 36,
|
|
37
|
+
ny: int = 32,
|
|
38
|
+
nz: int = 64,
|
|
39
|
+
major_radius: float = 3.8,
|
|
40
|
+
minor_radius: float = 0.7,
|
|
41
|
+
elongation: float = 1.45,
|
|
42
|
+
field_periods: int = 5,
|
|
43
|
+
island_mode: int = 2,
|
|
44
|
+
island_amplitude: float = 0.030,
|
|
45
|
+
mirror_amplitude: float = 0.16,
|
|
46
|
+
iota_axis: float = 0.38,
|
|
47
|
+
iota_edge: float = 0.58,
|
|
48
|
+
) -> SyntheticStellaratorGeometry:
|
|
49
|
+
"""Construct a deterministic analytic 3D stellarator/SOL validation geometry."""
|
|
50
|
+
|
|
51
|
+
s_1d = np.linspace(0.08, 1.0, nx)
|
|
52
|
+
phi_1d = np.linspace(0.0, 2.0 * np.pi, ny, endpoint=False)
|
|
53
|
+
theta_1d = np.linspace(0.0, 2.0 * np.pi, nz, endpoint=False)
|
|
54
|
+
s, phi, theta = np.meshgrid(s_1d, phi_1d, theta_1d, indexing="ij")
|
|
55
|
+
|
|
56
|
+
iota = iota_axis + (iota_edge - iota_axis) * s**1.7
|
|
57
|
+
rotating_angle = theta - 0.38 * np.sin(field_periods * phi)
|
|
58
|
+
radial_size = minor_radius * s
|
|
59
|
+
ellipse_modulation = (
|
|
60
|
+
1.0
|
|
61
|
+
+ 0.10 * np.cos(field_periods * phi)
|
|
62
|
+
+ 0.035 * s * np.cos(island_mode * theta - field_periods * phi)
|
|
63
|
+
)
|
|
64
|
+
vertical_modulation = 1.0 + 0.08 * np.sin(field_periods * phi + 0.4)
|
|
65
|
+
r_major = major_radius + radial_size * ellipse_modulation * np.cos(rotating_angle)
|
|
66
|
+
z_vertical = elongation * radial_size * vertical_modulation * np.sin(rotating_angle)
|
|
67
|
+
x_cart = r_major * np.cos(phi)
|
|
68
|
+
y_cart = r_major * np.sin(phi)
|
|
69
|
+
|
|
70
|
+
metric = _metric_from_coordinates(
|
|
71
|
+
x_cart,
|
|
72
|
+
y_cart,
|
|
73
|
+
z_vertical,
|
|
74
|
+
s_1d=s_1d,
|
|
75
|
+
phi_1d=phi_1d,
|
|
76
|
+
theta_1d=theta_1d,
|
|
77
|
+
Bxy=_magnetic_field_strength(
|
|
78
|
+
s=s,
|
|
79
|
+
phi=phi,
|
|
80
|
+
theta=theta,
|
|
81
|
+
field_periods=field_periods,
|
|
82
|
+
island_mode=island_mode,
|
|
83
|
+
mirror_amplitude=mirror_amplitude,
|
|
84
|
+
),
|
|
85
|
+
)
|
|
86
|
+
maps = _build_maps(
|
|
87
|
+
s=s,
|
|
88
|
+
phi=phi,
|
|
89
|
+
theta=theta,
|
|
90
|
+
iota=iota,
|
|
91
|
+
nx=nx,
|
|
92
|
+
ny=ny,
|
|
93
|
+
nz=nz,
|
|
94
|
+
field_periods=field_periods,
|
|
95
|
+
island_mode=island_mode,
|
|
96
|
+
island_amplitude=island_amplitude,
|
|
97
|
+
)
|
|
98
|
+
curvature = _curvature_proxy(
|
|
99
|
+
s=s,
|
|
100
|
+
phi=phi,
|
|
101
|
+
theta=theta,
|
|
102
|
+
field_periods=field_periods,
|
|
103
|
+
island_mode=island_mode,
|
|
104
|
+
major_radius=major_radius,
|
|
105
|
+
)
|
|
106
|
+
connection_length = _estimate_connection_length(maps, metric, max_steps=max(2 * ny, 16))
|
|
107
|
+
return SyntheticStellaratorGeometry(
|
|
108
|
+
coordinates_x=jnp.asarray(x_cart, dtype=jnp.float64),
|
|
109
|
+
coordinates_y=jnp.asarray(y_cart, dtype=jnp.float64),
|
|
110
|
+
coordinates_z=jnp.asarray(z_vertical, dtype=jnp.float64),
|
|
111
|
+
radial=jnp.asarray(s, dtype=jnp.float64),
|
|
112
|
+
toroidal_angle=jnp.asarray(phi, dtype=jnp.float64),
|
|
113
|
+
poloidal_angle=jnp.asarray(theta, dtype=jnp.float64),
|
|
114
|
+
iota=jnp.asarray(iota, dtype=jnp.float64),
|
|
115
|
+
curvature=jnp.asarray(curvature, dtype=jnp.float64),
|
|
116
|
+
connection_length=jnp.asarray(connection_length, dtype=jnp.float64),
|
|
117
|
+
metric=metric,
|
|
118
|
+
maps=maps,
|
|
119
|
+
metadata={
|
|
120
|
+
"geometry_family": "analytic_non_axisymmetric_stellarator",
|
|
121
|
+
"nx": int(nx),
|
|
122
|
+
"ny": int(ny),
|
|
123
|
+
"nz": int(nz),
|
|
124
|
+
"major_radius": float(major_radius),
|
|
125
|
+
"minor_radius": float(minor_radius),
|
|
126
|
+
"elongation": float(elongation),
|
|
127
|
+
"field_periods": int(field_periods),
|
|
128
|
+
"island_mode": int(island_mode),
|
|
129
|
+
"island_amplitude": float(island_amplitude),
|
|
130
|
+
"mirror_amplitude": float(mirror_amplitude),
|
|
131
|
+
"iota_axis": float(iota_axis),
|
|
132
|
+
"iota_edge": float(iota_edge),
|
|
133
|
+
},
|
|
134
|
+
)
|
|
135
|
+
|
|
136
|
+
|
|
137
|
+
def _magnetic_field_strength(
|
|
138
|
+
*,
|
|
139
|
+
s: np.ndarray,
|
|
140
|
+
phi: np.ndarray,
|
|
141
|
+
theta: np.ndarray,
|
|
142
|
+
field_periods: int,
|
|
143
|
+
island_mode: int,
|
|
144
|
+
mirror_amplitude: float,
|
|
145
|
+
) -> np.ndarray:
|
|
146
|
+
mirror = mirror_amplitude * np.cos(field_periods * phi - island_mode * theta)
|
|
147
|
+
radial = 0.10 * (s - np.mean(s))
|
|
148
|
+
corrugation = 0.035 * s * np.sin((field_periods + 1) * phi + theta)
|
|
149
|
+
return 1.0 + mirror + radial + corrugation
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
def _metric_from_coordinates(
|
|
153
|
+
x_cart: np.ndarray,
|
|
154
|
+
y_cart: np.ndarray,
|
|
155
|
+
z_cart: np.ndarray,
|
|
156
|
+
*,
|
|
157
|
+
s_1d: np.ndarray,
|
|
158
|
+
phi_1d: np.ndarray,
|
|
159
|
+
theta_1d: np.ndarray,
|
|
160
|
+
Bxy: np.ndarray,
|
|
161
|
+
) -> MetricTensor3D:
|
|
162
|
+
ds = float(s_1d[1] - s_1d[0]) if s_1d.size > 1 else 1.0
|
|
163
|
+
dphi = float(phi_1d[1] - phi_1d[0]) if phi_1d.size > 1 else 2.0 * np.pi
|
|
164
|
+
dtheta = float(theta_1d[1] - theta_1d[0]) if theta_1d.size > 1 else 2.0 * np.pi
|
|
165
|
+
|
|
166
|
+
derivs = []
|
|
167
|
+
for coords in (x_cart, y_cart, z_cart):
|
|
168
|
+
derivs.append(np.gradient(coords, ds, dphi, dtheta, edge_order=2))
|
|
169
|
+
|
|
170
|
+
r_s = np.stack([derivs[0][0], derivs[1][0], derivs[2][0]], axis=-1)
|
|
171
|
+
r_phi = np.stack([derivs[0][1], derivs[1][1], derivs[2][1]], axis=-1)
|
|
172
|
+
r_theta = np.stack([derivs[0][2], derivs[1][2], derivs[2][2]], axis=-1)
|
|
173
|
+
cov = np.empty(x_cart.shape + (3, 3), dtype=np.float64)
|
|
174
|
+
basis = (r_s, r_phi, r_theta)
|
|
175
|
+
for i, left in enumerate(basis):
|
|
176
|
+
for j, right in enumerate(basis):
|
|
177
|
+
cov[..., i, j] = np.sum(left * right, axis=-1)
|
|
178
|
+
determinant = np.linalg.det(cov)
|
|
179
|
+
regularization = np.maximum(1.0e-12, 1.0e-11 * np.nanmax(np.abs(determinant)))
|
|
180
|
+
bad = determinant <= regularization
|
|
181
|
+
if np.any(bad):
|
|
182
|
+
cov[bad] = cov[bad] + np.eye(3) * regularization
|
|
183
|
+
contrav = np.linalg.inv(cov)
|
|
184
|
+
jacobian = np.sqrt(np.maximum(np.linalg.det(cov), regularization))
|
|
185
|
+
dx = np.full_like(x_cart, ds)
|
|
186
|
+
dy = np.full_like(x_cart, dphi)
|
|
187
|
+
dz = np.full_like(x_cart, dtheta)
|
|
188
|
+
return MetricTensor3D(
|
|
189
|
+
dx=jnp.asarray(dx, dtype=jnp.float64),
|
|
190
|
+
dy=jnp.asarray(dy, dtype=jnp.float64),
|
|
191
|
+
dz=jnp.asarray(dz, dtype=jnp.float64),
|
|
192
|
+
J=jnp.asarray(jacobian, dtype=jnp.float64),
|
|
193
|
+
Bxy=jnp.asarray(Bxy, dtype=jnp.float64),
|
|
194
|
+
g11=jnp.asarray(contrav[..., 0, 0], dtype=jnp.float64),
|
|
195
|
+
g22=jnp.asarray(contrav[..., 1, 1], dtype=jnp.float64),
|
|
196
|
+
g33=jnp.asarray(contrav[..., 2, 2], dtype=jnp.float64),
|
|
197
|
+
g12=jnp.asarray(contrav[..., 0, 1], dtype=jnp.float64),
|
|
198
|
+
g13=jnp.asarray(contrav[..., 0, 2], dtype=jnp.float64),
|
|
199
|
+
g23=jnp.asarray(contrav[..., 1, 2], dtype=jnp.float64),
|
|
200
|
+
g_11=jnp.asarray(cov[..., 0, 0], dtype=jnp.float64),
|
|
201
|
+
g_22=jnp.asarray(cov[..., 1, 1], dtype=jnp.float64),
|
|
202
|
+
g_33=jnp.asarray(cov[..., 2, 2], dtype=jnp.float64),
|
|
203
|
+
g_12=jnp.asarray(cov[..., 0, 1], dtype=jnp.float64),
|
|
204
|
+
g_13=jnp.asarray(cov[..., 0, 2], dtype=jnp.float64),
|
|
205
|
+
g_23=jnp.asarray(cov[..., 1, 2], dtype=jnp.float64),
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def _build_maps(
|
|
210
|
+
*,
|
|
211
|
+
s: np.ndarray,
|
|
212
|
+
phi: np.ndarray,
|
|
213
|
+
theta: np.ndarray,
|
|
214
|
+
iota: np.ndarray,
|
|
215
|
+
nx: int,
|
|
216
|
+
ny: int,
|
|
217
|
+
nz: int,
|
|
218
|
+
field_periods: int,
|
|
219
|
+
island_mode: int,
|
|
220
|
+
island_amplitude: float,
|
|
221
|
+
) -> FciMaps:
|
|
222
|
+
dphi = 2.0 * np.pi / float(ny)
|
|
223
|
+
phase = island_mode * theta - field_periods * phi
|
|
224
|
+
island_envelope = np.exp(-((s - 0.74) / 0.19) ** 2)
|
|
225
|
+
dx_dphi = island_amplitude * island_envelope * np.sin(phase)
|
|
226
|
+
dtheta_dphi = iota + 0.07 * island_envelope * np.cos(phase)
|
|
227
|
+
x_index = np.arange(nx, dtype=np.float64)[:, None, None]
|
|
228
|
+
z_index = np.arange(nz, dtype=np.float64)[None, None, :]
|
|
229
|
+
forward_x = x_index + dx_dphi * dphi * (nx - 1)
|
|
230
|
+
backward_x = x_index - dx_dphi * dphi * (nx - 1)
|
|
231
|
+
forward_z = z_index + dtheta_dphi * dphi * nz / (2.0 * np.pi)
|
|
232
|
+
backward_z = z_index - dtheta_dphi * dphi * nz / (2.0 * np.pi)
|
|
233
|
+
return FciMaps(
|
|
234
|
+
forward_x=jnp.asarray(forward_x, dtype=jnp.float64),
|
|
235
|
+
forward_z=jnp.asarray(forward_z, dtype=jnp.float64),
|
|
236
|
+
backward_x=jnp.asarray(backward_x, dtype=jnp.float64),
|
|
237
|
+
backward_z=jnp.asarray(backward_z, dtype=jnp.float64),
|
|
238
|
+
forward_boundary=jnp.asarray((forward_x < 0.0) | (forward_x > nx - 1)),
|
|
239
|
+
backward_boundary=jnp.asarray((backward_x < 0.0) | (backward_x > nx - 1)),
|
|
240
|
+
dphi=float(dphi),
|
|
241
|
+
)
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
def _curvature_proxy(
|
|
245
|
+
*,
|
|
246
|
+
s: np.ndarray,
|
|
247
|
+
phi: np.ndarray,
|
|
248
|
+
theta: np.ndarray,
|
|
249
|
+
field_periods: int,
|
|
250
|
+
island_mode: int,
|
|
251
|
+
major_radius: float,
|
|
252
|
+
) -> np.ndarray:
|
|
253
|
+
bad_curvature = -np.cos(theta) / major_radius
|
|
254
|
+
non_axisymmetric = 0.35 * np.cos(field_periods * phi - island_mode * theta) / major_radius
|
|
255
|
+
radial_weight = 0.4 + 0.6 * s
|
|
256
|
+
return radial_weight * (bad_curvature + non_axisymmetric)
|
|
257
|
+
|
|
258
|
+
|
|
259
|
+
def _estimate_connection_length(maps: FciMaps, metric: MetricTensor3D, *, max_steps: int) -> np.ndarray:
|
|
260
|
+
nx, ny, nz = maps.shape
|
|
261
|
+
x0 = np.arange(nx, dtype=np.float64)[:, None, None]
|
|
262
|
+
z0 = np.arange(nz, dtype=np.float64)[None, None, :]
|
|
263
|
+
x = np.broadcast_to(x0, (nx, ny, nz)).copy()
|
|
264
|
+
z = np.broadcast_to(z0, (nx, ny, nz)).copy()
|
|
265
|
+
alive = np.ones((nx, ny, nz), dtype=bool)
|
|
266
|
+
steps = np.zeros((nx, ny, nz), dtype=np.float64)
|
|
267
|
+
step_length = float(np.nanmean(np.sqrt(np.asarray(metric.g_22)))) * float(maps.dphi)
|
|
268
|
+
forward_x = np.asarray(maps.forward_x)
|
|
269
|
+
forward_z = np.asarray(maps.forward_z)
|
|
270
|
+
for _ in range(max_steps):
|
|
271
|
+
i = np.clip(np.rint(x).astype(np.int64), 0, nx - 1)
|
|
272
|
+
k = np.mod(np.rint(z).astype(np.int64), nz)
|
|
273
|
+
j = np.broadcast_to(np.arange(ny, dtype=np.int64)[None, :, None], (nx, ny, nz))
|
|
274
|
+
next_x = forward_x[i, j, k]
|
|
275
|
+
next_z = forward_z[i, j, k]
|
|
276
|
+
still_inside = (next_x >= 0.0) & (next_x <= nx - 1.0)
|
|
277
|
+
steps = np.where(alive & still_inside, steps + 1.0, steps)
|
|
278
|
+
alive = alive & still_inside
|
|
279
|
+
x = np.where(alive, next_x, x)
|
|
280
|
+
z = np.where(alive, next_z, z)
|
|
281
|
+
radial = np.broadcast_to(x0 / float(max(nx - 1, 1)), (nx, ny, nz))
|
|
282
|
+
radial_shift = np.abs(forward_x - x0)
|
|
283
|
+
island_lobe = np.exp(-((radial - 0.76) / 0.16) ** 2) * (1.0 + 2.5 * radial_shift)
|
|
284
|
+
wall_distance = np.maximum(1.0 - radial, 0.02)
|
|
285
|
+
proxy_steps = 3.0 + 42.0 * wall_distance + 16.0 * island_lobe
|
|
286
|
+
bounded_steps = np.minimum(np.maximum(steps, 1.0), proxy_steps)
|
|
287
|
+
return bounded_steps * step_length
|