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,502 @@
1
+ from __future__ import annotations
2
+
3
+ import numpy as np
4
+ import torch
5
+
6
+ from ..scene import prepare_scene
7
+ from .excitation import inject_source_terms
8
+ from .io import save_frequency_solution as save_frequency_solution_impl
9
+ from .observers import (
10
+ accumulate_observers as accumulate_observers_impl,
11
+ accumulate_time_observers as accumulate_time_observers_impl,
12
+ add_plane_observer as add_plane_observer_impl,
13
+ add_point_observer as add_point_observer_impl,
14
+ clear_observers as clear_observers_impl,
15
+ clear_time_observers as clear_time_observers_impl,
16
+ get_component_coords as get_component_coords_impl,
17
+ get_observer_results as get_observer_results_impl,
18
+ get_time_observer_results as get_time_observer_results_impl,
19
+ prepare_observers as prepare_observers_impl,
20
+ prepare_time_observers as prepare_time_observers_impl,
21
+ resolve_plane_observer as resolve_plane_observer_impl,
22
+ resolve_point_observer as resolve_point_observer_impl,
23
+ )
24
+ from .plotting import (
25
+ plot_cross_section as plot_cross_section_impl,
26
+ plot_isotropic_3views as plot_isotropic_3views_impl,
27
+ )
28
+ from .postprocess import (
29
+ get_centered_permittivity as get_centered_permittivity_impl,
30
+ get_frequency_solution as get_frequency_solution_impl,
31
+ get_material_permittivity as get_material_permittivity_impl,
32
+ interpolate_yee_to_center as interpolate_yee_to_center_impl,
33
+ )
34
+ from .runtime import (
35
+ initialization as runtime_initialization,
36
+ accumulate_dft as accumulate_dft_impl,
37
+ accumulate_dft_gpu as accumulate_dft_gpu_impl,
38
+ build_dft_step_tables as build_dft_step_tables_impl,
39
+ advance_magnetic_component_dispersive_state as advance_magnetic_component_dispersive_state_impl,
40
+ advance_magnetic_dispersive_state as advance_magnetic_dispersive_state_impl,
41
+ advance_component_dispersive_state as advance_component_dispersive_state_impl,
42
+ advance_dispersive_state as advance_dispersive_state_impl,
43
+ advance_phase as advance_phase_impl,
44
+ apply_magnetic_component_dispersive_currents as apply_magnetic_component_dispersive_currents_impl,
45
+ apply_magnetic_dispersive_corrections as apply_magnetic_dispersive_corrections_impl,
46
+ apply_component_dispersive_currents as apply_component_dispersive_currents_impl,
47
+ apply_dispersive_corrections as apply_dispersive_corrections_impl,
48
+ average_node_to_component as average_node_to_component_impl,
49
+ average_node_to_magnetic_component as average_node_to_magnetic_component_impl,
50
+ build_dispersive_templates as build_dispersive_templates_impl,
51
+ build_magnetic_dispersive_templates as build_magnetic_dispersive_templates_impl,
52
+ build_materials as build_materials_impl,
53
+ build_update_coefficients as build_update_coefficients_impl,
54
+ clamp_field_face as clamp_field_face_impl,
55
+ clamp_pec_boundaries as clamp_pec_boundaries_impl,
56
+ compute_spectral_start_step as compute_spectral_start_step_impl,
57
+ compute_window_weight as compute_window_weight_impl,
58
+ cpml_layout_params as cpml_layout_params_impl,
59
+ enable_dft as enable_dft_impl,
60
+ enforce_pec_boundaries as enforce_pec_boundaries_impl,
61
+ get_fdtd_module,
62
+ init_field as init_field_impl,
63
+ initialize_dispersive_state as initialize_dispersive_state_impl,
64
+ initialize_magnetic_dispersive_state as initialize_magnetic_dispersive_state_impl,
65
+ initialize_solver,
66
+ iter_cpml_memory_regions as iter_cpml_memory_regions_impl,
67
+ normalize_target_frequencies as normalize_target_frequencies_impl,
68
+ reset_dft_runtime_state as reset_dft_runtime_state_impl,
69
+ require_cuda_scene,
70
+ resolve_spectral_window_type as resolve_spectral_window_type_impl,
71
+ solve as solve_impl,
72
+ source_time_kind as source_time_kind_impl,
73
+ sync_dft_entries_from_runtime_state as sync_dft_entries_from_runtime_state_impl,
74
+ sync_dft_legacy_state as sync_dft_legacy_state_impl,
75
+ sync_dft_primary_runtime_state as sync_dft_primary_runtime_state_impl,
76
+ sync_observer_legacy_state as sync_observer_legacy_state_impl,
77
+ sync_observer_primary_state as sync_observer_primary_state_impl,
78
+ synchronize_device as synchronize_device_impl,
79
+ update_kerr_electric_curls as update_kerr_electric_curls_impl,
80
+ update_nonlinear_electric_coefficients as update_nonlinear_electric_coefficients_impl,
81
+ update_electric_fields as update_electric_fields_impl,
82
+ update_electric_fields_bloch as update_electric_fields_bloch_impl,
83
+ update_electric_fields_cpml as update_electric_fields_cpml_impl,
84
+ update_electric_fields_cpml_compressed as update_electric_fields_cpml_compressed_impl,
85
+ update_electric_fields_cpml_dense as update_electric_fields_cpml_dense_impl,
86
+ update_electric_fields_standard as update_electric_fields_standard_impl,
87
+ update_magnetic_fields as update_magnetic_fields_impl,
88
+ update_magnetic_fields_cpml as update_magnetic_fields_cpml_impl,
89
+ update_magnetic_fields_cpml_compressed as update_magnetic_fields_cpml_compressed_impl,
90
+ update_magnetic_fields_cpml_dense as update_magnetic_fields_cpml_dense_impl,
91
+ update_magnetic_fields_standard as update_magnetic_fields_standard_impl,
92
+ )
93
+
94
+ _get_fdtd_module = get_fdtd_module
95
+ _require_cuda_scene = require_cuda_scene
96
+
97
+
98
+ def calculate_required_steps(
99
+ frequency,
100
+ dt,
101
+ c=299792458.0,
102
+ num_cycles=20,
103
+ transient_cycles=15,
104
+ domain_size=None,
105
+ source_time=None,
106
+ ):
107
+ period = 1.0 / frequency
108
+ transient_time = max(transient_cycles, 15) * period
109
+ if domain_size is not None:
110
+ propagation_time = 2 * domain_size / c
111
+ transient_time = max(transient_time, propagation_time * 5)
112
+ if source_time is not None:
113
+ settling_time = (
114
+ float(source_time.get("settling_time", 0.0))
115
+ if isinstance(source_time, dict)
116
+ else float(getattr(source_time, "settling_time", 0.0))
117
+ )
118
+ transient_time = max(transient_time, settling_time)
119
+ total_time = transient_time + num_cycles * period
120
+ return int(total_time / dt)
121
+
122
+
123
+ class FDTD:
124
+ def __init__(self, scene, frequency=1e9, absorber_type="cpml", cpml_config=None):
125
+ runtime_initialization.get_fdtd_module = _get_fdtd_module
126
+ runtime_initialization.require_cuda_scene = _require_cuda_scene
127
+ initialize_solver(
128
+ self,
129
+ prepare_scene(scene),
130
+ frequency=frequency,
131
+ absorber_type=absorber_type,
132
+ cpml_config=cpml_config,
133
+ )
134
+
135
+ def auto_dt(self, dx, dy, dz, frequency, source_time=None, c=299792458.0, steps_per_cycle=30):
136
+ # dx/dy/dz are the per-axis MINIMUM primal spacings (identical to the
137
+ # uniform steps on a uniform grid), so the Courant bound holds on
138
+ # nonuniform grids as well.
139
+ if source_time is not None:
140
+ characteristic_frequency = (
141
+ float(source_time.get("characteristic_frequency", frequency))
142
+ if isinstance(source_time, dict)
143
+ else float(getattr(source_time, "characteristic_frequency", frequency))
144
+ )
145
+ frequency = max(float(frequency), characteristic_frequency)
146
+ period = 1 / frequency
147
+ dt1 = period / steps_per_cycle
148
+ dt2 = 1 / (c * np.sqrt(1 / dx**2 + 1 / dy**2 + 1 / dz**2))
149
+ return min(dt1, dt2)
150
+
151
+ def _normalize_target_frequencies(self, frequencies) -> tuple[float, ...]:
152
+ return normalize_target_frequencies_impl(self, frequencies)
153
+
154
+ def _reset_dft_runtime_state(self):
155
+ reset_dft_runtime_state_impl(self)
156
+
157
+ def _sync_dft_entries_from_runtime_state(self):
158
+ sync_dft_entries_from_runtime_state_impl(self)
159
+
160
+ def _sync_dft_primary_runtime_state(self):
161
+ sync_dft_primary_runtime_state_impl(self)
162
+
163
+ def _sync_dft_legacy_state(self):
164
+ sync_dft_legacy_state_impl(self)
165
+
166
+ def _sync_dft_primary_state(self):
167
+ sync_dft_primary_runtime_state_impl(self)
168
+
169
+ def _sync_observer_legacy_state(self):
170
+ sync_observer_legacy_state_impl(self)
171
+
172
+ def _sync_observer_primary_state(self):
173
+ sync_observer_primary_state_impl(self)
174
+
175
+ def enable_dft(self, frequencies, window_type="hanning", end_step=None):
176
+ enable_dft_impl(self, frequencies, window_type=window_type, end_step=end_step)
177
+
178
+ def _source_time_kind(self):
179
+ return source_time_kind_impl(self)
180
+
181
+ def _resolve_spectral_window_type(self, window_type):
182
+ return resolve_spectral_window_type_impl(self, window_type)
183
+
184
+ def _compute_spectral_start_step(self, frequency, *, window_type=None):
185
+ return compute_spectral_start_step_impl(self, frequency, window_type=window_type)
186
+
187
+ def _compute_window_weight(self, n, start_step=None, end_step=None, window_type=None):
188
+ return compute_window_weight_impl(self, n, start_step=start_step, end_step=end_step, window_type=window_type)
189
+
190
+ def _advance_phase(self, cos_phase, sin_phase, step_cos, step_sin):
191
+ return advance_phase_impl(self, cos_phase, sin_phase, step_cos, step_sin)
192
+
193
+ def _synchronize_device(self):
194
+ synchronize_device_impl(self)
195
+
196
+ def accumulate_dft(self, n, phase_cos=None, phase_sin=None):
197
+ accumulate_dft_impl(self, n, phase_cos=phase_cos, phase_sin=phase_sin)
198
+
199
+ def build_dft_step_tables(self, time_steps):
200
+ return build_dft_step_tables_impl(self, time_steps)
201
+
202
+ def accumulate_dft_gpu(self):
203
+ accumulate_dft_gpu_impl(self)
204
+
205
+ def clear_observers(self):
206
+ clear_observers_impl(self)
207
+
208
+ def add_point_observer(self, name, position, component="Ez"):
209
+ add_point_observer_impl(self, name, position, component=component)
210
+
211
+ def add_plane_observer(self, name, axis="z", position=0.0, component="Ez"):
212
+ add_plane_observer_impl(self, name, axis=axis, position=position, component=component)
213
+
214
+ def _get_component_coords(self, component):
215
+ return get_component_coords_impl(self, component)
216
+
217
+ def _resolve_point_observer(self, observer):
218
+ return resolve_point_observer_impl(self, observer)
219
+
220
+ def _resolve_plane_observer(self, observer):
221
+ return resolve_plane_observer_impl(self, observer)
222
+
223
+ def _prepare_observers(self, frequencies, window_type, time_steps):
224
+ prepare_observers_impl(self, frequencies, window_type, time_steps)
225
+
226
+ def accumulate_observers(self, n, phase_cos=None, phase_sin=None):
227
+ accumulate_observers_impl(self, n, phase_cos=phase_cos, phase_sin=phase_sin)
228
+
229
+ def get_observer_results(self):
230
+ return get_observer_results_impl(self)
231
+
232
+ def clear_time_observers(self):
233
+ clear_time_observers_impl(self)
234
+
235
+ def _prepare_time_observers(self, time_steps):
236
+ prepare_time_observers_impl(self, time_steps)
237
+
238
+ def accumulate_time_observers(self, n):
239
+ accumulate_time_observers_impl(self, n)
240
+
241
+ def get_time_observer_results(self):
242
+ return get_time_observer_results_impl(self)
243
+
244
+ def get_frequency_solution(self, *, frequency=None, freq_index=None, all_frequencies=False):
245
+ return get_frequency_solution_impl(
246
+ self,
247
+ frequency=frequency,
248
+ freq_index=freq_index,
249
+ all_frequencies=all_frequencies,
250
+ )
251
+
252
+ def save_frequency_solution(self, output_path: str):
253
+ save_frequency_solution_impl(self, output_path)
254
+
255
+ def build_materials(self, scene):
256
+ build_materials_impl(self, scene)
257
+
258
+ def _average_node_to_component(self, node_tensor, component_name):
259
+ return average_node_to_component_impl(self, node_tensor, component_name)
260
+
261
+ def _average_node_to_magnetic_component(self, node_tensor, component_name):
262
+ return average_node_to_magnetic_component_impl(self, node_tensor, component_name)
263
+
264
+ def _build_dispersive_templates(self, material_model):
265
+ build_dispersive_templates_impl(self, material_model)
266
+
267
+ def _build_magnetic_dispersive_templates(self, material_model):
268
+ build_magnetic_dispersive_templates_impl(self, material_model)
269
+
270
+ def _initialize_dispersive_state(self):
271
+ initialize_dispersive_state_impl(self)
272
+
273
+ def _initialize_magnetic_dispersive_state(self):
274
+ initialize_magnetic_dispersive_state_impl(self)
275
+
276
+ def _advance_component_dispersive_state(self, component_name, field, *, imag=False):
277
+ advance_component_dispersive_state_impl(self, component_name, field, imag=imag)
278
+
279
+ def _advance_dispersive_state(self):
280
+ advance_dispersive_state_impl(self)
281
+
282
+ def _advance_magnetic_component_dispersive_state(self, component_name, field, *, imag=False):
283
+ advance_magnetic_component_dispersive_state_impl(self, component_name, field, imag=imag)
284
+
285
+ def _advance_magnetic_dispersive_state(self):
286
+ advance_magnetic_dispersive_state_impl(self)
287
+
288
+ def _apply_component_dispersive_currents(self, component_name, field, *, imag=False):
289
+ apply_component_dispersive_currents_impl(self, component_name, field, imag=imag)
290
+
291
+ def _apply_dispersive_corrections(self):
292
+ apply_dispersive_corrections_impl(self)
293
+
294
+ def _apply_magnetic_component_dispersive_currents(self, component_name, field, *, imag=False):
295
+ apply_magnetic_component_dispersive_currents_impl(self, component_name, field, imag=imag)
296
+
297
+ def _apply_magnetic_dispersive_corrections(self):
298
+ apply_magnetic_dispersive_corrections_impl(self)
299
+
300
+ def _build_update_coefficients(self):
301
+ build_update_coefficients_impl(self)
302
+
303
+ def _update_kerr_electric_curls(self):
304
+ update_kerr_electric_curls_impl(self)
305
+
306
+ def _update_nonlinear_electric_coefficients(self):
307
+ update_nonlinear_electric_coefficients_impl(self)
308
+
309
+ def _get_material_permittivity(self):
310
+ return get_material_permittivity_impl(self)
311
+
312
+ def _iter_source_images(self, source_position, cutoff):
313
+ src_x, src_y, src_z = source_position
314
+ boundary = self.scene.boundary
315
+ if not (boundary.uses_kind("periodic") or boundary.uses_kind("bloch")):
316
+ yield (src_x, src_y, src_z), 1.0, 0.0
317
+ return
318
+
319
+ lengths = (
320
+ self.scene.domain_range[1] - self.scene.domain_range[0],
321
+ self.scene.domain_range[3] - self.scene.domain_range[2],
322
+ self.scene.domain_range[5] - self.scene.domain_range[4],
323
+ )
324
+ axis_kinds = tuple(boundary.axis_kind(axis) for axis in ("x", "y", "z"))
325
+ spans = [
326
+ max(0, int(np.ceil(cutoff / length))) if axis_kind in {"periodic", "bloch"} else 0
327
+ for length, axis_kind in zip(lengths, axis_kinds)
328
+ ]
329
+ wavevector = self.scene.bloch_wavevector
330
+
331
+ for sx in range(-spans[0], spans[0] + 1):
332
+ for sy in range(-spans[1], spans[1] + 1):
333
+ for sz in range(-spans[2], spans[2] + 1):
334
+ phase_real = 1.0
335
+ phase_imag = 0.0
336
+ if boundary.uses_kind("bloch"):
337
+ phase_argument = 0.0
338
+ for axis_kind, shift, wave_number, length in zip(axis_kinds, (sx, sy, sz), wavevector, lengths):
339
+ if axis_kind == "bloch":
340
+ phase_argument += wave_number * shift * length
341
+ phase = np.exp(1j * phase_argument)
342
+ phase_real = float(phase.real)
343
+ phase_imag = float(phase.imag)
344
+ yield (
345
+ src_x + sx * lengths[0],
346
+ src_y + sy * lengths[1],
347
+ src_z + sz * lengths[2],
348
+ ), phase_real, phase_imag
349
+
350
+ def _component_plane_spec(self, field_name, axis, plane_index):
351
+ axis_index = {"x": 0, "y": 1, "z": 2}[axis]
352
+ field = getattr(self, field_name)
353
+ sizes = tuple(int(dim) for dim in field.shape)
354
+ offsets = [0, 0, 0]
355
+ offsets[axis_index] = min(max(int(plane_index), 0), sizes[axis_index] - 1)
356
+ shape = list(sizes)
357
+ shape[axis_index] = 1
358
+ return tuple(offsets), tuple(shape)
359
+
360
+ _COMPONENT_HALF_OFFSET_AXES = {
361
+ "Ex": (True, False, False),
362
+ "Ey": (False, True, False),
363
+ "Ez": (False, False, True),
364
+ "Hx": (False, True, True),
365
+ "Hy": (True, False, True),
366
+ "Hz": (True, True, False),
367
+ }
368
+
369
+ def _component_positions(self, field_name, offsets, shape, dtype):
370
+ half_axes = self._COMPONENT_HALF_OFFSET_AXES.get(field_name)
371
+ if half_axes is None:
372
+ raise ValueError(f"Unsupported field component {field_name!r}.")
373
+ scene = self.scene
374
+ axis_coords = (
375
+ (scene.x, scene.x_half),
376
+ (scene.y, scene.y_half),
377
+ (scene.z, scene.z_half),
378
+ )
379
+ px, py, pz = (
380
+ coords[half][offset : offset + size].to(device=self.device, dtype=dtype)
381
+ for coords, half, offset, size in zip(axis_coords, half_axes, offsets, shape)
382
+ )
383
+
384
+ px = px[:, None, None].expand(shape[0], shape[1], shape[2])
385
+ py = py[None, :, None].expand(shape[0], shape[1], shape[2])
386
+ pz = pz[None, None, :].expand(shape[0], shape[1], shape[2])
387
+ return torch.stack((px, py, pz), dim=-1)
388
+
389
+ def _plane_coordinate(self, axis, plane_index):
390
+ axis_values = {"x": self.scene.x, "y": self.scene.y, "z": self.scene.z}[axis]
391
+ plane_index = min(max(int(plane_index), 0), len(axis_values) - 1)
392
+ return float(axis_values[plane_index].item())
393
+
394
+ def _iter_cpml_memory_regions(self, attr_name):
395
+ yield from iter_cpml_memory_regions_impl(self, attr_name)
396
+
397
+ def _cpml_layout_params(self, attr_name):
398
+ return cpml_layout_params_impl(self, attr_name)
399
+
400
+ def _update_magnetic_fields_cpml_dense(self, hx, hy, hz, ex, ey, ez):
401
+ update_magnetic_fields_cpml_dense_impl(self, hx, hy, hz, ex, ey, ez)
402
+
403
+ def _update_magnetic_fields_cpml_compressed(self, hx, hy, hz, ex, ey, ez):
404
+ update_magnetic_fields_cpml_compressed_impl(self, hx, hy, hz, ex, ey, ez)
405
+
406
+ def _update_magnetic_fields_cpml(self, hx, hy, hz, ex, ey, ez):
407
+ update_magnetic_fields_cpml_impl(self, hx, hy, hz, ex, ey, ez)
408
+
409
+ def _update_magnetic_fields_standard(self, hx, hy, hz, ex, ey, ez):
410
+ update_magnetic_fields_standard_impl(self, hx, hy, hz, ex, ey, ez)
411
+
412
+ def _update_magnetic_fields(self, hx, hy, hz, ex, ey, ez):
413
+ update_magnetic_fields_impl(self, hx, hy, hz, ex, ey, ez)
414
+
415
+ def _update_electric_fields_cpml_dense(self, ex, ey, ez, hx, hy, hz):
416
+ update_electric_fields_cpml_dense_impl(self, ex, ey, ez, hx, hy, hz)
417
+
418
+ def _update_electric_fields_cpml_compressed(self, ex, ey, ez, hx, hy, hz):
419
+ update_electric_fields_cpml_compressed_impl(self, ex, ey, ez, hx, hy, hz)
420
+
421
+ def _update_electric_fields_cpml(self, ex, ey, ez, hx, hy, hz):
422
+ update_electric_fields_cpml_impl(self, ex, ey, ez, hx, hy, hz)
423
+
424
+ def _update_electric_fields_standard(self, ex, ey, ez, hx, hy, hz):
425
+ update_electric_fields_standard_impl(self, ex, ey, ez, hx, hy, hz)
426
+
427
+ def _update_electric_fields(self, ex, ey, ez, hx, hy, hz, *, time_value=None):
428
+ update_electric_fields_impl(self, ex, ey, ez, hx, hy, hz, time_value=time_value)
429
+
430
+ def _update_electric_fields_bloch(self):
431
+ update_electric_fields_bloch_impl(self)
432
+
433
+ def _clamp_field_face(self, field, axis, side):
434
+ clamp_field_face_impl(self, field, axis, side)
435
+
436
+ def _enforce_pec_boundaries(self):
437
+ enforce_pec_boundaries_impl(self)
438
+
439
+ def _clamp_pec_boundaries(self):
440
+ clamp_pec_boundaries_impl(self)
441
+
442
+ def init_field(self):
443
+ init_field_impl(self)
444
+
445
+ def add_source(self, n=None, signal=None, time_value=None):
446
+ inject_source_terms(self, n=n, signal=signal, time_value=time_value)
447
+
448
+ def solve(
449
+ self,
450
+ time_steps: int,
451
+ dft_frequency: float = None,
452
+ enable_plot: bool = False,
453
+ dft_window: str = "hanning",
454
+ full_field_dft: bool = True,
455
+ normalize_source: bool = False,
456
+ shutoff: float = 0.0,
457
+ shutoff_check_interval: int = 100,
458
+ use_cuda_graph: bool = False,
459
+ ):
460
+ return solve_impl(
461
+ self,
462
+ time_steps,
463
+ dft_frequency=dft_frequency,
464
+ enable_plot=enable_plot,
465
+ dft_window=dft_window,
466
+ full_field_dft=full_field_dft,
467
+ normalize_source=normalize_source,
468
+ shutoff=shutoff,
469
+ shutoff_check_interval=shutoff_check_interval,
470
+ use_cuda_graph=use_cuda_graph,
471
+ )
472
+
473
+ def _interpolate_yee_to_center(self, freq_solution):
474
+ return interpolate_yee_to_center_impl(self, freq_solution)
475
+
476
+ def _get_centered_permittivity(self):
477
+ return get_centered_permittivity_impl(self)
478
+
479
+ def plot_cross_section(self, axis="z", position=0.0, component="abs", field_log_scale=False,
480
+ figsize=(12, 5), save_path=None, verbose=True):
481
+ plot_cross_section_impl(
482
+ self,
483
+ axis=axis,
484
+ position=position,
485
+ component=component,
486
+ field_log_scale=field_log_scale,
487
+ figsize=figsize,
488
+ save_path=save_path,
489
+ verbose=verbose,
490
+ )
491
+
492
+ def plot_isotropic_3views(self, position=0.0, field_log_scale=True, figsize=(18, 5),
493
+ save_path=None, vmin_db=-60, verbose=True):
494
+ plot_isotropic_3views_impl(
495
+ self,
496
+ position=position,
497
+ field_log_scale=field_log_scale,
498
+ figsize=figsize,
499
+ save_path=save_path,
500
+ vmin_db=vmin_db,
501
+ verbose=verbose,
502
+ )
@@ -0,0 +1,5 @@
1
+ """Maxwell-specific geometry implementations."""
2
+
3
+ from .polyslab import ComplexPolySlab, PolySlab
4
+
5
+ __all__ = ["ComplexPolySlab", "PolySlab"]