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.
Files changed (107) hide show
  1. witwin/maxwell/__init__.py +164 -0
  2. witwin/maxwell/adapters/__init__.py +1 -0
  3. witwin/maxwell/adapters/gds.py +203 -0
  4. witwin/maxwell/adapters/tidy3d.py +1669 -0
  5. witwin/maxwell/adjoint_inputs.py +70 -0
  6. witwin/maxwell/compiler/__init__.py +11 -0
  7. witwin/maxwell/compiler/materials.py +1355 -0
  8. witwin/maxwell/compiler/monitors.py +164 -0
  9. witwin/maxwell/compiler/sources.py +222 -0
  10. witwin/maxwell/fdfd/__init__.py +3 -0
  11. witwin/maxwell/fdfd/adjoint/__init__.py +3 -0
  12. witwin/maxwell/fdfd/adjoint/bridge.py +180 -0
  13. witwin/maxwell/fdfd/ams.py +300 -0
  14. witwin/maxwell/fdfd/krylov.py +280 -0
  15. witwin/maxwell/fdfd/plotting.py +110 -0
  16. witwin/maxwell/fdfd/postprocess.py +33 -0
  17. witwin/maxwell/fdfd/solver.py +1057 -0
  18. witwin/maxwell/fdtd/__init__.py +4 -0
  19. witwin/maxwell/fdtd/adjoint/__init__.py +21 -0
  20. witwin/maxwell/fdtd/adjoint/bridge.py +746 -0
  21. witwin/maxwell/fdtd/adjoint/capabilities.py +29 -0
  22. witwin/maxwell/fdtd/adjoint/core.py +3614 -0
  23. witwin/maxwell/fdtd/adjoint/dispatch.py +684 -0
  24. witwin/maxwell/fdtd/adjoint/native.py +2561 -0
  25. witwin/maxwell/fdtd/adjoint/profiler.py +195 -0
  26. witwin/maxwell/fdtd/adjoint/reverse_common.py +207 -0
  27. witwin/maxwell/fdtd/adjoint/seeds.py +524 -0
  28. witwin/maxwell/fdtd/boundary/__init__.py +37 -0
  29. witwin/maxwell/fdtd/boundary/bloch.py +90 -0
  30. witwin/maxwell/fdtd/boundary/common.py +41 -0
  31. witwin/maxwell/fdtd/boundary/cpml.py +527 -0
  32. witwin/maxwell/fdtd/boundary/runtime.py +209 -0
  33. witwin/maxwell/fdtd/checkpoint.py +227 -0
  34. witwin/maxwell/fdtd/coords.py +32 -0
  35. witwin/maxwell/fdtd/cuda/__init__.py +11 -0
  36. witwin/maxwell/fdtd/cuda/backend.py +3532 -0
  37. witwin/maxwell/fdtd/cuda/build.py +292 -0
  38. witwin/maxwell/fdtd/cuda/extension.cpp +2053 -0
  39. witwin/maxwell/fdtd/cuda/kernels/adjoint.cu +5290 -0
  40. witwin/maxwell/fdtd/cuda/kernels/aniso.cu +1704 -0
  41. witwin/maxwell/fdtd/cuda/kernels/boundary.cu +424 -0
  42. witwin/maxwell/fdtd/cuda/kernels/common.cu +74 -0
  43. witwin/maxwell/fdtd/cuda/kernels/common.cuh +82 -0
  44. witwin/maxwell/fdtd/cuda/kernels/dispersive.cu +782 -0
  45. witwin/maxwell/fdtd/cuda/kernels/electric.cu +3613 -0
  46. witwin/maxwell/fdtd/cuda/kernels/magnetic.cu +781 -0
  47. witwin/maxwell/fdtd/cuda/kernels/observers.cu +347 -0
  48. witwin/maxwell/fdtd/cuda/kernels/projection.cu +211 -0
  49. witwin/maxwell/fdtd/cuda/kernels/sources.cu +1482 -0
  50. witwin/maxwell/fdtd/cuda/kernels/spectral.cu +297 -0
  51. witwin/maxwell/fdtd/cuda/launch.h +23 -0
  52. witwin/maxwell/fdtd/cuda/prebuilt/witwin_maxwell_fdtd_cuda.pyd +0 -0
  53. witwin/maxwell/fdtd/cuda/runtime/__init__.py +6 -0
  54. witwin/maxwell/fdtd/cuda/runtime/dispatcher.py +6 -0
  55. witwin/maxwell/fdtd/cuda/runtime/graph.py +33 -0
  56. witwin/maxwell/fdtd/cuda/tensors.h +35 -0
  57. witwin/maxwell/fdtd/dispersion.py +48 -0
  58. witwin/maxwell/fdtd/evaluation.py +290 -0
  59. witwin/maxwell/fdtd/excitation/__init__.py +27 -0
  60. witwin/maxwell/fdtd/excitation/injection.py +1102 -0
  61. witwin/maxwell/fdtd/excitation/modes.py +1675 -0
  62. witwin/maxwell/fdtd/excitation/spatial.py +469 -0
  63. witwin/maxwell/fdtd/excitation/temporal.py +510 -0
  64. witwin/maxwell/fdtd/excitation/tfsf_apply.py +264 -0
  65. witwin/maxwell/fdtd/excitation/tfsf_common.py +421 -0
  66. witwin/maxwell/fdtd/excitation/tfsf_specs.py +490 -0
  67. witwin/maxwell/fdtd/excitation/tfsf_state.py +778 -0
  68. witwin/maxwell/fdtd/io.py +31 -0
  69. witwin/maxwell/fdtd/material_pullback.py +371 -0
  70. witwin/maxwell/fdtd/meshing/__init__.py +3 -0
  71. witwin/maxwell/fdtd/meshing/autogrid.py +335 -0
  72. witwin/maxwell/fdtd/observers.py +1453 -0
  73. witwin/maxwell/fdtd/plotting.py +121 -0
  74. witwin/maxwell/fdtd/postprocess.py +205 -0
  75. witwin/maxwell/fdtd/runtime/__init__.py +119 -0
  76. witwin/maxwell/fdtd/runtime/initialization.py +236 -0
  77. witwin/maxwell/fdtd/runtime/materials.py +1563 -0
  78. witwin/maxwell/fdtd/runtime/module_cache.py +31 -0
  79. witwin/maxwell/fdtd/runtime/spectral.py +581 -0
  80. witwin/maxwell/fdtd/runtime/stepping.py +1987 -0
  81. witwin/maxwell/fdtd/solver.py +502 -0
  82. witwin/maxwell/geometry/__init__.py +5 -0
  83. witwin/maxwell/geometry/polyslab.py +299 -0
  84. witwin/maxwell/materials.py +3 -0
  85. witwin/maxwell/media.py +1467 -0
  86. witwin/maxwell/monitors.py +743 -0
  87. witwin/maxwell/ports.py +113 -0
  88. witwin/maxwell/postprocess/RCS.py +139 -0
  89. witwin/maxwell/postprocess/__init__.py +42 -0
  90. witwin/maxwell/postprocess/diffraction.py +219 -0
  91. witwin/maxwell/postprocess/directivity.py +152 -0
  92. witwin/maxwell/postprocess/emission.py +67 -0
  93. witwin/maxwell/postprocess/modal.py +324 -0
  94. witwin/maxwell/postprocess/nfft.py +266 -0
  95. witwin/maxwell/postprocess/scattering_parameters.py +358 -0
  96. witwin/maxwell/postprocess/stratton_chu.py +1193 -0
  97. witwin/maxwell/result.py +967 -0
  98. witwin/maxwell/scene.py +1338 -0
  99. witwin/maxwell/simulation.py +659 -0
  100. witwin/maxwell/sources.py +917 -0
  101. witwin/maxwell/visualization/__init__.py +28 -0
  102. witwin/maxwell/visualization/interactive.py +484 -0
  103. witwin/maxwell/visualization/plots.py +568 -0
  104. witwin_maxwell-0.3.0.dist-info/METADATA +184 -0
  105. witwin_maxwell-0.3.0.dist-info/RECORD +107 -0
  106. witwin_maxwell-0.3.0.dist-info/WHEEL +4 -0
  107. witwin_maxwell-0.3.0.dist-info/licenses/LICENSE +13 -0
@@ -0,0 +1,782 @@
1
+ #include "../launch.h"
2
+ #include "../tensors.h"
3
+ #include "common.cuh"
4
+
5
+ namespace {
6
+
7
+ dim3 field_block3d() {
8
+ return dim3(32, 4, 2);
9
+ }
10
+
11
+ dim3 field_grid3d(int64_t nx, int64_t ny, int64_t nz, dim3 block) {
12
+ return dim3(
13
+ static_cast<unsigned int>((nz + block.x - 1) / block.x),
14
+ static_cast<unsigned int>((ny + block.y - 1) / block.y),
15
+ static_cast<unsigned int>((nx + block.z - 1) / block.z));
16
+ }
17
+
18
+ __global__ void update_debye_kernel(
19
+ int64_t total,
20
+ const float* __restrict__ electric,
21
+ const float* __restrict__ drive,
22
+ float decay,
23
+ float inv_dt,
24
+ float* __restrict__ polarization,
25
+ float* __restrict__ current) {
26
+ const int64_t index = static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
27
+ if (index >= total) {
28
+ return;
29
+ }
30
+ const float previous = polarization[index];
31
+ const float next = decay * previous + drive[index] * electric[index];
32
+ polarization[index] = next;
33
+ current[index] = (next - previous) * inv_dt;
34
+ }
35
+
36
+ __global__ void update_drude_kernel(
37
+ int64_t total,
38
+ const float* __restrict__ electric,
39
+ const float* __restrict__ drive,
40
+ float decay,
41
+ float* __restrict__ current) {
42
+ const int64_t index = static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
43
+ if (index >= total) {
44
+ return;
45
+ }
46
+ current[index] = decay * current[index] + drive[index] * electric[index];
47
+ }
48
+
49
+ __global__ void update_lorentz_kernel(
50
+ int64_t total,
51
+ const float* __restrict__ electric,
52
+ const float* __restrict__ drive,
53
+ float decay,
54
+ float restoring,
55
+ float dt,
56
+ float* __restrict__ polarization,
57
+ float* __restrict__ current) {
58
+ const int64_t index = static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
59
+ if (index >= total) {
60
+ return;
61
+ }
62
+ const float previous_current = current[index];
63
+ const float previous_polarization = polarization[index];
64
+ const float next_current =
65
+ decay * previous_current -
66
+ restoring * previous_polarization +
67
+ drive[index] * electric[index];
68
+ current[index] = next_current;
69
+ polarization[index] = previous_polarization + dt * next_current;
70
+ }
71
+
72
+ __global__ void apply_polarization_kernel(
73
+ int64_t total,
74
+ const float* __restrict__ current,
75
+ const float* __restrict__ inv_permittivity,
76
+ float dt,
77
+ float* __restrict__ electric) {
78
+ const int64_t index = static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
79
+ if (index >= total) {
80
+ return;
81
+ }
82
+ electric[index] -= dt * current[index] * inv_permittivity[index];
83
+ }
84
+
85
+ // Space-time modulated variant of the ADE polarization-current subtraction.
86
+ // The modulated E update divides the curl(H) term by the instantaneous
87
+ // modulation factor m_next(x) = 1 + mod_cos*cos(W(x) t_next) - mod_sin*sin(W(x) t_next),
88
+ // with the per-cell angular frequency W(x) supplied as the mod_omega field;
89
+ // for the conservative eps_inf(x,t) = eps_inf(x) * m(x,t) update the dispersive
90
+ // polarization current must be divided by the SAME eps_inf * m_next, so the
91
+ // resonant response and the modulated background stay mutually consistent inside
92
+ // a cell that is both modulated and dispersive. Where the modulation depth is
93
+ // zero (m_next = 1) this reduces bit-exactly to apply_polarization_kernel.
94
+ __global__ void apply_polarization_modulated_kernel(
95
+ int64_t total,
96
+ const float* __restrict__ current,
97
+ const float* __restrict__ inv_permittivity,
98
+ const float* __restrict__ mod_cos,
99
+ const float* __restrict__ mod_sin,
100
+ const float* __restrict__ mod_omega,
101
+ const float* __restrict__ modulation_time,
102
+ float dt,
103
+ float* __restrict__ electric) {
104
+ const int64_t index = static_cast<int64_t>(blockIdx.x) * blockDim.x + threadIdx.x;
105
+ if (index >= total) {
106
+ return;
107
+ }
108
+ // Per-cell modulation frequency: evaluate the new-time phase from this cell's own
109
+ // angular frequency so a dispersive cell divides by the SAME m_next its modulated
110
+ // curl(H) update used, even when the scene mixes several modulation frequencies.
111
+ float sin_next, cos_next;
112
+ sincosf(mod_omega[index] * modulation_time[1], &sin_next, &cos_next);
113
+ const float m_next =
114
+ fmaxf(1.0f + mod_cos[index] * cos_next - mod_sin[index] * sin_next, 1.0e-6f);
115
+ electric[index] -= dt * current[index] * inv_permittivity[index] / m_next;
116
+ }
117
+
118
+ __device__ __forceinline__ int clamp_index(int index, int size) {
119
+ if (index <= 0) {
120
+ return 0;
121
+ }
122
+ const int max_index = size - 1;
123
+ if (index > max_index) {
124
+ return max_index;
125
+ }
126
+ return index;
127
+ }
128
+
129
+ __device__ __forceinline__ float sample_direct(
130
+ const float* __restrict__ field,
131
+ int i,
132
+ int j,
133
+ int k,
134
+ int size_y,
135
+ int size_z) {
136
+ return field[offset3d(
137
+ static_cast<unsigned int>(i),
138
+ static_cast<unsigned int>(j),
139
+ static_cast<unsigned int>(k),
140
+ static_cast<unsigned int>(size_y),
141
+ static_cast<unsigned int>(size_z))];
142
+ }
143
+
144
+ __device__ __forceinline__ float sample_clamped(
145
+ const float* __restrict__ field,
146
+ int i,
147
+ int j,
148
+ int k,
149
+ int size_x,
150
+ int size_y,
151
+ int size_z) {
152
+ return field[offset3d(
153
+ static_cast<unsigned int>(clamp_index(i, size_x)),
154
+ static_cast<unsigned int>(clamp_index(j, size_y)),
155
+ static_cast<unsigned int>(clamp_index(k, size_z)),
156
+ static_cast<unsigned int>(size_y),
157
+ static_cast<unsigned int>(size_z))];
158
+ }
159
+
160
+ // Collocate the three E components onto the Yee edge of `Component`
161
+ // (0 = Ex, 1 = Ey, 2 = Ez). The two off-axis components are 4-point averaged
162
+ // from the surrounding edges (clamped at domain faces); the own component is
163
+ // read directly at `linear`.
164
+ template <int Component>
165
+ __device__ __forceinline__ void collocate_electric_components(
166
+ int i,
167
+ int j,
168
+ int k,
169
+ long long linear,
170
+ int ex_x,
171
+ int ex_y,
172
+ int ex_z,
173
+ int ey_x,
174
+ int ey_y,
175
+ int ey_z,
176
+ int ez_x,
177
+ int ez_y,
178
+ int ez_z,
179
+ const float* __restrict__ ex,
180
+ const float* __restrict__ ey,
181
+ const float* __restrict__ ez,
182
+ float& ex_value,
183
+ float& ey_value,
184
+ float& ez_value) {
185
+ if constexpr (Component == 0) {
186
+ ex_value = ex[linear];
187
+ const bool ey_interior = i + 1 < ey_x && j > 0 && j < ey_y && k < ey_z;
188
+ ey_value = ey_interior
189
+ ? 0.25f * (
190
+ sample_direct(ey, i, j - 1, k, ey_y, ey_z) +
191
+ sample_direct(ey, i, j, k, ey_y, ey_z) +
192
+ sample_direct(ey, i + 1, j - 1, k, ey_y, ey_z) +
193
+ sample_direct(ey, i + 1, j, k, ey_y, ey_z))
194
+ : 0.25f * (
195
+ sample_clamped(ey, i, j - 1, k, ey_x, ey_y, ey_z) +
196
+ sample_clamped(ey, i, j, k, ey_x, ey_y, ey_z) +
197
+ sample_clamped(ey, i + 1, j - 1, k, ey_x, ey_y, ey_z) +
198
+ sample_clamped(ey, i + 1, j, k, ey_x, ey_y, ey_z));
199
+ const bool ez_interior = i + 1 < ez_x && j < ez_y && k > 0 && k < ez_z;
200
+ ez_value = ez_interior
201
+ ? 0.25f * (
202
+ sample_direct(ez, i, j, k - 1, ez_y, ez_z) +
203
+ sample_direct(ez, i, j, k, ez_y, ez_z) +
204
+ sample_direct(ez, i + 1, j, k - 1, ez_y, ez_z) +
205
+ sample_direct(ez, i + 1, j, k, ez_y, ez_z))
206
+ : 0.25f * (
207
+ sample_clamped(ez, i, j, k - 1, ez_x, ez_y, ez_z) +
208
+ sample_clamped(ez, i, j, k, ez_x, ez_y, ez_z) +
209
+ sample_clamped(ez, i + 1, j, k - 1, ez_x, ez_y, ez_z) +
210
+ sample_clamped(ez, i + 1, j, k, ez_x, ez_y, ez_z));
211
+ } else if constexpr (Component == 1) {
212
+ const bool ex_interior = i > 0 && i < ex_x && j + 1 < ex_y && k < ex_z;
213
+ ex_value = ex_interior
214
+ ? 0.25f * (
215
+ sample_direct(ex, i - 1, j, k, ex_y, ex_z) +
216
+ sample_direct(ex, i, j, k, ex_y, ex_z) +
217
+ sample_direct(ex, i - 1, j + 1, k, ex_y, ex_z) +
218
+ sample_direct(ex, i, j + 1, k, ex_y, ex_z))
219
+ : 0.25f * (
220
+ sample_clamped(ex, i - 1, j, k, ex_x, ex_y, ex_z) +
221
+ sample_clamped(ex, i, j, k, ex_x, ex_y, ex_z) +
222
+ sample_clamped(ex, i - 1, j + 1, k, ex_x, ex_y, ex_z) +
223
+ sample_clamped(ex, i, j + 1, k, ex_x, ex_y, ex_z));
224
+ ey_value = ey[linear];
225
+ const bool ez_interior = i < ez_x && j + 1 < ez_y && k > 0 && k < ez_z;
226
+ ez_value = ez_interior
227
+ ? 0.25f * (
228
+ sample_direct(ez, i, j, k - 1, ez_y, ez_z) +
229
+ sample_direct(ez, i, j, k, ez_y, ez_z) +
230
+ sample_direct(ez, i, j + 1, k - 1, ez_y, ez_z) +
231
+ sample_direct(ez, i, j + 1, k, ez_y, ez_z))
232
+ : 0.25f * (
233
+ sample_clamped(ez, i, j, k - 1, ez_x, ez_y, ez_z) +
234
+ sample_clamped(ez, i, j, k, ez_x, ez_y, ez_z) +
235
+ sample_clamped(ez, i, j + 1, k - 1, ez_x, ez_y, ez_z) +
236
+ sample_clamped(ez, i, j + 1, k, ez_x, ez_y, ez_z));
237
+ } else {
238
+ const bool ex_interior = i > 0 && i < ex_x && j < ex_y && k + 1 < ex_z;
239
+ ex_value = ex_interior
240
+ ? 0.25f * (
241
+ sample_direct(ex, i - 1, j, k, ex_y, ex_z) +
242
+ sample_direct(ex, i, j, k, ex_y, ex_z) +
243
+ sample_direct(ex, i - 1, j, k + 1, ex_y, ex_z) +
244
+ sample_direct(ex, i, j, k + 1, ex_y, ex_z))
245
+ : 0.25f * (
246
+ sample_clamped(ex, i - 1, j, k, ex_x, ex_y, ex_z) +
247
+ sample_clamped(ex, i, j, k, ex_x, ex_y, ex_z) +
248
+ sample_clamped(ex, i - 1, j, k + 1, ex_x, ex_y, ex_z) +
249
+ sample_clamped(ex, i, j, k + 1, ex_x, ex_y, ex_z));
250
+ const bool ey_interior = i < ey_x && j > 0 && j < ey_y && k + 1 < ey_z;
251
+ ey_value = ey_interior
252
+ ? 0.25f * (
253
+ sample_direct(ey, i, j - 1, k, ey_y, ey_z) +
254
+ sample_direct(ey, i, j, k, ey_y, ey_z) +
255
+ sample_direct(ey, i, j - 1, k + 1, ey_y, ey_z) +
256
+ sample_direct(ey, i, j, k + 1, ey_y, ey_z))
257
+ : 0.25f * (
258
+ sample_clamped(ey, i, j - 1, k, ey_x, ey_y, ey_z) +
259
+ sample_clamped(ey, i, j, k, ey_x, ey_y, ey_z) +
260
+ sample_clamped(ey, i, j - 1, k + 1, ey_x, ey_y, ey_z) +
261
+ sample_clamped(ey, i, j, k + 1, ey_x, ey_y, ey_z));
262
+ ez_value = ez[linear];
263
+ }
264
+ }
265
+
266
+ template <int Component>
267
+ __global__ void update_kerr_curl_kernel(
268
+ int dynamic_x,
269
+ int dynamic_y,
270
+ int dynamic_z,
271
+ int ex_x,
272
+ int ex_y,
273
+ int ex_z,
274
+ int ey_x,
275
+ int ey_y,
276
+ int ey_z,
277
+ int ez_x,
278
+ int ez_y,
279
+ int ez_z,
280
+ const float* __restrict__ ex,
281
+ const float* __restrict__ ey,
282
+ const float* __restrict__ ez,
283
+ const float* __restrict__ linear_permittivity,
284
+ const float* __restrict__ decay,
285
+ const float* __restrict__ chi3,
286
+ float dt,
287
+ float eps0,
288
+ float* __restrict__ dynamic_curl) {
289
+ const unsigned int k_u = blockIdx.x * blockDim.x + threadIdx.x;
290
+ const unsigned int j_u = blockIdx.y * blockDim.y + threadIdx.y;
291
+ const unsigned int i_u = blockIdx.z * blockDim.z + threadIdx.z;
292
+ if (i_u >= static_cast<unsigned int>(dynamic_x)
293
+ || j_u >= static_cast<unsigned int>(dynamic_y)
294
+ || k_u >= static_cast<unsigned int>(dynamic_z)) {
295
+ return;
296
+ }
297
+ const long long linear = offset3d(i_u, j_u, k_u, dynamic_y, dynamic_z);
298
+ const int i = static_cast<int>(i_u);
299
+ const int j = static_cast<int>(j_u);
300
+ const int k = static_cast<int>(k_u);
301
+
302
+ float ex_value;
303
+ float ey_value;
304
+ float ez_value;
305
+ collocate_electric_components<Component>(
306
+ i, j, k, linear,
307
+ ex_x, ex_y, ex_z,
308
+ ey_x, ey_y, ey_z,
309
+ ez_x, ez_y, ez_z,
310
+ ex, ey, ez,
311
+ ex_value, ey_value, ez_value);
312
+
313
+ float effective =
314
+ linear_permittivity[linear] +
315
+ eps0 * chi3[linear] * (ex_value * ex_value + ey_value * ey_value + ez_value * ez_value);
316
+ const float floor = 1.0e-12f * eps0;
317
+ if (effective < floor) {
318
+ effective = floor;
319
+ }
320
+ dynamic_curl[linear] = (dt / effective) * decay[linear];
321
+ }
322
+
323
+ // General instantaneous-nonlinearity coefficient kernel. Recomposes the
324
+ // semi-implicit lossy decay/curl pair every step from
325
+ // eps_eff = eps_lin + eps0 * (chi2 * E_own + chi3 * |E|^2)
326
+ // sigma = sigma_static + tpa_sigma * |E|^2
327
+ // half = 0.5 * sigma * dt / eps_eff
328
+ // decay = external * (1 - half) / (1 + half)
329
+ // curl = external * (dt / eps_eff) / (1 + half)
330
+ // where `external` carries the PML split-field decay and the PEC open
331
+ // fraction. With all nonlinear channels zero this reproduces the static
332
+ // coefficients of `_electric_update_coefficients` exactly.
333
+ template <int Component>
334
+ __global__ void update_nonlinear_coefficients_kernel(
335
+ int dynamic_x,
336
+ int dynamic_y,
337
+ int dynamic_z,
338
+ int ex_x,
339
+ int ex_y,
340
+ int ex_z,
341
+ int ey_x,
342
+ int ey_y,
343
+ int ey_z,
344
+ int ez_x,
345
+ int ez_y,
346
+ int ez_z,
347
+ const float* __restrict__ ex,
348
+ const float* __restrict__ ey,
349
+ const float* __restrict__ ez,
350
+ const float* __restrict__ linear_permittivity,
351
+ const float* __restrict__ external_decay,
352
+ const float* __restrict__ sigma_static,
353
+ const float* __restrict__ chi2,
354
+ const float* __restrict__ chi3,
355
+ const float* __restrict__ tpa_sigma,
356
+ float dt,
357
+ float eps0,
358
+ float* __restrict__ dynamic_decay,
359
+ float* __restrict__ dynamic_curl) {
360
+ const unsigned int k_u = blockIdx.x * blockDim.x + threadIdx.x;
361
+ const unsigned int j_u = blockIdx.y * blockDim.y + threadIdx.y;
362
+ const unsigned int i_u = blockIdx.z * blockDim.z + threadIdx.z;
363
+ if (i_u >= static_cast<unsigned int>(dynamic_x)
364
+ || j_u >= static_cast<unsigned int>(dynamic_y)
365
+ || k_u >= static_cast<unsigned int>(dynamic_z)) {
366
+ return;
367
+ }
368
+ const long long linear = offset3d(i_u, j_u, k_u, dynamic_y, dynamic_z);
369
+ const int i = static_cast<int>(i_u);
370
+ const int j = static_cast<int>(j_u);
371
+ const int k = static_cast<int>(k_u);
372
+
373
+ float ex_value;
374
+ float ey_value;
375
+ float ez_value;
376
+ collocate_electric_components<Component>(
377
+ i, j, k, linear,
378
+ ex_x, ex_y, ex_z,
379
+ ey_x, ey_y, ey_z,
380
+ ez_x, ez_y, ez_z,
381
+ ex, ey, ez,
382
+ ex_value, ey_value, ez_value);
383
+
384
+ const float field_sq = ex_value * ex_value + ey_value * ey_value + ez_value * ez_value;
385
+ float own_value;
386
+ if constexpr (Component == 0) {
387
+ own_value = ex_value;
388
+ } else if constexpr (Component == 1) {
389
+ own_value = ey_value;
390
+ } else {
391
+ own_value = ez_value;
392
+ }
393
+
394
+ float effective =
395
+ linear_permittivity[linear] +
396
+ eps0 * (chi2[linear] * own_value + chi3[linear] * field_sq);
397
+ const float floor = 1.0e-12f * eps0;
398
+ if (effective < floor) {
399
+ effective = floor;
400
+ }
401
+ float sigma = sigma_static[linear] + tpa_sigma[linear] * field_sq;
402
+ if (sigma < 0.0f) {
403
+ sigma = 0.0f;
404
+ }
405
+ const float half = 0.5f * sigma * dt / effective;
406
+ const float inv_denom = 1.0f / (1.0f + half);
407
+ const float external = external_decay[linear];
408
+ dynamic_decay[linear] = external * (1.0f - half) * inv_denom;
409
+ dynamic_curl[linear] = external * (dt / effective) * inv_denom;
410
+ }
411
+
412
+ template <int Component>
413
+ void launch_kerr_curl_kernel(
414
+ torch::stable::Tensor dynamic_curl,
415
+ const torch::stable::Tensor& ex,
416
+ const torch::stable::Tensor& ey,
417
+ const torch::stable::Tensor& ez,
418
+ const torch::stable::Tensor& linear_permittivity,
419
+ const torch::stable::Tensor& decay,
420
+ const torch::stable::Tensor& chi3,
421
+ double dt,
422
+ double eps0) {
423
+ const dim3 block = field_block3d();
424
+ update_kerr_curl_kernel<Component><<<field_grid3d(dynamic_curl.size(0), dynamic_curl.size(1), dynamic_curl.size(2), block), block, 0, current_cuda_stream()>>>(
425
+ dynamic_curl.size(0),
426
+ dynamic_curl.size(1),
427
+ dynamic_curl.size(2),
428
+ ex.size(0),
429
+ ex.size(1),
430
+ ex.size(2),
431
+ ey.size(0),
432
+ ey.size(1),
433
+ ey.size(2),
434
+ ez.size(0),
435
+ ez.size(1),
436
+ ez.size(2),
437
+ ex.mutable_data_ptr<float>(),
438
+ ey.mutable_data_ptr<float>(),
439
+ ez.mutable_data_ptr<float>(),
440
+ linear_permittivity.mutable_data_ptr<float>(),
441
+ decay.mutable_data_ptr<float>(),
442
+ chi3.mutable_data_ptr<float>(),
443
+ static_cast<float>(dt),
444
+ static_cast<float>(eps0),
445
+ dynamic_curl.mutable_data_ptr<float>());
446
+ }
447
+
448
+ void check_matching_field(const torch::stable::Tensor& reference, const torch::stable::Tensor& value, const char* name) {
449
+ check_float32_tensor(value, name);
450
+ check_contiguous_tensor(value, name);
451
+ check_same_cuda_device(reference, value, name);
452
+ STD_TORCH_CHECK(value.sizes().equals(reference.sizes()), name, " must match field shape");
453
+ }
454
+
455
+ void check_field3d(const torch::stable::Tensor& value, const char* name) {
456
+ check_float32_tensor(value, name);
457
+ check_contiguous_tensor(value, name);
458
+ STD_TORCH_CHECK(value.dim() == 3, name, " must be a 3D tensor");
459
+ }
460
+
461
+ void launch_kerr_curl(
462
+ int component,
463
+ torch::stable::Tensor dynamic_curl,
464
+ const torch::stable::Tensor& ex,
465
+ const torch::stable::Tensor& ey,
466
+ const torch::stable::Tensor& ez,
467
+ const torch::stable::Tensor& linear_permittivity,
468
+ const torch::stable::Tensor& decay,
469
+ const torch::stable::Tensor& chi3,
470
+ double dt,
471
+ double eps0) {
472
+ check_field3d(dynamic_curl, "dynamic_curl");
473
+ check_field3d(ex, "ex");
474
+ check_field3d(ey, "ey");
475
+ check_field3d(ez, "ez");
476
+ check_same_cuda_device(dynamic_curl, ex, "ex");
477
+ check_same_cuda_device(dynamic_curl, ey, "ey");
478
+ check_same_cuda_device(dynamic_curl, ez, "ez");
479
+ check_matching_field(dynamic_curl, linear_permittivity, "linear_permittivity");
480
+ check_matching_field(dynamic_curl, decay, "decay");
481
+ check_matching_field(dynamic_curl, chi3, "chi3");
482
+ STD_TORCH_CHECK(component >= 0 && component < 3, "component must be in [0, 3)");
483
+ if (component == 0) {
484
+ STD_TORCH_CHECK(ex.sizes().equals(dynamic_curl.sizes()), "ex must match dynamic_curl shape");
485
+ } else if (component == 1) {
486
+ STD_TORCH_CHECK(ey.sizes().equals(dynamic_curl.sizes()), "ey must match dynamic_curl shape");
487
+ } else {
488
+ STD_TORCH_CHECK(ez.sizes().equals(dynamic_curl.sizes()), "ez must match dynamic_curl shape");
489
+ }
490
+ torch::stable::accelerator::DeviceGuard guard(dynamic_curl.get_device_index());
491
+ if (component == 0) {
492
+ launch_kerr_curl_kernel<0>(dynamic_curl, ex, ey, ez, linear_permittivity, decay, chi3, dt, eps0);
493
+ } else if (component == 1) {
494
+ launch_kerr_curl_kernel<1>(dynamic_curl, ex, ey, ez, linear_permittivity, decay, chi3, dt, eps0);
495
+ } else {
496
+ launch_kerr_curl_kernel<2>(dynamic_curl, ex, ey, ez, linear_permittivity, decay, chi3, dt, eps0);
497
+ }
498
+ WITWIN_CUDA_CHECK();
499
+ }
500
+
501
+ template <int Component>
502
+ void launch_nonlinear_coefficients_kernel(
503
+ torch::stable::Tensor dynamic_decay,
504
+ torch::stable::Tensor dynamic_curl,
505
+ const torch::stable::Tensor& ex,
506
+ const torch::stable::Tensor& ey,
507
+ const torch::stable::Tensor& ez,
508
+ const torch::stable::Tensor& linear_permittivity,
509
+ const torch::stable::Tensor& external_decay,
510
+ const torch::stable::Tensor& sigma_static,
511
+ const torch::stable::Tensor& chi2,
512
+ const torch::stable::Tensor& chi3,
513
+ const torch::stable::Tensor& tpa_sigma,
514
+ double dt,
515
+ double eps0) {
516
+ const dim3 block = field_block3d();
517
+ update_nonlinear_coefficients_kernel<Component><<<field_grid3d(dynamic_curl.size(0), dynamic_curl.size(1), dynamic_curl.size(2), block), block, 0, current_cuda_stream()>>>(
518
+ dynamic_curl.size(0),
519
+ dynamic_curl.size(1),
520
+ dynamic_curl.size(2),
521
+ ex.size(0),
522
+ ex.size(1),
523
+ ex.size(2),
524
+ ey.size(0),
525
+ ey.size(1),
526
+ ey.size(2),
527
+ ez.size(0),
528
+ ez.size(1),
529
+ ez.size(2),
530
+ ex.mutable_data_ptr<float>(),
531
+ ey.mutable_data_ptr<float>(),
532
+ ez.mutable_data_ptr<float>(),
533
+ linear_permittivity.mutable_data_ptr<float>(),
534
+ external_decay.mutable_data_ptr<float>(),
535
+ sigma_static.mutable_data_ptr<float>(),
536
+ chi2.mutable_data_ptr<float>(),
537
+ chi3.mutable_data_ptr<float>(),
538
+ tpa_sigma.mutable_data_ptr<float>(),
539
+ static_cast<float>(dt),
540
+ static_cast<float>(eps0),
541
+ dynamic_decay.mutable_data_ptr<float>(),
542
+ dynamic_curl.mutable_data_ptr<float>());
543
+ }
544
+
545
+ void launch_nonlinear_coefficients(
546
+ int component,
547
+ torch::stable::Tensor dynamic_decay,
548
+ torch::stable::Tensor dynamic_curl,
549
+ const torch::stable::Tensor& ex,
550
+ const torch::stable::Tensor& ey,
551
+ const torch::stable::Tensor& ez,
552
+ const torch::stable::Tensor& linear_permittivity,
553
+ const torch::stable::Tensor& external_decay,
554
+ const torch::stable::Tensor& sigma_static,
555
+ const torch::stable::Tensor& chi2,
556
+ const torch::stable::Tensor& chi3,
557
+ const torch::stable::Tensor& tpa_sigma,
558
+ double dt,
559
+ double eps0) {
560
+ check_field3d(dynamic_curl, "dynamic_curl");
561
+ check_field3d(ex, "ex");
562
+ check_field3d(ey, "ey");
563
+ check_field3d(ez, "ez");
564
+ check_same_cuda_device(dynamic_curl, ex, "ex");
565
+ check_same_cuda_device(dynamic_curl, ey, "ey");
566
+ check_same_cuda_device(dynamic_curl, ez, "ez");
567
+ check_matching_field(dynamic_curl, dynamic_decay, "dynamic_decay");
568
+ check_matching_field(dynamic_curl, linear_permittivity, "linear_permittivity");
569
+ check_matching_field(dynamic_curl, external_decay, "external_decay");
570
+ check_matching_field(dynamic_curl, sigma_static, "sigma_static");
571
+ check_matching_field(dynamic_curl, chi2, "chi2");
572
+ check_matching_field(dynamic_curl, chi3, "chi3");
573
+ check_matching_field(dynamic_curl, tpa_sigma, "tpa_sigma");
574
+ STD_TORCH_CHECK(component >= 0 && component < 3, "component must be in [0, 3)");
575
+ if (component == 0) {
576
+ STD_TORCH_CHECK(ex.sizes().equals(dynamic_curl.sizes()), "ex must match dynamic_curl shape");
577
+ } else if (component == 1) {
578
+ STD_TORCH_CHECK(ey.sizes().equals(dynamic_curl.sizes()), "ey must match dynamic_curl shape");
579
+ } else {
580
+ STD_TORCH_CHECK(ez.sizes().equals(dynamic_curl.sizes()), "ez must match dynamic_curl shape");
581
+ }
582
+ torch::stable::accelerator::DeviceGuard guard(dynamic_curl.get_device_index());
583
+ if (component == 0) {
584
+ launch_nonlinear_coefficients_kernel<0>(
585
+ dynamic_decay, dynamic_curl, ex, ey, ez, linear_permittivity, external_decay,
586
+ sigma_static, chi2, chi3, tpa_sigma, dt, eps0);
587
+ } else if (component == 1) {
588
+ launch_nonlinear_coefficients_kernel<1>(
589
+ dynamic_decay, dynamic_curl, ex, ey, ez, linear_permittivity, external_decay,
590
+ sigma_static, chi2, chi3, tpa_sigma, dt, eps0);
591
+ } else {
592
+ launch_nonlinear_coefficients_kernel<2>(
593
+ dynamic_decay, dynamic_curl, ex, ey, ez, linear_permittivity, external_decay,
594
+ sigma_static, chi2, chi3, tpa_sigma, dt, eps0);
595
+ }
596
+ WITWIN_CUDA_CHECK();
597
+ }
598
+
599
+ } // namespace
600
+
601
+ void update_debye_current_cuda(
602
+ const torch::stable::Tensor& electric,
603
+ torch::stable::Tensor polarization,
604
+ torch::stable::Tensor current,
605
+ const torch::stable::Tensor& drive,
606
+ double decay,
607
+ double dt) {
608
+ check_float32_tensor(electric, "electric");
609
+ check_contiguous_tensor(electric, "electric");
610
+ check_matching_field(electric, polarization, "polarization");
611
+ check_matching_field(electric, current, "current");
612
+ check_matching_field(electric, drive, "drive");
613
+ torch::stable::accelerator::DeviceGuard guard(electric.get_device_index());
614
+ update_debye_kernel<<<linear_grid(electric.numel()), 256, 0, current_cuda_stream()>>>(
615
+ electric.numel(),
616
+ electric.mutable_data_ptr<float>(),
617
+ drive.mutable_data_ptr<float>(),
618
+ static_cast<float>(decay),
619
+ static_cast<float>(1.0 / dt),
620
+ polarization.mutable_data_ptr<float>(),
621
+ current.mutable_data_ptr<float>());
622
+ WITWIN_CUDA_CHECK();
623
+ }
624
+
625
+ void update_drude_current_cuda(
626
+ const torch::stable::Tensor& electric,
627
+ torch::stable::Tensor current,
628
+ const torch::stable::Tensor& drive,
629
+ double decay) {
630
+ check_float32_tensor(electric, "electric");
631
+ check_contiguous_tensor(electric, "electric");
632
+ check_matching_field(electric, current, "current");
633
+ check_matching_field(electric, drive, "drive");
634
+ torch::stable::accelerator::DeviceGuard guard(electric.get_device_index());
635
+ update_drude_kernel<<<linear_grid(electric.numel()), 256, 0, current_cuda_stream()>>>(
636
+ electric.numel(),
637
+ electric.mutable_data_ptr<float>(),
638
+ drive.mutable_data_ptr<float>(),
639
+ static_cast<float>(decay),
640
+ current.mutable_data_ptr<float>());
641
+ WITWIN_CUDA_CHECK();
642
+ }
643
+
644
+ void update_lorentz_current_cuda(
645
+ const torch::stable::Tensor& electric,
646
+ torch::stable::Tensor polarization,
647
+ torch::stable::Tensor current,
648
+ const torch::stable::Tensor& drive,
649
+ double decay,
650
+ double restoring,
651
+ double dt) {
652
+ check_float32_tensor(electric, "electric");
653
+ check_contiguous_tensor(electric, "electric");
654
+ check_matching_field(electric, polarization, "polarization");
655
+ check_matching_field(electric, current, "current");
656
+ check_matching_field(electric, drive, "drive");
657
+ torch::stable::accelerator::DeviceGuard guard(electric.get_device_index());
658
+ update_lorentz_kernel<<<linear_grid(electric.numel()), 256, 0, current_cuda_stream()>>>(
659
+ electric.numel(),
660
+ electric.mutable_data_ptr<float>(),
661
+ drive.mutable_data_ptr<float>(),
662
+ static_cast<float>(decay),
663
+ static_cast<float>(restoring),
664
+ static_cast<float>(dt),
665
+ polarization.mutable_data_ptr<float>(),
666
+ current.mutable_data_ptr<float>());
667
+ WITWIN_CUDA_CHECK();
668
+ }
669
+
670
+ void apply_polarization_current_cuda(
671
+ torch::stable::Tensor electric,
672
+ const torch::stable::Tensor& current,
673
+ const torch::stable::Tensor& inv_permittivity,
674
+ double dt) {
675
+ check_float32_tensor(electric, "electric");
676
+ check_contiguous_tensor(electric, "electric");
677
+ check_matching_field(electric, current, "current");
678
+ check_matching_field(electric, inv_permittivity, "inv_permittivity");
679
+ torch::stable::accelerator::DeviceGuard guard(electric.get_device_index());
680
+ apply_polarization_kernel<<<linear_grid(electric.numel()), 256, 0, current_cuda_stream()>>>(
681
+ electric.numel(),
682
+ current.mutable_data_ptr<float>(),
683
+ inv_permittivity.mutable_data_ptr<float>(),
684
+ static_cast<float>(dt),
685
+ electric.mutable_data_ptr<float>());
686
+ WITWIN_CUDA_CHECK();
687
+ }
688
+
689
+ void apply_polarization_current_modulated_cuda(
690
+ torch::stable::Tensor electric,
691
+ const torch::stable::Tensor& current,
692
+ const torch::stable::Tensor& inv_permittivity,
693
+ const torch::stable::Tensor& mod_cos,
694
+ const torch::stable::Tensor& mod_sin,
695
+ const torch::stable::Tensor& mod_omega,
696
+ const torch::stable::Tensor& modulation_time,
697
+ double dt) {
698
+ check_float32_tensor(electric, "electric");
699
+ check_contiguous_tensor(electric, "electric");
700
+ check_matching_field(electric, current, "current");
701
+ check_matching_field(electric, inv_permittivity, "inv_permittivity");
702
+ check_matching_field(electric, mod_cos, "mod_cos");
703
+ check_matching_field(electric, mod_sin, "mod_sin");
704
+ check_matching_field(electric, mod_omega, "mod_omega");
705
+ check_float32_tensor(modulation_time, "modulation_time");
706
+ check_contiguous_tensor(modulation_time, "modulation_time");
707
+ check_same_cuda_device(electric, modulation_time, "modulation_time");
708
+ STD_TORCH_CHECK(
709
+ modulation_time.dim() == 1 && modulation_time.numel() == 2,
710
+ "modulation_time must be a contiguous float32 CUDA tensor with two elements");
711
+ torch::stable::accelerator::DeviceGuard guard(electric.get_device_index());
712
+ apply_polarization_modulated_kernel<<<linear_grid(electric.numel()), 256, 0, current_cuda_stream()>>>(
713
+ electric.numel(),
714
+ current.mutable_data_ptr<float>(),
715
+ inv_permittivity.mutable_data_ptr<float>(),
716
+ mod_cos.mutable_data_ptr<float>(),
717
+ mod_sin.mutable_data_ptr<float>(),
718
+ mod_omega.mutable_data_ptr<float>(),
719
+ modulation_time.mutable_data_ptr<float>(),
720
+ static_cast<float>(dt),
721
+ electric.mutable_data_ptr<float>());
722
+ WITWIN_CUDA_CHECK();
723
+ }
724
+
725
+ void update_kerr_ex_curl_cuda(
726
+ torch::stable::Tensor dynamic_curl,
727
+ const torch::stable::Tensor& ex,
728
+ const torch::stable::Tensor& ey,
729
+ const torch::stable::Tensor& ez,
730
+ const torch::stable::Tensor& linear_permittivity,
731
+ const torch::stable::Tensor& ex_decay,
732
+ const torch::stable::Tensor& chi3,
733
+ double dt,
734
+ double eps0) {
735
+ launch_kerr_curl(0, dynamic_curl, ex, ey, ez, linear_permittivity, ex_decay, chi3, dt, eps0);
736
+ }
737
+
738
+ void update_kerr_ey_curl_cuda(
739
+ torch::stable::Tensor dynamic_curl,
740
+ const torch::stable::Tensor& ex,
741
+ const torch::stable::Tensor& ey,
742
+ const torch::stable::Tensor& ez,
743
+ const torch::stable::Tensor& linear_permittivity,
744
+ const torch::stable::Tensor& ey_decay,
745
+ const torch::stable::Tensor& chi3,
746
+ double dt,
747
+ double eps0) {
748
+ launch_kerr_curl(1, dynamic_curl, ex, ey, ez, linear_permittivity, ey_decay, chi3, dt, eps0);
749
+ }
750
+
751
+ void update_kerr_ez_curl_cuda(
752
+ torch::stable::Tensor dynamic_curl,
753
+ const torch::stable::Tensor& ex,
754
+ const torch::stable::Tensor& ey,
755
+ const torch::stable::Tensor& ez,
756
+ const torch::stable::Tensor& linear_permittivity,
757
+ const torch::stable::Tensor& ez_decay,
758
+ const torch::stable::Tensor& chi3,
759
+ double dt,
760
+ double eps0) {
761
+ launch_kerr_curl(2, dynamic_curl, ex, ey, ez, linear_permittivity, ez_decay, chi3, dt, eps0);
762
+ }
763
+
764
+ void update_nonlinear_coefficients_cuda(
765
+ torch::stable::Tensor dynamic_decay,
766
+ torch::stable::Tensor dynamic_curl,
767
+ const torch::stable::Tensor& ex,
768
+ const torch::stable::Tensor& ey,
769
+ const torch::stable::Tensor& ez,
770
+ const torch::stable::Tensor& linear_permittivity,
771
+ const torch::stable::Tensor& external_decay,
772
+ const torch::stable::Tensor& sigma_static,
773
+ const torch::stable::Tensor& chi2,
774
+ const torch::stable::Tensor& chi3,
775
+ const torch::stable::Tensor& tpa_sigma,
776
+ int64_t component,
777
+ double dt,
778
+ double eps0) {
779
+ launch_nonlinear_coefficients(
780
+ static_cast<int>(component), dynamic_decay, dynamic_curl, ex, ey, ez,
781
+ linear_permittivity, external_decay, sigma_static, chi2, chi3, tpa_sigma, dt, eps0);
782
+ }