From 29face6f1d6821066b639780fc1db95930429092 Mon Sep 17 00:00:00 2001 From: Juho Park Date: Fri, 27 Mar 2026 21:22:54 -0500 Subject: [PATCH 1/2] Add example for extracting reflection/transmission phase conv_solve() returns complex Rayleigh coefficients (R_s, R_p, T_s, T_p) that carry phase information, but this is not shown in existing examples. This example demonstrates: - Accessing result.res.R_s for complex reflection amplitude - Extracting phase with np.angle() - Correct array indexing for 1D gratings: R_s[0, fto] - Phase variation with grating thickness Co-Authored-By: Claude Opus 4.6 (1M context) --- examples/phase_extraction.py | 81 ++++++++++++++++++++++++++++++++++++ 1 file changed, 81 insertions(+) create mode 100644 examples/phase_extraction.py diff --git a/examples/phase_extraction.py b/examples/phase_extraction.py new file mode 100644 index 0000000..ca16da1 --- /dev/null +++ b/examples/phase_extraction.py @@ -0,0 +1,81 @@ +"""Example: Extracting reflection/transmission phase from meent results. + +conv_solve() returns a Result object containing complex Rayleigh +coefficients (R_s, R_p, T_s, T_p) in addition to real-valued +diffraction efficiencies (de_ri, de_ti). + +The complex coefficients carry phase information, which is essential +for metasurface design and wavefront engineering applications. + +Access pattern: + result = mee.conv_solve() + R_s = result.res.R_s # complex array + phase = np.angle(R_s) # phase in radians + +For 1D gratings, R_s has shape (1, 2*fto+1) where the 0th order +is at index [:, fto]. +""" + +import numpy as np +import meent + + +def run(): + wavelength = 900 # nm + n_si = 3.48 + n_air = 1.0 + fto = 10 + + # 1D Si grating on Si substrate + nx = 100 + ucell = np.ones((1, 1, nx)) * n_air + ucell[0, 0, 30:70] = n_si # 40% fill factor + + mee = meent.call_mee( + backend=0, + pol=0, # TE + n_top=n_air, + n_bot=n_si, + theta=0, + fto=[fto], + wavelength=wavelength, + period=[500], + ucell=ucell, + thickness=[200], + type_complex=np.complex128, + ) + + result = mee.conv_solve() + + # --- Diffraction efficiencies (real) --- + de_ri = result.res.de_ri # shape: (1, 2*fto+1) + + # --- Complex Rayleigh coefficients --- + R_s = result.res.R_s # complex reflection amplitude (TE) + T_s = result.res.T_s # complex transmission amplitude (TE) + + # 0th order: index [0, fto] for 1D + r0 = R_s[0, fto] + t0 = T_s[0, fto] + + print("=== 1D Si grating, TE, normal incidence ===") + print(f"Wavelength: {wavelength} nm, Period: 500 nm, Thickness: 200 nm") + print(f"\n0th order reflection:") + print(f" |r0|^2 = {abs(r0)**2:.6f} (de_ri = {de_ri[0, fto]:.6f})") + print(f" phase = {np.degrees(np.angle(r0)):+.2f} deg") + print(f"\n0th order transmission:") + print(f" |t0|^2 = {abs(t0)**2:.6f}") + print(f" phase = {np.degrees(np.angle(t0)):+.2f} deg") + + # --- Phase vs grating thickness --- + print("\n=== Reflection phase vs grating thickness ===") + print(f"{'Thickness (nm)':>15s} {'Phase (deg)':>12s} {'|r0|^2':>10s}") + for t in [50, 100, 150, 200, 250, 300]: + mee.thickness = [t] + res = mee.conv_solve() + r = res.res.R_s[0, fto] + print(f"{t:>15d} {np.degrees(np.angle(r)):>+12.2f} {abs(r)**2:>10.6f}") + + +if __name__ == '__main__': + run() From aefcd88af30bdb133293b37958fedfbfe71026ae Mon Sep 17 00:00:00 2001 From: Juho Park Date: Fri, 27 Mar 2026 21:28:59 -0500 Subject: [PATCH 2/2] Add R_s, R_p, T_s, T_p properties to Result classes Currently, accessing complex reflection/transmission amplitudes requires result.res.R_s. This adds top-level properties so users can write result.R_s directly, consistent with existing result.de_ri. Changes: - ResultNumpy, ResultTorch, ResultJax: add R_s, R_p, T_s, T_p properties - examples/phase_extraction.py: demonstrate usage with result.R_s Co-Authored-By: Claude Opus 4.6 (1M context) --- examples/phase_extraction.py | 9 +++++---- meent/on_jax/emsolver/rcwa.py | 32 ++++++++++++++++++++++++++++++++ meent/on_numpy/emsolver/rcwa.py | 32 ++++++++++++++++++++++++++++++++ meent/on_torch/emsolver/rcwa.py | 32 ++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 4 deletions(-) diff --git a/examples/phase_extraction.py b/examples/phase_extraction.py index ca16da1..e79bc8b 100644 --- a/examples/phase_extraction.py +++ b/examples/phase_extraction.py @@ -9,7 +9,8 @@ Access pattern: result = mee.conv_solve() - R_s = result.res.R_s # complex array + R_s = result.R_s # complex array (top-level property) + R_s = result.R_s # equivalent, via sub-result phase = np.angle(R_s) # phase in radians For 1D gratings, R_s has shape (1, 2*fto+1) where the 0th order @@ -51,8 +52,8 @@ def run(): de_ri = result.res.de_ri # shape: (1, 2*fto+1) # --- Complex Rayleigh coefficients --- - R_s = result.res.R_s # complex reflection amplitude (TE) - T_s = result.res.T_s # complex transmission amplitude (TE) + R_s = result.R_s # complex reflection amplitude (TE) + T_s = result.T_s # complex transmission amplitude (TE) # 0th order: index [0, fto] for 1D r0 = R_s[0, fto] @@ -73,7 +74,7 @@ def run(): for t in [50, 100, 150, 200, 250, 300]: mee.thickness = [t] res = mee.conv_solve() - r = res.res.R_s[0, fto] + r = res.R_s[0, fto] print(f"{t:>15d} {np.degrees(np.angle(r)):>+12.2f} {abs(r)**2:>10.6f}") diff --git a/meent/on_jax/emsolver/rcwa.py b/meent/on_jax/emsolver/rcwa.py index 2839f68..aadc3f2 100644 --- a/meent/on_jax/emsolver/rcwa.py +++ b/meent/on_jax/emsolver/rcwa.py @@ -31,6 +31,38 @@ def de_ti(self): else: return None + @property + def R_s(self): + """Complex reflection amplitude (TE component).""" + if self.res is not None: + return self.res.R_s + else: + return None + + @property + def R_p(self): + """Complex reflection amplitude (TM component).""" + if self.res is not None: + return self.res.R_p + else: + return None + + @property + def T_s(self): + """Complex transmission amplitude (TE component).""" + if self.res is not None: + return self.res.T_s + else: + return None + + @property + def T_p(self): + """Complex transmission amplitude (TM component).""" + if self.res is not None: + return self.res.T_p + else: + return None + class ResultSubJax: def __init__(self, R_s, R_p, T_s, T_p, de_ri, de_ri_s, de_ri_p, de_ti, de_ti_s, de_ti_p): diff --git a/meent/on_numpy/emsolver/rcwa.py b/meent/on_numpy/emsolver/rcwa.py index 429e9b2..9c2885c 100644 --- a/meent/on_numpy/emsolver/rcwa.py +++ b/meent/on_numpy/emsolver/rcwa.py @@ -25,6 +25,38 @@ def de_ti(self): else: return None + @property + def R_s(self): + """Complex reflection amplitude (TE component).""" + if self.res is not None: + return self.res.R_s + else: + return None + + @property + def R_p(self): + """Complex reflection amplitude (TM component).""" + if self.res is not None: + return self.res.R_p + else: + return None + + @property + def T_s(self): + """Complex transmission amplitude (TE component).""" + if self.res is not None: + return self.res.T_s + else: + return None + + @property + def T_p(self): + """Complex transmission amplitude (TM component).""" + if self.res is not None: + return self.res.T_p + else: + return None + class ResultSubNumpy: def __init__(self, R_s, R_p, T_s, T_p, de_ri, de_ri_s, de_ri_p, de_ti, de_ti_s, de_ti_p): diff --git a/meent/on_torch/emsolver/rcwa.py b/meent/on_torch/emsolver/rcwa.py index 41f0ae8..9396df4 100644 --- a/meent/on_torch/emsolver/rcwa.py +++ b/meent/on_torch/emsolver/rcwa.py @@ -28,6 +28,38 @@ def de_ti(self): else: return None + @property + def R_s(self): + """Complex reflection amplitude (TE component).""" + if self.res is not None: + return self.res.R_s + else: + return None + + @property + def R_p(self): + """Complex reflection amplitude (TM component).""" + if self.res is not None: + return self.res.R_p + else: + return None + + @property + def T_s(self): + """Complex transmission amplitude (TE component).""" + if self.res is not None: + return self.res.T_s + else: + return None + + @property + def T_p(self): + """Complex transmission amplitude (TM component).""" + if self.res is not None: + return self.res.T_p + else: + return None + class ResultSubTorch: def __init__(self, R_s, R_p, T_s, T_p, de_ri, de_ri_s, de_ri_p, de_ti, de_ti_s, de_ti_p):