Skip to content

Commit e8059ad

Browse files
Grid correction to Poynting in 2D monitor (#839) (#1003)
Signed-off-by: Lucas Heitzmann Gabrielli <[email protected]>
1 parent d1dfab3 commit e8059ad

File tree

3 files changed

+47
-14
lines changed

3 files changed

+47
-14
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ that the fields match exactly except for a ``pi`` phase shift. This interpretati
2424
- Point-like objects correctly appear as single points using `plt.scatter`.
2525
- Cleaner display of `ArrayLike` in docs.
2626
- `ArrayLike` validation properly fails with `None` or `nan` contents.
27+
- Apply finite grid correction to the fields when calculating the Poynting vector from 2D monitors.
2728

2829
## [2.3.0] - 2023-6-30
2930

tidy3d/components/data/monitor_data.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -197,20 +197,16 @@ def _tangential_dims(self) -> List[str]:
197197
return tangential_dims
198198

199199
@property
200-
def _grid_corrected_fields(self) -> Dict[str, DataArray]:
200+
def _in_plane(self) -> Dict[str, DataArray]:
201201
"""Dictionary of field components with finite grid correction factors applied and symmetry
202202
expanded."""
203203
if len(self.monitor.zero_dims) != 1:
204204
raise DataError("Data must be 2D to apply grid corrections.")
205+
205206
normal_dim = "xyz"[self.monitor.zero_dims[0]]
206207
fields = {}
207-
for field_name, field in self.symmetry_expanded_copy.field_components.items():
208-
eig_val = self.symmetry_eigenvalues[field_name](normal_dim)
209-
if eig_val < 0:
210-
fields[field_name] = field * self.grid_dual_correction
211-
else:
212-
fields[field_name] = field * self.grid_primal_correction
213-
fields[field_name] = fields[field_name].squeeze(dim=normal_dim, drop=True)
208+
for field_name, field in self.grid_corrected_copy.field_components.items():
209+
fields[field_name] = field.squeeze(dim=normal_dim, drop=True)
214210
return fields
215211

216212
@property
@@ -307,7 +303,7 @@ def _tangential_fields(self) -> Dict[str, DataArray]:
307303
----
308304
The finite grid correction factors are applied and symmetry is expanded.
309305
"""
310-
return self._tangential_corrected(self._grid_corrected_fields)
306+
return self._tangential_corrected(self._in_plane)
311307

312308
@property
313309
def _centered_fields(self) -> Dict[str, DataArray]:
@@ -319,7 +315,8 @@ def _centered_fields(self) -> Dict[str, DataArray]:
319315
The finite grid correction factors are applied and symmetry is expanded.
320316
"""
321317

322-
field_components = self._grid_corrected_fields
318+
field_components = self._in_plane
319+
323320
if self.monitor.colocate:
324321
return field_components
325322

@@ -346,6 +343,24 @@ def _centered_tangential_fields(self) -> Dict[str, DataArray]:
346343
"""
347344
return self._tangential_corrected(self._centered_fields)
348345

346+
@property
347+
def grid_corrected_copy(self) -> ElectromagneticFieldData:
348+
"""Return a copy of self with grid correction factors applied (if necessary) and symmetry
349+
expanded."""
350+
field_data = self.symmetry_expanded_copy
351+
if len(self.monitor.zero_dims) != 1:
352+
return field_data
353+
354+
normal_dim = "xyz"[self.monitor.zero_dims[0]]
355+
update = {"grid_primal_correction": 1.0, "grid_dual_correction": 1.0}
356+
for field_name, field in field_data.field_components.items():
357+
eig_val = self.symmetry_eigenvalues[field_name](normal_dim)
358+
if eig_val < 0:
359+
update[field_name] = field * self.grid_dual_correction
360+
else:
361+
update[field_name] = field * self.grid_primal_correction
362+
return field_data.copy(update=update)
363+
349364
@property
350365
def intensity(self) -> ScalarFieldDataArray:
351366
"""Return the sum of the squared absolute electric field components."""

tidy3d/components/data/sim_data.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -216,8 +216,23 @@ def at_centers(self, field_monitor_name: str) -> xr.Dataset:
216216
interpolated to center locations on Yee grid.
217217
"""
218218

219-
# get the data
220-
monitor_data = self.load_field_monitor(field_monitor_name)
219+
return self._at_centers(self.load_field_monitor(field_monitor_name))
220+
221+
def _at_centers(self, monitor_data: xr.Dataset) -> xr.Dataset:
222+
"""return xarray.Dataset representation of field monitor data
223+
co-located at Yee cell centers.
224+
225+
Parameters
226+
----------
227+
monitor_data : xr.Dataset
228+
Monitor data to be co-located.
229+
230+
Returns
231+
-------
232+
xarray.Dataset
233+
Dataset containing all of the fields in the data
234+
interpolated to center locations on Yee grid.
235+
"""
221236

222237
# discretize the monitor and get center locations
223238
sub_grid = self.simulation.discretize(monitor_data.monitor, extend=False)
@@ -233,6 +248,7 @@ def at_centers(self, field_monitor_name: str) -> xr.Dataset:
233248

234249
return monitor_data.colocate(**xyz_kwargs)
235250

251+
# pylint: disable=too-many-locals
236252
def get_poynting_vector(self, field_monitor_name: str) -> xr.Dataset:
237253
"""return ``xarray.Dataset`` of the Poynting vector at Yee cell centers.
238254
@@ -253,8 +269,9 @@ def get_poynting_vector(self, field_monitor_name: str) -> xr.Dataset:
253269
DataArray containing the Poynting vector calculated based on the field components
254270
colocated at the center locations of the Yee grid.
255271
"""
256-
257-
field_dataset = self.at_centers(field_monitor_name)
272+
# Fields from 2D monitors need a correction factor
273+
mon_data = self.load_field_monitor(field_monitor_name).grid_corrected_copy
274+
field_dataset = self._at_centers(mon_data)
258275

259276
time_domain = isinstance(self.monitor_data[field_monitor_name], FieldTimeData)
260277

0 commit comments

Comments
 (0)