witwin-maxwell 0.3.0__py3-none-win_amd64.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.
- witwin/maxwell/__init__.py +164 -0
- witwin/maxwell/adapters/__init__.py +1 -0
- witwin/maxwell/adapters/gds.py +203 -0
- witwin/maxwell/adapters/tidy3d.py +1669 -0
- witwin/maxwell/adjoint_inputs.py +70 -0
- witwin/maxwell/compiler/__init__.py +11 -0
- witwin/maxwell/compiler/materials.py +1355 -0
- witwin/maxwell/compiler/monitors.py +164 -0
- witwin/maxwell/compiler/sources.py +222 -0
- witwin/maxwell/fdfd/__init__.py +3 -0
- witwin/maxwell/fdfd/adjoint/__init__.py +3 -0
- witwin/maxwell/fdfd/adjoint/bridge.py +180 -0
- witwin/maxwell/fdfd/ams.py +300 -0
- witwin/maxwell/fdfd/krylov.py +280 -0
- witwin/maxwell/fdfd/plotting.py +110 -0
- witwin/maxwell/fdfd/postprocess.py +33 -0
- witwin/maxwell/fdfd/solver.py +1057 -0
- witwin/maxwell/fdtd/__init__.py +4 -0
- witwin/maxwell/fdtd/adjoint/__init__.py +21 -0
- witwin/maxwell/fdtd/adjoint/bridge.py +746 -0
- witwin/maxwell/fdtd/adjoint/capabilities.py +29 -0
- witwin/maxwell/fdtd/adjoint/core.py +3614 -0
- witwin/maxwell/fdtd/adjoint/dispatch.py +684 -0
- witwin/maxwell/fdtd/adjoint/native.py +2561 -0
- witwin/maxwell/fdtd/adjoint/profiler.py +195 -0
- witwin/maxwell/fdtd/adjoint/reverse_common.py +207 -0
- witwin/maxwell/fdtd/adjoint/seeds.py +524 -0
- witwin/maxwell/fdtd/boundary/__init__.py +37 -0
- witwin/maxwell/fdtd/boundary/bloch.py +90 -0
- witwin/maxwell/fdtd/boundary/common.py +41 -0
- witwin/maxwell/fdtd/boundary/cpml.py +527 -0
- witwin/maxwell/fdtd/boundary/runtime.py +209 -0
- witwin/maxwell/fdtd/checkpoint.py +227 -0
- witwin/maxwell/fdtd/coords.py +32 -0
- witwin/maxwell/fdtd/cuda/__init__.py +11 -0
- witwin/maxwell/fdtd/cuda/backend.py +3532 -0
- witwin/maxwell/fdtd/cuda/build.py +292 -0
- witwin/maxwell/fdtd/cuda/extension.cpp +2053 -0
- witwin/maxwell/fdtd/cuda/kernels/adjoint.cu +5290 -0
- witwin/maxwell/fdtd/cuda/kernels/aniso.cu +1704 -0
- witwin/maxwell/fdtd/cuda/kernels/boundary.cu +424 -0
- witwin/maxwell/fdtd/cuda/kernels/common.cu +74 -0
- witwin/maxwell/fdtd/cuda/kernels/common.cuh +82 -0
- witwin/maxwell/fdtd/cuda/kernels/dispersive.cu +782 -0
- witwin/maxwell/fdtd/cuda/kernels/electric.cu +3613 -0
- witwin/maxwell/fdtd/cuda/kernels/magnetic.cu +781 -0
- witwin/maxwell/fdtd/cuda/kernels/observers.cu +347 -0
- witwin/maxwell/fdtd/cuda/kernels/projection.cu +211 -0
- witwin/maxwell/fdtd/cuda/kernels/sources.cu +1482 -0
- witwin/maxwell/fdtd/cuda/kernels/spectral.cu +297 -0
- witwin/maxwell/fdtd/cuda/launch.h +23 -0
- witwin/maxwell/fdtd/cuda/prebuilt/witwin_maxwell_fdtd_cuda.pyd +0 -0
- witwin/maxwell/fdtd/cuda/runtime/__init__.py +6 -0
- witwin/maxwell/fdtd/cuda/runtime/dispatcher.py +6 -0
- witwin/maxwell/fdtd/cuda/runtime/graph.py +33 -0
- witwin/maxwell/fdtd/cuda/tensors.h +35 -0
- witwin/maxwell/fdtd/dispersion.py +48 -0
- witwin/maxwell/fdtd/evaluation.py +290 -0
- witwin/maxwell/fdtd/excitation/__init__.py +27 -0
- witwin/maxwell/fdtd/excitation/injection.py +1102 -0
- witwin/maxwell/fdtd/excitation/modes.py +1675 -0
- witwin/maxwell/fdtd/excitation/spatial.py +469 -0
- witwin/maxwell/fdtd/excitation/temporal.py +510 -0
- witwin/maxwell/fdtd/excitation/tfsf_apply.py +264 -0
- witwin/maxwell/fdtd/excitation/tfsf_common.py +421 -0
- witwin/maxwell/fdtd/excitation/tfsf_specs.py +490 -0
- witwin/maxwell/fdtd/excitation/tfsf_state.py +778 -0
- witwin/maxwell/fdtd/io.py +31 -0
- witwin/maxwell/fdtd/material_pullback.py +371 -0
- witwin/maxwell/fdtd/meshing/__init__.py +3 -0
- witwin/maxwell/fdtd/meshing/autogrid.py +335 -0
- witwin/maxwell/fdtd/observers.py +1453 -0
- witwin/maxwell/fdtd/plotting.py +121 -0
- witwin/maxwell/fdtd/postprocess.py +205 -0
- witwin/maxwell/fdtd/runtime/__init__.py +119 -0
- witwin/maxwell/fdtd/runtime/initialization.py +236 -0
- witwin/maxwell/fdtd/runtime/materials.py +1563 -0
- witwin/maxwell/fdtd/runtime/module_cache.py +31 -0
- witwin/maxwell/fdtd/runtime/spectral.py +581 -0
- witwin/maxwell/fdtd/runtime/stepping.py +1987 -0
- witwin/maxwell/fdtd/solver.py +502 -0
- witwin/maxwell/geometry/__init__.py +5 -0
- witwin/maxwell/geometry/polyslab.py +299 -0
- witwin/maxwell/materials.py +3 -0
- witwin/maxwell/media.py +1467 -0
- witwin/maxwell/monitors.py +743 -0
- witwin/maxwell/ports.py +113 -0
- witwin/maxwell/postprocess/RCS.py +139 -0
- witwin/maxwell/postprocess/__init__.py +42 -0
- witwin/maxwell/postprocess/diffraction.py +219 -0
- witwin/maxwell/postprocess/directivity.py +152 -0
- witwin/maxwell/postprocess/emission.py +67 -0
- witwin/maxwell/postprocess/modal.py +324 -0
- witwin/maxwell/postprocess/nfft.py +266 -0
- witwin/maxwell/postprocess/scattering_parameters.py +358 -0
- witwin/maxwell/postprocess/stratton_chu.py +1193 -0
- witwin/maxwell/result.py +967 -0
- witwin/maxwell/scene.py +1338 -0
- witwin/maxwell/simulation.py +659 -0
- witwin/maxwell/sources.py +917 -0
- witwin/maxwell/visualization/__init__.py +28 -0
- witwin/maxwell/visualization/interactive.py +484 -0
- witwin/maxwell/visualization/plots.py +568 -0
- witwin_maxwell-0.3.0.dist-info/METADATA +184 -0
- witwin_maxwell-0.3.0.dist-info/RECORD +107 -0
- witwin_maxwell-0.3.0.dist-info/WHEEL +4 -0
- witwin_maxwell-0.3.0.dist-info/licenses/LICENSE +13 -0
|
@@ -0,0 +1,424 @@
|
|
|
1
|
+
#include "../launch.h"
|
|
2
|
+
#include "../tensors.h"
|
|
3
|
+
#include "common.cuh"
|
|
4
|
+
|
|
5
|
+
#include <type_traits>
|
|
6
|
+
|
|
7
|
+
namespace {
|
|
8
|
+
|
|
9
|
+
void check_field3d(const torch::stable::Tensor& field, const char* name) {
|
|
10
|
+
check_float32_tensor(field, name);
|
|
11
|
+
check_contiguous_tensor(field, name);
|
|
12
|
+
STD_TORCH_CHECK(field.dim() == 3, name, " must be a contiguous 3D float32 CUDA tensor");
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
int64_t face_area(int64_t axis, int64_t nx, int64_t ny, int64_t nz) {
|
|
16
|
+
if (axis == 0) {
|
|
17
|
+
return ny * nz;
|
|
18
|
+
}
|
|
19
|
+
if (axis == 1) {
|
|
20
|
+
return nx * nz;
|
|
21
|
+
}
|
|
22
|
+
return nx * ny;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
template <int Axis>
|
|
26
|
+
__device__ __forceinline__ long long boundary_face_offset(
|
|
27
|
+
int nx,
|
|
28
|
+
int ny,
|
|
29
|
+
int nz,
|
|
30
|
+
int side,
|
|
31
|
+
int64_t face_linear,
|
|
32
|
+
int& i_out,
|
|
33
|
+
int& j_out,
|
|
34
|
+
int& k_out) {
|
|
35
|
+
if constexpr (Axis == 0) {
|
|
36
|
+
i_out = side == 0 ? 0 : nx - 1;
|
|
37
|
+
j_out = static_cast<int>(face_linear / nz);
|
|
38
|
+
k_out = static_cast<int>(face_linear - static_cast<int64_t>(j_out) * nz);
|
|
39
|
+
return offset3d(
|
|
40
|
+
static_cast<unsigned int>(i_out),
|
|
41
|
+
static_cast<unsigned int>(j_out),
|
|
42
|
+
static_cast<unsigned int>(k_out),
|
|
43
|
+
static_cast<unsigned int>(ny),
|
|
44
|
+
static_cast<unsigned int>(nz));
|
|
45
|
+
}
|
|
46
|
+
if constexpr (Axis == 1) {
|
|
47
|
+
i_out = static_cast<int>(face_linear / nz);
|
|
48
|
+
j_out = side == 0 ? 0 : ny - 1;
|
|
49
|
+
k_out = static_cast<int>(face_linear - static_cast<int64_t>(i_out) * nz);
|
|
50
|
+
return offset3d(
|
|
51
|
+
static_cast<unsigned int>(i_out),
|
|
52
|
+
static_cast<unsigned int>(j_out),
|
|
53
|
+
static_cast<unsigned int>(k_out),
|
|
54
|
+
static_cast<unsigned int>(ny),
|
|
55
|
+
static_cast<unsigned int>(nz));
|
|
56
|
+
}
|
|
57
|
+
i_out = static_cast<int>(face_linear / ny);
|
|
58
|
+
j_out = static_cast<int>(face_linear - static_cast<int64_t>(i_out) * ny);
|
|
59
|
+
k_out = side == 0 ? 0 : nz - 1;
|
|
60
|
+
return offset3d(
|
|
61
|
+
static_cast<unsigned int>(i_out),
|
|
62
|
+
static_cast<unsigned int>(j_out),
|
|
63
|
+
static_cast<unsigned int>(k_out),
|
|
64
|
+
static_cast<unsigned int>(ny),
|
|
65
|
+
static_cast<unsigned int>(nz));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
template <int Axis, int Side>
|
|
69
|
+
__global__ void clamp_field_face_kernel(
|
|
70
|
+
int nx,
|
|
71
|
+
int ny,
|
|
72
|
+
int nz,
|
|
73
|
+
float* __restrict__ field) {
|
|
74
|
+
const int u = static_cast<int>(blockIdx.x) * blockDim.x + threadIdx.x;
|
|
75
|
+
const int v = static_cast<int>(blockIdx.y) * blockDim.y + threadIdx.y;
|
|
76
|
+
if constexpr (Axis == 0) {
|
|
77
|
+
if (u >= nz || v >= ny) {
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
const int i = Side == 0 ? 0 : nx - 1;
|
|
81
|
+
field[offset3d(
|
|
82
|
+
static_cast<unsigned int>(i),
|
|
83
|
+
static_cast<unsigned int>(v),
|
|
84
|
+
static_cast<unsigned int>(u),
|
|
85
|
+
static_cast<unsigned int>(ny),
|
|
86
|
+
static_cast<unsigned int>(nz))] = 0.0f;
|
|
87
|
+
} else if constexpr (Axis == 1) {
|
|
88
|
+
if (u >= nz || v >= nx) {
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
const int j = Side == 0 ? 0 : ny - 1;
|
|
92
|
+
field[offset3d(
|
|
93
|
+
static_cast<unsigned int>(v),
|
|
94
|
+
static_cast<unsigned int>(j),
|
|
95
|
+
static_cast<unsigned int>(u),
|
|
96
|
+
static_cast<unsigned int>(ny),
|
|
97
|
+
static_cast<unsigned int>(nz))] = 0.0f;
|
|
98
|
+
} else {
|
|
99
|
+
if (u >= ny || v >= nx) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
const int k = Side == 0 ? 0 : nz - 1;
|
|
103
|
+
field[offset3d(
|
|
104
|
+
static_cast<unsigned int>(v),
|
|
105
|
+
static_cast<unsigned int>(u),
|
|
106
|
+
static_cast<unsigned int>(k),
|
|
107
|
+
static_cast<unsigned int>(ny),
|
|
108
|
+
static_cast<unsigned int>(nz))] = 0.0f;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
template <int Axis, int Side>
|
|
113
|
+
void launch_clamp_field_face(int nx, int ny, int nz, float* __restrict__ field) {
|
|
114
|
+
int width = nz;
|
|
115
|
+
int height = Axis == 0 ? ny : nx;
|
|
116
|
+
if constexpr (Axis == 2) {
|
|
117
|
+
width = ny;
|
|
118
|
+
}
|
|
119
|
+
const dim3 block(32, 8, 1);
|
|
120
|
+
const dim3 grid(
|
|
121
|
+
static_cast<unsigned int>((width + block.x - 1) / block.x),
|
|
122
|
+
static_cast<unsigned int>((height + block.y - 1) / block.y),
|
|
123
|
+
1);
|
|
124
|
+
clamp_field_face_kernel<Axis, Side><<<grid, block, 0, current_cuda_stream()>>>(nx, ny, nz, field);
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
template <int AxisA, int AxisB>
|
|
128
|
+
__global__ void clamp_pec_boundary_kernel(
|
|
129
|
+
int64_t total,
|
|
130
|
+
int nx,
|
|
131
|
+
int ny,
|
|
132
|
+
int nz,
|
|
133
|
+
int64_t face_area_a,
|
|
134
|
+
int64_t face_area_b,
|
|
135
|
+
float* __restrict__ field) {
|
|
136
|
+
const int64_t linear = static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
|
|
137
|
+
if (linear >= total) {
|
|
138
|
+
return;
|
|
139
|
+
}
|
|
140
|
+
const int64_t axis_a_total = 2 * face_area_a;
|
|
141
|
+
const bool second_axis = linear >= axis_a_total;
|
|
142
|
+
int64_t local = linear;
|
|
143
|
+
int64_t area = face_area_a;
|
|
144
|
+
if (second_axis) {
|
|
145
|
+
local = linear - axis_a_total;
|
|
146
|
+
area = face_area_b;
|
|
147
|
+
}
|
|
148
|
+
const int side = local >= area ? 1 : 0;
|
|
149
|
+
const int64_t face_linear = local - static_cast<int64_t>(side) * area;
|
|
150
|
+
int i = 0;
|
|
151
|
+
int j = 0;
|
|
152
|
+
int k = 0;
|
|
153
|
+
long long offset = 0;
|
|
154
|
+
if (second_axis) {
|
|
155
|
+
offset = boundary_face_offset<AxisB>(nx, ny, nz, side, face_linear, i, j, k);
|
|
156
|
+
} else {
|
|
157
|
+
offset = boundary_face_offset<AxisA>(nx, ny, nz, side, face_linear, i, j, k);
|
|
158
|
+
}
|
|
159
|
+
if constexpr (AxisA != AxisB) {
|
|
160
|
+
const int axis_a_coord = AxisA == 0 ? i : (AxisA == 1 ? j : k);
|
|
161
|
+
const int axis_a_size = AxisA == 0 ? nx : (AxisA == 1 ? ny : nz);
|
|
162
|
+
if (second_axis && (axis_a_coord == 0 || axis_a_coord + 1 == axis_a_size)) {
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
field[offset] = 0.0f;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
template <int AxisA, int AxisB>
|
|
170
|
+
void launch_clamp_pec_boundary(
|
|
171
|
+
int64_t total,
|
|
172
|
+
int nx,
|
|
173
|
+
int ny,
|
|
174
|
+
int nz,
|
|
175
|
+
int64_t face_area_a,
|
|
176
|
+
int64_t face_area_b,
|
|
177
|
+
float* __restrict__ field) {
|
|
178
|
+
clamp_pec_boundary_kernel<AxisA, AxisB><<<linear_grid(total), 256, 0, current_cuda_stream()>>>(
|
|
179
|
+
total,
|
|
180
|
+
nx,
|
|
181
|
+
ny,
|
|
182
|
+
nz,
|
|
183
|
+
face_area_a,
|
|
184
|
+
face_area_b,
|
|
185
|
+
field);
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
__device__ __forceinline__ long long mur_plane_offset(
|
|
189
|
+
int axis,
|
|
190
|
+
int normal_index,
|
|
191
|
+
int64_t plane_linear,
|
|
192
|
+
int ny,
|
|
193
|
+
int nz) {
|
|
194
|
+
// Row-major 3D offset of plane element `plane_linear` at the given normal
|
|
195
|
+
// index. The plane spans the two axes other than `axis`, iterated in
|
|
196
|
+
// ascending-axis order, matching a `field.select(axis, normal_index)` view.
|
|
197
|
+
if (axis == 0) {
|
|
198
|
+
const unsigned int j = static_cast<unsigned int>(plane_linear / nz);
|
|
199
|
+
const unsigned int k = static_cast<unsigned int>(plane_linear - static_cast<int64_t>(j) * nz);
|
|
200
|
+
return offset3d(static_cast<unsigned int>(normal_index), j, k, ny, nz);
|
|
201
|
+
}
|
|
202
|
+
if (axis == 1) {
|
|
203
|
+
const unsigned int i = static_cast<unsigned int>(plane_linear / nz);
|
|
204
|
+
const unsigned int k = static_cast<unsigned int>(plane_linear - static_cast<int64_t>(i) * nz);
|
|
205
|
+
return offset3d(i, static_cast<unsigned int>(normal_index), k, ny, nz);
|
|
206
|
+
}
|
|
207
|
+
const unsigned int i = static_cast<unsigned int>(plane_linear / ny);
|
|
208
|
+
const unsigned int j = static_cast<unsigned int>(plane_linear - static_cast<int64_t>(i) * ny);
|
|
209
|
+
return offset3d(i, j, static_cast<unsigned int>(normal_index), ny, nz);
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// First-order Mur absorbing boundary on one outer face of a single E component.
|
|
213
|
+
// Persistent `prev_boundary` / `prev_adjacent` plane buffers carry the previous
|
|
214
|
+
// step's boundary and first-interior slices; the kernel reads the current
|
|
215
|
+
// adjacent slice, writes the extrapolated boundary slice, and updates both
|
|
216
|
+
// buffers in place. No allocation and fixed pointers, so it is safe to capture
|
|
217
|
+
// into a CUDA graph and replay.
|
|
218
|
+
__global__ void mur_abc_face_kernel(
|
|
219
|
+
int64_t plane_size,
|
|
220
|
+
int axis,
|
|
221
|
+
int ny,
|
|
222
|
+
int nz,
|
|
223
|
+
int boundary_index,
|
|
224
|
+
int adjacent_index,
|
|
225
|
+
float coef,
|
|
226
|
+
float* __restrict__ field,
|
|
227
|
+
float* __restrict__ prev_boundary,
|
|
228
|
+
float* __restrict__ prev_adjacent) {
|
|
229
|
+
const int64_t t = static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
|
|
230
|
+
if (t >= plane_size) {
|
|
231
|
+
return;
|
|
232
|
+
}
|
|
233
|
+
const float na = field[mur_plane_offset(axis, adjacent_index, t, ny, nz)];
|
|
234
|
+
const float pb = prev_boundary[t];
|
|
235
|
+
const float pa = prev_adjacent[t];
|
|
236
|
+
// E_boundary(n+1) = E_adjacent(n) + coef * (E_adjacent(n+1) - E_boundary(n)).
|
|
237
|
+
const float nb = pa + coef * (na - pb);
|
|
238
|
+
field[mur_plane_offset(axis, boundary_index, t, ny, nz)] = nb;
|
|
239
|
+
prev_boundary[t] = nb;
|
|
240
|
+
prev_adjacent[t] = na;
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
__global__ void sibc_surface_kernel(
|
|
244
|
+
int64_t plane_size,
|
|
245
|
+
int axis,
|
|
246
|
+
int e_ny,
|
|
247
|
+
int e_nz,
|
|
248
|
+
int h_ny,
|
|
249
|
+
int h_nz,
|
|
250
|
+
int e_index,
|
|
251
|
+
int h_index,
|
|
252
|
+
float sign,
|
|
253
|
+
float surface_r,
|
|
254
|
+
float surface_l_over_dt,
|
|
255
|
+
float* __restrict__ electric,
|
|
256
|
+
const float* __restrict__ magnetic,
|
|
257
|
+
float* __restrict__ h_prev) {
|
|
258
|
+
const int64_t t = static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
|
|
259
|
+
if (t >= plane_size) {
|
|
260
|
+
return;
|
|
261
|
+
}
|
|
262
|
+
const float h_now = magnetic[mur_plane_offset(axis, h_index, t, h_ny, h_nz)];
|
|
263
|
+
electric[mur_plane_offset(axis, e_index, t, e_ny, e_nz)] =
|
|
264
|
+
sign * (surface_r * h_now + surface_l_over_dt * (h_now - h_prev[t]));
|
|
265
|
+
h_prev[t] = h_now;
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
} // namespace
|
|
269
|
+
|
|
270
|
+
void clamp_field_face_cuda(torch::stable::Tensor field, int64_t axis, int64_t side) {
|
|
271
|
+
check_field3d(field, "field");
|
|
272
|
+
STD_TORCH_CHECK(axis >= 0 && axis < 3, "axis must be in [0, 3)");
|
|
273
|
+
STD_TORCH_CHECK(side == 0 || side == 1, "side must be 0 (low) or 1 (high)");
|
|
274
|
+
const torch::stable::accelerator::DeviceGuard device_guard(field.get_device_index());
|
|
275
|
+
const int nx = static_cast<int>(field.size(0));
|
|
276
|
+
const int ny = static_cast<int>(field.size(1));
|
|
277
|
+
const int nz = static_cast<int>(field.size(2));
|
|
278
|
+
if (field.numel() == 0) {
|
|
279
|
+
return;
|
|
280
|
+
}
|
|
281
|
+
if (axis == 0) {
|
|
282
|
+
if (side == 0) {
|
|
283
|
+
launch_clamp_field_face<0, 0>(nx, ny, nz, field.mutable_data_ptr<float>());
|
|
284
|
+
} else {
|
|
285
|
+
launch_clamp_field_face<0, 1>(nx, ny, nz, field.mutable_data_ptr<float>());
|
|
286
|
+
}
|
|
287
|
+
} else if (axis == 1) {
|
|
288
|
+
if (side == 0) {
|
|
289
|
+
launch_clamp_field_face<1, 0>(nx, ny, nz, field.mutable_data_ptr<float>());
|
|
290
|
+
} else {
|
|
291
|
+
launch_clamp_field_face<1, 1>(nx, ny, nz, field.mutable_data_ptr<float>());
|
|
292
|
+
}
|
|
293
|
+
} else {
|
|
294
|
+
if (side == 0) {
|
|
295
|
+
launch_clamp_field_face<2, 0>(nx, ny, nz, field.mutable_data_ptr<float>());
|
|
296
|
+
} else {
|
|
297
|
+
launch_clamp_field_face<2, 1>(nx, ny, nz, field.mutable_data_ptr<float>());
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
WITWIN_CUDA_CHECK();
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
void clamp_pec_boundary_cuda(torch::stable::Tensor field, int64_t axis_a, int64_t axis_b) {
|
|
304
|
+
check_field3d(field, "field");
|
|
305
|
+
STD_TORCH_CHECK(axis_a >= 0 && axis_a < 3, "axis_a must be in [0, 3)");
|
|
306
|
+
STD_TORCH_CHECK(axis_b >= 0 && axis_b < 3, "axis_b must be in [0, 3)");
|
|
307
|
+
const torch::stable::accelerator::DeviceGuard device_guard(field.get_device_index());
|
|
308
|
+
const int64_t nx = field.size(0);
|
|
309
|
+
const int64_t ny = field.size(1);
|
|
310
|
+
const int64_t nz = field.size(2);
|
|
311
|
+
const int64_t face_area_a = face_area(axis_a, nx, ny, nz);
|
|
312
|
+
const int64_t face_area_b = axis_a == axis_b ? 0 : face_area(axis_b, nx, ny, nz);
|
|
313
|
+
const int64_t total = 2 * (face_area_a + face_area_b);
|
|
314
|
+
if (total == 0) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const auto launch_for_axis_b = [&](auto axis_a_tag) {
|
|
318
|
+
constexpr int axis_a_value = decltype(axis_a_tag)::value;
|
|
319
|
+
if (axis_b == 0) {
|
|
320
|
+
launch_clamp_pec_boundary<axis_a_value, 0>(
|
|
321
|
+
total, static_cast<int>(nx), static_cast<int>(ny), static_cast<int>(nz), face_area_a, face_area_b, field.mutable_data_ptr<float>());
|
|
322
|
+
} else if (axis_b == 1) {
|
|
323
|
+
launch_clamp_pec_boundary<axis_a_value, 1>(
|
|
324
|
+
total, static_cast<int>(nx), static_cast<int>(ny), static_cast<int>(nz), face_area_a, face_area_b, field.mutable_data_ptr<float>());
|
|
325
|
+
} else {
|
|
326
|
+
launch_clamp_pec_boundary<axis_a_value, 2>(
|
|
327
|
+
total, static_cast<int>(nx), static_cast<int>(ny), static_cast<int>(nz), face_area_a, face_area_b, field.mutable_data_ptr<float>());
|
|
328
|
+
}
|
|
329
|
+
};
|
|
330
|
+
if (axis_a == 0) {
|
|
331
|
+
launch_for_axis_b(std::integral_constant<int, 0>{});
|
|
332
|
+
} else if (axis_a == 1) {
|
|
333
|
+
launch_for_axis_b(std::integral_constant<int, 1>{});
|
|
334
|
+
} else {
|
|
335
|
+
launch_for_axis_b(std::integral_constant<int, 2>{});
|
|
336
|
+
}
|
|
337
|
+
WITWIN_CUDA_CHECK();
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
void mur_abc_face_cuda(
|
|
341
|
+
torch::stable::Tensor field,
|
|
342
|
+
int64_t axis,
|
|
343
|
+
int64_t boundary_index,
|
|
344
|
+
int64_t adjacent_index,
|
|
345
|
+
double coef,
|
|
346
|
+
torch::stable::Tensor prev_boundary,
|
|
347
|
+
torch::stable::Tensor prev_adjacent) {
|
|
348
|
+
check_field3d(field, "field");
|
|
349
|
+
check_float32_tensor(prev_boundary, "prev_boundary");
|
|
350
|
+
check_contiguous_tensor(prev_boundary, "prev_boundary");
|
|
351
|
+
check_float32_tensor(prev_adjacent, "prev_adjacent");
|
|
352
|
+
check_contiguous_tensor(prev_adjacent, "prev_adjacent");
|
|
353
|
+
STD_TORCH_CHECK(axis >= 0 && axis < 3, "axis must be in [0, 3)");
|
|
354
|
+
const torch::stable::accelerator::DeviceGuard device_guard(field.get_device_index());
|
|
355
|
+
const int ny = static_cast<int>(field.size(1));
|
|
356
|
+
const int nz = static_cast<int>(field.size(2));
|
|
357
|
+
const int64_t plane_size = prev_boundary.numel();
|
|
358
|
+
STD_TORCH_CHECK(
|
|
359
|
+
prev_adjacent.numel() == plane_size,
|
|
360
|
+
"prev_adjacent and prev_boundary must have the same number of elements");
|
|
361
|
+
if (plane_size == 0) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
mur_abc_face_kernel<<<linear_grid(plane_size), 256, 0, current_cuda_stream()>>>(
|
|
365
|
+
plane_size,
|
|
366
|
+
static_cast<int>(axis),
|
|
367
|
+
ny,
|
|
368
|
+
nz,
|
|
369
|
+
static_cast<int>(boundary_index),
|
|
370
|
+
static_cast<int>(adjacent_index),
|
|
371
|
+
static_cast<float>(coef),
|
|
372
|
+
field.mutable_data_ptr<float>(),
|
|
373
|
+
prev_boundary.mutable_data_ptr<float>(),
|
|
374
|
+
prev_adjacent.mutable_data_ptr<float>());
|
|
375
|
+
WITWIN_CUDA_CHECK();
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
void apply_sibc_surface_cuda(
|
|
379
|
+
torch::stable::Tensor electric,
|
|
380
|
+
const torch::stable::Tensor& magnetic,
|
|
381
|
+
int64_t axis,
|
|
382
|
+
int64_t electric_index,
|
|
383
|
+
int64_t magnetic_index,
|
|
384
|
+
double sign,
|
|
385
|
+
double surface_r,
|
|
386
|
+
double surface_l_over_dt,
|
|
387
|
+
torch::stable::Tensor h_prev) {
|
|
388
|
+
check_field3d(electric, "electric");
|
|
389
|
+
check_field3d(magnetic, "magnetic");
|
|
390
|
+
check_float32_tensor(h_prev, "h_prev");
|
|
391
|
+
check_contiguous_tensor(h_prev, "h_prev");
|
|
392
|
+
check_same_cuda_device(electric, magnetic, "magnetic");
|
|
393
|
+
check_same_cuda_device(electric, h_prev, "h_prev");
|
|
394
|
+
STD_TORCH_CHECK(axis >= 0 && axis < 3, "axis must be in [0, 3)");
|
|
395
|
+
const int64_t e_axis_size = electric.size(axis);
|
|
396
|
+
const int64_t h_axis_size = magnetic.size(axis);
|
|
397
|
+
STD_TORCH_CHECK(electric_index >= 0 && electric_index < e_axis_size, "electric_index is out of bounds");
|
|
398
|
+
STD_TORCH_CHECK(magnetic_index >= 0 && magnetic_index < h_axis_size, "magnetic_index is out of bounds");
|
|
399
|
+
const int64_t plane_size = face_area(axis, magnetic.size(0), magnetic.size(1), magnetic.size(2));
|
|
400
|
+
STD_TORCH_CHECK(h_prev.numel() == plane_size, "h_prev must match the magnetic face area");
|
|
401
|
+
STD_TORCH_CHECK(
|
|
402
|
+
face_area(axis, electric.size(0), electric.size(1), electric.size(2)) == plane_size,
|
|
403
|
+
"electric and magnetic face shapes must match");
|
|
404
|
+
if (plane_size == 0) {
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const torch::stable::accelerator::DeviceGuard device_guard(electric.get_device_index());
|
|
408
|
+
sibc_surface_kernel<<<linear_grid(plane_size), 256, 0, current_cuda_stream()>>>(
|
|
409
|
+
plane_size,
|
|
410
|
+
static_cast<int>(axis),
|
|
411
|
+
static_cast<int>(electric.size(1)),
|
|
412
|
+
static_cast<int>(electric.size(2)),
|
|
413
|
+
static_cast<int>(magnetic.size(1)),
|
|
414
|
+
static_cast<int>(magnetic.size(2)),
|
|
415
|
+
static_cast<int>(electric_index),
|
|
416
|
+
static_cast<int>(magnetic_index),
|
|
417
|
+
static_cast<float>(sign),
|
|
418
|
+
static_cast<float>(surface_r),
|
|
419
|
+
static_cast<float>(surface_l_over_dt),
|
|
420
|
+
electric.mutable_data_ptr<float>(),
|
|
421
|
+
magnetic.mutable_data_ptr<float>(),
|
|
422
|
+
h_prev.mutable_data_ptr<float>());
|
|
423
|
+
WITWIN_CUDA_CHECK();
|
|
424
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
#include <tuple>
|
|
2
|
+
#include <vector>
|
|
3
|
+
|
|
4
|
+
#include <torch/csrc/stable/ops.h>
|
|
5
|
+
|
|
6
|
+
#include "../launch.h"
|
|
7
|
+
#include "../tensors.h"
|
|
8
|
+
#include "common.cuh"
|
|
9
|
+
|
|
10
|
+
namespace {
|
|
11
|
+
|
|
12
|
+
__global__ void noop_kernel() {}
|
|
13
|
+
|
|
14
|
+
__global__ void debug_linear_indices_kernel(
|
|
15
|
+
int64_t total,
|
|
16
|
+
int64_t size_y,
|
|
17
|
+
int64_t size_z,
|
|
18
|
+
int64_t* linear,
|
|
19
|
+
int64_t* i_index,
|
|
20
|
+
int64_t* j_index,
|
|
21
|
+
int64_t* k_index) {
|
|
22
|
+
const int64_t index = static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
|
|
23
|
+
if (index >= total) {
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const Index3D coord = unflatten3d(
|
|
27
|
+
static_cast<unsigned int>(index),
|
|
28
|
+
static_cast<unsigned int>(size_y),
|
|
29
|
+
static_cast<unsigned int>(size_z));
|
|
30
|
+
linear[index] = index;
|
|
31
|
+
i_index[index] = static_cast<int64_t>(coord.i);
|
|
32
|
+
j_index[index] = static_cast<int64_t>(coord.j);
|
|
33
|
+
k_index[index] = static_cast<int64_t>(coord.k);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
} // namespace
|
|
37
|
+
|
|
38
|
+
void synchronize_noop_cuda() {
|
|
39
|
+
noop_kernel<<<1, 1, 0, current_cuda_stream()>>>();
|
|
40
|
+
WITWIN_CUDA_CHECK();
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
std::tuple<
|
|
44
|
+
torch::stable::Tensor,
|
|
45
|
+
torch::stable::Tensor,
|
|
46
|
+
torch::stable::Tensor,
|
|
47
|
+
torch::stable::Tensor>
|
|
48
|
+
debug_linear_indices_cuda(int64_t size_x, int64_t size_y, int64_t size_z) {
|
|
49
|
+
STD_TORCH_CHECK(size_x > 0 && size_y > 0 && size_z > 0, "shape dimensions must be positive");
|
|
50
|
+
const std::vector<int64_t> shape{size_x, size_y, size_z};
|
|
51
|
+
const int64_t total = shape[0] * shape[1] * shape[2];
|
|
52
|
+
const torch::stable::Device device(
|
|
53
|
+
torch::headeronly::DeviceType::CUDA,
|
|
54
|
+
torch::stable::accelerator::getCurrentDeviceIndex());
|
|
55
|
+
auto linear = torch::stable::empty(
|
|
56
|
+
shape, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
57
|
+
auto i_index = torch::stable::empty(
|
|
58
|
+
shape, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
59
|
+
auto j_index = torch::stable::empty(
|
|
60
|
+
shape, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
61
|
+
auto k_index = torch::stable::empty(
|
|
62
|
+
shape, torch::headeronly::ScalarType::Long, std::nullopt, device);
|
|
63
|
+
torch::stable::accelerator::DeviceGuard guard(linear.get_device_index());
|
|
64
|
+
debug_linear_indices_kernel<<<linear_grid(total), 256, 0, current_cuda_stream()>>>(
|
|
65
|
+
total,
|
|
66
|
+
shape[1],
|
|
67
|
+
shape[2],
|
|
68
|
+
linear.mutable_data_ptr<int64_t>(),
|
|
69
|
+
i_index.mutable_data_ptr<int64_t>(),
|
|
70
|
+
j_index.mutable_data_ptr<int64_t>(),
|
|
71
|
+
k_index.mutable_data_ptr<int64_t>());
|
|
72
|
+
WITWIN_CUDA_CHECK();
|
|
73
|
+
return std::make_tuple(linear, i_index, j_index, k_index);
|
|
74
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <type_traits>
|
|
4
|
+
|
|
5
|
+
struct Index3D {
|
|
6
|
+
unsigned int i;
|
|
7
|
+
unsigned int j;
|
|
8
|
+
unsigned int k;
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
// Dispatch a kernel templated on <UniformDecay, UniformCurl>. Uniform
|
|
12
|
+
// coefficients skip the full-volume decay/curl tensor reads, which removes up
|
|
13
|
+
// to two of the six global-memory streams of the field update.
|
|
14
|
+
template <typename LaunchFn>
|
|
15
|
+
inline void dispatch_uniform_coefficients(bool uniform_decay, bool uniform_curl, LaunchFn&& launch) {
|
|
16
|
+
if (uniform_decay) {
|
|
17
|
+
if (uniform_curl) {
|
|
18
|
+
launch(std::integral_constant<bool, true>{}, std::integral_constant<bool, true>{});
|
|
19
|
+
} else {
|
|
20
|
+
launch(std::integral_constant<bool, true>{}, std::integral_constant<bool, false>{});
|
|
21
|
+
}
|
|
22
|
+
} else {
|
|
23
|
+
if (uniform_curl) {
|
|
24
|
+
launch(std::integral_constant<bool, false>{}, std::integral_constant<bool, true>{});
|
|
25
|
+
} else {
|
|
26
|
+
launch(std::integral_constant<bool, false>{}, std::integral_constant<bool, false>{});
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
constexpr int BOUNDARY_NONE = 0;
|
|
32
|
+
constexpr int BOUNDARY_PML = 1;
|
|
33
|
+
constexpr int BOUNDARY_PERIODIC = 2;
|
|
34
|
+
constexpr int BOUNDARY_BLOCH = 3;
|
|
35
|
+
constexpr int BOUNDARY_PEC = 4;
|
|
36
|
+
constexpr int BOUNDARY_PMC = 5;
|
|
37
|
+
|
|
38
|
+
__device__ __forceinline__ Index3D unflatten3d(unsigned int linear, unsigned int size_y, unsigned int size_z) {
|
|
39
|
+
const unsigned int plane = size_y * size_z;
|
|
40
|
+
const unsigned int i = linear / plane;
|
|
41
|
+
const unsigned int remainder = linear - i * plane;
|
|
42
|
+
const unsigned int j = remainder / size_z;
|
|
43
|
+
const unsigned int k = remainder - j * size_z;
|
|
44
|
+
return {i, j, k};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
__device__ __forceinline__ long long offset3d(unsigned int i, unsigned int j, unsigned int k, unsigned int size_y, unsigned int size_z) {
|
|
48
|
+
return (static_cast<long long>(i) * size_y + j) * size_z + k;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
__device__ __forceinline__ int compact_local_index(
|
|
52
|
+
unsigned int coord,
|
|
53
|
+
int low_length,
|
|
54
|
+
int high_start,
|
|
55
|
+
int high_length) {
|
|
56
|
+
if (coord < static_cast<unsigned int>(low_length)) {
|
|
57
|
+
return static_cast<int>(coord);
|
|
58
|
+
}
|
|
59
|
+
if (coord >= static_cast<unsigned int>(high_start) &&
|
|
60
|
+
coord < static_cast<unsigned int>(high_start + high_length)) {
|
|
61
|
+
return low_length + static_cast<int>(coord) - high_start;
|
|
62
|
+
}
|
|
63
|
+
return -1;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
template <int Axis>
|
|
67
|
+
__device__ __forceinline__ long long compact_offset3d_axis(
|
|
68
|
+
unsigned int i,
|
|
69
|
+
unsigned int j,
|
|
70
|
+
unsigned int k,
|
|
71
|
+
unsigned int size_y,
|
|
72
|
+
unsigned int size_z,
|
|
73
|
+
int local,
|
|
74
|
+
unsigned int compact_length) {
|
|
75
|
+
if constexpr (Axis == 0) {
|
|
76
|
+
return offset3d(static_cast<unsigned int>(local), j, k, size_y, size_z);
|
|
77
|
+
} else if constexpr (Axis == 1) {
|
|
78
|
+
return offset3d(i, static_cast<unsigned int>(local), k, compact_length, size_z);
|
|
79
|
+
} else {
|
|
80
|
+
return offset3d(i, j, static_cast<unsigned int>(local), size_y, compact_length);
|
|
81
|
+
}
|
|
82
|
+
}
|